]> gerrit.simantics Code Review - simantics/platform.git/blob - docs/Developer/Database/ResourceAdaptation.md
Rest API for Historian data
[simantics/platform.git] / docs / Developer / Database / ResourceAdaptation.md
1 ## Problem Statement\r
2 \r
3 No language can define itself. There have to be extra-language mechanisms for defining basic concepts of the language. For\r
4 computers to understand the language, this means some code. Here is a basic example:\r
5 \r
6 ~~~\r
7 public class ShapeFactory {\r
8     public static Shape create(Graph g, Resource r) {\r
9         ShapeResources sr = ShapeResource.getInstance(g);\r
10         if(g.isInstanceOf(r, sr.Rectangle)) {\r
11             ...\r
12             return new Rectangle2D.Double(...);\r
13         }\r
14         else if(g.isInstanceOf(r, sr.Ellipse)) {\r
15             ...\r
16             return new Ellipse2D.Double(...);\r
17         }\r
18         ...\r
19 \r
20         throw new IllegalArgumentException("Resource is not a shape or the shape is unsupported.");\r
21     }\r
22 }\r
23 ~~~\r
24 \r
25 This works as long as there is only a fixed set of shapes. Addition of every new shape needs modification to the code.\r
26 We would like to have something like:\r
27 * A declaration telling that instances of Shape can be adapted to objects of Shape class.\r
28 * For each concrete subtype of Shape, a code creating an object of the corresponding Shape class.\r
29 * Declarations connecting subtypes and code snippets.\r
30 * Utility that implements the creation pattern.\r
31 \r
32 ## Solution\r
33 \r
34 Declarations are written into adapters.xml-file that has to be located in the plugin root:\r
35 \r
36 ~~~\r
37 <?xml version="1.0" encoding="UTF-8"?>\r
38 <adapters>\r
39 \r
40     <target interface="org.simantics.form.model.IWidgetModel">\r
41         <baseType uri = "http://www.simantics.org/Form-1.0/Widget"/>\r
42         <type uri = "http://www.simantics.org/Form-1.0/Label"\r
43               class = "org.simantics.form.model.adapters.LabelAdapter"/>\r
44         <type uri = "http://www.simantics.org/Form-1.0/InputText"\r
45               class = "org.simantics.form.model.adapters.InputTextAdapter"/>\r
46         ...\r
47     </target>\r
48 \r
49     <target interface="org.simantics.form.model.ILayoutModel">\r
50         <baseType uri = "http://www.simantics.org/Form-1.0/Layout"/>\r
51 \r
52         <!--\r
53             Direct adaption to the specified class via\r
54             constructor and possible arguments\r
55         -->\r
56         <type uri = "http://www.simantics.org/Form-1.0/GridLayout"\r
57               class = "org.simantics.form.model.adapters.GridLayout">\r
58             <graph/>\r
59             <this/>\r
60         </type>\r
61 \r
62         <!--\r
63             A procedural adapter definition. adapterClass implements\r
64             org.simantics.db.adaption.Adapter to construct an instance\r
65             of the target interface.\r
66         -->\r
67         <adapter uri="http://www.simantics.org/Form-1.0/FormLayout"\r
68               adapterClass="org.simantics.form.model.adapters.FormLayoutAdapter" />\r
69     </target>\r
70 \r
71 </adapters>\r
72 ~~~\r
73 \r
74 Each `<target>...</target>` section defines adaption to given interface.\r
75 \r
76 `<baseType>` gives one or more types where all classes implementing the adaption have been inherited from.\r
77 \r
78 `<type>` defines direct adaptation from instances of given type (**uri**) by construction the specified class (**class**) through Java Reflection API's using static method (**constructor**) if specified and a constructor of the class otherwise whereas `<adapter>` defines adaptation from instances of given type (**uri**) by using the given adapter (**adapterClass**). The adapter has to implement the following interface:\r
79 \r
80 ~~~\r
81 public interface Adapter<T> {\r
82     void adapt(AsyncReadGraph g, Resource r, AsyncProcedure<T> procedure);\r
83 }\r
84 ~~~\r
85 \r
86 In addition the adapter may contain this kind of definitions:\r
87 \r
88 ~~~\r
89       <resource uri="http://www.simantics.org/Layer0-1.0/OrderedSetElements"\r
90           class="org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate"/>\r
91 ~~~\r
92 \r
93 This means that the resource defined by the uri is always adapted to an instance of the given class.\r
94 \r
95 The main difference between `<type>`/`<resource>` definitions and `<adapter>` definitions is that `<type>`/`<resource>` adaptation cannot be used for complex adaptation since both can only be used to adapt to instances of the defined adapter class and nothing else. `<adapter>` on the other hand can perform more complex analysis and return any instance of the adaptation target interface.\r
96 \r
97 Defined adapters can be used with the following synchronous methods, where `clazz`-parameter refers to the interface in the adapter declaration:\r
98 \r
99 ~~~\r
100 public interface ReadGraph {\r
101     ....\r
102     <T> T adapt(Resource resource, Class<T> clazz)\r
103             throws AdaptionException, ValidationException, ServiceException;\r
104 \r
105     <T> T adaptUnique(Resource resource, Class<T> clazz)\r
106             throws AdaptionException, ValidationException, ServiceException;\r
107 \r
108     <T> T getPossibleAdapter(Resource resource, Class<T> clazz)\r
109             throws ValidationException, ServiceException;\r
110 \r
111     <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz)\r
112             throws ValidationException, ServiceException;\r
113     ...\r
114 }\r
115 ~~~\r
116 \r
117 For details, see [[svn:db/trunk/org.simantics.db/src/org/simantics/db/ReadGraph.java|ReadGraph interface]].\r
118 \r
119 In addition to `<adapter>`-elements, the file may contain `<installer>`-elements, with *class*-attribute referring to an implementation of the interface:\r
120 \r
121 ~~~\r
122 public interface AdapterInstaller {\r
123     void install(ReadGraph g, AdaptionService service) throws Exception;\r
124 }\r
125 ~~~\r
126 \r
127 where\r
128 \r
129 ~~~\r
130 public interface AdaptionService {\r
131     <T> void adapt(AsyncReadGraph g,\r
132                    Resource r, Class<T> clazz, boolean possible,\r
133                    AsyncProcedure<T> procedure);\r
134 \r
135     <T> void adaptNew(AsyncReadGraph g,\r
136                       Resource r, Class<T> clazz, boolean possible,\r
137                       AsyncProcedure<T> procedure);\r
138 \r
139     <T> void declareAdapter(Resource type, Class<T> clazz);\r
140 \r
141     <T> void addAdapter(Resource type, Class<T> clazz, Adapter<T> adapter);\r
142 \r
143     <T> void addInstanceAdapter(Resource resource, Class<T> clazz, Adapter<T> adapter);    \r
144 }\r
145 ~~~\r
146 \r
147 The class installs adapters by using method `addAdapter` (and `addInstanceAdapter`).\r
148 You should use the xml-file to define your adapters if possible. The installer-mechanism is provided for cases where you want to install an adapter that is constructed with special parameters.\r
149 \r
150 ### Direct Adapters\r
151 \r
152 Direct adapters are used, when the user has a Resource and wants a specific Java interface e.g. for 2D diagrams, the user has an instance of DIA.Element and obtains an instance of org.simantics.diagram.adapter.ElementFactory. The Java instance can operate on the given resource for data-driven implementation of the ElementFactory.\r
153 \r
154 ### Related Adapters\r
155 \r
156 Related adapters are used, when the user has a relation Resource and a subject Resource and wishes to obtain a Java interface associated to the L0.HasRange of the predicate, configured by a single statement defined by subject and relation. The adapter implementations are bound to the object Resource of the defining statement. The adapter implementation obtains the defining statement as parameter for data-driven implementation.\r
157 \r
158 An example:\r
159 \r
160 ~~~\r
161 L0X.StringAdapter <T L0X.StatementAdapter\r
162 L0.String <T L0.Literal <T L0X.StringAdapter\r
163 \r
164 L0.HasLabel <R L0.HasProperty : L0.FunctionalRelation\r
165   L0.HasRange L0X.StringAdapter\r
166 ~~~\r
167 \r
168 L0X.StringAdapter is defined so that it requires an implementation of an adapter to java.lang.String (there is currently no syntax yet for this).\r
169 \r
170 L0.HasLabel is defined so that it refers to an object, which can be adapted to java.lang.String. This directs the user to obtain labels by using the adapter instead of expecting a L0.String. Thus we can make arbitrary data-driven and procedural implementations of this property.\r
171 \r
172 ## Construction-time Parameters\r
173 Certain parameters can be specified for adapters defined with `<type>` and `<resource>` elements. These arguments will be directly forwarded to a constructor matching this argument list in your adapter implementation class.\r
174 \r
175 \r
176 | Term | Description |\r
177 |--------|--------|\r
178 |`<this/>`|The resource that is being adapted.|\r
179 |`<graph/>`|`ReadGraph` for reading the graph database during construction of the adapted class instance.|\r
180 |`<bundle/>`|`Bundle` class instance which identifies the bundle in which this adapter is defined. Can also be used to specify the referenced bundle explicitly using its symbolic name, e.g. `<bundle>bundle.id</bundle>`.|\r
181 |`<string>FOO</string>`|Any string constant contained as text within the <string> tag. Passed to the constructor as a `java.lang.String` instance.|\r
182 |`<single/>`|Requires attribute uri which must specify a URI to a relation resource. If adaption is performed for resource S, this argument element looks for a single object O from the statement (S, R, O) and passes O as an argument to the adapter class. If no single object O exists, the adapter is given null.|\r
183 |`<related/>`|Requires attribute uri which must specify a URI to a relation resource. If adaption is performed for resource S, this argument element looks for all objects O existing in the database (S, R, O) and the objects to the adapter as a `Collection<Resource>`.|\r
184 |`<orderedSet/>`|Requires attribute uri which must specify a URI to an ordered set resource. Looks for the specified URI in the database, assumes it is an ordered set resource and loads the whole ordered set into a Collection&lt;Resource&gt; instance. This collection is passed as an argument to the adapter class.|\r
185 \r
186 ## See Also\r
187 \r
188 [XML schema for adapter definition XML files](TODO: link to adapters.xsd)\r