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