--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010 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;
+
+import java.io.IOException;\r
+import java.util.Comparator;\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.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.ByteBinding;\r
+import org.simantics.databoard.binding.DoubleBinding;\r
+import org.simantics.databoard.binding.FloatBinding;\r
+import org.simantics.databoard.binding.IntegerBinding;\r
+import org.simantics.databoard.binding.LongBinding;\r
+import org.simantics.databoard.binding.StringBinding;\r
+import org.simantics.databoard.binding.VariantBinding;\r
+import org.simantics.databoard.binding.classfactory.TypeClassFactory;\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.TypeBindingFactory;\r
+import org.simantics.databoard.binding.impl.BooleanArrayBinding;\r
+import org.simantics.databoard.binding.impl.BooleanBindingDefault;\r
+import org.simantics.databoard.binding.impl.ByteArrayBinding;\r
+import org.simantics.databoard.binding.impl.ByteBindingDefault;\r
+import org.simantics.databoard.binding.impl.DoubleArrayBinding;\r
+import org.simantics.databoard.binding.impl.DoubleBindingDefault;\r
+import org.simantics.databoard.binding.impl.FloatArrayBinding;\r
+import org.simantics.databoard.binding.impl.FloatBindingDefault;\r
+import org.simantics.databoard.binding.impl.IntArrayBinding;\r
+import org.simantics.databoard.binding.impl.IntegerBindingDefault;\r
+import org.simantics.databoard.binding.impl.LongArrayBinding;\r
+import org.simantics.databoard.binding.impl.LongBindingDefault;\r
+import org.simantics.databoard.binding.impl.StringArrayBinding;\r
+import org.simantics.databoard.binding.impl.StringBindingDefault;\r
+import org.simantics.databoard.binding.impl.UnsignedByteBinding;\r
+import org.simantics.databoard.binding.impl.UnsignedIntegerBinding;\r
+import org.simantics.databoard.binding.impl.UnsignedLongBinding;\r
+import org.simantics.databoard.binding.mutable.MutableBooleanBinding;\r
+import org.simantics.databoard.binding.mutable.MutableByteBinding;\r
+import org.simantics.databoard.binding.mutable.MutableDoubleBinding;\r
+import org.simantics.databoard.binding.mutable.MutableFloatBinding;\r
+import org.simantics.databoard.binding.mutable.MutableIntegerBinding;\r
+import org.simantics.databoard.binding.mutable.MutableLongBinding;\r
+import org.simantics.databoard.binding.mutable.MutableStringBinding;\r
+import org.simantics.databoard.binding.mutable.MutableVariantBinding;\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.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.ArrayType;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.util.DataValueUtil;\r
+
+/**
+ * This ia a facade class for the binding services.
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class Bindings {\r
+ \r
+ public static final Databoard databoard;
+\r
+ // Repositories\r
+\r
+ /** Repository of mutable bindings */\r
+ public static final Map<Datatype, Binding> mutableBindingRepository;\r
+\r
+ /** Repository of default bindings */\r
+ public static final Map<Datatype, Binding> defaultBindingRepository;\r
+\r
+ /** Repository of class Bindings */\r
+ public static final BindingRepository bindingRepository;\r
+\r
+ /** Repository of serializers */\r
+ public static final Map<Binding, Serializer> serializerRepository;\r
+ \r
+ \r
+ // Factories\r
+\r
+ /** Mutable Bindings Factory */
+ public static final TypeBindingFactory mutableBindingFactory;\r
+\r
+ /** Default Bindings Factory */\r
+ public static final TypeBindingFactory defaultBindingFactory;\r
+\r
+ /** Reflection based Binding Factory, create binding to class */\r
+ public static final ClassBindingFactory classBindingFactory;\r
+\r
+ /** Serializer Factory */\r
+ public static final SerializerFactory serializationFactory;\r
+\r
+ /** Adapter Factory */\r
+ public static final AdapterFactory adapterFactory;\r
+ \r
+ /** Class Factory */ \r
+ public static final TypeClassFactory typeClassFactory;\r
+ \r
+ \r
+ // Bindings to various primitives\r
+ public static final StringBinding STRING; // java.lang.String \r
+ public static final IntegerBinding INTEGER; // java.lang.Integer \r
+ public static final BooleanBinding BOOLEAN; // java.lang.Boolean \r
+ public static final ByteBinding BYTE; // java.lang.Byte \r
+ public static final LongBinding LONG; // java.lang.Long\r
+ public static final DoubleBinding DOUBLE; // java.lang.Double \r
+ public static final FloatBinding FLOAT; // java.lang.Float \r
+ public static final VariantBinding VARIANT; // Variant \r
+ public static final VariantBinding OBJECT; // java.lang.Object ( as variant ) \r
+ public static final VariantBinding STR_VARIANT; // java.lang.String ( as variant )\r
+ \r
+ public static final Binding VOID; // void ( as {} )\r
+ public static final Binding BEAN; // Bean ( as variant ) \r
+\r
+ public static final ArrayBinding BOOLEAN_ARRAY; // boolean[] \r
+ public static final ArrayBinding BYTE_ARRAY; // byte[]\r
+ public static final ArrayBinding INT_ARRAY; // int[]\r
+ public static final ArrayBinding LONG_ARRAY; // long[]\r
+ public static final ArrayBinding FLOAT_ARRAY; // float[]\r
+ public static final ArrayBinding DOUBLE_ARRAY; // double[]\r
+ public static final ArrayBinding STRING_ARRAY; // String[]\r
+\r
+ public static final StringBinding MUTABLE_STRING; // MutableString\r
+ public static final IntegerBinding MUTABLE_INTEGER; // MutableInteger\r
+ public static final BooleanBinding MUTABLE_BOOLEAN; // MutableBoolean\r
+ public static final ByteBinding MUTABLE_BYTE; // MutableByte\r
+ public static final LongBinding MUTABLE_LONG; // MutableLong\r
+ public static final FloatBinding MUTABLE_FLOAT; // MutableFloat\r
+ public static final DoubleBinding MUTABLE_DOUBLE; // MutableDouble\r
+ public static final VariantBinding MUTABLE_VARIANT; // MutableVariant\r
+\r
+ public static final IntegerBinding UNSIGNED_INTEGER; // UnsignedInteger.Immutable\r
+ public static final ByteBinding UNSIGNED_BYTE; // UnsignedByte.Immutable\r
+ public static final LongBinding UNSIGNED_LONG; // UnsignedLong.Immutable\r
+\r
+ public static final IntegerBinding MUTABLE_UNSIGNED_INTEGER; // UnsignedInteger.Mutable\r
+ public static final ByteBinding MUTABLE_UNSIGNED_BYTE; // UnsignedByte.Mutable\r
+ public static final LongBinding MUTABLE_UNSIGNED_LONG; // UnsignedLong.Mutable \r
+ \r
+ /**
+ * 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\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>
+ *
+ * @param type the type to create binding to
+ * @return binding binding to a mutable class
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Binding> T getMutableBinding(Datatype type) {
+ 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
+ * 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 static <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
+
+ /**
+ * 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.
+ * <p>
+ *
+ * Whether the result is a completely mutable or not depends on the \r
+ * 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>\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
+ * Is asm library is available, the binding is bytecode generated. Then read\r
+ * and write operations are direct get/set calls or direct field read/writes. \r
+ * There is no reflection used. <p>\r
+ *
+ * @see ClassBindingFactory
+ * @param clazz
+ * @return binding
+ * @throws BindingConstructionException
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Binding> T getBinding(Class<?> clazz)
+ throws BindingConstructionException
+ {\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
+ }
+ return (T) binding;
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ public static <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 = Bindings.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 = Bindings.getBinding(List.class, Integer.class);\r
+ * List<Integer> list = (List<Integer>) d.createRandom(5);\r
+ * \r
+ * Example 3:\r
+ * \r
+ * Binding d = Bindings.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 static <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
+ * Try to get a binding for the actual class of a Java object.\r
+ * @param obj A Java object\r
+ * @return A binding for the class of the object\r
+ * @throws BindingConstructionException if no binding can be constructed\r
+ */\r
+ public static <T extends Binding> T getInstanceBinding(Object obj)\r
+ throws BindingConstructionException\r
+ {\r
+ return getBinding(obj.getClass());\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 static <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
+ * 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 = Bindings.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 = Bindings.getBinding(List.class, Integer.class);\r
+ * List<Integer> list = (List<Integer>) d.createRandom(5);\r
+ * \r
+ * Example 3:\r
+ * \r
+ * Binding d = Bindings.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 static <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 static 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 static 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 static 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 static 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 static 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 a default array binding for a given component type binding.\r
+ * Returns a primitive array type binding for primitive types and an\r
+ * ObjectArrayBinding for others.\r
+ * \r
+ * @param componentBinding A binding for a component type\r
+ * @return A binding for the array type\r
+ */\r
+ public static Binding getArrayBinding(Binding componentBinding) {\r
+ return getBinding(new ArrayType(componentBinding.type()));\r
+ }\r
+\r
+ /**\r
+ * Get serializer that follows Databoard serialization spec.\r
+ * \r
+ * @param binding\r
+ * @return serializer\r
+ * @throws SerializerConstructionException\r
+ */\r
+ public static Serializer getSerializer(Binding binding) throws SerializerConstructionException {\r
+ return serializationFactory.construct(binding);\r
+ }
+\r
+ /**\r
+ * Get serializer that follows Databoard serialization spec.\r
+ * \r
+ * @param binding\r
+ * @return serializer\r
+ * @throws RuntimeSerializerConstructionException\r
+ */\r
+ public static 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 static 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 static 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
+ }
+ /**
+ * 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 static 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 static 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\r
+ * 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 static 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 static 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 static Object adapt(Object value, Binding domain, Binding range)
+ throws AdaptException
+ {
+ try {
+ if (domain.equals(range)) {\r
+ return value;\r
+ }\r
+ else if (range instanceof VariantBinding) {\r
+ if (domain instanceof VariantBinding) {\r
+ // Copy variant contents directly\r
+ Binding contentBinding = ((VariantBinding)domain).getContentBinding( value );\r
+ Object content = ((VariantBinding)domain).getContent( value ); \r
+ return ((VariantBinding)range).create( contentBinding, content );\r
+ }\r
+ else {\r
+ // Default to just wrapping the value (avoid adapter construction to save memory)\r
+ return ((VariantBinding)range).create(domain, value);\r
+ }\r
+ }\r
+ else if (domain instanceof VariantBinding) {\r
+ return adapt(((VariantBinding)domain).getContent( value ), ((VariantBinding)domain).getContentBinding( value ), range );\r
+ }\r
+ else {\r
+ return adapterFactory.getAdapter(domain, range, true, false).adapt(value);\r
+ }
+ } catch (AdapterConstructionException | BindingException e) {
+ throw new AdaptException(e);
+ }\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.
+ *
+ * @param value
+ * @param domain
+ * @param range
+ * @return adapted value
+ * @throws AdapterConstructionException
+ * @throws AdaptException
+ */
+ public static Object adaptUnchecked(Object value, Binding domain, Binding range)
+ throws RuntimeAdapterConstructionException, RuntimeAdaptException
+ {\r
+ try {
+ if (domain==range) {\r
+ return value;\r
+ }\r
+ if (range instanceof VariantBinding && !(domain instanceof VariantBinding)) {\r
+ // Default to just wrapping the value (avoid adapter construction to save memory)\r
+ return ((VariantBinding)range).create(domain, value);\r
+ }\r
+ 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));
+ } catch (BindingException e) {\r
+ throw new RuntimeAdaptException(new AdaptException(e));\r
+ }
+ }
+
+ /**
+ * Adapt and clone a value instance to another type. Immutable \r
+ * 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 static Object clone(Object value, Binding domain, Binding range)
+ throws AdaptException
+ {
+ try {\r
+ if (domain==range) {\r
+ if (domain.isImmutable()) {\r
+ return value;\r
+ } else { \r
+ return domain.clone(value);\r
+ }\r
+ }
+ 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.
+ * \r
+ * This method throws only runtime exceptions. Use this if it is safe to assume\r
+ * that the conversion will be successful.\r
+ *
+ * @param value
+ * @param domain
+ * @param range
+ * @return adapted value
+ * @throws AdapterConstructionException
+ * @throws AdaptException
+ */
+ public static 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 \r
+ * 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 static 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 static boolean equals(Binding b1, Object o1, Binding b2, Object o2)
+ throws BindingException
+ {
+ return DataValueUtil.equals(b1, o1, b2, o2);
+ }
+
+ public static Comparator<Object> createComparator(final Binding b1, final Binding b2)
+ {
+ return DataValueUtil.createComparator(b1, b2);
+ }\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 static String toString(Object o) {\r
+ try {\r
+ Binding b = Bindings.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
+ static {\r
+ STRING = new StringBindingDefault( Datatypes.STRING ); \r
+ INTEGER = new IntegerBindingDefault( Datatypes.INTEGER ); \r
+ BOOLEAN = new BooleanBindingDefault( Datatypes.BOOLEAN ); \r
+ BYTE = new ByteBindingDefault( Datatypes.BYTE ); \r
+ LONG = new LongBindingDefault( Datatypes.LONG ); \r
+ DOUBLE = new DoubleBindingDefault( Datatypes.DOUBLE ); \r
+ FLOAT = new FloatBindingDefault( Datatypes.FLOAT ); \r
+ VOID = VoidBinding.VOID_BINDING;\r
+ BOOLEAN_ARRAY = new BooleanArrayBinding( Datatypes.BOOLEAN_ARRAY, BOOLEAN ); \r
+ BYTE_ARRAY = new ByteArrayBinding( Datatypes.BYTE_ARRAY, BYTE );\r
+ INT_ARRAY = new IntArrayBinding( Datatypes.INTEGER_ARRAY, INTEGER );\r
+ LONG_ARRAY = new LongArrayBinding( Datatypes.LONG_ARRAY, LONG );\r
+ FLOAT_ARRAY = new FloatArrayBinding( Datatypes.FLOAT_ARRAY, FLOAT );\r
+ DOUBLE_ARRAY = new DoubleArrayBinding( Datatypes.DOUBLE_ARRAY, DOUBLE );\r
+ STRING_ARRAY = new StringArrayBinding( Datatypes.STRING_ARRAY, STRING );\r
+ UNSIGNED_INTEGER = new UnsignedIntegerBinding.Immutable( Datatypes.INTEGER );\r
+ UNSIGNED_BYTE = new UnsignedByteBinding.Immutable( Datatypes.BYTE );\r
+ UNSIGNED_LONG = new UnsignedLongBinding.Immutable( Datatypes.LONG );\r
+ MUTABLE_STRING = new MutableStringBinding( Datatypes.STRING );\r
+ MUTABLE_INTEGER = new MutableIntegerBinding( Datatypes.INTEGER );\r
+ MUTABLE_BOOLEAN = new MutableBooleanBinding( Datatypes.BOOLEAN );\r
+ MUTABLE_BYTE = new MutableByteBinding( Datatypes.BYTE );\r
+ MUTABLE_LONG = new MutableLongBinding( Datatypes.LONG );\r
+ MUTABLE_FLOAT = new MutableFloatBinding( Datatypes.FLOAT );\r
+ MUTABLE_DOUBLE = new MutableDoubleBinding( Datatypes.DOUBLE );\r
+ MUTABLE_UNSIGNED_INTEGER = new UnsignedIntegerBinding.Mutable( Datatypes.INTEGER );\r
+ MUTABLE_UNSIGNED_BYTE = new UnsignedByteBinding.Mutable( Datatypes.BYTE );\r
+ MUTABLE_UNSIGNED_LONG = new UnsignedLongBinding.Mutable( Datatypes.LONG );\r
+ \r
+ databoard = new Databoard();\r
+ \r
+ mutableBindingRepository = databoard.mutableBindingRepository;\r
+ defaultBindingRepository = databoard.defaultBindingRepository;\r
+ bindingRepository = databoard.bindingRepository;\r
+ serializerRepository = databoard.serializerRepository;\r
+ mutableBindingFactory = databoard.mutableBindingFactory;\r
+ defaultBindingFactory = databoard.defaultBindingFactory;\r
+ classBindingFactory = databoard.classBindingFactory;\r
+ serializationFactory = databoard.serializationFactory;\r
+ adapterFactory = databoard.adapterFactory;\r
+ typeClassFactory = databoard.typeClassFactory;\r
+ \r
+ BEAN = databoard.BEAN;\r
+ VARIANT = databoard.VARIANT;\r
+ MUTABLE_VARIANT = new MutableVariantBinding( classBindingFactory, adapterFactory );\r
+ STR_VARIANT = databoard.STR_VARIANT;\r
+ OBJECT = databoard.OBJECT;\r
+ \r
+ databoard.initialize();\r
+ }\r
+
+}
+