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