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