]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
index befbe35c5bb6e84ecd4e0003308e0a564bb37c3e..da488e0a81b087f423b0bfe0171102f305bf625f 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2012 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.databoard;\r
-\r
-import java.io.IOException;\r
-import java.lang.reflect.Constructor;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.adapter.Adapter;\r
-import org.simantics.databoard.adapter.AdapterConstructionException;\r
-import org.simantics.databoard.adapter.AdapterFactory;\r
-import org.simantics.databoard.adapter.RuntimeAdaptException;\r
-import org.simantics.databoard.adapter.RuntimeAdapterConstructionException;\r
-import org.simantics.databoard.annotations.ArgumentImpl;\r
-import org.simantics.databoard.annotations.Arguments;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.VariantBinding;\r
-import org.simantics.databoard.binding.classfactory.ImmutableClassesFactory;\r
-import org.simantics.databoard.binding.classfactory.TypeClassFactory;\r
-import org.simantics.databoard.binding.classfactory.TypeClassSubFactory;\r
-import org.simantics.databoard.binding.error.BindingConstructionException;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
-import org.simantics.databoard.binding.factory.BindingRepository;\r
-import org.simantics.databoard.binding.factory.DefaultBindingFactory;\r
-import org.simantics.databoard.binding.factory.JavaUtilBindingsProvider;\r
-import org.simantics.databoard.binding.factory.MutableBindingFactory;\r
-import org.simantics.databoard.binding.factory.TroveBindingsProvider;\r
-import org.simantics.databoard.binding.factory.TypeBindingFactory;\r
-import org.simantics.databoard.binding.impl.BeanBinding;\r
-import org.simantics.databoard.binding.impl.ObjectVariantBinding;\r
-import org.simantics.databoard.binding.impl.StringVariantBinding;\r
-import org.simantics.databoard.binding.mutable.ImmutableVariantBinding;\r
-import org.simantics.databoard.binding.mutable.MutableVariant;\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.databoard.binding.reflection.BindingProvider;\r
-import org.simantics.databoard.binding.reflection.BindingRequest;\r
-import org.simantics.databoard.binding.reflection.ClassBindingFactory;\r
-import org.simantics.databoard.binding.reflection.VoidBinding;\r
-import org.simantics.databoard.serialization.DefaultSerializerFactory;\r
-import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.serialization.SerializerConstructionException;\r
-import org.simantics.databoard.serialization.SerializerFactory;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.DataValueUtil;\r
-\r
-public class Databoard {\r
-\r
-       // Repositories\r
-\r
-       /** Repository of mutable bindings */\r
-    public final Map<Datatype, Binding>       mutableBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );\r
-\r
-    /** Repository of default bindings */\r
-    public final Map<Datatype, Binding>       defaultBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );\r
-\r
-    /** Repository of class Bindings */\r
-    public final BindingRepository            bindingRepository = new BindingRepository();\r
-\r
-    /** Repository of serializers */\r
-    public final Map<Binding, Serializer>     serializerRepository        = Collections.synchronizedMap( new HashMap<Binding, Serializer>() ); \r
-       \r
-    \r
-    // Factories\r
-\r
-    /** Mutable Bindings Factory */\r
-       public final TypeBindingFactory           mutableBindingFactory = new MutableBindingFactory( mutableBindingRepository );\r
-\r
-       /** Default Bindings Factory */\r
-       public final TypeBindingFactory           defaultBindingFactory = new DefaultBindingFactory( defaultBindingRepository );\r
-\r
-       /** Reflection based Binding Factory, create binding to class */\r
-    public final ClassBindingFactory            classBindingFactory = new ClassBindingFactory( bindingRepository, defaultBindingFactory );\r
-\r
-    /** Serializer Factory */\r
-    public final SerializerFactory              serializationFactory = new DefaultSerializerFactory( serializerRepository );\r
-\r
-    /** Adapter Factory */\r
-       public final AdapterFactory              adapterFactory = new AdapterFactory();\r
-       \r
-       /** Class Factory */ \r
-       public final TypeClassFactory typeClassFactory = new TypeClassFactory();\r
-       \r
-       \r
-       public final VariantBinding VARIANT;                    // Variant      \r
-       public final VariantBinding OBJECT;                     // java.lang.Object ( as variant )      \r
-       public final VariantBinding STR_VARIANT;                // java.lang.String ( as variant )\r
-       public final Binding        BEAN;            // Bean ( as variant )                     \r
-\r
-       public Databoard() {\r
-       classBindingFactory.addFactory( new TroveBindingsProvider() );\r
-       classBindingFactory.addFactory( new JavaUtilBindingsProvider() );\r
-       \r
-       addDefaultBinding( Datatypes.STRING, Bindings.STRING );\r
-       addDefaultBinding( Datatypes.INTEGER, Bindings.INTEGER );\r
-       addDefaultBinding( Datatypes.BOOLEAN, Bindings.BOOLEAN );\r
-       addDefaultBinding( Datatypes.BYTE, Bindings.BYTE );\r
-       addDefaultBinding( Datatypes.LONG, Bindings.LONG );\r
-       addDefaultBinding( Datatypes.DOUBLE, Bindings.DOUBLE ); \r
-       addDefaultBinding( Datatypes.FLOAT, Bindings.FLOAT );   \r
-        addDefaultBinding( Datatypes.VOID, Bindings.VOID );\r
-       addDefaultBinding( Datatypes.BOOLEAN_ARRAY, Bindings.BOOLEAN_ARRAY );\r
-       addDefaultBinding( Datatypes.BYTE_ARRAY, Bindings.BYTE_ARRAY );\r
-       addDefaultBinding( Datatypes.INTEGER_ARRAY, Bindings.INT_ARRAY );\r
-       addDefaultBinding( Datatypes.LONG_ARRAY, Bindings.LONG_ARRAY );\r
-       addDefaultBinding( Datatypes.FLOAT_ARRAY, Bindings.FLOAT_ARRAY );\r
-       addDefaultBinding( Datatypes.DOUBLE_ARRAY, Bindings.DOUBLE_ARRAY );\r
-       addDefaultBinding( Datatypes.STRING_ARRAY, Bindings.STRING_ARRAY );\r
-       \r
-       VARIANT        = new ImmutableVariantBinding( classBindingFactory, adapterFactory );\r
-       OBJECT         = new ObjectVariantBinding( classBindingFactory, adapterFactory );\r
-        BEAN           = new BeanBinding( classBindingFactory, typeClassFactory, adapterFactory );\r
-       STR_VARIANT    = new StringVariantBinding( serializationFactory, VARIANT );     \r
-\r
-       // Add sub-factory that creates binding for Bean\r
-       classBindingFactory.addFactory( new DataboardBindings() );\r
-       \r
-               // Add class factory that constructs basic types\r
-               typeClassFactory.addFactory( new ImmutableClassesFactory() );\r
-               \r
-               // Bindings.databoard cannot initialize itself\r
-               if (Bindings.databoard != null) {\r
-                       initialize();\r
-               }\r
-       }\r
-       \r
-       void initialize() {\r
-               // Add run-time class factory, if objectweb.asm-library is available.\r
-               try {\r
-                       // Check ASM Exists\r
-                       Class.forName("org.objectweb.asm.ClassWriter");\r
-                       Class<?> y = Class.forName("org.simantics.databoard.binding.classfactory.AsmTypeClassFactory");\r
-                       Constructor<?> c = y.getConstructor( TypeClassFactory.class );\r
-                       TypeClassSubFactory f = (TypeClassSubFactory) c.newInstance(typeClassFactory);\r
-                       typeClassFactory.addFactory( f );\r
-                       \r
-                       BindingRequest br = new BindingRequest( Datatype.class ); \r
-                       Binding datatypeBinding = getBinding( br );\r
-                       typeClassFactory.getRepository().put(datatypeBinding.type(), br);\r
-               } catch (ClassNotFoundException e) {\r
-               } catch (InstantiationException e) {\r
-               } catch (IllegalAccessException e) {\r
-               } catch (IllegalArgumentException e) {\r
-               } catch (InvocationTargetException e) {\r
-               } catch (SecurityException e) {\r
-               } catch (NoSuchMethodException e) {\r
-               } catch (BindingConstructionException e) {\r
-                       e.printStackTrace();\r
-               }\r
-       }\r
-       \r
-       public void clear() {\r
-               mutableBindingRepository.clear();\r
-               defaultBindingRepository.clear();\r
-               bindingRepository.clear();\r
-               serializerRepository.clear();           \r
-       }\r
-               \r
-    /**\r
-     * Get or create a binding that is completely mutable java class. \r
-     * \r
-        * DataType           | Class of the bound instance\r
-        * ===================|==================\r
-        * UnionType          | GenericBinding.TaggedObject.class\r
-        * OptionType         | ValueContainer.class\r
-        * RecordType         | Object[].class\r
-        * BooleanType        | MutableBoolean.class\r
-        * DoubleType         | MutableDouble.class\r
-        * FloatType          | MutableFloat.class\r
-        * ByteType           | MutableByte.class\r
-        * IntegerType        | MutableInt.class\r
-        * LongType           | MutableLong.class\r
-        * StringType         | ValueContainer.class\r
-        * ArrayType          | ArrayList.class\r
-        * MapType            | TreeMap.class\r
-        * VariantType        | MutableVariant.class\r
-        * \r
-        * Note, requesting a binding with this convenience method stores the \r
-        * binding and the type with strong reference, thus preventing garbage \r
-        * collection. To allow garbage collection, please use another instance of \r
-        * GenericBindingFactory and binding repository (Map<Datatype, Binding>). <p>\r
-     *\r
-        * @param type the type to create binding to\r
-        * @return binding binding to a mutable class \r
-     */    \r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getMutableBinding(Datatype type) {\r
-       try {\r
-               Binding binding = mutableBindingRepository.get(type);\r
-               if (binding!=null) return (T) binding;\r
-               synchronized(mutableBindingRepository) {\r
-                       return (T) mutableBindingFactory.getBinding(type);\r
-               }\r
-               } catch (BindingConstructionException e) {\r
-                       // Unexpected - if error is thrown there is fault in GenericBindingScheme\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-    }\r
-    \r
-    /**\r
-     * Get or create a binding based on default java classes, such as \r
-     * Integer.class, or byte[].class. The result is often binding for an \r
-     * immutable classs. These bindings are more efficient than mutable bindings (above).\r
-     * \r
-        * DataType           | Class of the bound instance\r
-        * ===================|==================\r
-     * BooleanType        | Boolean.class\r
-     * ByteType           | Byte.class\r
-     * FloatType          | Float.class\r
-     * DoubleType         | Double.class\r
-     * IntegerType        | Int.class\r
-     * LongType           | Long.class\r
-     * StringType         | String.class\r
-     * UnionType          | TaggedObject.class\r
-     * OptionType         | ValueContainer.class\r
-     * RecordType         | Object[].class\r
-     * MapType            | TreeMap.class\r
-     * VariantType        | Variant.class\r
-     * ArrayType(Boolean) | boolean[].class\r
-     * ArrayType(Byte)    | byte[].class\r
-     * ArrayType(Integer) | int[].class\r
-     * ArrayType(Long)    | long[].class\r
-     * ArrayType(Float)   | float[].class\r
-     * ArrayType(Double)  | double[].class\r
-     * ArrayType(Byte)    | byte[].class\r
-     * ArrayType( T )     | Object[].class\r
-     * \r
-        * Note, requesting a binding with this convenience method stores the \r
-        * binding and the type with strong reference, thus preventing garbage \r
-        * collection. To allow garbage collection, please use another instance of \r
-        * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>\r
-     *\r
-        * @param type the type to create binding to\r
-        * @return binding binding to a mutable class \r
-     */    \r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(Datatype type) {\r
-       try {\r
-               Binding binding = defaultBindingRepository.get(type);\r
-               if (binding!=null) return (T) binding;\r
-               synchronized(defaultBindingRepository) {\r
-                       return (T) defaultBindingFactory.getBinding(type);\r
-               }\r
-        } catch (BindingConstructionException e) {\r
-                       // Unexpected - if error is thrown there is fault in DefaultBindingScheme\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-    }    \r
-       \r
-       /**\r
-        * Get a binding to a Java Class. Details can be added by placing annotations\r
-        * to the java classes. See more in package org.simantics.databoard.annotations. \r
-        * <p>\r
-        *  \r
-        * Whether the result is a completely mutable or not depends on the \r
-        * requested class. For instance, fields such as Boolean, Integer, Long\r
-        * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.\r
-        * The length of Object[] is not mutable, but length of List<Object> is. <p>\r
-        * \r
-        * Note, requesting a binding with this convenience method stores the \r
-        * binding and the class with strong reference, thus preventing garbage \r
-        * collection. To allow garbage collection, please use another instance of \r
-        * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p> \r
-        * \r
-        * @see ClassBindingFactory  \r
-        * @param clazz \r
-        * @return binding\r
-        * @throws BindingConstructionException\r
-        */\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(Class<?> clazz)\r
-    throws BindingConstructionException\r
-    {\r
-       Binding binding = bindingRepository.get( clazz );\r
-       if (binding != null) {\r
-               return (T) binding;\r
-       }\r
-       \r
-       BindingRequest request = new BindingRequest( clazz );\r
-       synchronized(classBindingFactory) {\r
-               binding = classBindingFactory.construct(request);\r
-       }\r
-               return (T) binding;\r
-    }\r
-\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(BindingRequest request)\r
-    throws BindingConstructionException\r
-    {\r
-       synchronized(classBindingFactory) {\r
-               return (T) classBindingFactory.construct(request);\r
-       }\r
-    }\r
-    \r
-       /**\r
-        * Get a binding for a Java Class. Use this method to acquire class \r
-        * parameters for a generics class. <p>\r
-        * \r
-        * Example 1: \r
-        * \r
-        *    Binding binding = getBinding(Map.class, String.class, Integer.class);\r
-        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();\r
-        *    \r
-        * Example 2:\r
-        *    \r
-     *  Binding d = getBinding(List.class, Integer.class);\r
-        *  List<Integer> list = (List<Integer>) d.createRandom(5);\r
-        *    \r
-        * Example 3:\r
-        *    \r
-     *  Binding d = getBinding(List.class, List.class, Integer.class);\r
-        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);\r
-        * \r
-        * @see ClassBindingFactory  \r
-        * @param clazz\r
-        * @return binding\r
-        * @throws BindingConstructionException\r
-        */\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)\r
-    throws BindingConstructionException\r
-    {\r
-       BindingRequest request = new BindingRequest( clazz, parameters );\r
-       synchronized(classBindingFactory) {\r
-               return (T) classBindingFactory.construct(request);\r
-       }\r
-    }    \r
-    \r
-    /**\r
-        * Read binding and type from a class. DataType details and parameters\r
-        * are read as annotations placed in the class.  \r
-        * (See org.simantics.databoard.annotations)\r
-        * <p>\r
-        * As an exception, in the subclasses of {@link Throwable}, the fields of\r
-        * Throwable are omited.\r
-        * <p>\r
-        * This method is used for well-known classes where the caller is 100% sure\r
-        * that a binding is construable without exception. <p> \r
-        * \r
-        * @param clazz\r
-        * @return binding\r
-        * @throws RuntimeBindingConstructionException\r
-     */\r
-       @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBindingUnchecked(Class<?> clazz)\r
-    throws RuntimeBindingConstructionException\r
-    {\r
-               try {\r
-               return (T) getBinding(clazz);\r
-               } catch (BindingConstructionException e) {\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-    }    \r
-\r
-       /**\r
-        * Get a binding for a Java Class. Use this method to acquire class \r
-        * parameters for a generics class. <p>\r
-        * \r
-        * Example 1: \r
-        * \r
-        *    Binding binding = getBinding(Map.class, String.class, Integer.class);\r
-        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();\r
-        *    \r
-        * Example 2:\r
-        *    \r
-     *  Binding d = getBinding(List.class, Integer.class);\r
-        *  List<Integer> list = (List<Integer>) d.createRandom(5);\r
-        *    \r
-        * Example 3:\r
-        *    \r
-     *  Binding d = getBinding(List.class, List.class, Integer.class);\r
-        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);\r
-        * \r
-        * @see ClassBindingFactory  \r
-        * @param clazz\r
-        * @return binding\r
-        * @throws BindingConstructionException\r
-        */\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)\r
-    throws RuntimeBindingConstructionException\r
-    {\r
-       try {\r
-               Arguments args = new ArgumentImpl(parameters);\r
-               BindingRequest request = new BindingRequest( clazz, args );\r
-               Binding binding = bindingRepository.get( request );\r
-               if (binding!=null);\r
-               synchronized(classBindingFactory) {\r
-                       binding = classBindingFactory.construct(request);\r
-               }\r
-                       return (T) binding;\r
-       } catch (BindingConstructionException e) {\r
-               throw new RuntimeBindingConstructionException(e);\r
-       }\r
-    }    \r
-    \r
-    /**\r
-     * Add a simple binding to reflection binding factory.\r
-     *  \r
-     * @param binding\r
-     * @param clazz\r
-     * @param parameters parameter classes\r
-     */\r
-    public void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )\r
-    {\r
-       ArgumentImpl args = new ArgumentImpl( parameters );\r
-       BindingRequest request = new BindingRequest( clazz, args );\r
-       bindingRepository.put( request, binding );\r
-    }\r
-    \r
-    /**\r
-     * Add binding factory for compositive bindings \r
-     * \r
-     * @param factory\r
-     */\r
-    public void addBindingFactory( BindingProvider factory )\r
-    {\r
-       classBindingFactory.addFactory( factory );\r
-    }\r
-    \r
-    /**\r
-     * Creates a bean class \r
-     * @param type\r
-     * @return class\r
-     */\r
-    public BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {\r
-       try {\r
-                       return typeClassFactory.getClass(type);\r
-               } catch (BindingConstructionException e) {\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-    }\r
-\r
-    /**\r
-     * Creates a bean class \r
-     * @param type\r
-     * @return class\r
-     */\r
-    public Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {\r
-       BindingRequest br = typeClassFactory.getClass(type);\r
-       return br.getClazz();\r
-    }\r
-\r
-    /**\r
-     * Create binding from datatype that instantiates java classes. \r
-     * RecordTypes are Beans, UnionTypes are Classes with @Union annotation, \r
-     * ArrayTypes are []. \r
-     * \r
-     * @param type\r
-     * @return class\r
-     */\r
-    public Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {\r
-               try {\r
-               BindingRequest br = typeClassFactory.getClass(type);\r
-               return getBinding( br );\r
-               } catch (BindingConstructionException e) {\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-    }\r
-\r
-       /**\r
-        * Get serializer that follows Databoard serialization spec.\r
-        *  \r
-        * @param binding\r
-        * @return serializer\r
-        * @throws SerializerConstructionException\r
-        */\r
-       public Serializer getSerializer(Binding binding) throws SerializerConstructionException {\r
-               return serializationFactory.construct(binding);\r
-       }\r
-\r
-       /**\r
-        * Get serializer that follows Databoard serialization spec.\r
-        * \r
-        * @param binding\r
-        * @return serializer\r
-        * @throws RuntimeSerializerConstructionException\r
-        */\r
-       public Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {\r
-               try {\r
-                       return serializationFactory.construct(binding);\r
-               } catch (SerializerConstructionException e) {\r
-                       throw new RuntimeSerializerConstructionException(e);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Get serializer that follows Databoard serialization spec.\r
-        *  \r
-        * @param clazz\r
-        * @return serializer\r
-        * @throws SerializerConstructionException\r
-        */\r
-       public Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {\r
-               try {\r
-                       Binding binding = getBinding(clazz);\r
-                       return serializationFactory.construct(binding);\r
-               } catch (BindingConstructionException e) {\r
-                       throw new SerializerConstructionException( e );\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Get serializer that follows Databoard serialization spec.\r
-        * \r
-        * @param clazz\r
-        * @return serializer serializer\r
-        * @throws RuntimeSerializerConstructionException\r
-        */\r
-       public Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {\r
-               try {\r
-                       Binding binding = getBinding(clazz);\r
-                       return serializationFactory.construct(binding);\r
-               } catch (SerializerConstructionException e) {\r
-                       throw new RuntimeSerializerConstructionException(e);\r
-               } catch (BindingConstructionException e) {\r
-                       throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );\r
-               }\r
-       }       \r
-    /**\r
-     * Create an adapter that adapts two bindings of the same\r
-     * data type.\r
-     * \r
-     * @param domain binding of the source instance\r
-     * @param range binding of the result instance\r
-     * @return result adapter\r
-     * @throws AdapterConstructionException \r
-     */\r
-    public Adapter getAdapter(Binding domain, Binding range)\r
-    throws AdapterConstructionException\r
-    {\r
-       return adapterFactory.getAdapter(domain, range, false, false);\r
-    }\r
-    \r
-    /**\r
-     * Create an adapter that adapts between two bindings of the same\r
-     * data type.\r
-     * \r
-     * @param domain binding of the source instance\r
-     * @param range binding of the result instance\r
-     * @return result adapter\r
-     * @throws AdapterConstructionException \r
-     */\r
-    public Adapter getAdapterUnchecked(Binding domain, Binding range)\r
-    throws RuntimeAdapterConstructionException\r
-    {\r
-       try {\r
-                       return adapterFactory.getAdapter(domain, range, false, false);\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new RuntimeAdapterConstructionException(e);\r
-               }\r
-    }\r
-\r
-    /**\r
-     * Create a type adapter that adapts instances from one Datatype to \r
-     * another. Type Adapter does the following conversions: \r
-     * \r
-     *    o Number Types, e.g. long -> double\r
-     *    o Unit Types, e.g. mph -> km/h\r
-     *    o Record Types, for each field of the range, there must be equal in domain \r
-     *    o Union Types, for each tag type of the domain, there must be equal in range\r
-     * \r
-     * {@link AdaptException} is thrown at runtime, if number conversion is not \r
-     * posible, e.g. converting value 500 from Integer to Byte.\r
-     * Note, there is also a possibility of precision loss, in many conversions\r
-     * e.g. from double to int.\r
-     * \r
-     * @param domain binding of the source instance\r
-     * @param range binding of the result instance\r
-     * @return adapter\r
-     * @throws AdapterConstructionException \r
-     */\r
-    public Adapter getTypeAdapter(Binding domain, Binding range)\r
-    throws AdapterConstructionException\r
-    {\r
-       return adapterFactory.getAdapter(domain, range, true, false);\r
-    }\r
-\r
-    /**\r
-     * Create a type adapter that adapts instances from one DataType to \r
-     * another. Type Adapter does the following conversions: \r
-     * \r
-     *    o Number Types, e.g. long -> double\r
-     *    o Unit Types, e.g. mph -> km/h\r
-     *    o Record Types, for each field of the range, there must be equal in domain \r
-     *    o Union Types, for each tag type of the domain, there must be equal in range\r
-     * \r
-     * {@link AdaptException} is thrown at runtime, if number values are \r
-     * not compatible, e.g. converting value 500 from Long to Byte.\r
-     * Note, there is also a possibility of precision loss, e.g. when \r
-     * converting from double to int.\r
-     * \r
-     * @param domain binding of the source instance\r
-     * @param range binding of the result instance\r
-     * @return result adapter\r
-     * @throws AdapterConstructionException \r
-     */\r
-    public Adapter getTypeAdapterUnchecked(Binding domain, Binding range)\r
-    {\r
-       try {\r
-                       return adapterFactory.getAdapter(domain, range, true, false);\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new RuntimeAdapterConstructionException(e);\r
-               }\r
-    }\r
-    \r
-    /**\r
-     * Adapt a value of one type to another. \r
-     * \r
-     * @param value\r
-     * @param domain\r
-     * @param range\r
-     * @return adapted value\r
-     * @throws AdapterConstructionException\r
-     * @throws AdaptException\r
-     */\r
-    public Object adapt(Object value, Binding domain, Binding range)\r
-    throws AdaptException\r
-    {\r
-       try {\r
-               if (domain==range) {\r
-                               return value;\r
-               }\r
-                       return adapterFactory.getAdapter(domain, range, true, false).adapt(value);\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new AdaptException(e);\r
-               }\r
-    }\r
-    \r
-    /**\r
-     * Adapt a value of one type to another. Exceptions are run-time. Use this\r
-     * if it safe to assume the conversion will be successful.\r
-     * \r
-     * @param value\r
-     * @param domain\r
-     * @param range\r
-     * @return adapted value\r
-     * @throws AdapterConstructionException\r
-     * @throws AdaptException\r
-     */\r
-    public Object adaptUnchecked(Object value, Binding domain, Binding range)\r
-    throws RuntimeAdapterConstructionException, RuntimeAdaptException\r
-    {\r
-       try {\r
-               if (domain==range) {\r
-                               return value;\r
-               }\r
-               return  adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);\r
-               } catch (RuntimeAdapterConstructionException e) {\r
-                       throw new RuntimeAdaptException(new AdaptException(e.getCause()));\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new RuntimeAdaptException(new AdaptException(e));\r
-               }\r
-    }    \r
-    \r
-    /**\r
-     * Adapt and clone a value instance to another type. Immutable \r
-     * bindings may return the argument as is, others return a cloned copy.  \r
-     * \r
-     * @param value\r
-     * @param domain\r
-     * @param range\r
-     * @return adapted value\r
-     * @throws AdapterConstructionException\r
-     * @throws AdaptException\r
-     */\r
-    public Object clone(Object value, Binding domain, Binding range)\r
-    throws AdaptException\r
-    {\r
-       try {\r
-               if (domain==range) {\r
-                       if (domain.isImmutable()) {\r
-                               return value;\r
-                       } else { \r
-                               return domain.clone(value);\r
-                       }\r
-               }\r
-                       return adapterFactory.getAdapter(domain, range, true, true).adapt(value);\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new AdaptException(e);\r
-               }\r
-    }\r
-    \r
-\r
-    /**\r
-     * Clone a value of one binding to another. Bindings that handle immutable values\r
-     * may return the same instance, others will guarantee a complete copy.\r
-     * \r
-     * This method throws only runtime exceptions. Use this if it is safe to assume\r
-     * that the conversion will be successful.\r
-     * \r
-     * @param value\r
-     * @param domain\r
-     * @param range\r
-     * @return adapted value\r
-     * @throws AdapterConstructionException\r
-     * @throws AdaptException\r
-     */\r
-    public Object cloneUnchecked(Object value, Binding domain, Binding range)\r
-    throws RuntimeAdapterConstructionException, RuntimeAdaptException\r
-    {\r
-       try {\r
-                       return adapterFactory.getAdapter(domain, range, true, true).adapt(value);\r
-               } catch (AdaptException e) {\r
-                       throw new RuntimeAdaptException(e);\r
-               } catch (RuntimeAdapterConstructionException e) {\r
-                       throw new RuntimeAdaptException(new AdaptException(e.getCause()));\r
-               } catch (AdapterConstructionException e) {\r
-                       throw new RuntimeAdaptException(new AdaptException(e));\r
-               }\r
-    }\r
-    \r
-    /**\r
-     * Compares two data values for order. Returns a negative integer,\r
-     * zero, or a positive integer if, the first argument precedes/lesser than \r
-     * the second, is equal to, or successor/greater than the second.<p>\r
-     * \r
-     * DataTypes of b1 and b2 are not equal, then data types are compared. <p>\r
-     *\r
-     * The comparison function is defined at \r
-     * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>\r
-     * \r
-     * Note, comparing 2 different number types will not result a value comparison.\r
-     * Instead values have the following type precedence ByteType, IntegerType, LongType,\r
-     * FloatType, and the highest DoubleType. <p>\r
-     *\r
-     * @param b1 Binding of o1 \r
-     * @param o1 the first object to be compared.\r
-     * @param b2 Binding of o2\r
-     * @param o2 the second object to be compared.\r
-     * @return a negative integer, zero, or a positive integer as the\r
-     *                first argument is less than, equal to, or greater than the\r
-     *        second.\r
-     * @throws BindingException if object cannot be handled by a binding\r
-     */\r
-    public int compare(Binding b1, Object o1, Binding b2, Object o2) \r
-    throws BindingException\r
-    {\r
-       return DataValueUtil.compare(b1, o1, b2, o2);\r
-    }\r
-    \r
-    /**\r
-     * Compare two data values for equality. <p>\r
-     * \r
-     * Note, comparing 2 different number types will not result a value comparison.\r
-     * Instead values have the following type precedence ByteType, IntegerType, LongType,\r
-     * FloatType, and the highest DoubleType. <p>\r
-     * \r
-     * @param b1\r
-     * @param o1\r
-     * @param b2\r
-     * @param o2\r
-     * @return true if equal\r
-     * @throws BindingException\r
-     */\r
-    public boolean equals(Binding b1, Object o1, Binding b2, Object o2)\r
-    throws BindingException\r
-    {\r
-       return DataValueUtil.equals(b1, o1, b2, o2);\r
-    }\r
-    \r
-    public Comparator<Object> createComparator(final Binding b1, final Binding b2)\r
-    {\r
-       return DataValueUtil.createComparator(b1, b2);\r
-    }\r
-    \r
-    /**\r
-     * Print the content of an object as a structure.\r
-     * Utility function for debug purposes.\r
-     * \r
-     * @param o\r
-     * @return content\r
-     */\r
-    public String toString(Object o) {\r
-       try {\r
-                       Binding b = getBinding( o.getClass() );\r
-                       return b.printValueDefinition(o, true);\r
-               } catch (BindingConstructionException e) {\r
-                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
-               } catch (IOException e) {\r
-                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
-               } catch (BindingException e) {\r
-                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";\r
-               }\r
-    }\r
-    \r
-    class DataboardBindings implements BindingProvider {\r
-               @Override\r
-               public Binding provideBinding(ClassBindingFactory mainFactory, BindingRequest request) throws BindingConstructionException {\r
-                       // Variant Type\r
-               if (request.getClazz().equals( Object.class )) return OBJECT;\r
-               if (request.getClazz().equals( Void.class ) || request.getClazz().equals(void.class) ) return VoidBinding.VOID_BINDING;\r
-               if (request.getClazz().equals( Variant.class) ) return Bindings.VARIANT;\r
-               if (request.getClazz().equals( MutableVariant.class) ) return Bindings.MUTABLE_VARIANT;\r
-                       if (request.getClazz().equals( Bean.class ) ) return BEAN;\r
-                               \r
-                       return null;\r
-               }\r
-       } \r
-                               \r
-    private void addDefaultBinding(Datatype datatype, Binding binding ) {\r
-       defaultBindingRepository.put(datatype, binding);\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.databoard;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.adapter.Adapter;
+import org.simantics.databoard.adapter.AdapterConstructionException;
+import org.simantics.databoard.adapter.AdapterFactory;
+import org.simantics.databoard.adapter.RuntimeAdaptException;
+import org.simantics.databoard.adapter.RuntimeAdapterConstructionException;
+import org.simantics.databoard.annotations.ArgumentImpl;
+import org.simantics.databoard.annotations.Arguments;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.VariantBinding;
+import org.simantics.databoard.binding.classfactory.ImmutableClassesFactory;
+import org.simantics.databoard.binding.classfactory.TypeClassFactory;
+import org.simantics.databoard.binding.classfactory.TypeClassSubFactory;
+import org.simantics.databoard.binding.error.BindingConstructionException;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
+import org.simantics.databoard.binding.factory.BindingRepository;
+import org.simantics.databoard.binding.factory.DefaultBindingFactory;
+import org.simantics.databoard.binding.factory.JavaUtilBindingsProvider;
+import org.simantics.databoard.binding.factory.MutableBindingFactory;
+import org.simantics.databoard.binding.factory.TroveBindingsProvider;
+import org.simantics.databoard.binding.factory.TypeBindingFactory;
+import org.simantics.databoard.binding.impl.BeanBinding;
+import org.simantics.databoard.binding.impl.ObjectVariantBinding;
+import org.simantics.databoard.binding.impl.StringVariantBinding;
+import org.simantics.databoard.binding.mutable.ImmutableVariantBinding;
+import org.simantics.databoard.binding.mutable.MutableVariant;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.binding.reflection.BindingProvider;
+import org.simantics.databoard.binding.reflection.BindingRequest;
+import org.simantics.databoard.binding.reflection.ClassBindingFactory;
+import org.simantics.databoard.binding.reflection.VoidBinding;
+import org.simantics.databoard.serialization.DefaultSerializerFactory;
+import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.serialization.SerializerConstructionException;
+import org.simantics.databoard.serialization.SerializerFactory;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.DataValueUtil;
+
+public class Databoard {
+
+       // Repositories
+
+       /** Repository of mutable bindings */
+    public final Map<Datatype, Binding>       mutableBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );
+
+    /** Repository of default bindings */
+    public final Map<Datatype, Binding>       defaultBindingRepository    = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );
+
+    /** Repository of class Bindings */
+    public final BindingRepository            bindingRepository = new BindingRepository();
+
+    /** Repository of serializers */
+    public final Map<Binding, Serializer>     serializerRepository        = Collections.synchronizedMap( new HashMap<Binding, Serializer>() ); 
+       
+    
+    // Factories
+
+    /** Mutable Bindings Factory */
+       public final TypeBindingFactory           mutableBindingFactory = new MutableBindingFactory( mutableBindingRepository );
+
+       /** Default Bindings Factory */
+       public final TypeBindingFactory           defaultBindingFactory = new DefaultBindingFactory( defaultBindingRepository );
+
+       /** Reflection based Binding Factory, create binding to class */
+    public final ClassBindingFactory            classBindingFactory = new ClassBindingFactory( bindingRepository, defaultBindingFactory );
+
+    /** Serializer Factory */
+    public final SerializerFactory              serializationFactory = new DefaultSerializerFactory( serializerRepository );
+
+    /** Adapter Factory */
+       public final AdapterFactory              adapterFactory = new AdapterFactory();
+       
+       /** Class Factory */ 
+       public final TypeClassFactory typeClassFactory = new TypeClassFactory();
+       
+       
+       public final VariantBinding VARIANT;                    // Variant      
+       public final VariantBinding OBJECT;                     // java.lang.Object ( as variant )      
+       public final VariantBinding STR_VARIANT;                // java.lang.String ( as variant )
+       public final Binding        BEAN;            // Bean ( as variant )                     
+
+       public Databoard() {
+       classBindingFactory.addFactory( new TroveBindingsProvider() );
+       classBindingFactory.addFactory( new JavaUtilBindingsProvider() );
+       
+       addDefaultBinding( Datatypes.STRING, Bindings.STRING );
+       addDefaultBinding( Datatypes.INTEGER, Bindings.INTEGER );
+       addDefaultBinding( Datatypes.BOOLEAN, Bindings.BOOLEAN );
+       addDefaultBinding( Datatypes.BYTE, Bindings.BYTE );
+       addDefaultBinding( Datatypes.LONG, Bindings.LONG );
+       addDefaultBinding( Datatypes.DOUBLE, Bindings.DOUBLE ); 
+       addDefaultBinding( Datatypes.FLOAT, Bindings.FLOAT );   
+        addDefaultBinding( Datatypes.VOID, Bindings.VOID );
+       addDefaultBinding( Datatypes.BOOLEAN_ARRAY, Bindings.BOOLEAN_ARRAY );
+       addDefaultBinding( Datatypes.BYTE_ARRAY, Bindings.BYTE_ARRAY );
+       addDefaultBinding( Datatypes.INTEGER_ARRAY, Bindings.INT_ARRAY );
+       addDefaultBinding( Datatypes.LONG_ARRAY, Bindings.LONG_ARRAY );
+       addDefaultBinding( Datatypes.FLOAT_ARRAY, Bindings.FLOAT_ARRAY );
+       addDefaultBinding( Datatypes.DOUBLE_ARRAY, Bindings.DOUBLE_ARRAY );
+       addDefaultBinding( Datatypes.STRING_ARRAY, Bindings.STRING_ARRAY );
+       
+       VARIANT        = new ImmutableVariantBinding( classBindingFactory, adapterFactory );
+       OBJECT         = new ObjectVariantBinding( classBindingFactory, adapterFactory );
+        BEAN           = new BeanBinding( classBindingFactory, typeClassFactory, adapterFactory );
+       STR_VARIANT    = new StringVariantBinding( serializationFactory, VARIANT );     
+
+       // Add sub-factory that creates binding for Bean
+       classBindingFactory.addFactory( new DataboardBindings() );
+       
+               // Add class factory that constructs basic types
+               typeClassFactory.addFactory( new ImmutableClassesFactory() );
+               
+               // Bindings.databoard cannot initialize itself
+               if (Bindings.databoard != null) {
+                       initialize();
+               }
+       }
+       
+       void initialize() {
+               // Add run-time class factory, if objectweb.asm-library is available.
+               try {
+                       // Check ASM Exists
+                       Class.forName("org.objectweb.asm.ClassWriter");
+                       Class<?> y = Class.forName("org.simantics.databoard.binding.classfactory.AsmTypeClassFactory");
+                       Constructor<?> c = y.getConstructor( TypeClassFactory.class );
+                       TypeClassSubFactory f = (TypeClassSubFactory) c.newInstance(typeClassFactory);
+                       typeClassFactory.addFactory( f );
+                       
+                       BindingRequest br = new BindingRequest( Datatype.class ); 
+                       Binding datatypeBinding = getBinding( br );
+                       typeClassFactory.getRepository().put(datatypeBinding.type(), br);
+                       bindingRepository.put(br, datatypeBinding);
+               } catch (ClassNotFoundException e) {
+               } catch (InstantiationException e) {
+               } catch (IllegalAccessException e) {
+               } catch (IllegalArgumentException e) {
+               } catch (InvocationTargetException e) {
+               } catch (SecurityException e) {
+               } catch (NoSuchMethodException e) {
+               } catch (BindingConstructionException e) {
+                       e.printStackTrace();
+               }
+       }
+       
+       public void clear() {
+               mutableBindingRepository.clear();
+               defaultBindingRepository.clear();
+               bindingRepository.clear();
+               serializerRepository.clear();           
+       }
+               
+    /**
+     * Get or create a binding that is completely mutable java class. 
+     * 
+        * DataType           | Class of the bound instance
+        * ===================|==================
+        * UnionType          | GenericBinding.TaggedObject.class
+        * OptionType         | ValueContainer.class
+        * RecordType         | Object[].class
+        * BooleanType        | MutableBoolean.class
+        * DoubleType         | MutableDouble.class
+        * FloatType          | MutableFloat.class
+        * ByteType           | MutableByte.class
+        * IntegerType        | MutableInt.class
+        * LongType           | MutableLong.class
+        * StringType         | ValueContainer.class
+        * ArrayType          | ArrayList.class
+        * MapType            | TreeMap.class
+        * VariantType        | MutableVariant.class
+        * 
+        * Note, requesting a binding with this convenience method stores the 
+        * binding and the type with strong reference, thus preventing garbage 
+        * collection. To allow garbage collection, please use another instance of 
+        * GenericBindingFactory and binding repository (Map<Datatype, Binding>). <p>
+     *
+        * @param type the type to create binding to
+        * @return binding binding to a mutable class 
+     */    
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getMutableBinding(Datatype type) {
+       try {
+               Binding binding = mutableBindingRepository.get(type);
+               if (binding!=null) return (T) binding;
+               synchronized(mutableBindingRepository) {
+                       return (T) mutableBindingFactory.getBinding(type);
+               }
+               } catch (BindingConstructionException e) {
+                       // Unexpected - if error is thrown there is fault in GenericBindingScheme
+                       throw new RuntimeBindingConstructionException(e);
+               }
+    }
+    
+    /**
+     * Get or create a binding based on default java classes, such as 
+     * Integer.class, or byte[].class. The result is often binding for an 
+     * immutable classs. These bindings are more efficient than mutable bindings (above).
+     * 
+        * DataType           | Class of the bound instance
+        * ===================|==================
+     * BooleanType        | Boolean.class
+     * ByteType           | Byte.class
+     * FloatType          | Float.class
+     * DoubleType         | Double.class
+     * IntegerType        | Int.class
+     * LongType           | Long.class
+     * StringType         | String.class
+     * UnionType          | TaggedObject.class
+     * OptionType         | ValueContainer.class
+     * RecordType         | Object[].class
+     * MapType            | TreeMap.class
+     * VariantType        | Variant.class
+     * ArrayType(Boolean) | boolean[].class
+     * ArrayType(Byte)    | byte[].class
+     * ArrayType(Integer) | int[].class
+     * ArrayType(Long)    | long[].class
+     * ArrayType(Float)   | float[].class
+     * ArrayType(Double)  | double[].class
+     * ArrayType(Byte)    | byte[].class
+     * ArrayType( T )     | Object[].class
+     * 
+        * Note, requesting a binding with this convenience method stores the 
+        * binding and the type with strong reference, thus preventing garbage 
+        * collection. To allow garbage collection, please use another instance of 
+        * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>
+     *
+        * @param type the type to create binding to
+        * @return binding binding to a mutable class 
+     */    
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(Datatype type) {
+       try {
+               Binding binding = defaultBindingRepository.get(type);
+               if (binding!=null) return (T) binding;
+               synchronized(defaultBindingRepository) {
+                       return (T) defaultBindingFactory.getBinding(type);
+               }
+        } catch (BindingConstructionException e) {
+                       // Unexpected - if error is thrown there is fault in DefaultBindingScheme
+                       throw new RuntimeBindingConstructionException(e);
+               }
+    }    
+       
+       /**
+        * Get a binding to a Java Class. Details can be added by placing annotations
+        * to the java classes. See more in package org.simantics.databoard.annotations. 
+        * <p>
+        *  
+        * Whether the result is a completely mutable or not depends on the 
+        * requested class. For instance, fields such as Boolean, Integer, Long
+        * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.
+        * The length of Object[] is not mutable, but length of List<Object> is. <p>
+        * 
+        * Note, requesting a binding with this convenience method stores the 
+        * binding and the class with strong reference, thus preventing garbage 
+        * collection. To allow garbage collection, please use another instance of 
+        * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p> 
+        * 
+        * @see ClassBindingFactory  
+        * @param clazz 
+        * @return binding
+        * @throws BindingConstructionException
+        */
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(Class<?> clazz)
+    throws BindingConstructionException
+    {
+       Binding binding = bindingRepository.get( clazz );
+       if (binding != null) {
+               return (T) binding;
+       }
+       
+       BindingRequest request = new BindingRequest( clazz );
+       synchronized(classBindingFactory) {
+               binding = classBindingFactory.construct(request);
+       }
+               return (T) binding;
+    }
+
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(BindingRequest request)
+    throws BindingConstructionException
+    {
+       synchronized(classBindingFactory) {
+               return (T) classBindingFactory.construct(request);
+       }
+    }
+    
+       /**
+        * Get a binding for a Java Class. Use this method to acquire class 
+        * parameters for a generics class. <p>
+        * 
+        * Example 1: 
+        * 
+        *    Binding binding = getBinding(Map.class, String.class, Integer.class);
+        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
+        *    
+        * Example 2:
+        *    
+     *  Binding d = getBinding(List.class, Integer.class);
+        *  List<Integer> list = (List<Integer>) d.createRandom(5);
+        *    
+        * Example 3:
+        *    
+     *  Binding d = getBinding(List.class, List.class, Integer.class);
+        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
+        * 
+        * @see ClassBindingFactory  
+        * @param clazz
+        * @return binding
+        * @throws BindingConstructionException
+        */
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)
+    throws BindingConstructionException
+    {
+       BindingRequest request = new BindingRequest( clazz, parameters );
+       synchronized(classBindingFactory) {
+               return (T) classBindingFactory.construct(request);
+       }
+    }    
+    
+    /**
+        * Read binding and type from a class. DataType details and parameters
+        * are read as annotations placed in the class.  
+        * (See org.simantics.databoard.annotations)
+        * <p>
+        * As an exception, in the subclasses of {@link Throwable}, the fields of
+        * Throwable are omited.
+        * <p>
+        * This method is used for well-known classes where the caller is 100% sure
+        * that a binding is construable without exception. <p> 
+        * 
+        * @param clazz
+        * @return binding
+        * @throws RuntimeBindingConstructionException
+     */
+       @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBindingUnchecked(Class<?> clazz)
+    throws RuntimeBindingConstructionException
+    {
+               try {
+               return (T) getBinding(clazz);
+               } catch (BindingConstructionException e) {
+                       throw new RuntimeBindingConstructionException(e);
+               }
+    }    
+
+       /**
+        * Get a binding for a Java Class. Use this method to acquire class 
+        * parameters for a generics class. <p>
+        * 
+        * Example 1: 
+        * 
+        *    Binding binding = getBinding(Map.class, String.class, Integer.class);
+        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
+        *    
+        * Example 2:
+        *    
+     *  Binding d = getBinding(List.class, Integer.class);
+        *  List<Integer> list = (List<Integer>) d.createRandom(5);
+        *    
+        * Example 3:
+        *    
+     *  Binding d = getBinding(List.class, List.class, Integer.class);
+        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
+        * 
+        * @see ClassBindingFactory  
+        * @param clazz
+        * @return binding
+        * @throws BindingConstructionException
+        */
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)
+    throws RuntimeBindingConstructionException
+    {
+       try {
+               Arguments args = new ArgumentImpl(parameters);
+               BindingRequest request = new BindingRequest( clazz, args );
+               Binding binding = bindingRepository.get( request );
+               if (binding!=null);
+               synchronized(classBindingFactory) {
+                       binding = classBindingFactory.construct(request);
+               }
+                       return (T) binding;
+       } catch (BindingConstructionException e) {
+               throw new RuntimeBindingConstructionException(e);
+       }
+    }    
+    
+    /**
+     * Add a simple binding to reflection binding factory.
+     *  
+     * @param binding
+     * @param clazz
+     * @param parameters parameter classes
+     */
+    public void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )
+    {
+       ArgumentImpl args = new ArgumentImpl( parameters );
+       BindingRequest request = new BindingRequest( clazz, args );
+       bindingRepository.put( request, binding );
+    }
+    
+    /**
+     * Add binding factory for compositive bindings 
+     * 
+     * @param factory
+     */
+    public void addBindingFactory( BindingProvider factory )
+    {
+       classBindingFactory.addFactory( factory );
+    }
+    
+    /**
+     * Creates a bean class 
+     * @param type
+     * @return class
+     */
+    public BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {
+       try {
+                       return typeClassFactory.getClass(type);
+               } catch (BindingConstructionException e) {
+                       throw new RuntimeBindingConstructionException(e);
+               }
+    }
+
+    /**
+     * Creates a bean class 
+     * @param type
+     * @return class
+     */
+    public Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {
+       BindingRequest br = typeClassFactory.getClass(type);
+       return br.getClazz();
+    }
+
+    /**
+     * Create binding from datatype that instantiates java classes. 
+     * RecordTypes are Beans, UnionTypes are Classes with @Union annotation, 
+     * ArrayTypes are []. 
+     * 
+     * @param type
+     * @return class
+     */
+    public Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {
+               try {
+               BindingRequest br = typeClassFactory.getClass(type);
+               return getBinding( br );
+               } catch (BindingConstructionException e) {
+                       throw new RuntimeBindingConstructionException(e);
+               }
+    }
+
+       /**
+        * Get serializer that follows Databoard serialization spec.
+        *  
+        * @param binding
+        * @return serializer
+        * @throws SerializerConstructionException
+        */
+       public Serializer getSerializer(Binding binding) throws SerializerConstructionException {
+               return serializationFactory.construct(binding);
+       }
+
+       /**
+        * Get serializer that follows Databoard serialization spec.
+        * 
+        * @param binding
+        * @return serializer
+        * @throws RuntimeSerializerConstructionException
+        */
+       public Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {
+               try {
+                       return serializationFactory.construct(binding);
+               } catch (SerializerConstructionException e) {
+                       throw new RuntimeSerializerConstructionException(e);
+               }
+       }
+
+       /**
+        * Get serializer that follows Databoard serialization spec.
+        *  
+        * @param clazz
+        * @return serializer
+        * @throws SerializerConstructionException
+        */
+       public Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {
+               try {
+                       Binding binding = getBinding(clazz);
+                       return serializationFactory.construct(binding);
+               } catch (BindingConstructionException e) {
+                       throw new SerializerConstructionException( e );
+               }
+       }
+
+       /**
+        * Get serializer that follows Databoard serialization spec.
+        * 
+        * @param clazz
+        * @return serializer serializer
+        * @throws RuntimeSerializerConstructionException
+        */
+       public Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {
+               try {
+                       Binding binding = getBinding(clazz);
+                       return serializationFactory.construct(binding);
+               } catch (SerializerConstructionException e) {
+                       throw new RuntimeSerializerConstructionException(e);
+               } catch (BindingConstructionException e) {
+                       throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );
+               }
+       }       
+    /**
+     * Create an adapter that adapts two bindings of the same
+     * data type.
+     * 
+     * @param domain binding of the source instance
+     * @param range binding of the result instance
+     * @return result adapter
+     * @throws AdapterConstructionException 
+     */
+    public Adapter getAdapter(Binding domain, Binding range)
+    throws AdapterConstructionException
+    {
+       return adapterFactory.getAdapter(domain, range, false, false);
+    }
+    
+    /**
+     * Create an adapter that adapts between two bindings of the same
+     * data type.
+     * 
+     * @param domain binding of the source instance
+     * @param range binding of the result instance
+     * @return result adapter
+     * @throws AdapterConstructionException 
+     */
+    public Adapter getAdapterUnchecked(Binding domain, Binding range)
+    throws RuntimeAdapterConstructionException
+    {
+       try {
+                       return adapterFactory.getAdapter(domain, range, false, false);
+               } catch (AdapterConstructionException e) {
+                       throw new RuntimeAdapterConstructionException(e);
+               }
+    }
+
+    /**
+     * Create a type adapter that adapts instances from one Datatype to 
+     * another. Type Adapter does the following conversions: 
+     * 
+     *    o Number Types, e.g. long -> double
+     *    o Unit Types, e.g. mph -> km/h
+     *    o Record Types, for each field of the range, there must be equal in domain 
+     *    o Union Types, for each tag type of the domain, there must be equal in range
+     * 
+     * {@link AdaptException} is thrown at runtime, if number conversion is not 
+     * posible, e.g. converting value 500 from Integer to Byte.
+     * Note, there is also a possibility of precision loss, in many conversions
+     * e.g. from double to int.
+     * 
+     * @param domain binding of the source instance
+     * @param range binding of the result instance
+     * @return adapter
+     * @throws AdapterConstructionException 
+     */
+    public Adapter getTypeAdapter(Binding domain, Binding range)
+    throws AdapterConstructionException
+    {
+       return adapterFactory.getAdapter(domain, range, true, false);
+    }
+
+    /**
+     * Create a type adapter that adapts instances from one DataType to 
+     * another. Type Adapter does the following conversions: 
+     * 
+     *    o Number Types, e.g. long -> double
+     *    o Unit Types, e.g. mph -> km/h
+     *    o Record Types, for each field of the range, there must be equal in domain 
+     *    o Union Types, for each tag type of the domain, there must be equal in range
+     * 
+     * {@link AdaptException} is thrown at runtime, if number values are 
+     * not compatible, e.g. converting value 500 from Long to Byte.
+     * Note, there is also a possibility of precision loss, e.g. when 
+     * converting from double to int.
+     * 
+     * @param domain binding of the source instance
+     * @param range binding of the result instance
+     * @return result adapter
+     * @throws AdapterConstructionException 
+     */
+    public Adapter getTypeAdapterUnchecked(Binding domain, Binding range)
+    {
+       try {
+                       return adapterFactory.getAdapter(domain, range, true, false);
+               } catch (AdapterConstructionException e) {
+                       throw new RuntimeAdapterConstructionException(e);
+               }
+    }
+    
+    /**
+     * Adapt a value of one type to another. 
+     * 
+     * @param value
+     * @param domain
+     * @param range
+     * @return adapted value
+     * @throws AdapterConstructionException
+     * @throws AdaptException
+     */
+    public Object adapt(Object value, Binding domain, Binding range)
+    throws AdaptException
+    {
+       try {
+               if (domain==range) {
+                               return value;
+               }
+                       return adapterFactory.getAdapter(domain, range, true, false).adapt(value);
+               } catch (AdapterConstructionException e) {
+                       throw new AdaptException(e);
+               }
+    }
+    
+    /**
+     * Adapt a value of one type to another. Exceptions are run-time. Use this
+     * if it safe to assume the conversion will be successful.
+     * 
+     * @param value
+     * @param domain
+     * @param range
+     * @return adapted value
+     * @throws AdapterConstructionException
+     * @throws AdaptException
+     */
+    public Object adaptUnchecked(Object value, Binding domain, Binding range)
+    throws RuntimeAdapterConstructionException, RuntimeAdaptException
+    {
+       try {
+               if (domain==range) {
+                               return value;
+               }
+               return  adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);
+               } catch (RuntimeAdapterConstructionException e) {
+                       throw new RuntimeAdaptException(new AdaptException(e.getCause()));
+               } catch (AdapterConstructionException e) {
+                       throw new RuntimeAdaptException(new AdaptException(e));
+               }
+    }    
+    
+    /**
+     * Adapt and clone a value instance to another type. Immutable 
+     * bindings may return the argument as is, others return a cloned copy.  
+     * 
+     * @param value
+     * @param domain
+     * @param range
+     * @return adapted value
+     * @throws AdapterConstructionException
+     * @throws AdaptException
+     */
+    public Object clone(Object value, Binding domain, Binding range)
+    throws AdaptException
+    {
+       try {
+               if (domain==range) {
+                       if (domain.isImmutable()) {
+                               return value;
+                       } else { 
+                               return domain.clone(value);
+                       }
+               }
+                       return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
+               } catch (AdapterConstructionException e) {
+                       throw new AdaptException(e);
+               }
+    }
+    
+
+    /**
+     * Clone a value of one binding to another. Bindings that handle immutable values
+     * may return the same instance, others will guarantee a complete copy.
+     * 
+     * This method throws only runtime exceptions. Use this if it is safe to assume
+     * that the conversion will be successful.
+     * 
+     * @param value
+     * @param domain
+     * @param range
+     * @return adapted value
+     * @throws AdapterConstructionException
+     * @throws AdaptException
+     */
+    public Object cloneUnchecked(Object value, Binding domain, Binding range)
+    throws RuntimeAdapterConstructionException, RuntimeAdaptException
+    {
+       try {
+                       return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
+               } catch (AdaptException e) {
+                       throw new RuntimeAdaptException(e);
+               } catch (RuntimeAdapterConstructionException e) {
+                       throw new RuntimeAdaptException(new AdaptException(e.getCause()));
+               } catch (AdapterConstructionException e) {
+                       throw new RuntimeAdaptException(new AdaptException(e));
+               }
+    }
+    
+    /**
+     * Compares two data values for order. Returns a negative integer,
+     * zero, or a positive integer if, the first argument precedes/lesser than 
+     * the second, is equal to, or successor/greater than the second.<p>
+     * 
+     * DataTypes of b1 and b2 are not equal, then data types are compared. <p>
+     *
+     * The comparison function is defined at 
+     * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>
+     * 
+     * Note, comparing 2 different number types will not result a value comparison.
+     * Instead values have the following type precedence ByteType, IntegerType, LongType,
+     * FloatType, and the highest DoubleType. <p>
+     *
+     * @param b1 Binding of o1 
+     * @param o1 the first object to be compared.
+     * @param b2 Binding of o2
+     * @param o2 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     *                first argument is less than, equal to, or greater than the
+     *        second.
+     * @throws BindingException if object cannot be handled by a binding
+     */
+    public int compare(Binding b1, Object o1, Binding b2, Object o2) 
+    throws BindingException
+    {
+       return DataValueUtil.compare(b1, o1, b2, o2);
+    }
+    
+    /**
+     * Compare two data values for equality. <p>
+     * 
+     * Note, comparing 2 different number types will not result a value comparison.
+     * Instead values have the following type precedence ByteType, IntegerType, LongType,
+     * FloatType, and the highest DoubleType. <p>
+     * 
+     * @param b1
+     * @param o1
+     * @param b2
+     * @param o2
+     * @return true if equal
+     * @throws BindingException
+     */
+    public boolean equals(Binding b1, Object o1, Binding b2, Object o2)
+    throws BindingException
+    {
+       return DataValueUtil.equals(b1, o1, b2, o2);
+    }
+    
+    public Comparator<Object> createComparator(final Binding b1, final Binding b2)
+    {
+       return DataValueUtil.createComparator(b1, b2);
+    }
+    
+    /**
+     * Print the content of an object as a structure.
+     * Utility function for debug purposes.
+     * 
+     * @param o
+     * @return content
+     */
+    public String toString(Object o) {
+       try {
+                       Binding b = getBinding( o.getClass() );
+                       return b.printValueDefinition(o, true);
+               } catch (BindingConstructionException e) {
+                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
+               } catch (IOException e) {
+                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
+               } catch (BindingException e) {
+                       return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
+               }
+    }
+    
+    class DataboardBindings implements BindingProvider {
+               @Override
+               public Binding provideBinding(ClassBindingFactory mainFactory, BindingRequest request) throws BindingConstructionException {
+                       // Variant Type
+               if (request.getClazz().equals( Object.class )) return OBJECT;
+               if (request.getClazz().equals( Void.class ) || request.getClazz().equals(void.class) ) return VoidBinding.VOID_BINDING;
+               if (request.getClazz().equals( Variant.class) ) return Bindings.VARIANT;
+               if (request.getClazz().equals( MutableVariant.class) ) return Bindings.MUTABLE_VARIANT;
+                       if (request.getClazz().equals( Bean.class ) ) return BEAN;
+                               
+                       return null;
+               }
+       } 
+                               
+    private void addDefaultBinding(Datatype datatype, Binding binding ) {
+       defaultBindingRepository.put(datatype, binding);
+    }
+
+}