]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/Bindings.java
Rest API for Historian data
[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
139         public static final ArrayBinding   BOOLEAN_ARRAY;       // boolean[]    
140         public static final ArrayBinding   BYTE_ARRAY;          // byte[]
141         public static final ArrayBinding   INT_ARRAY;           // int[]
142         public static final ArrayBinding   LONG_ARRAY;          // long[]
143         public static final ArrayBinding   FLOAT_ARRAY;         // float[]
144         public static final ArrayBinding   DOUBLE_ARRAY;        // double[]
145         public static final ArrayBinding   STRING_ARRAY;        // String[]
146
147         public static final StringBinding  MUTABLE_STRING;      // MutableString
148         public static final IntegerBinding MUTABLE_INTEGER;     // MutableInteger
149         public static final BooleanBinding MUTABLE_BOOLEAN; // MutableBoolean
150         public static final ByteBinding    MUTABLE_BYTE;        // MutableByte
151         public static final LongBinding    MUTABLE_LONG;        // MutableLong
152         public static final FloatBinding   MUTABLE_FLOAT;       // MutableFloat
153         public static final DoubleBinding  MUTABLE_DOUBLE;      // MutableDouble
154         public static final VariantBinding MUTABLE_VARIANT; // MutableVariant
155
156         public static final IntegerBinding UNSIGNED_INTEGER;                    // UnsignedInteger.Immutable
157         public static final ByteBinding    UNSIGNED_BYTE;                               // UnsignedByte.Immutable
158         public static final LongBinding    UNSIGNED_LONG;                               // UnsignedLong.Immutable
159
160         public static final IntegerBinding MUTABLE_UNSIGNED_INTEGER;    // UnsignedInteger.Mutable
161         public static final ByteBinding    MUTABLE_UNSIGNED_BYTE;               // UnsignedByte.Mutable
162         public static final LongBinding    MUTABLE_UNSIGNED_LONG;               // UnsignedLong.Mutable 
163                 
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
182          * 
183          * Note, requesting a binding with this convenience method stores the 
184          * binding and the type with strong reference, thus preventing garbage 
185          * collection. To allow garbage collection, please use another instance of 
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 {
194                 Binding binding = mutableBindingRepository.get(type);
195                 if (binding!=null) return (T) binding;
196                 synchronized(mutableBindingRepository) {
197                         return (T) mutableBindingFactory.getBinding(type);
198                 }
199                 } catch (BindingConstructionException e) {
200                         // Unexpected - if error is thrown there is fault in GenericBindingScheme
201                         throw new RuntimeBindingConstructionException(e);
202                 }
203     }
204     
205     /**
206      * Get or create a binding based on default java classes, such as 
207      * Integer.class, or byte[].class. The result is often binding for an 
208      * immutable classs. These bindings are more efficient than mutable bindings (above).
209      * 
210          * DataType           | Class of the bound instance
211          * ===================|==================
212      * BooleanType        | Boolean.class
213      * ByteType           | Byte.class
214      * FloatType          | Float.class
215      * DoubleType         | Double.class
216      * IntegerType        | Int.class
217      * LongType           | Long.class
218      * StringType         | String.class
219      * UnionType          | TaggedObject.class
220      * OptionType         | ValueContainer.class
221      * RecordType         | Object[].class
222      * MapType            | TreeMap.class
223      * VariantType        | Variant.class
224      * ArrayType(Boolean) | boolean[].class
225      * ArrayType(Byte)    | byte[].class
226      * ArrayType(Integer) | int[].class
227      * ArrayType(Long)    | long[].class
228      * ArrayType(Float)   | float[].class
229      * ArrayType(Double)  | double[].class
230      * ArrayType(Byte)    | byte[].class
231      * ArrayType( T )     | Object[].class
232      * 
233          * Note, requesting a binding with this convenience method stores the 
234          * binding and the type with strong reference, thus preventing garbage 
235          * collection. To allow garbage collection, please use another instance of 
236          * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>
237      *
238          * @param type the type to create binding to
239          * @return binding binding to a mutable class 
240      */    
241     @SuppressWarnings("unchecked")
242         public static <T extends Binding> T getBinding(Datatype type) {
243         try {
244                 Binding binding = defaultBindingRepository.get(type);
245                 if (binding!=null) return (T) binding;
246                 synchronized(defaultBindingRepository) {
247                         return (T) defaultBindingFactory.getBinding(type);
248                 }
249         } catch (BindingConstructionException e) {
250                         // Unexpected - if error is thrown there is fault in DefaultBindingScheme
251                         throw new RuntimeBindingConstructionException(e);
252                 }
253     }    
254         
255         /**
256          * Get a binding to a Java Class. Details can be added by placing annotations
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 
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>
264          * 
265          * Note, requesting a binding with this convenience method stores the 
266          * binding and the class with strong reference, thus preventing garbage 
267          * collection. To allow garbage collection, please use another instance of 
268          * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p>
269          * 
270          * Is asm library is available, the binding is bytecode generated. Then read
271          * and write operations are direct get/set calls or direct field read/writes. 
272          * There is no reflection used. <p>
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     {
283         Binding binding = bindingRepository.get( clazz );
284         if (binding != null) {
285                 return (T) binding;
286         }
287         
288         BindingRequest request = new BindingRequest( clazz );
289         synchronized(classBindingFactory) {
290                 binding = classBindingFactory.construct(request);
291         }
292                 return (T) binding;
293     }
294
295     @SuppressWarnings("unchecked")
296         public static <T extends Binding> T getBinding(BindingRequest request)
297     throws BindingConstructionException
298     {
299         synchronized(classBindingFactory) {
300                 return (T) classBindingFactory.construct(request);
301         }
302     }
303     
304         /**
305          * Get a binding for a Java Class. Use this method to acquire class 
306          * parameters for a generics class. <p>
307          * 
308          * Example 1: 
309          * 
310          *    Binding binding = Bindings.getBinding(Map.class, String.class, Integer.class);
311          *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
312          *    
313          * Example 2:
314          *    
315      *  Binding d = Bindings.getBinding(List.class, Integer.class);
316          *  List<Integer> list = (List<Integer>) d.createRandom(5);
317          *    
318          * Example 3:
319          *    
320      *  Binding d = Bindings.getBinding(List.class, List.class, Integer.class);
321          *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
322          * 
323          * @see ClassBindingFactory  
324          * @param clazz
325          * @return binding
326          * @throws BindingConstructionException
327          */
328     @SuppressWarnings("unchecked")
329         public static <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)
330     throws BindingConstructionException
331     {
332         BindingRequest request = new BindingRequest( clazz, parameters );
333         synchronized(classBindingFactory) {
334                 return (T) classBindingFactory.construct(request);
335         }
336     }
337
338     /**
339      * Try to get a binding for the actual class of a Java object.
340      * @param obj  A Java object
341      * @return  A binding for the class of the object
342      * @throws BindingConstructionException  if no binding can be constructed
343      */
344     public static <T extends Binding> T getInstanceBinding(Object obj)
345     throws BindingConstructionException
346     {
347         return getBinding(obj.getClass());
348     }
349     
350     /**
351          * Read binding and type from a class. DataType details and parameters
352          * are read as annotations placed in the class.  
353          * (See org.simantics.databoard.annotations)
354          * <p>
355          * As an exception, in the subclasses of {@link Throwable}, the fields of
356          * Throwable are omited.
357          * <p>
358          * This method is used for well-known classes where the caller is 100% sure
359          * that a binding is construable without exception. <p> 
360          * 
361          * @param clazz
362          * @return binding
363          * @throws RuntimeBindingConstructionException
364      */
365         @SuppressWarnings("unchecked")
366         public static <T extends Binding> T getBindingUnchecked(Class<?> clazz)
367     throws RuntimeBindingConstructionException
368     {
369                 try {
370                 return (T) getBinding(clazz);
371                 } catch (BindingConstructionException e) {
372                         throw new RuntimeBindingConstructionException(e);
373                 }
374     }    
375
376         /**
377          * Get a binding for a Java Class. Use this method to acquire class 
378          * parameters for a generics class. <p>
379          * 
380          * Example 1: 
381          * 
382          *    Binding binding = Bindings.getBinding(Map.class, String.class, Integer.class);
383          *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
384          *    
385          * Example 2:
386          *    
387      *  Binding d = Bindings.getBinding(List.class, Integer.class);
388          *  List<Integer> list = (List<Integer>) d.createRandom(5);
389          *    
390          * Example 3:
391          *    
392      *  Binding d = Bindings.getBinding(List.class, List.class, Integer.class);
393          *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
394          * 
395          * @see ClassBindingFactory  
396          * @param clazz
397          * @return binding
398          * @throws BindingConstructionException
399          */
400     @SuppressWarnings("unchecked")
401         public static <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)
402     throws RuntimeBindingConstructionException
403     {
404         try {
405                 Arguments args = new ArgumentImpl(parameters);
406                 BindingRequest request = new BindingRequest( clazz, args );
407                 Binding binding = bindingRepository.get( request );
408                 if (binding!=null);
409                 synchronized(classBindingFactory) {
410                         binding = classBindingFactory.construct(request);
411                 }
412                         return (T) binding;
413         } catch (BindingConstructionException e) {
414                 throw new RuntimeBindingConstructionException(e);
415         }
416     }    
417     
418     /**
419      * Add a simple binding to reflection binding factory.
420      *  
421      * @param binding
422      * @param clazz
423      * @param parameters parameter classes
424      */
425     public static void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )
426     {
427         ArgumentImpl args = new ArgumentImpl( parameters );
428         BindingRequest request = new BindingRequest( clazz, args );
429         bindingRepository.put( request, binding );
430     }
431     
432     /**
433      * Add binding factory for compositive bindings 
434      * 
435      * @param factory
436      */
437     public static void addBindingFactory( BindingProvider factory )
438     {
439         classBindingFactory.addFactory( factory );
440     }
441     
442     /**
443      * Creates a bean class 
444      * @param type
445      * @return class
446      */
447     public static BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {
448         try {
449                         return typeClassFactory.getClass(type);
450                 } catch (BindingConstructionException e) {
451                         throw new RuntimeBindingConstructionException(e);
452                 }
453     }
454
455     /**
456      * Creates a bean class 
457      * @param type
458      * @return class
459      */
460     public static Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {
461         BindingRequest br = typeClassFactory.getClass(type);
462         return br.getClazz();
463     }
464
465     /**
466      * Create binding from datatype that instantiates java classes. 
467      * RecordTypes are Beans, UnionTypes are Classes with @Union annotation, 
468      * ArrayTypes are []. 
469      * 
470      * @param type
471      * @return class
472      */
473     public static Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {
474                 try {
475                 BindingRequest br = typeClassFactory.getClass(type);
476                 return getBinding( br );
477                 } catch (BindingConstructionException e) {
478                         throw new RuntimeBindingConstructionException(e);
479                 }
480     }
481     
482     /**
483      * Get a default array binding for a given component type binding.
484      * Returns a primitive array type binding for primitive types and an
485      * ObjectArrayBinding for others.
486      * 
487      * @param componentBinding  A binding for a component type
488      * @return  A binding for the array type
489      */
490     public static Binding getArrayBinding(Binding componentBinding) {
491         return getBinding(new ArrayType(componentBinding.type()));
492     }
493
494         /**
495          * Get serializer that follows Databoard serialization spec.
496          *  
497          * @param binding
498          * @return serializer
499          * @throws SerializerConstructionException
500          */
501         public static Serializer getSerializer(Binding binding) throws SerializerConstructionException {
502                 return serializationFactory.construct(binding);
503         }
504
505         /**
506          * Get serializer that follows Databoard serialization spec.
507          * 
508          * @param binding
509          * @return serializer
510          * @throws RuntimeSerializerConstructionException
511          */
512         public static Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {
513                 try {
514                         return serializationFactory.construct(binding);
515                 } catch (SerializerConstructionException e) {
516                         throw new RuntimeSerializerConstructionException(e);
517                 }
518         }
519
520         /**
521          * Get serializer that follows Databoard serialization spec.
522          *  
523          * @param clazz
524          * @return serializer
525          * @throws SerializerConstructionException
526          */
527         public static Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {
528                 try {
529                         Binding binding = getBinding(clazz);
530                         return serializationFactory.construct(binding);
531                 } catch (BindingConstructionException e) {
532                         throw new SerializerConstructionException( e );
533                 }
534         }
535
536         /**
537          * Get serializer that follows Databoard serialization spec.
538          * 
539          * @param clazz
540          * @return serializer serializer
541          * @throws RuntimeSerializerConstructionException
542          */
543         public static Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {
544                 try {
545                         Binding binding = getBinding(clazz);
546                         return serializationFactory.construct(binding);
547                 } catch (SerializerConstructionException e) {
548                         throw new RuntimeSerializerConstructionException(e);
549                 } catch (BindingConstructionException e) {
550                         throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );
551                 }
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
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)) {
655                                 return value;
656                 }
657                 else if (range instanceof VariantBinding) {
658                     if (domain instanceof VariantBinding) {
659                         // Copy variant contents directly
660                         Binding contentBinding = ((VariantBinding)domain).getContentBinding( value );
661                         Object content = ((VariantBinding)domain).getContent( value ); 
662                         return ((VariantBinding)range).create( contentBinding, content );
663                     }
664                     else {
665                                 // Default to just wrapping the value (avoid adapter construction to save memory)
666                                 return ((VariantBinding)range).create(domain, value);
667                     }
668                 }
669                 else if (domain instanceof VariantBinding) {
670                     return adapt(((VariantBinding)domain).getContent( value ), ((VariantBinding)domain).getContentBinding( value ), range );
671                 }
672                 else {
673                     return adapterFactory.getAdapter(domain, range, true, false).adapt(value);
674                 }
675                 } catch (AdapterConstructionException | BindingException e) {
676                         throw new AdaptException(e);
677                 }
678     }
679     
680     /**
681      * Adapt a value of one type to another. Exceptions are run-time. Use this
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     {
694         try {
695                 if (domain==range) {
696                                 return value;
697                 }
698                 if (range instanceof VariantBinding && !(domain instanceof VariantBinding)) {
699                         // Default to just wrapping the value (avoid adapter construction to save memory)
700                         return ((VariantBinding)range).create(domain, value);
701                 }
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) {
708                         throw new RuntimeAdaptException(new AdaptException(e));
709                 }
710     }    
711     
712     /**
713      * Adapt and clone a value instance to another type. Immutable 
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 {
727                 if (domain==range) {
728                         if (domain.isImmutable()) {
729                                 return value;
730                         } else { 
731                                 return domain.clone(value);
732                         }
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      * 
745      * This method throws only runtime exceptions. Use this if it is safe to assume
746      * that the conversion will be successful.
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 
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     }
822     
823     /**
824      * Print the content of an object as a structure.
825      * Utility function for debug purposes.
826      * 
827      * @param o
828      * @return content
829      */
830     public static String toString(Object o) {
831         try {
832                         Binding b = Bindings.getBinding( o.getClass() );
833                         return b.printValueDefinition(o, true);
834                 } catch (BindingConstructionException e) {
835                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
836                 } catch (IOException e) {
837                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
838                 } catch (BindingException e) {
839                         return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
840                 }
841     }
842     
843     static {
844         STRING         = new StringBindingDefault( Datatypes.STRING );  
845         INTEGER        = new IntegerBindingDefault( Datatypes.INTEGER );        
846         BOOLEAN        = new BooleanBindingDefault( Datatypes.BOOLEAN );        
847         BYTE           = new ByteBindingDefault( Datatypes.BYTE );      
848         LONG           = new LongBindingDefault( Datatypes.LONG );      
849         DOUBLE         = new DoubleBindingDefault( Datatypes.DOUBLE );  
850         FLOAT          = new FloatBindingDefault( Datatypes.FLOAT );    
851         VOID           = VoidBinding.VOID_BINDING;
852         BOOLEAN_ARRAY  = new BooleanArrayBinding( Datatypes.BOOLEAN_ARRAY, BOOLEAN );   
853         BYTE_ARRAY     = new ByteArrayBinding( Datatypes.BYTE_ARRAY, BYTE );
854         INT_ARRAY      = new IntArrayBinding( Datatypes.INTEGER_ARRAY, INTEGER );
855         LONG_ARRAY     = new LongArrayBinding( Datatypes.LONG_ARRAY, LONG );
856         FLOAT_ARRAY    = new FloatArrayBinding( Datatypes.FLOAT_ARRAY, FLOAT );
857         DOUBLE_ARRAY   = new DoubleArrayBinding( Datatypes.DOUBLE_ARRAY, DOUBLE );
858         STRING_ARRAY   = new StringArrayBinding( Datatypes.STRING_ARRAY, STRING );
859         UNSIGNED_INTEGER         = new UnsignedIntegerBinding.Immutable( Datatypes.INTEGER );
860         UNSIGNED_BYTE            = new UnsignedByteBinding.Immutable( Datatypes.BYTE );
861         UNSIGNED_LONG            = new UnsignedLongBinding.Immutable( Datatypes.LONG );
862         MUTABLE_STRING           = new MutableStringBinding( Datatypes.STRING );
863         MUTABLE_INTEGER          = new MutableIntegerBinding( Datatypes.INTEGER );
864         MUTABLE_BOOLEAN          = new MutableBooleanBinding( Datatypes.BOOLEAN );
865         MUTABLE_BYTE             = new MutableByteBinding( Datatypes.BYTE );
866         MUTABLE_LONG             = new MutableLongBinding( Datatypes.LONG );
867         MUTABLE_FLOAT            = new MutableFloatBinding( Datatypes.FLOAT );
868         MUTABLE_DOUBLE           = new MutableDoubleBinding( Datatypes.DOUBLE );
869         MUTABLE_UNSIGNED_INTEGER = new UnsignedIntegerBinding.Mutable( Datatypes.INTEGER );
870         MUTABLE_UNSIGNED_BYTE    = new UnsignedByteBinding.Mutable( Datatypes.BYTE );
871         MUTABLE_UNSIGNED_LONG    = new UnsignedLongBinding.Mutable( Datatypes.LONG );
872         
873         databoard = new Databoard();
874         
875         mutableBindingRepository = databoard.mutableBindingRepository;
876         defaultBindingRepository = databoard.defaultBindingRepository;
877         bindingRepository = databoard.bindingRepository;
878         serializerRepository = databoard.serializerRepository;
879         mutableBindingFactory = databoard.mutableBindingFactory;
880         defaultBindingFactory = databoard.defaultBindingFactory;
881         classBindingFactory = databoard.classBindingFactory;
882         serializationFactory = databoard.serializationFactory;
883         adapterFactory = databoard.adapterFactory;
884         typeClassFactory = databoard.typeClassFactory;
885         
886         BEAN                             = databoard.BEAN;
887         VARIANT                          = databoard.VARIANT;
888         MUTABLE_VARIANT          = new MutableVariantBinding( classBindingFactory, adapterFactory );
889         STR_VARIANT                      = databoard.STR_VARIANT;
890         OBJECT                           = databoard.OBJECT;
891         
892         databoard.initialize();
893     }
894     
895 }
896