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