f9cf1002317a7c4ddd2285e8a6306bd17e3812a5
[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.SerializerScheme;
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 SerializerScheme                 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.getSerializer(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                 return serializationFactory.getSerializerUnchecked(binding);
515         }
516
517         /**
518          * Get serializer that follows Databoard serialization spec.
519          *  
520          * @param clazz
521          * @return serializer
522          * @throws SerializerConstructionException
523          */
524         public static Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {
525                 try {
526                         Binding binding = getBinding(clazz);
527                         return serializationFactory.getSerializer(binding);
528                 } catch (BindingConstructionException e) {
529                         throw new SerializerConstructionException( e );
530                 }
531         }
532
533         /**
534          * Get serializer that follows Databoard serialization spec.
535          * 
536          * @param clazz
537          * @return serializer serializer
538          * @throws RuntimeSerializerConstructionException
539          */
540         public static Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {
541                 try {
542                         Binding binding = getBinding(clazz);
543                         return serializationFactory.getSerializerUnchecked(binding);
544                 } catch (BindingConstructionException e) {
545                         throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );
546                 }
547         }       
548     /**
549      * Create an adapter that adapts two bindings of the same
550      * data type.
551      * 
552      * @param domain binding of the source instance
553      * @param range binding of the result instance
554      * @return result adapter
555      * @throws AdapterConstructionException 
556      */
557     public static Adapter getAdapter(Binding domain, Binding range)
558     throws AdapterConstructionException
559     {
560         return adapterFactory.getAdapter(domain, range, false, false);
561     }
562     
563     /**
564      * Create an adapter that adapts between two bindings of the same
565      * data type.
566      * 
567      * @param domain binding of the source instance
568      * @param range binding of the result instance
569      * @return result adapter
570      * @throws AdapterConstructionException 
571      */
572     public static Adapter getAdapterUnchecked(Binding domain, Binding range)
573     throws RuntimeAdapterConstructionException
574     {
575         try {
576                         return adapterFactory.getAdapter(domain, range, false, false);
577                 } catch (AdapterConstructionException e) {
578                         throw new RuntimeAdapterConstructionException(e);
579                 }
580     }
581
582     /**
583      * Create a type adapter that adapts instances from one Datatype to 
584      * another. Type Adapter does the following conversions: 
585      * 
586      *    o Number Types, e.g. long -> double
587      *    o Unit Types, e.g. mph -> km/h
588      *    o Record Types, for each field of the range, there must be equal in domain 
589      *    o Union Types, for each tag type of the domain, there must be equal in range
590      * 
591      * {@link AdaptException} is thrown at runtime, if number conversion is not 
592      * posible, e.g. converting value 500 from Integer to Byte.
593      * Note, there is also a possibility of precision loss, in many conversions
594      * e.g. from double to int.
595      * 
596      * @param domain binding of the source instance
597      * @param range binding of the result instance
598      * @return adapter
599      * @throws AdapterConstructionException 
600      */
601     public static Adapter getTypeAdapter(Binding domain, Binding range)
602     throws AdapterConstructionException
603     {
604         return adapterFactory.getAdapter(domain, range, true, false);
605     }
606
607     /**
608      * Create a type adapter that adapts instances from one DataType to 
609      * another. Type Adapter does the following conversions: 
610      * 
611      *    o Number Types, e.g. long -> double
612      *    o Unit Types, e.g. mph -> km/h
613      *    o Record Types, for each field of the range, there must be equal in domain 
614      *    o Union Types, for each tag type of the domain, there must be equal in range
615      * 
616      * {@link AdaptException} is thrown at runtime, if number values are 
617      * not compatible, e.g. converting value 500 from Long to Byte.
618      * Note, there is also a possibility of precision loss, e.g. when 
619      * converting from double to int.
620      * 
621      * @param domain binding of the source instance
622      * @param range binding of the result instance
623      * @return result adapter
624      * @throws AdapterConstructionException 
625      */
626     public static Adapter getTypeAdapterUnchecked(Binding domain, Binding range)
627     {
628         try {
629                         return adapterFactory.getAdapter(domain, range, true, false);
630                 } catch (AdapterConstructionException e) {
631                         throw new RuntimeAdapterConstructionException(e);
632                 }
633     }
634     
635     /**
636      * Adapt a value of one type to another. 
637      * 
638      * @param value
639      * @param domain
640      * @param range
641      * @return adapted value
642      * @throws AdapterConstructionException
643      * @throws AdaptException
644      */
645     public static Object adapt(Object value, Binding domain, Binding range)
646     throws AdaptException
647     {
648         try {
649                 if (domain.equals(range)) {
650                                 return value;
651                 }
652                 else if (range instanceof VariantBinding) {
653                     if (domain instanceof VariantBinding) {
654                         // Copy variant contents directly
655                         Binding contentBinding = ((VariantBinding)domain).getContentBinding( value );
656                         Object content = ((VariantBinding)domain).getContent( value ); 
657                         return ((VariantBinding)range).create( contentBinding, content );
658                     }
659                     else {
660                                 // Default to just wrapping the value (avoid adapter construction to save memory)
661                                 return ((VariantBinding)range).create(domain, value);
662                     }
663                 }
664                 else if (domain instanceof VariantBinding) {
665                     return adapt(((VariantBinding)domain).getContent( value ), ((VariantBinding)domain).getContentBinding( value ), range );
666                 }
667                 else {
668                     return adapterFactory.getAdapter(domain, range, true, false).adapt(value);
669                 }
670                 } catch (AdapterConstructionException | BindingException e) {
671                         throw new AdaptException(e);
672                 }
673     }
674     
675     /**
676      * Adapt a value of one type to another. Exceptions are run-time. Use this
677      * if it safe to assume the conversion will be successful.
678      * 
679      * @param value
680      * @param domain
681      * @param range
682      * @return adapted value
683      * @throws AdapterConstructionException
684      * @throws AdaptException
685      */
686     public static Object adaptUnchecked(Object value, Binding domain, Binding range)
687     throws RuntimeAdapterConstructionException, RuntimeAdaptException
688     {
689         try {
690                 if (domain==range) {
691                                 return value;
692                 }
693                 if (range instanceof VariantBinding && !(domain instanceof VariantBinding)) {
694                         // Default to just wrapping the value (avoid adapter construction to save memory)
695                         return ((VariantBinding)range).create(domain, value);
696                 }
697                 return  adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);
698                 } catch (RuntimeAdapterConstructionException e) {
699                         throw new RuntimeAdaptException(new AdaptException(e.getCause()));
700                 } catch (AdapterConstructionException e) {
701                         throw new RuntimeAdaptException(new AdaptException(e));
702                 } catch (BindingException e) {
703                         throw new RuntimeAdaptException(new AdaptException(e));
704                 }
705     }    
706     
707     /**
708      * Adapt and clone a value instance to another type. Immutable 
709      * bindings may return the argument as is, others return a cloned copy.  
710      * 
711      * @param value
712      * @param domain
713      * @param range
714      * @return adapted value
715      * @throws AdapterConstructionException
716      * @throws AdaptException
717      */
718     public static Object clone(Object value, Binding domain, Binding range)
719     throws AdaptException
720     {
721         try {
722                 if (domain==range) {
723                         if (domain.isImmutable()) {
724                                 return value;
725                         } else { 
726                                 return domain.clone(value);
727                         }
728                 }
729                         return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
730                 } catch (AdapterConstructionException e) {
731                         throw new AdaptException(e);
732                 }
733     }
734     
735
736     /**
737      * Clone a value of one binding to another. Bindings that handle immutable values
738      * may return the same instance, others will guarantee a complete copy.
739      * 
740      * This method throws only runtime exceptions. Use this if it is safe to assume
741      * that the conversion will be successful.
742      * 
743      * @param value
744      * @param domain
745      * @param range
746      * @return adapted value
747      * @throws AdapterConstructionException
748      * @throws AdaptException
749      */
750     public static Object cloneUnchecked(Object value, Binding domain, Binding range)
751     throws RuntimeAdapterConstructionException, RuntimeAdaptException
752     {
753         try {
754                         return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
755                 } catch (AdaptException e) {
756                         throw new RuntimeAdaptException(e);
757                 } catch (RuntimeAdapterConstructionException e) {
758                         throw new RuntimeAdaptException(new AdaptException(e.getCause()));
759                 } catch (AdapterConstructionException e) {
760                         throw new RuntimeAdaptException(new AdaptException(e));
761                 }
762     }
763     
764     /**
765      * Compares two data values for order. Returns a negative integer,
766      * zero, or a positive integer if, the first argument precedes/lesser than 
767      * the second, is equal to, or successor/greater than the second.<p>
768      * 
769      * DataTypes of b1 and b2 are not equal, then data types are compared. <p>
770      *
771      * The comparison function is defined at 
772      * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>
773      * 
774      * Note, comparing 2 different number types will not result a value comparison.
775      * Instead values have the following type precedence ByteType, IntegerType, LongType,
776      * FloatType, and the highest DoubleType. <p>
777      *
778      * @param b1 Binding of o1 
779      * @param o1 the first object to be compared.
780      * @param b2 Binding of o2
781      * @param o2 the second object to be compared.
782      * @return a negative integer, zero, or a positive integer as the
783      *         first argument is less than, equal to, or greater than the
784      *         second.
785      * @throws BindingException if object cannot be handled by a binding
786      */
787     public static int compare(Binding b1, Object o1, Binding b2, Object o2) 
788     throws BindingException
789     {
790         return DataValueUtil.compare(b1, o1, b2, o2);
791     }
792     
793     /**
794      * Compare two data values for equality. <p>
795      * 
796      * Note, comparing 2 different number types will not result a value comparison.
797      * Instead values have the following type precedence ByteType, IntegerType, LongType,
798      * FloatType, and the highest DoubleType. <p>
799      * 
800      * @param b1
801      * @param o1
802      * @param b2
803      * @param o2
804      * @return true if equal
805      * @throws BindingException
806      */
807     public static boolean equals(Binding b1, Object o1, Binding b2, Object o2)
808     throws BindingException
809     {
810         return DataValueUtil.equals(b1, o1, b2, o2);
811     }
812     
813     public static Comparator<Object> createComparator(final Binding b1, final Binding b2)
814     {
815         return DataValueUtil.createComparator(b1, b2);
816     }
817     
818     /**
819      * Print the content of an object as a structure.
820      * Utility function for debug purposes.
821      * 
822      * @param o
823      * @return content
824      */
825     public static String toString(Object o) {
826         try {
827                         Binding b = Bindings.getBinding( o.getClass() );
828                         return b.printValueDefinition(o, true);
829                 } catch (BindingConstructionException e) {
830                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
831                 } catch (IOException e) {
832                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
833                 } catch (BindingException e) {
834                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
835                 }
836     }
837     
838     static {
839         STRING         = new StringBindingDefault( Datatypes.STRING );  
840         INTEGER        = new IntegerBindingDefault( Datatypes.INTEGER );        
841         BOOLEAN        = new BooleanBindingDefault( Datatypes.BOOLEAN );        
842         BYTE           = new ByteBindingDefault( Datatypes.BYTE );      
843         LONG           = new LongBindingDefault( Datatypes.LONG );      
844         DOUBLE         = new DoubleBindingDefault( Datatypes.DOUBLE );  
845         FLOAT          = new FloatBindingDefault( Datatypes.FLOAT );    
846         VOID           = VoidBinding.VOID_BINDING;
847         BOOLEAN_ARRAY  = new BooleanArrayBinding( Datatypes.BOOLEAN_ARRAY, BOOLEAN );   
848         BYTE_ARRAY     = new ByteArrayBinding( Datatypes.BYTE_ARRAY, BYTE );
849         INT_ARRAY      = new IntArrayBinding( Datatypes.INTEGER_ARRAY, INTEGER );
850         LONG_ARRAY     = new LongArrayBinding( Datatypes.LONG_ARRAY, LONG );
851         FLOAT_ARRAY    = new FloatArrayBinding( Datatypes.FLOAT_ARRAY, FLOAT );
852         DOUBLE_ARRAY   = new DoubleArrayBinding( Datatypes.DOUBLE_ARRAY, DOUBLE );
853         STRING_ARRAY   = new StringArrayBinding( Datatypes.STRING_ARRAY, STRING );
854         UNSIGNED_INTEGER         = new UnsignedIntegerBinding.Immutable( Datatypes.INTEGER );
855         UNSIGNED_BYTE            = new UnsignedByteBinding.Immutable( Datatypes.BYTE );
856         UNSIGNED_LONG            = new UnsignedLongBinding.Immutable( Datatypes.LONG );
857         MUTABLE_STRING           = new MutableStringBinding( Datatypes.STRING );
858         MUTABLE_INTEGER          = new MutableIntegerBinding( Datatypes.INTEGER );
859         MUTABLE_BOOLEAN          = new MutableBooleanBinding( Datatypes.BOOLEAN );
860         MUTABLE_BYTE             = new MutableByteBinding( Datatypes.BYTE );
861         MUTABLE_LONG             = new MutableLongBinding( Datatypes.LONG );
862         MUTABLE_FLOAT            = new MutableFloatBinding( Datatypes.FLOAT );
863         MUTABLE_DOUBLE           = new MutableDoubleBinding( Datatypes.DOUBLE );
864         MUTABLE_UNSIGNED_INTEGER = new UnsignedIntegerBinding.Mutable( Datatypes.INTEGER );
865         MUTABLE_UNSIGNED_BYTE    = new UnsignedByteBinding.Mutable( Datatypes.BYTE );
866         MUTABLE_UNSIGNED_LONG    = new UnsignedLongBinding.Mutable( Datatypes.LONG );
867         
868         databoard = new Databoard();
869         
870         mutableBindingRepository = databoard.mutableBindingRepository;
871         defaultBindingRepository = databoard.defaultBindingRepository;
872         bindingRepository = databoard.bindingRepository;
873         serializerRepository = databoard.serializerRepository;
874         mutableBindingFactory = databoard.mutableBindingFactory;
875         defaultBindingFactory = databoard.defaultBindingFactory;
876         classBindingFactory = databoard.classBindingFactory;
877         serializationFactory = databoard.serializationFactory;
878         adapterFactory = databoard.adapterFactory;
879         typeClassFactory = databoard.typeClassFactory;
880         
881         BEAN                             = databoard.BEAN;
882         VARIANT                          = databoard.VARIANT;
883         MUTABLE_VARIANT          = new MutableVariantBinding( classBindingFactory, adapterFactory );
884         STR_VARIANT                      = databoard.STR_VARIANT;
885         OBJECT                           = databoard.OBJECT;
886         
887         databoard.initialize();
888         
889                 DATATYPE = getBindingUnchecked(Datatype.class);
890     }
891
892 }
893