Difference between revisions of "Resource Adaptation"
Line 4: | Line 4: | ||
computers to understand the language, this means some code. Here is a basic example: | computers to understand the language, this means some code. Here is a basic example: | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
public class ShapeFactory { | public class ShapeFactory { | ||
public static Shape create(Graph g, Resource r) { | public static Shape create(Graph g, Resource r) { | ||
Line 23: | Line 22: | ||
} | } | ||
} | } | ||
− | </ | + | </pre> |
− | |||
This works as long as there is only a fixed set of shapes. Addition of every new shape needs modification to the code. | This works as long as there is only a fixed set of shapes. Addition of every new shape needs modification to the code. | ||
Line 36: | Line 34: | ||
Declarations are written into adapters.xml-file that has to be located in the plugin root: | Declarations are written into adapters.xml-file that has to be located in the plugin root: | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||
<adapters> | <adapters> | ||
Line 70: | Line 67: | ||
</adapters> | </adapters> | ||
− | </ | + | </pre> |
− | |||
Each <code><target>...</target></code> section defines adaption to given interface. | Each <code><target>...</target></code> section defines adaption to given interface. | ||
Line 77: | Line 73: | ||
<code><baseType></code> gives one or more types where all classes implementing the adaption have been inherited from. | <code><baseType></code> gives one or more types where all classes implementing the adaption have been inherited from. | ||
− | <code><type></code> defines direct adaptation from instances of given type ('''uri''') by construction the specified class ('''class''') through Java Reflection API's whereas <code><adapter></code> defines adaptation from instances of given type ('''uri''') by using the given adapter ('''adapterClass'''). The adapter has | + | <code><type></code> defines direct adaptation from instances of given type ('''uri''') by construction the specified class ('''class''') through Java Reflection API's whereas <code><adapter></code> defines adaptation from instances of given type ('''uri''') by using the given adapter ('''adapterClass'''). The adapter has to implement the following interface: |
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
− | |||
public interface Adapter<T> { | public interface Adapter<T> { | ||
void adapt(AsyncReadGraph g, Resource r, AsyncProcedure<T> procedure); | void adapt(AsyncReadGraph g, Resource r, AsyncProcedure<T> procedure); | ||
} | } | ||
− | </ | + | </pre> |
− | |||
In addition the adapter may contain this kind of definitions: | In addition the adapter may contain this kind of definitions: | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
<resource uri="http://www.simantics.org/Layer0-1.0/OrderedSetElements" | <resource uri="http://www.simantics.org/Layer0-1.0/OrderedSetElements" | ||
class="org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate"/> | class="org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate"/> | ||
− | </ | + | </pre> |
− | |||
This means that the resource defined by the uri is always adapted to an instance of the given class. | This means that the resource defined by the uri is always adapted to an instance of the given class. | ||
Line 98: | Line 89: | ||
Defined adapters can be used with the following synchronous methods, where <code>clazz</code>-parameter refers to the interface in the adapter declaration: | Defined adapters can be used with the following synchronous methods, where <code>clazz</code>-parameter refers to the interface in the adapter declaration: | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
public interface ReadGraph { | public interface ReadGraph { | ||
.... | .... | ||
Line 108: | Line 98: | ||
... | ... | ||
} | } | ||
− | </ | + | </pre> |
− | |||
For details, see [[svn:db/trunk/org.simantics.db/src/org/simantics/db/ReadGraph.java|ReadGraph interface]]. | For details, see [[svn:db/trunk/org.simantics.db/src/org/simantics/db/ReadGraph.java|ReadGraph interface]]. | ||
In addition to <code><adapter></code>-elements, the file may contain <code><installer></code>-elements, with ''class''-attribute referring to an implementation of the interface: | In addition to <code><adapter></code>-elements, the file may contain <code><installer></code>-elements, with ''class''-attribute referring to an implementation of the interface: | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
public interface AdapterInstaller { | public interface AdapterInstaller { | ||
void install(ReadGraph g, AdaptionService service) throws Exception; | void install(ReadGraph g, AdaptionService service) throws Exception; | ||
} | } | ||
− | </ | + | </pre> |
− | |||
where | where | ||
− | < | + | <pre style="white-space: pre-wrap;"> |
− | |||
public interface AdaptionService { | public interface AdaptionService { | ||
<T> void adapt(AsyncReadGraph g, Resource r, Class<T> clazz, boolean possible, AsyncProcedure<T> procedure); | <T> void adapt(AsyncReadGraph g, Resource r, Class<T> clazz, boolean possible, AsyncProcedure<T> procedure); | ||
Line 130: | Line 116: | ||
<T> void addInstanceAdapter(Resource resource, Class<T> clazz, Adapter<T> adapter); | <T> void addInstanceAdapter(Resource resource, Class<T> clazz, Adapter<T> adapter); | ||
} | } | ||
− | </ | + | </pre> |
− | |||
The class installs adapters by using method <code>addAdapter</code> (and <code>addInstanceAdapter</code>). | The class installs adapters by using method <code>addAdapter</code> (and <code>addInstanceAdapter</code>). | ||
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. | 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. |
Revision as of 11:44, 6 October 2010
Problem Statement
No language can define itself. There have to be extra-language mechanisms for defining basic concepts of the language. For computers to understand the language, this means some code. Here is a basic example:
public class ShapeFactory { public static Shape create(Graph g, Resource r) { ShapeResources sr = ShapeResource.getInstance(g); if(g.isInstanceOf(r, sr.Rectangle)) { ... return new Rectangle2D.Double(...); } else if(g.isInstanceOf(r, sr.Ellipse)) { ... return new Ellipse2D.Double(...); } ... else { throw new IllegalArgumentException("Resource is not a shape or the implementation does not support it."); } } }
This works as long as there is only a fixed set of shapes. Addition of every new shape needs modification to the code. We would like to have something like:
- A declaration telling that instances of Shape can be adapted to objects of Shape class.
- For each concrete subtype of Shape, a code creating an object of the corresponding Shape class.
- Declarations connecting subtypes and code snippets.
- Utility that implements the creation pattern.
Solution
Declarations are written into adapters.xml-file that has to be located in the plugin root:
<?xml version="1.0" encoding="UTF-8"?> <adapters> <target interface="org.simantics.form.model.IWidgetModel"> <baseType uri = "http://www.simantics.org/Form-1.0/Widget"/> <type uri = "http://www.simantics.org/Form-1.0/Label" class = "org.simantics.form.model.adapters.LabelAdapter"/> <type uri = "http://www.simantics.org/Form-1.0/InputText" class = "org.simantics.form.model.adapters.InputTextAdapter"/> ... </target> <target interface="org.simantics.form.model.ILayoutModel"> <baseType uri = "http://www.simantics.org/Form-1.0/Layout"/> <!-- Direct adaption to the specified class via constructor and possible arguments --> <type uri = "http://www.simantics.org/Form-1.0/GridLayout" class = "org.simantics.form.model.adapters.GridLayout"> <graph/> <this/> </type> <!-- A procedural adapter definition. adapterClass implements org.simantics.db.adaption.Adapter to construct an instance of the target interface. --> <adapter uri="http://www.simantics.org/Form-1.0/FormLayout" adapterClass="org.simantics.form.model.adapters.FormLayoutAdapter" /> </target> </adapters>
Each <target>...</target>
section defines adaption to given interface.
<baseType>
gives one or more types where all classes implementing the adaption have been inherited from.
<type>
defines direct adaptation from instances of given type (uri) by construction the specified class (class) through Java Reflection API's whereas <adapter>
defines adaptation from instances of given type (uri) by using the given adapter (adapterClass). The adapter has to implement the following interface:
public interface Adapter<T> { void adapt(AsyncReadGraph g, Resource r, AsyncProcedure<T> procedure); }
In addition the adapter may contain this kind of definitions:
<resource uri="http://www.simantics.org/Layer0-1.0/OrderedSetElements" class="org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate"/>
This means that the resource defined by the uri is always adapted to an instance of the given class.
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.
Defined adapters can be used with the following synchronous methods, where clazz
-parameter refers to the interface in the adapter declaration:
public interface ReadGraph { .... <T> T adapt(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException; <T> T adaptUnique(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException; <T> T getPossibleAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException; <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException; ... }
For details, see ReadGraph interface.
In addition to <adapter>
-elements, the file may contain <installer>
-elements, with class-attribute referring to an implementation of the interface:
public interface AdapterInstaller { void install(ReadGraph g, AdaptionService service) throws Exception; }
where
public interface AdaptionService { <T> void adapt(AsyncReadGraph g, Resource r, Class<T> clazz, boolean possible, AsyncProcedure<T> procedure); <T> void adaptNew(AsyncReadGraph g, Resource r, Class<T> clazz, boolean possible, AsyncProcedure<T> procedure); <T> void declareAdapter(Resource type, Class<T> clazz); <T> void addAdapter(Resource type, Class<T> clazz, Adapter<T> adapter); <T> void addInstanceAdapter(Resource resource, Class<T> clazz, Adapter<T> adapter); }
The class installs adapters by using method addAdapter
(and addInstanceAdapter
).
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.
Adapter Parameters
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.
- <this/>
The resource that is being adapted.
- <graph/>
ReadGraph
for reading the graph database during construction of the adapted class instance.
- <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>
.
- <string>FOO</string>
Any string constant contained as text within the <string> tag. Passed to the constructor as a
java.lang.String
instance.
- <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.
- <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>.
- <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<Resource> instance. This collection is passed as an argument to the adapter class.