]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java
Re-implement URIStringUtils escape and unescape using Unicode
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / Databoard.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2012 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard;\r
13 \r
14 import java.io.IOException;\r
15 import java.lang.reflect.Constructor;\r
16 import java.lang.reflect.InvocationTargetException;\r
17 import java.util.Collections;\r
18 import java.util.Comparator;\r
19 import java.util.HashMap;\r
20 import java.util.Map;\r
21 \r
22 import org.simantics.databoard.adapter.AdaptException;\r
23 import org.simantics.databoard.adapter.Adapter;\r
24 import org.simantics.databoard.adapter.AdapterConstructionException;\r
25 import org.simantics.databoard.adapter.AdapterFactory;\r
26 import org.simantics.databoard.adapter.RuntimeAdaptException;\r
27 import org.simantics.databoard.adapter.RuntimeAdapterConstructionException;\r
28 import org.simantics.databoard.annotations.ArgumentImpl;\r
29 import org.simantics.databoard.annotations.Arguments;\r
30 import org.simantics.databoard.binding.Binding;\r
31 import org.simantics.databoard.binding.VariantBinding;\r
32 import org.simantics.databoard.binding.classfactory.ImmutableClassesFactory;\r
33 import org.simantics.databoard.binding.classfactory.TypeClassFactory;\r
34 import org.simantics.databoard.binding.classfactory.TypeClassSubFactory;\r
35 import org.simantics.databoard.binding.error.BindingConstructionException;\r
36 import org.simantics.databoard.binding.error.BindingException;\r
37 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
38 import org.simantics.databoard.binding.factory.BindingRepository;\r
39 import org.simantics.databoard.binding.factory.DefaultBindingFactory;\r
40 import org.simantics.databoard.binding.factory.JavaUtilBindingsProvider;\r
41 import org.simantics.databoard.binding.factory.MutableBindingFactory;\r
42 import org.simantics.databoard.binding.factory.TroveBindingsProvider;\r
43 import org.simantics.databoard.binding.factory.TypeBindingFactory;\r
44 import org.simantics.databoard.binding.impl.BeanBinding;\r
45 import org.simantics.databoard.binding.impl.ObjectVariantBinding;\r
46 import org.simantics.databoard.binding.impl.StringVariantBinding;\r
47 import org.simantics.databoard.binding.mutable.ImmutableVariantBinding;\r
48 import org.simantics.databoard.binding.mutable.MutableVariant;\r
49 import org.simantics.databoard.binding.mutable.Variant;\r
50 import org.simantics.databoard.binding.reflection.BindingProvider;\r
51 import org.simantics.databoard.binding.reflection.BindingRequest;\r
52 import org.simantics.databoard.binding.reflection.ClassBindingFactory;\r
53 import org.simantics.databoard.binding.reflection.VoidBinding;\r
54 import org.simantics.databoard.serialization.DefaultSerializerFactory;\r
55 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
56 import org.simantics.databoard.serialization.Serializer;\r
57 import org.simantics.databoard.serialization.SerializerConstructionException;\r
58 import org.simantics.databoard.serialization.SerializerFactory;\r
59 import org.simantics.databoard.type.Datatype;\r
60 import org.simantics.databoard.util.Bean;\r
61 import org.simantics.databoard.util.DataValueUtil;\r
62 \r
63 public class Databoard {\r
64 \r
65         // Repositories\r
66 \r
67         /** Repository of mutable bindings */\r
68     public final Map<Datatype, Binding>       mutableBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );\r
69 \r
70     /** Repository of default bindings */\r
71     public final Map<Datatype, Binding>       defaultBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );\r
72 \r
73     /** Repository of class Bindings */\r
74     public final BindingRepository            bindingRepository = new BindingRepository();\r
75 \r
76     /** Repository of serializers */\r
77     public final Map<Binding, Serializer>     serializerRepository        = Collections.synchronizedMap( new HashMap<Binding, Serializer>() ); \r
78         \r
79     \r
80     // Factories\r
81 \r
82     /** Mutable Bindings Factory */\r
83         public final TypeBindingFactory           mutableBindingFactory = new MutableBindingFactory( mutableBindingRepository );\r
84 \r
85         /** Default Bindings Factory */\r
86         public final TypeBindingFactory           defaultBindingFactory = new DefaultBindingFactory( defaultBindingRepository );\r
87 \r
88         /** Reflection based Binding Factory, create binding to class */\r
89     public final ClassBindingFactory             classBindingFactory = new ClassBindingFactory( bindingRepository, defaultBindingFactory );\r
90 \r
91     /** Serializer Factory */\r
92     public final SerializerFactory               serializationFactory = new DefaultSerializerFactory( serializerRepository );\r
93 \r
94     /** Adapter Factory */\r
95         public final AdapterFactory              adapterFactory = new AdapterFactory();\r
96         \r
97         /** Class Factory */ \r
98         public final TypeClassFactory typeClassFactory = new TypeClassFactory();\r
99         \r
100         \r
101         public final VariantBinding VARIANT;                    // Variant      \r
102         public final VariantBinding OBJECT;                     // java.lang.Object ( as variant )      \r
103         public final VariantBinding STR_VARIANT;                // java.lang.String ( as variant )\r
104         public final Binding        BEAN;            // Bean ( as variant )                     \r
105 \r
106         public Databoard() {\r
107         classBindingFactory.addFactory( new TroveBindingsProvider() );\r
108         classBindingFactory.addFactory( new JavaUtilBindingsProvider() );\r
109         \r
110         addDefaultBinding( Datatypes.STRING, Bindings.STRING );\r
111         addDefaultBinding( Datatypes.INTEGER, Bindings.INTEGER );\r
112         addDefaultBinding( Datatypes.BOOLEAN, Bindings.BOOLEAN );\r
113         addDefaultBinding( Datatypes.BYTE, Bindings.BYTE );\r
114         addDefaultBinding( Datatypes.LONG, Bindings.LONG );\r
115         addDefaultBinding( Datatypes.DOUBLE, Bindings.DOUBLE ); \r
116         addDefaultBinding( Datatypes.FLOAT, Bindings.FLOAT );   \r
117         addDefaultBinding( Datatypes.VOID, Bindings.VOID );\r
118         addDefaultBinding( Datatypes.BOOLEAN_ARRAY, Bindings.BOOLEAN_ARRAY );\r
119         addDefaultBinding( Datatypes.BYTE_ARRAY, Bindings.BYTE_ARRAY );\r
120         addDefaultBinding( Datatypes.INTEGER_ARRAY, Bindings.INT_ARRAY );\r
121         addDefaultBinding( Datatypes.LONG_ARRAY, Bindings.LONG_ARRAY );\r
122         addDefaultBinding( Datatypes.FLOAT_ARRAY, Bindings.FLOAT_ARRAY );\r
123         addDefaultBinding( Datatypes.DOUBLE_ARRAY, Bindings.DOUBLE_ARRAY );\r
124         addDefaultBinding( Datatypes.STRING_ARRAY, Bindings.STRING_ARRAY );\r
125         \r
126         VARIANT        = new ImmutableVariantBinding( classBindingFactory, adapterFactory );\r
127         OBJECT         = new ObjectVariantBinding( classBindingFactory, adapterFactory );\r
128         BEAN           = new BeanBinding( classBindingFactory, typeClassFactory, adapterFactory );\r
129         STR_VARIANT    = new StringVariantBinding( serializationFactory, VARIANT );     \r
130 \r
131         // Add sub-factory that creates binding for Bean\r
132         classBindingFactory.addFactory( new DataboardBindings() );\r
133         \r
134                 // Add class factory that constructs basic types\r
135                 typeClassFactory.addFactory( new ImmutableClassesFactory() );\r
136                 \r
137                 // Bindings.databoard cannot initialize itself\r
138                 if (Bindings.databoard != null) {\r
139                         initialize();\r
140                 }\r
141         }\r
142         \r
143         void initialize() {\r
144                 // Add run-time class factory, if objectweb.asm-library is available.\r
145                 try {\r
146                         // Check ASM Exists\r
147                         Class.forName("org.objectweb.asm.ClassWriter");\r
148                         Class<?> y = Class.forName("org.simantics.databoard.binding.classfactory.AsmTypeClassFactory");\r
149                         Constructor<?> c = y.getConstructor( TypeClassFactory.class );\r
150                         TypeClassSubFactory f = (TypeClassSubFactory) c.newInstance(typeClassFactory);\r
151                         typeClassFactory.addFactory( f );\r
152                         \r
153                         BindingRequest br = new BindingRequest( Datatype.class ); \r
154                         Binding datatypeBinding = getBinding( br );\r
155                         typeClassFactory.getRepository().put(datatypeBinding.type(), br);\r
156                 } catch (ClassNotFoundException e) {\r
157                 } catch (InstantiationException e) {\r
158                 } catch (IllegalAccessException e) {\r
159                 } catch (IllegalArgumentException e) {\r
160                 } catch (InvocationTargetException e) {\r
161                 } catch (SecurityException e) {\r
162                 } catch (NoSuchMethodException e) {\r
163                 } catch (BindingConstructionException e) {\r
164                         e.printStackTrace();\r
165                 }\r
166         }\r
167         \r
168         public void clear() {\r
169                 mutableBindingRepository.clear();\r
170                 defaultBindingRepository.clear();\r
171                 bindingRepository.clear();\r
172                 serializerRepository.clear();           \r
173         }\r
174                 \r
175     /**\r
176      * Get or create a binding that is completely mutable java class. \r
177      * \r
178          * DataType           | Class of the bound instance\r
179          * ===================|==================\r
180          * UnionType          | GenericBinding.TaggedObject.class\r
181          * OptionType         | ValueContainer.class\r
182          * RecordType         | Object[].class\r
183          * BooleanType        | MutableBoolean.class\r
184          * DoubleType         | MutableDouble.class\r
185          * FloatType          | MutableFloat.class\r
186          * ByteType           | MutableByte.class\r
187          * IntegerType        | MutableInt.class\r
188          * LongType           | MutableLong.class\r
189          * StringType         | ValueContainer.class\r
190          * ArrayType          | ArrayList.class\r
191          * MapType            | TreeMap.class\r
192          * VariantType        | MutableVariant.class\r
193          * \r
194          * Note, requesting a binding with this convenience method stores the \r
195          * binding and the type with strong reference, thus preventing garbage \r
196          * collection. To allow garbage collection, please use another instance of \r
197          * GenericBindingFactory and binding repository (Map<Datatype, Binding>). <p>\r
198      *\r
199          * @param type the type to create binding to\r
200          * @return binding binding to a mutable class \r
201      */    \r
202     @SuppressWarnings("unchecked")\r
203         public <T extends Binding> T getMutableBinding(Datatype type) {\r
204         try {\r
205                 Binding binding = mutableBindingRepository.get(type);\r
206                 if (binding!=null) return (T) binding;\r
207                 synchronized(mutableBindingRepository) {\r
208                         return (T) mutableBindingFactory.getBinding(type);\r
209                 }\r
210                 } catch (BindingConstructionException e) {\r
211                         // Unexpected - if error is thrown there is fault in GenericBindingScheme\r
212                         throw new RuntimeBindingConstructionException(e);\r
213                 }\r
214     }\r
215     \r
216     /**\r
217      * Get or create a binding based on default java classes, such as \r
218      * Integer.class, or byte[].class. The result is often binding for an \r
219      * immutable classs. These bindings are more efficient than mutable bindings (above).\r
220      * \r
221          * DataType           | Class of the bound instance\r
222          * ===================|==================\r
223      * BooleanType        | Boolean.class\r
224      * ByteType           | Byte.class\r
225      * FloatType          | Float.class\r
226      * DoubleType         | Double.class\r
227      * IntegerType        | Int.class\r
228      * LongType           | Long.class\r
229      * StringType         | String.class\r
230      * UnionType          | TaggedObject.class\r
231      * OptionType         | ValueContainer.class\r
232      * RecordType         | Object[].class\r
233      * MapType            | TreeMap.class\r
234      * VariantType        | Variant.class\r
235      * ArrayType(Boolean) | boolean[].class\r
236      * ArrayType(Byte)    | byte[].class\r
237      * ArrayType(Integer) | int[].class\r
238      * ArrayType(Long)    | long[].class\r
239      * ArrayType(Float)   | float[].class\r
240      * ArrayType(Double)  | double[].class\r
241      * ArrayType(Byte)    | byte[].class\r
242      * ArrayType( T )     | Object[].class\r
243      * \r
244          * Note, requesting a binding with this convenience method stores the \r
245          * binding and the type with strong reference, thus preventing garbage \r
246          * collection. To allow garbage collection, please use another instance of \r
247          * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>\r
248      *\r
249          * @param type the type to create binding to\r
250          * @return binding binding to a mutable class \r
251      */    \r
252     @SuppressWarnings("unchecked")\r
253         public <T extends Binding> T getBinding(Datatype type) {\r
254         try {\r
255                 Binding binding = defaultBindingRepository.get(type);\r
256                 if (binding!=null) return (T) binding;\r
257                 synchronized(defaultBindingRepository) {\r
258                         return (T) defaultBindingFactory.getBinding(type);\r
259                 }\r
260         } catch (BindingConstructionException e) {\r
261                         // Unexpected - if error is thrown there is fault in DefaultBindingScheme\r
262                         throw new RuntimeBindingConstructionException(e);\r
263                 }\r
264     }    \r
265         \r
266         /**\r
267          * Get a binding to a Java Class. Details can be added by placing annotations\r
268          * to the java classes. See more in package org.simantics.databoard.annotations. \r
269          * <p>\r
270          *  \r
271          * Whether the result is a completely mutable or not depends on the \r
272          * requested class. For instance, fields such as Boolean, Integer, Long\r
273          * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.\r
274          * The length of Object[] is not mutable, but length of List<Object> is. <p>\r
275          * \r
276          * Note, requesting a binding with this convenience method stores the \r
277          * binding and the class with strong reference, thus preventing garbage \r
278          * collection. To allow garbage collection, please use another instance of \r
279          * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p> \r
280          * \r
281          * @see ClassBindingFactory  \r
282          * @param clazz \r
283          * @return binding\r
284          * @throws BindingConstructionException\r
285          */\r
286     @SuppressWarnings("unchecked")\r
287         public <T extends Binding> T getBinding(Class<?> clazz)\r
288     throws BindingConstructionException\r
289     {\r
290         Binding binding = bindingRepository.get( clazz );\r
291         if (binding != null) {\r
292                 return (T) binding;\r
293         }\r
294         \r
295         BindingRequest request = new BindingRequest( clazz );\r
296         synchronized(classBindingFactory) {\r
297                 binding = classBindingFactory.construct(request);\r
298         }\r
299                 return (T) binding;\r
300     }\r
301 \r
302     @SuppressWarnings("unchecked")\r
303         public <T extends Binding> T getBinding(BindingRequest request)\r
304     throws BindingConstructionException\r
305     {\r
306         synchronized(classBindingFactory) {\r
307                 return (T) classBindingFactory.construct(request);\r
308         }\r
309     }\r
310     \r
311         /**\r
312          * Get a binding for a Java Class. Use this method to acquire class \r
313          * parameters for a generics class. <p>\r
314          * \r
315          * Example 1: \r
316          * \r
317          *    Binding binding = getBinding(Map.class, String.class, Integer.class);\r
318          *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();\r
319          *    \r
320          * Example 2:\r
321          *    \r
322      *  Binding d = getBinding(List.class, Integer.class);\r
323          *  List<Integer> list = (List<Integer>) d.createRandom(5);\r
324          *    \r
325          * Example 3:\r
326          *    \r
327      *  Binding d = getBinding(List.class, List.class, Integer.class);\r
328          *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);\r
329          * \r
330          * @see ClassBindingFactory  \r
331          * @param clazz\r
332          * @return binding\r
333          * @throws BindingConstructionException\r
334          */\r
335     @SuppressWarnings("unchecked")\r
336         public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)\r
337     throws BindingConstructionException\r
338     {\r
339         BindingRequest request = new BindingRequest( clazz, parameters );\r
340         synchronized(classBindingFactory) {\r
341                 return (T) classBindingFactory.construct(request);\r
342         }\r
343     }    \r
344     \r
345     /**\r
346          * Read binding and type from a class. DataType details and parameters\r
347          * are read as annotations placed in the class.  \r
348          * (See org.simantics.databoard.annotations)\r
349          * <p>\r
350          * As an exception, in the subclasses of {@link Throwable}, the fields of\r
351          * Throwable are omited.\r
352          * <p>\r
353          * This method is used for well-known classes where the caller is 100% sure\r
354          * that a binding is construable without exception. <p> \r
355          * \r
356          * @param clazz\r
357          * @return binding\r
358          * @throws RuntimeBindingConstructionException\r
359      */\r
360         @SuppressWarnings("unchecked")\r
361         public <T extends Binding> T getBindingUnchecked(Class<?> clazz)\r
362     throws RuntimeBindingConstructionException\r
363     {\r
364                 try {\r
365                 return (T) getBinding(clazz);\r
366                 } catch (BindingConstructionException e) {\r
367                         throw new RuntimeBindingConstructionException(e);\r
368                 }\r
369     }    \r
370 \r
371         /**\r
372          * Get a binding for a Java Class. Use this method to acquire class \r
373          * parameters for a generics class. <p>\r
374          * \r
375          * Example 1: \r
376          * \r
377          *    Binding binding = getBinding(Map.class, String.class, Integer.class);\r
378          *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();\r
379          *    \r
380          * Example 2:\r
381          *    \r
382      *  Binding d = getBinding(List.class, Integer.class);\r
383          *  List<Integer> list = (List<Integer>) d.createRandom(5);\r
384          *    \r
385          * Example 3:\r
386          *    \r
387      *  Binding d = getBinding(List.class, List.class, Integer.class);\r
388          *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);\r
389          * \r
390          * @see ClassBindingFactory  \r
391          * @param clazz\r
392          * @return binding\r
393          * @throws BindingConstructionException\r
394          */\r
395     @SuppressWarnings("unchecked")\r
396         public <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)\r
397     throws RuntimeBindingConstructionException\r
398     {\r
399         try {\r
400                 Arguments args = new ArgumentImpl(parameters);\r
401                 BindingRequest request = new BindingRequest( clazz, args );\r
402                 Binding binding = bindingRepository.get( request );\r
403                 if (binding!=null);\r
404                 synchronized(classBindingFactory) {\r
405                         binding = classBindingFactory.construct(request);\r
406                 }\r
407                         return (T) binding;\r
408         } catch (BindingConstructionException e) {\r
409                 throw new RuntimeBindingConstructionException(e);\r
410         }\r
411     }    \r
412     \r
413     /**\r
414      * Add a simple binding to reflection binding factory.\r
415      *  \r
416      * @param binding\r
417      * @param clazz\r
418      * @param parameters parameter classes\r
419      */\r
420     public void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )\r
421     {\r
422         ArgumentImpl args = new ArgumentImpl( parameters );\r
423         BindingRequest request = new BindingRequest( clazz, args );\r
424         bindingRepository.put( request, binding );\r
425     }\r
426     \r
427     /**\r
428      * Add binding factory for compositive bindings \r
429      * \r
430      * @param factory\r
431      */\r
432     public void addBindingFactory( BindingProvider factory )\r
433     {\r
434         classBindingFactory.addFactory( factory );\r
435     }\r
436     \r
437     /**\r
438      * Creates a bean class \r
439      * @param type\r
440      * @return class\r
441      */\r
442     public BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {\r
443         try {\r
444                         return typeClassFactory.getClass(type);\r
445                 } catch (BindingConstructionException e) {\r
446                         throw new RuntimeBindingConstructionException(e);\r
447                 }\r
448     }\r
449 \r
450     /**\r
451      * Creates a bean class \r
452      * @param type\r
453      * @return class\r
454      */\r
455     public Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {\r
456         BindingRequest br = typeClassFactory.getClass(type);\r
457         return br.getClazz();\r
458     }\r
459 \r
460     /**\r
461      * Create binding from datatype that instantiates java classes. \r
462      * RecordTypes are Beans, UnionTypes are Classes with @Union annotation, \r
463      * ArrayTypes are []. \r
464      * \r
465      * @param type\r
466      * @return class\r
467      */\r
468     public Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {\r
469                 try {\r
470                 BindingRequest br = typeClassFactory.getClass(type);\r
471                 return getBinding( br );\r
472                 } catch (BindingConstructionException e) {\r
473                         throw new RuntimeBindingConstructionException(e);\r
474                 }\r
475     }\r
476 \r
477         /**\r
478          * Get serializer that follows Databoard serialization spec.\r
479          *  \r
480          * @param binding\r
481          * @return serializer\r
482          * @throws SerializerConstructionException\r
483          */\r
484         public Serializer getSerializer(Binding binding) throws SerializerConstructionException {\r
485                 return serializationFactory.construct(binding);\r
486         }\r
487 \r
488         /**\r
489          * Get serializer that follows Databoard serialization spec.\r
490          * \r
491          * @param binding\r
492          * @return serializer\r
493          * @throws RuntimeSerializerConstructionException\r
494          */\r
495         public Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {\r
496                 try {\r
497                         return serializationFactory.construct(binding);\r
498                 } catch (SerializerConstructionException e) {\r
499                         throw new RuntimeSerializerConstructionException(e);\r
500                 }\r
501         }\r
502 \r
503         /**\r
504          * Get serializer that follows Databoard serialization spec.\r
505          *  \r
506          * @param clazz\r
507          * @return serializer\r
508          * @throws SerializerConstructionException\r
509          */\r
510         public Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {\r
511                 try {\r
512                         Binding binding = getBinding(clazz);\r
513                         return serializationFactory.construct(binding);\r
514                 } catch (BindingConstructionException e) {\r
515                         throw new SerializerConstructionException( e );\r
516                 }\r
517         }\r
518 \r
519         /**\r
520          * Get serializer that follows Databoard serialization spec.\r
521          * \r
522          * @param clazz\r
523          * @return serializer serializer\r
524          * @throws RuntimeSerializerConstructionException\r
525          */\r
526         public Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {\r
527                 try {\r
528                         Binding binding = getBinding(clazz);\r
529                         return serializationFactory.construct(binding);\r
530                 } catch (SerializerConstructionException e) {\r
531                         throw new RuntimeSerializerConstructionException(e);\r
532                 } catch (BindingConstructionException e) {\r
533                         throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );\r
534                 }\r
535         }       \r
536     /**\r
537      * Create an adapter that adapts two bindings of the same\r
538      * data type.\r
539      * \r
540      * @param domain binding of the source instance\r
541      * @param range binding of the result instance\r
542      * @return result adapter\r
543      * @throws AdapterConstructionException \r
544      */\r
545     public Adapter getAdapter(Binding domain, Binding range)\r
546     throws AdapterConstructionException\r
547     {\r
548         return adapterFactory.getAdapter(domain, range, false, false);\r
549     }\r
550     \r
551     /**\r
552      * Create an adapter that adapts between two bindings of the same\r
553      * data type.\r
554      * \r
555      * @param domain binding of the source instance\r
556      * @param range binding of the result instance\r
557      * @return result adapter\r
558      * @throws AdapterConstructionException \r
559      */\r
560     public Adapter getAdapterUnchecked(Binding domain, Binding range)\r
561     throws RuntimeAdapterConstructionException\r
562     {\r
563         try {\r
564                         return adapterFactory.getAdapter(domain, range, false, false);\r
565                 } catch (AdapterConstructionException e) {\r
566                         throw new RuntimeAdapterConstructionException(e);\r
567                 }\r
568     }\r
569 \r
570     /**\r
571      * Create a type adapter that adapts instances from one Datatype to \r
572      * another. Type Adapter does the following conversions: \r
573      * \r
574      *    o Number Types, e.g. long -> double\r
575      *    o Unit Types, e.g. mph -> km/h\r
576      *    o Record Types, for each field of the range, there must be equal in domain \r
577      *    o Union Types, for each tag type of the domain, there must be equal in range\r
578      * \r
579      * {@link AdaptException} is thrown at runtime, if number conversion is not \r
580      * posible, e.g. converting value 500 from Integer to Byte.\r
581      * Note, there is also a possibility of precision loss, in many conversions\r
582      * e.g. from double to int.\r
583      * \r
584      * @param domain binding of the source instance\r
585      * @param range binding of the result instance\r
586      * @return adapter\r
587      * @throws AdapterConstructionException \r
588      */\r
589     public Adapter getTypeAdapter(Binding domain, Binding range)\r
590     throws AdapterConstructionException\r
591     {\r
592         return adapterFactory.getAdapter(domain, range, true, false);\r
593     }\r
594 \r
595     /**\r
596      * Create a type adapter that adapts instances from one DataType to \r
597      * another. Type Adapter does the following conversions: \r
598      * \r
599      *    o Number Types, e.g. long -> double\r
600      *    o Unit Types, e.g. mph -> km/h\r
601      *    o Record Types, for each field of the range, there must be equal in domain \r
602      *    o Union Types, for each tag type of the domain, there must be equal in range\r
603      * \r
604      * {@link AdaptException} is thrown at runtime, if number values are \r
605      * not compatible, e.g. converting value 500 from Long to Byte.\r
606      * Note, there is also a possibility of precision loss, e.g. when \r
607      * converting from double to int.\r
608      * \r
609      * @param domain binding of the source instance\r
610      * @param range binding of the result instance\r
611      * @return result adapter\r
612      * @throws AdapterConstructionException \r
613      */\r
614     public Adapter getTypeAdapterUnchecked(Binding domain, Binding range)\r
615     {\r
616         try {\r
617                         return adapterFactory.getAdapter(domain, range, true, false);\r
618                 } catch (AdapterConstructionException e) {\r
619                         throw new RuntimeAdapterConstructionException(e);\r
620                 }\r
621     }\r
622     \r
623     /**\r
624      * Adapt a value of one type to another. \r
625      * \r
626      * @param value\r
627      * @param domain\r
628      * @param range\r
629      * @return adapted value\r
630      * @throws AdapterConstructionException\r
631      * @throws AdaptException\r
632      */\r
633     public Object adapt(Object value, Binding domain, Binding range)\r
634     throws AdaptException\r
635     {\r
636         try {\r
637                 if (domain==range) {\r
638                                 return value;\r
639                 }\r
640                         return adapterFactory.getAdapter(domain, range, true, false).adapt(value);\r
641                 } catch (AdapterConstructionException e) {\r
642                         throw new AdaptException(e);\r
643                 }\r
644     }\r
645     \r
646     /**\r
647      * Adapt a value of one type to another. Exceptions are run-time. Use this\r
648      * if it safe to assume the conversion will be successful.\r
649      * \r
650      * @param value\r
651      * @param domain\r
652      * @param range\r
653      * @return adapted value\r
654      * @throws AdapterConstructionException\r
655      * @throws AdaptException\r
656      */\r
657     public Object adaptUnchecked(Object value, Binding domain, Binding range)\r
658     throws RuntimeAdapterConstructionException, RuntimeAdaptException\r
659     {\r
660         try {\r
661                 if (domain==range) {\r
662                                 return value;\r
663                 }\r
664                 return  adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);\r
665                 } catch (RuntimeAdapterConstructionException e) {\r
666                         throw new RuntimeAdaptException(new AdaptException(e.getCause()));\r
667                 } catch (AdapterConstructionException e) {\r
668                         throw new RuntimeAdaptException(new AdaptException(e));\r
669                 }\r
670     }    \r
671     \r
672     /**\r
673      * Adapt and clone a value instance to another type. Immutable \r
674      * bindings may return the argument as is, others return a cloned copy.  \r
675      * \r
676      * @param value\r
677      * @param domain\r
678      * @param range\r
679      * @return adapted value\r
680      * @throws AdapterConstructionException\r
681      * @throws AdaptException\r
682      */\r
683     public Object clone(Object value, Binding domain, Binding range)\r
684     throws AdaptException\r
685     {\r
686         try {\r
687                 if (domain==range) {\r
688                         if (domain.isImmutable()) {\r
689                                 return value;\r
690                         } else { \r
691                                 return domain.clone(value);\r
692                         }\r
693                 }\r
694                         return adapterFactory.getAdapter(domain, range, true, true).adapt(value);\r
695                 } catch (AdapterConstructionException e) {\r
696                         throw new AdaptException(e);\r
697                 }\r
698     }\r
699     \r
700 \r
701     /**\r
702      * Clone a value of one binding to another. Bindings that handle immutable values\r
703      * may return the same instance, others will guarantee a complete copy.\r
704      * \r
705      * This method throws only runtime exceptions. Use this if it is safe to assume\r
706      * that the conversion will be successful.\r
707      * \r
708      * @param value\r
709      * @param domain\r
710      * @param range\r
711      * @return adapted value\r
712      * @throws AdapterConstructionException\r
713      * @throws AdaptException\r
714      */\r
715     public Object cloneUnchecked(Object value, Binding domain, Binding range)\r
716     throws RuntimeAdapterConstructionException, RuntimeAdaptException\r
717     {\r
718         try {\r
719                         return adapterFactory.getAdapter(domain, range, true, true).adapt(value);\r
720                 } catch (AdaptException e) {\r
721                         throw new RuntimeAdaptException(e);\r
722                 } catch (RuntimeAdapterConstructionException e) {\r
723                         throw new RuntimeAdaptException(new AdaptException(e.getCause()));\r
724                 } catch (AdapterConstructionException e) {\r
725                         throw new RuntimeAdaptException(new AdaptException(e));\r
726                 }\r
727     }\r
728     \r
729     /**\r
730      * Compares two data values for order. Returns a negative integer,\r
731      * zero, or a positive integer if, the first argument precedes/lesser than \r
732      * the second, is equal to, or successor/greater than the second.<p>\r
733      * \r
734      * DataTypes of b1 and b2 are not equal, then data types are compared. <p>\r
735      *\r
736      * The comparison function is defined at \r
737      * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>\r
738      * \r
739      * Note, comparing 2 different number types will not result a value comparison.\r
740      * Instead values have the following type precedence ByteType, IntegerType, LongType,\r
741      * FloatType, and the highest DoubleType. <p>\r
742      *\r
743      * @param b1 Binding of o1 \r
744      * @param o1 the first object to be compared.\r
745      * @param b2 Binding of o2\r
746      * @param o2 the second object to be compared.\r
747      * @return a negative integer, zero, or a positive integer as the\r
748      *         first argument is less than, equal to, or greater than the\r
749      *         second.\r
750      * @throws BindingException if object cannot be handled by a binding\r
751      */\r
752     public int compare(Binding b1, Object o1, Binding b2, Object o2) \r
753     throws BindingException\r
754     {\r
755         return DataValueUtil.compare(b1, o1, b2, o2);\r
756     }\r
757     \r
758     /**\r
759      * Compare two data values for equality. <p>\r
760      * \r
761      * Note, comparing 2 different number types will not result a value comparison.\r
762      * Instead values have the following type precedence ByteType, IntegerType, LongType,\r
763      * FloatType, and the highest DoubleType. <p>\r
764      * \r
765      * @param b1\r
766      * @param o1\r
767      * @param b2\r
768      * @param o2\r
769      * @return true if equal\r
770      * @throws BindingException\r
771      */\r
772     public boolean equals(Binding b1, Object o1, Binding b2, Object o2)\r
773     throws BindingException\r
774     {\r
775         return DataValueUtil.equals(b1, o1, b2, o2);\r
776     }\r
777     \r
778     public Comparator<Object> createComparator(final Binding b1, final Binding b2)\r
779     {\r
780         return DataValueUtil.createComparator(b1, b2);\r
781     }\r
782     \r
783     /**\r
784      * Print the content of an object as a structure.\r
785      * Utility function for debug purposes.\r
786      * \r
787      * @param o\r
788      * @return content\r
789      */\r
790     public String toString(Object o) {\r
791         try {\r
792                         Binding b = getBinding( o.getClass() );\r
793                         return b.printValueDefinition(o, true);\r
794                 } catch (BindingConstructionException e) {\r
795                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
796                 } catch (IOException e) {\r
797                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
798                 } catch (BindingException e) {\r
799                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
800                 }\r
801     }\r
802     \r
803     class DataboardBindings implements BindingProvider {\r
804                 @Override\r
805                 public Binding provideBinding(ClassBindingFactory mainFactory, BindingRequest request) throws BindingConstructionException {\r
806                         // Variant Type\r
807                 if (request.getClazz().equals( Object.class )) return OBJECT;\r
808                 if (request.getClazz().equals( Void.class ) || request.getClazz().equals(void.class) ) return VoidBinding.VOID_BINDING;\r
809                 if (request.getClazz().equals( Variant.class) ) return Bindings.VARIANT;\r
810                 if (request.getClazz().equals( MutableVariant.class) ) return Bindings.MUTABLE_VARIANT;\r
811                         if (request.getClazz().equals( Bean.class ) ) return BEAN;\r
812                                 \r
813                         return null;\r
814                 }\r
815         } \r
816                                 \r
817     private void addDefaultBinding(Datatype datatype, Binding binding ) {\r
818         defaultBindingRepository.put(datatype, binding);\r
819     }\r
820 \r
821 }\r