1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard;
\r
14 import java.io.IOException;
\r
15 import java.lang.reflect.Constructor;
\r
16 import java.lang.reflect.InvocationTargetException;
\r
17 import java.util.Collections;
\r
18 import java.util.Comparator;
\r
19 import java.util.HashMap;
\r
20 import java.util.Map;
\r
22 import org.simantics.databoard.adapter.AdaptException;
\r
23 import org.simantics.databoard.adapter.Adapter;
\r
24 import org.simantics.databoard.adapter.AdapterConstructionException;
\r
25 import org.simantics.databoard.adapter.AdapterFactory;
\r
26 import org.simantics.databoard.adapter.RuntimeAdaptException;
\r
27 import org.simantics.databoard.adapter.RuntimeAdapterConstructionException;
\r
28 import org.simantics.databoard.annotations.ArgumentImpl;
\r
29 import org.simantics.databoard.annotations.Arguments;
\r
30 import org.simantics.databoard.binding.Binding;
\r
31 import org.simantics.databoard.binding.VariantBinding;
\r
32 import org.simantics.databoard.binding.classfactory.ImmutableClassesFactory;
\r
33 import org.simantics.databoard.binding.classfactory.TypeClassFactory;
\r
34 import org.simantics.databoard.binding.classfactory.TypeClassSubFactory;
\r
35 import org.simantics.databoard.binding.error.BindingConstructionException;
\r
36 import org.simantics.databoard.binding.error.BindingException;
\r
37 import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
\r
38 import org.simantics.databoard.binding.factory.BindingRepository;
\r
39 import org.simantics.databoard.binding.factory.DefaultBindingFactory;
\r
40 import org.simantics.databoard.binding.factory.JavaUtilBindingsProvider;
\r
41 import org.simantics.databoard.binding.factory.MutableBindingFactory;
\r
42 import org.simantics.databoard.binding.factory.TroveBindingsProvider;
\r
43 import org.simantics.databoard.binding.factory.TypeBindingFactory;
\r
44 import org.simantics.databoard.binding.impl.BeanBinding;
\r
45 import org.simantics.databoard.binding.impl.ObjectVariantBinding;
\r
46 import org.simantics.databoard.binding.impl.StringVariantBinding;
\r
47 import org.simantics.databoard.binding.mutable.ImmutableVariantBinding;
\r
48 import org.simantics.databoard.binding.mutable.MutableVariant;
\r
49 import org.simantics.databoard.binding.mutable.Variant;
\r
50 import org.simantics.databoard.binding.reflection.BindingProvider;
\r
51 import org.simantics.databoard.binding.reflection.BindingRequest;
\r
52 import org.simantics.databoard.binding.reflection.ClassBindingFactory;
\r
53 import org.simantics.databoard.binding.reflection.VoidBinding;
\r
54 import org.simantics.databoard.serialization.DefaultSerializerFactory;
\r
55 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
\r
56 import org.simantics.databoard.serialization.Serializer;
\r
57 import org.simantics.databoard.serialization.SerializerConstructionException;
\r
58 import org.simantics.databoard.serialization.SerializerFactory;
\r
59 import org.simantics.databoard.type.Datatype;
\r
60 import org.simantics.databoard.util.Bean;
\r
61 import org.simantics.databoard.util.DataValueUtil;
\r
63 public class Databoard {
\r
67 /** Repository of mutable bindings */
\r
68 public final Map<Datatype, Binding> mutableBindingRepository = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );
\r
70 /** Repository of default bindings */
\r
71 public final Map<Datatype, Binding> defaultBindingRepository = Collections.synchronizedMap( new HashMap<Datatype, Binding>() );
\r
73 /** Repository of class Bindings */
\r
74 public final BindingRepository bindingRepository = new BindingRepository();
\r
76 /** Repository of serializers */
\r
77 public final Map<Binding, Serializer> serializerRepository = Collections.synchronizedMap( new HashMap<Binding, Serializer>() );
\r
82 /** Mutable Bindings Factory */
\r
83 public final TypeBindingFactory mutableBindingFactory = new MutableBindingFactory( mutableBindingRepository );
\r
85 /** Default Bindings Factory */
\r
86 public final TypeBindingFactory defaultBindingFactory = new DefaultBindingFactory( defaultBindingRepository );
\r
88 /** Reflection based Binding Factory, create binding to class */
\r
89 public final ClassBindingFactory classBindingFactory = new ClassBindingFactory( bindingRepository, defaultBindingFactory );
\r
91 /** Serializer Factory */
\r
92 public final SerializerFactory serializationFactory = new DefaultSerializerFactory( serializerRepository );
\r
94 /** Adapter Factory */
\r
95 public final AdapterFactory adapterFactory = new AdapterFactory();
\r
97 /** Class Factory */
\r
98 public final TypeClassFactory typeClassFactory = new TypeClassFactory();
\r
101 public final VariantBinding VARIANT; // Variant
\r
102 public final VariantBinding OBJECT; // java.lang.Object ( as variant )
\r
103 public final VariantBinding STR_VARIANT; // java.lang.String ( as variant )
\r
104 public final Binding BEAN; // Bean ( as variant )
\r
106 public Databoard() {
\r
107 classBindingFactory.addFactory( new TroveBindingsProvider() );
\r
108 classBindingFactory.addFactory( new JavaUtilBindingsProvider() );
\r
110 addDefaultBinding( Datatypes.STRING, Bindings.STRING );
\r
111 addDefaultBinding( Datatypes.INTEGER, Bindings.INTEGER );
\r
112 addDefaultBinding( Datatypes.BOOLEAN, Bindings.BOOLEAN );
\r
113 addDefaultBinding( Datatypes.BYTE, Bindings.BYTE );
\r
114 addDefaultBinding( Datatypes.LONG, Bindings.LONG );
\r
115 addDefaultBinding( Datatypes.DOUBLE, Bindings.DOUBLE );
\r
116 addDefaultBinding( Datatypes.FLOAT, Bindings.FLOAT );
\r
117 addDefaultBinding( Datatypes.VOID, Bindings.VOID );
\r
118 addDefaultBinding( Datatypes.BOOLEAN_ARRAY, Bindings.BOOLEAN_ARRAY );
\r
119 addDefaultBinding( Datatypes.BYTE_ARRAY, Bindings.BYTE_ARRAY );
\r
120 addDefaultBinding( Datatypes.INTEGER_ARRAY, Bindings.INT_ARRAY );
\r
121 addDefaultBinding( Datatypes.LONG_ARRAY, Bindings.LONG_ARRAY );
\r
122 addDefaultBinding( Datatypes.FLOAT_ARRAY, Bindings.FLOAT_ARRAY );
\r
123 addDefaultBinding( Datatypes.DOUBLE_ARRAY, Bindings.DOUBLE_ARRAY );
\r
124 addDefaultBinding( Datatypes.STRING_ARRAY, Bindings.STRING_ARRAY );
\r
126 VARIANT = new ImmutableVariantBinding( classBindingFactory, adapterFactory );
\r
127 OBJECT = new ObjectVariantBinding( classBindingFactory, adapterFactory );
\r
128 BEAN = new BeanBinding( classBindingFactory, typeClassFactory, adapterFactory );
\r
129 STR_VARIANT = new StringVariantBinding( serializationFactory, VARIANT );
\r
131 // Add sub-factory that creates binding for Bean
\r
132 classBindingFactory.addFactory( new DataboardBindings() );
\r
134 // Add class factory that constructs basic types
\r
135 typeClassFactory.addFactory( new ImmutableClassesFactory() );
\r
137 // Bindings.databoard cannot initialize itself
\r
138 if (Bindings.databoard != null) {
\r
143 void initialize() {
\r
144 // Add run-time class factory, if objectweb.asm-library is available.
\r
146 // Check ASM Exists
\r
147 Class.forName("org.objectweb.asm.ClassWriter");
\r
148 Class<?> y = Class.forName("org.simantics.databoard.binding.classfactory.AsmTypeClassFactory");
\r
149 Constructor<?> c = y.getConstructor( TypeClassFactory.class );
\r
150 TypeClassSubFactory f = (TypeClassSubFactory) c.newInstance(typeClassFactory);
\r
151 typeClassFactory.addFactory( f );
\r
153 BindingRequest br = new BindingRequest( Datatype.class );
\r
154 Binding datatypeBinding = getBinding( br );
\r
155 typeClassFactory.getRepository().put(datatypeBinding.type(), br);
\r
156 } catch (ClassNotFoundException e) {
\r
157 } catch (InstantiationException e) {
\r
158 } catch (IllegalAccessException e) {
\r
159 } catch (IllegalArgumentException e) {
\r
160 } catch (InvocationTargetException e) {
\r
161 } catch (SecurityException e) {
\r
162 } catch (NoSuchMethodException e) {
\r
163 } catch (BindingConstructionException e) {
\r
164 e.printStackTrace();
\r
168 public void clear() {
\r
169 mutableBindingRepository.clear();
\r
170 defaultBindingRepository.clear();
\r
171 bindingRepository.clear();
\r
172 serializerRepository.clear();
\r
176 * Get or create a binding that is completely mutable java class.
\r
178 * DataType | Class of the bound instance
\r
179 * ===================|==================
\r
180 * UnionType | GenericBinding.TaggedObject.class
\r
181 * OptionType | ValueContainer.class
\r
182 * RecordType | Object[].class
\r
183 * BooleanType | MutableBoolean.class
\r
184 * DoubleType | MutableDouble.class
\r
185 * FloatType | MutableFloat.class
\r
186 * ByteType | MutableByte.class
\r
187 * IntegerType | MutableInt.class
\r
188 * LongType | MutableLong.class
\r
189 * StringType | ValueContainer.class
\r
190 * ArrayType | ArrayList.class
\r
191 * MapType | TreeMap.class
\r
192 * VariantType | MutableVariant.class
\r
194 * Note, requesting a binding with this convenience method stores the
\r
195 * binding and the type with strong reference, thus preventing garbage
\r
196 * collection. To allow garbage collection, please use another instance of
\r
197 * GenericBindingFactory and binding repository (Map<Datatype, Binding>). <p>
\r
199 * @param type the type to create binding to
\r
200 * @return binding binding to a mutable class
\r
202 @SuppressWarnings("unchecked")
\r
203 public <T extends Binding> T getMutableBinding(Datatype type) {
\r
205 Binding binding = mutableBindingRepository.get(type);
\r
206 if (binding!=null) return (T) binding;
\r
207 synchronized(mutableBindingRepository) {
\r
208 return (T) mutableBindingFactory.getBinding(type);
\r
210 } catch (BindingConstructionException e) {
\r
211 // Unexpected - if error is thrown there is fault in GenericBindingScheme
\r
212 throw new RuntimeBindingConstructionException(e);
\r
217 * Get or create a binding based on default java classes, such as
\r
218 * Integer.class, or byte[].class. The result is often binding for an
\r
219 * immutable classs. These bindings are more efficient than mutable bindings (above).
\r
221 * DataType | Class of the bound instance
\r
222 * ===================|==================
\r
223 * BooleanType | Boolean.class
\r
224 * ByteType | Byte.class
\r
225 * FloatType | Float.class
\r
226 * DoubleType | Double.class
\r
227 * IntegerType | Int.class
\r
228 * LongType | Long.class
\r
229 * StringType | String.class
\r
230 * UnionType | TaggedObject.class
\r
231 * OptionType | ValueContainer.class
\r
232 * RecordType | Object[].class
\r
233 * MapType | TreeMap.class
\r
234 * VariantType | Variant.class
\r
235 * ArrayType(Boolean) | boolean[].class
\r
236 * ArrayType(Byte) | byte[].class
\r
237 * ArrayType(Integer) | int[].class
\r
238 * ArrayType(Long) | long[].class
\r
239 * ArrayType(Float) | float[].class
\r
240 * ArrayType(Double) | double[].class
\r
241 * ArrayType(Byte) | byte[].class
\r
242 * ArrayType( T ) | Object[].class
\r
244 * Note, requesting a binding with this convenience method stores the
\r
245 * binding and the type with strong reference, thus preventing garbage
\r
246 * collection. To allow garbage collection, please use another instance of
\r
247 * DefaultBindingFactory and binding repository (Map<Datatype, Binding>). <p>
\r
249 * @param type the type to create binding to
\r
250 * @return binding binding to a mutable class
\r
252 @SuppressWarnings("unchecked")
\r
253 public <T extends Binding> T getBinding(Datatype type) {
\r
255 Binding binding = defaultBindingRepository.get(type);
\r
256 if (binding!=null) return (T) binding;
\r
257 synchronized(defaultBindingRepository) {
\r
258 return (T) defaultBindingFactory.getBinding(type);
\r
260 } catch (BindingConstructionException e) {
\r
261 // Unexpected - if error is thrown there is fault in DefaultBindingScheme
\r
262 throw new RuntimeBindingConstructionException(e);
\r
267 * Get a binding to a Java Class. Details can be added by placing annotations
\r
268 * to the java classes. See more in package org.simantics.databoard.annotations.
\r
271 * Whether the result is a completely mutable or not depends on the
\r
272 * requested class. For instance, fields such as Boolean, Integer, Long
\r
273 * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.
\r
274 * The length of Object[] is not mutable, but length of List<Object> is. <p>
\r
276 * Note, requesting a binding with this convenience method stores the
\r
277 * binding and the class with strong reference, thus preventing garbage
\r
278 * collection. To allow garbage collection, please use another instance of
\r
279 * BindingFactory and binding repository (Map<BindingRequest, Binding>). <p>
\r
281 * @see ClassBindingFactory
\r
284 * @throws BindingConstructionException
\r
286 @SuppressWarnings("unchecked")
\r
287 public <T extends Binding> T getBinding(Class<?> clazz)
\r
288 throws BindingConstructionException
\r
290 Binding binding = bindingRepository.get( clazz );
\r
291 if (binding != null) {
\r
292 return (T) binding;
\r
295 BindingRequest request = new BindingRequest( clazz );
\r
296 synchronized(classBindingFactory) {
\r
297 binding = classBindingFactory.construct(request);
\r
299 return (T) binding;
\r
302 @SuppressWarnings("unchecked")
\r
303 public <T extends Binding> T getBinding(BindingRequest request)
\r
304 throws BindingConstructionException
\r
306 synchronized(classBindingFactory) {
\r
307 return (T) classBindingFactory.construct(request);
\r
312 * Get a binding for a Java Class. Use this method to acquire class
\r
313 * parameters for a generics class. <p>
\r
317 * Binding binding = getBinding(Map.class, String.class, Integer.class);
\r
318 * Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
\r
322 * Binding d = getBinding(List.class, Integer.class);
\r
323 * List<Integer> list = (List<Integer>) d.createRandom(5);
\r
327 * Binding d = getBinding(List.class, List.class, Integer.class);
\r
328 * List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
\r
330 * @see ClassBindingFactory
\r
333 * @throws BindingConstructionException
\r
335 @SuppressWarnings("unchecked")
\r
336 public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)
\r
337 throws BindingConstructionException
\r
339 BindingRequest request = new BindingRequest( clazz, parameters );
\r
340 synchronized(classBindingFactory) {
\r
341 return (T) classBindingFactory.construct(request);
\r
346 * Read binding and type from a class. DataType details and parameters
\r
347 * are read as annotations placed in the class.
\r
348 * (See org.simantics.databoard.annotations)
\r
350 * As an exception, in the subclasses of {@link Throwable}, the fields of
\r
351 * Throwable are omited.
\r
353 * This method is used for well-known classes where the caller is 100% sure
\r
354 * that a binding is construable without exception. <p>
\r
358 * @throws RuntimeBindingConstructionException
\r
360 @SuppressWarnings("unchecked")
\r
361 public <T extends Binding> T getBindingUnchecked(Class<?> clazz)
\r
362 throws RuntimeBindingConstructionException
\r
365 return (T) getBinding(clazz);
\r
366 } catch (BindingConstructionException e) {
\r
367 throw new RuntimeBindingConstructionException(e);
\r
372 * Get a binding for a Java Class. Use this method to acquire class
\r
373 * parameters for a generics class. <p>
\r
377 * Binding binding = getBinding(Map.class, String.class, Integer.class);
\r
378 * Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
\r
382 * Binding d = getBinding(List.class, Integer.class);
\r
383 * List<Integer> list = (List<Integer>) d.createRandom(5);
\r
387 * Binding d = getBinding(List.class, List.class, Integer.class);
\r
388 * List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
\r
390 * @see ClassBindingFactory
\r
393 * @throws BindingConstructionException
\r
395 @SuppressWarnings("unchecked")
\r
396 public <T extends Binding> T getBindingUnchecked(Class<?> clazz, Class<?>...parameters)
\r
397 throws RuntimeBindingConstructionException
\r
400 Arguments args = new ArgumentImpl(parameters);
\r
401 BindingRequest request = new BindingRequest( clazz, args );
\r
402 Binding binding = bindingRepository.get( request );
\r
403 if (binding!=null);
\r
404 synchronized(classBindingFactory) {
\r
405 binding = classBindingFactory.construct(request);
\r
407 return (T) binding;
\r
408 } catch (BindingConstructionException e) {
\r
409 throw new RuntimeBindingConstructionException(e);
\r
414 * Add a simple binding to reflection binding factory.
\r
418 * @param parameters parameter classes
\r
420 public void addBinding( Binding binding, Class<?> clazz, Class<?>...parameters )
\r
422 ArgumentImpl args = new ArgumentImpl( parameters );
\r
423 BindingRequest request = new BindingRequest( clazz, args );
\r
424 bindingRepository.put( request, binding );
\r
428 * Add binding factory for compositive bindings
\r
432 public void addBindingFactory( BindingProvider factory )
\r
434 classBindingFactory.addFactory( factory );
\r
438 * Creates a bean class
\r
442 public BindingRequest getBeanBindingRequest( Datatype type ) throws RuntimeBindingConstructionException {
\r
444 return typeClassFactory.getClass(type);
\r
445 } catch (BindingConstructionException e) {
\r
446 throw new RuntimeBindingConstructionException(e);
\r
451 * Creates a bean class
\r
455 public Class<?> getBeanClass( Datatype type ) throws BindingConstructionException {
\r
456 BindingRequest br = typeClassFactory.getClass(type);
\r
457 return br.getClazz();
\r
461 * Create binding from datatype that instantiates java classes.
\r
462 * RecordTypes are Beans, UnionTypes are Classes with @Union annotation,
\r
463 * ArrayTypes are [].
\r
468 public Binding getBeanBinding( Datatype type ) throws RuntimeBindingConstructionException {
\r
470 BindingRequest br = typeClassFactory.getClass(type);
\r
471 return getBinding( br );
\r
472 } catch (BindingConstructionException e) {
\r
473 throw new RuntimeBindingConstructionException(e);
\r
478 * Get serializer that follows Databoard serialization spec.
\r
481 * @return serializer
\r
482 * @throws SerializerConstructionException
\r
484 public Serializer getSerializer(Binding binding) throws SerializerConstructionException {
\r
485 return serializationFactory.construct(binding);
\r
489 * Get serializer that follows Databoard serialization spec.
\r
492 * @return serializer
\r
493 * @throws RuntimeSerializerConstructionException
\r
495 public Serializer getSerializerUnchecked(Binding binding) throws RuntimeSerializerConstructionException {
\r
497 return serializationFactory.construct(binding);
\r
498 } catch (SerializerConstructionException e) {
\r
499 throw new RuntimeSerializerConstructionException(e);
\r
504 * Get serializer that follows Databoard serialization spec.
\r
507 * @return serializer
\r
508 * @throws SerializerConstructionException
\r
510 public Serializer getSerializer(Class<?> clazz) throws SerializerConstructionException {
\r
512 Binding binding = getBinding(clazz);
\r
513 return serializationFactory.construct(binding);
\r
514 } catch (BindingConstructionException e) {
\r
515 throw new SerializerConstructionException( e );
\r
520 * Get serializer that follows Databoard serialization spec.
\r
523 * @return serializer serializer
\r
524 * @throws RuntimeSerializerConstructionException
\r
526 public Serializer getSerializerUnchecked(Class<?> clazz) throws RuntimeSerializerConstructionException {
\r
528 Binding binding = getBinding(clazz);
\r
529 return serializationFactory.construct(binding);
\r
530 } catch (SerializerConstructionException e) {
\r
531 throw new RuntimeSerializerConstructionException(e);
\r
532 } catch (BindingConstructionException e) {
\r
533 throw new RuntimeSerializerConstructionException( new SerializerConstructionException(e) );
\r
537 * Create an adapter that adapts two bindings of the same
\r
540 * @param domain binding of the source instance
\r
541 * @param range binding of the result instance
\r
542 * @return result adapter
\r
543 * @throws AdapterConstructionException
\r
545 public Adapter getAdapter(Binding domain, Binding range)
\r
546 throws AdapterConstructionException
\r
548 return adapterFactory.getAdapter(domain, range, false, false);
\r
552 * Create an adapter that adapts between two bindings of the same
\r
555 * @param domain binding of the source instance
\r
556 * @param range binding of the result instance
\r
557 * @return result adapter
\r
558 * @throws AdapterConstructionException
\r
560 public Adapter getAdapterUnchecked(Binding domain, Binding range)
\r
561 throws RuntimeAdapterConstructionException
\r
564 return adapterFactory.getAdapter(domain, range, false, false);
\r
565 } catch (AdapterConstructionException e) {
\r
566 throw new RuntimeAdapterConstructionException(e);
\r
571 * Create a type adapter that adapts instances from one Datatype to
\r
572 * another. Type Adapter does the following conversions:
\r
574 * o Number Types, e.g. long -> double
\r
575 * o Unit Types, e.g. mph -> km/h
\r
576 * o Record Types, for each field of the range, there must be equal in domain
\r
577 * o Union Types, for each tag type of the domain, there must be equal in range
\r
579 * {@link AdaptException} is thrown at runtime, if number conversion is not
\r
580 * posible, e.g. converting value 500 from Integer to Byte.
\r
581 * Note, there is also a possibility of precision loss, in many conversions
\r
582 * e.g. from double to int.
\r
584 * @param domain binding of the source instance
\r
585 * @param range binding of the result instance
\r
587 * @throws AdapterConstructionException
\r
589 public Adapter getTypeAdapter(Binding domain, Binding range)
\r
590 throws AdapterConstructionException
\r
592 return adapterFactory.getAdapter(domain, range, true, false);
\r
596 * Create a type adapter that adapts instances from one DataType to
\r
597 * another. Type Adapter does the following conversions:
\r
599 * o Number Types, e.g. long -> double
\r
600 * o Unit Types, e.g. mph -> km/h
\r
601 * o Record Types, for each field of the range, there must be equal in domain
\r
602 * o Union Types, for each tag type of the domain, there must be equal in range
\r
604 * {@link AdaptException} is thrown at runtime, if number values are
\r
605 * not compatible, e.g. converting value 500 from Long to Byte.
\r
606 * Note, there is also a possibility of precision loss, e.g. when
\r
607 * converting from double to int.
\r
609 * @param domain binding of the source instance
\r
610 * @param range binding of the result instance
\r
611 * @return result adapter
\r
612 * @throws AdapterConstructionException
\r
614 public Adapter getTypeAdapterUnchecked(Binding domain, Binding range)
\r
617 return adapterFactory.getAdapter(domain, range, true, false);
\r
618 } catch (AdapterConstructionException e) {
\r
619 throw new RuntimeAdapterConstructionException(e);
\r
624 * Adapt a value of one type to another.
\r
629 * @return adapted value
\r
630 * @throws AdapterConstructionException
\r
631 * @throws AdaptException
\r
633 public Object adapt(Object value, Binding domain, Binding range)
\r
634 throws AdaptException
\r
637 if (domain==range) {
\r
640 return adapterFactory.getAdapter(domain, range, true, false).adapt(value);
\r
641 } catch (AdapterConstructionException e) {
\r
642 throw new AdaptException(e);
\r
647 * Adapt a value of one type to another. Exceptions are run-time. Use this
\r
648 * if it safe to assume the conversion will be successful.
\r
653 * @return adapted value
\r
654 * @throws AdapterConstructionException
\r
655 * @throws AdaptException
\r
657 public Object adaptUnchecked(Object value, Binding domain, Binding range)
\r
658 throws RuntimeAdapterConstructionException, RuntimeAdaptException
\r
661 if (domain==range) {
\r
664 return adapterFactory.getAdapter(domain, range, true, false).adaptUnchecked(value);
\r
665 } catch (RuntimeAdapterConstructionException e) {
\r
666 throw new RuntimeAdaptException(new AdaptException(e.getCause()));
\r
667 } catch (AdapterConstructionException e) {
\r
668 throw new RuntimeAdaptException(new AdaptException(e));
\r
673 * Adapt and clone a value instance to another type. Immutable
\r
674 * bindings may return the argument as is, others return a cloned copy.
\r
679 * @return adapted value
\r
680 * @throws AdapterConstructionException
\r
681 * @throws AdaptException
\r
683 public Object clone(Object value, Binding domain, Binding range)
\r
684 throws AdaptException
\r
687 if (domain==range) {
\r
688 if (domain.isImmutable()) {
\r
691 return domain.clone(value);
\r
694 return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
\r
695 } catch (AdapterConstructionException e) {
\r
696 throw new AdaptException(e);
\r
702 * Clone a value of one binding to another. Bindings that handle immutable values
\r
703 * may return the same instance, others will guarantee a complete copy.
\r
705 * This method throws only runtime exceptions. Use this if it is safe to assume
\r
706 * that the conversion will be successful.
\r
711 * @return adapted value
\r
712 * @throws AdapterConstructionException
\r
713 * @throws AdaptException
\r
715 public Object cloneUnchecked(Object value, Binding domain, Binding range)
\r
716 throws RuntimeAdapterConstructionException, RuntimeAdaptException
\r
719 return adapterFactory.getAdapter(domain, range, true, true).adapt(value);
\r
720 } catch (AdaptException e) {
\r
721 throw new RuntimeAdaptException(e);
\r
722 } catch (RuntimeAdapterConstructionException e) {
\r
723 throw new RuntimeAdaptException(new AdaptException(e.getCause()));
\r
724 } catch (AdapterConstructionException e) {
\r
725 throw new RuntimeAdaptException(new AdaptException(e));
\r
730 * Compares two data values for order. Returns a negative integer,
\r
731 * zero, or a positive integer if, the first argument precedes/lesser than
\r
732 * the second, is equal to, or successor/greater than the second.<p>
\r
734 * DataTypes of b1 and b2 are not equal, then data types are compared. <p>
\r
736 * The comparison function is defined at
\r
737 * http://dev.simantics.org/index.php/Org.simantics.datatype_Manual#CompareTo_and_Equals <p>
\r
739 * Note, comparing 2 different number types will not result a value comparison.
\r
740 * Instead values have the following type precedence ByteType, IntegerType, LongType,
\r
741 * FloatType, and the highest DoubleType. <p>
\r
743 * @param b1 Binding of o1
\r
744 * @param o1 the first object to be compared.
\r
745 * @param b2 Binding of o2
\r
746 * @param o2 the second object to be compared.
\r
747 * @return a negative integer, zero, or a positive integer as the
\r
748 * first argument is less than, equal to, or greater than the
\r
750 * @throws BindingException if object cannot be handled by a binding
\r
752 public int compare(Binding b1, Object o1, Binding b2, Object o2)
\r
753 throws BindingException
\r
755 return DataValueUtil.compare(b1, o1, b2, o2);
\r
759 * Compare two data values for equality. <p>
\r
761 * Note, comparing 2 different number types will not result a value comparison.
\r
762 * Instead values have the following type precedence ByteType, IntegerType, LongType,
\r
763 * FloatType, and the highest DoubleType. <p>
\r
769 * @return true if equal
\r
770 * @throws BindingException
\r
772 public boolean equals(Binding b1, Object o1, Binding b2, Object o2)
\r
773 throws BindingException
\r
775 return DataValueUtil.equals(b1, o1, b2, o2);
\r
778 public Comparator<Object> createComparator(final Binding b1, final Binding b2)
\r
780 return DataValueUtil.createComparator(b1, b2);
\r
784 * Print the content of an object as a structure.
\r
785 * Utility function for debug purposes.
\r
790 public String toString(Object o) {
\r
792 Binding b = getBinding( o.getClass() );
\r
793 return b.printValueDefinition(o, true);
\r
794 } catch (BindingConstructionException e) {
\r
795 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
796 } catch (IOException e) {
\r
797 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
798 } catch (BindingException e) {
\r
799 return "<error "+e.getClass().getName()+" "+e.getMessage()+">";
\r
803 class DataboardBindings implements BindingProvider {
\r
805 public Binding provideBinding(ClassBindingFactory mainFactory, BindingRequest request) throws BindingConstructionException {
\r
807 if (request.getClazz().equals( Object.class )) return OBJECT;
\r
808 if (request.getClazz().equals( Void.class ) || request.getClazz().equals(void.class) ) return VoidBinding.VOID_BINDING;
\r
809 if (request.getClazz().equals( Variant.class) ) return Bindings.VARIANT;
\r
810 if (request.getClazz().equals( MutableVariant.class) ) return Bindings.MUTABLE_VARIANT;
\r
811 if (request.getClazz().equals( Bean.class ) ) return BEAN;
\r
817 private void addDefaultBinding(Datatype datatype, Binding binding ) {
\r
818 defaultBindingRepository.put(datatype, binding);
\r