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