X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2FDataboard.java;h=da488e0a81b087f423b0bfe0171102f305bf625f;hp=befbe35c5bb6e84ecd4e0003308e0a564bb37c3e;hb=a1696e5257fae039410c924155fdeffc1ce1b3e9;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java index befbe35c5..da488e0a8 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/Databoard.java @@ -1,821 +1,822 @@ -/******************************************************************************* - * 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 mutableBindingRepository = Collections.synchronizedMap( new HashMap() ); - - /** Repository of default bindings */ - public final Map defaultBindingRepository = Collections.synchronizedMap( new HashMap() ); - - /** Repository of class Bindings */ - public final BindingRepository bindingRepository = new BindingRepository(); - - /** Repository of serializers */ - public final Map serializerRepository = Collections.synchronizedMap( new HashMap() ); - - - // 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); - } 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).

- * - * @param type the type to create binding to - * @return binding binding to a mutable class - */ - @SuppressWarnings("unchecked") - public 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).

- * - * @param type the type to create binding to - * @return binding binding to a mutable class - */ - @SuppressWarnings("unchecked") - public 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. - *

- * - * 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 is.

- * - * 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).

- * - * @see ClassBindingFactory - * @param clazz - * @return binding - * @throws BindingConstructionException - */ - @SuppressWarnings("unchecked") - public 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 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.

- * - * Example 1: - * - * Binding binding = getBinding(Map.class, String.class, Integer.class); - * Map map = (Map) binding.createDefault(); - * - * Example 2: - * - * Binding d = getBinding(List.class, Integer.class); - * List list = (List) d.createRandom(5); - * - * Example 3: - * - * Binding d = getBinding(List.class, List.class, Integer.class); - * List> list = (List>) d.createRandom(5); - * - * @see ClassBindingFactory - * @param clazz - * @return binding - * @throws BindingConstructionException - */ - @SuppressWarnings("unchecked") - public 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) - *

- * As an exception, in the subclasses of {@link Throwable}, the fields of - * Throwable are omited. - *

- * This method is used for well-known classes where the caller is 100% sure - * that a binding is construable without exception.

- * - * @param clazz - * @return binding - * @throws RuntimeBindingConstructionException - */ - @SuppressWarnings("unchecked") - public 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.

- * - * Example 1: - * - * Binding binding = getBinding(Map.class, String.class, Integer.class); - * Map map = (Map) binding.createDefault(); - * - * Example 2: - * - * Binding d = getBinding(List.class, Integer.class); - * List list = (List) d.createRandom(5); - * - * Example 3: - * - * Binding d = getBinding(List.class, List.class, Integer.class); - * List> list = (List>) d.createRandom(5); - * - * @see ClassBindingFactory - * @param clazz - * @return binding - * @throws BindingConstructionException - */ - @SuppressWarnings("unchecked") - public 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.

- * - * DataTypes of b1 and b2 are not equal, then data types are compared.

- * - * The comparison function is defined at - * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals

- * - * 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.

- * - * @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.

- * - * 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.

- * - * @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 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 ""; - } catch (IOException e) { - return ""; - } catch (BindingException e) { - return ""; - } - } - - 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); - } - -} +/******************************************************************************* + * 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 mutableBindingRepository = Collections.synchronizedMap( new HashMap() ); + + /** Repository of default bindings */ + public final Map defaultBindingRepository = Collections.synchronizedMap( new HashMap() ); + + /** Repository of class Bindings */ + public final BindingRepository bindingRepository = new BindingRepository(); + + /** Repository of serializers */ + public final Map serializerRepository = Collections.synchronizedMap( new HashMap() ); + + + // 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).

+ * + * @param type the type to create binding to + * @return binding binding to a mutable class + */ + @SuppressWarnings("unchecked") + public 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).

+ * + * @param type the type to create binding to + * @return binding binding to a mutable class + */ + @SuppressWarnings("unchecked") + public 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. + *

+ * + * 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 is.

+ * + * 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).

+ * + * @see ClassBindingFactory + * @param clazz + * @return binding + * @throws BindingConstructionException + */ + @SuppressWarnings("unchecked") + public 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 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.

+ * + * Example 1: + * + * Binding binding = getBinding(Map.class, String.class, Integer.class); + * Map map = (Map) binding.createDefault(); + * + * Example 2: + * + * Binding d = getBinding(List.class, Integer.class); + * List list = (List) d.createRandom(5); + * + * Example 3: + * + * Binding d = getBinding(List.class, List.class, Integer.class); + * List> list = (List>) d.createRandom(5); + * + * @see ClassBindingFactory + * @param clazz + * @return binding + * @throws BindingConstructionException + */ + @SuppressWarnings("unchecked") + public 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) + *

+ * As an exception, in the subclasses of {@link Throwable}, the fields of + * Throwable are omited. + *

+ * This method is used for well-known classes where the caller is 100% sure + * that a binding is construable without exception.

+ * + * @param clazz + * @return binding + * @throws RuntimeBindingConstructionException + */ + @SuppressWarnings("unchecked") + public 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.

+ * + * Example 1: + * + * Binding binding = getBinding(Map.class, String.class, Integer.class); + * Map map = (Map) binding.createDefault(); + * + * Example 2: + * + * Binding d = getBinding(List.class, Integer.class); + * List list = (List) d.createRandom(5); + * + * Example 3: + * + * Binding d = getBinding(List.class, List.class, Integer.class); + * List> list = (List>) d.createRandom(5); + * + * @see ClassBindingFactory + * @param clazz + * @return binding + * @throws BindingConstructionException + */ + @SuppressWarnings("unchecked") + public 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.

+ * + * DataTypes of b1 and b2 are not equal, then data types are compared.

+ * + * The comparison function is defined at + * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals

+ * + * 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.

+ * + * @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.

+ * + * 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.

+ * + * @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 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 ""; + } catch (IOException e) { + return ""; + } catch (BindingException e) { + return ""; + } + } + + 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); + } + +}