--- /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.binding.mutable;
+
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InvalidObjectException;\r
+import java.io.ObjectStreamException;\r
+import java.io.Serializable;\r
+\r
+import org.simantics.databoard.Accessors;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.accessor.java.JavaObject;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.reflection.VoidBinding;\r
+import org.simantics.databoard.type.Datatype;\r
+
+/**
+ * MutableVariant is a container to a data value of any type.
+ * The value and type can be changed.
+ *
+ * MutableVariant is hash-equals-comparable, even variants of bindings (and types).
+ * The hash function and comparison rules are defined in the manual.
+ *\r
+ * @see MutableVariantBinding is binding for Variant-class
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class MutableVariant extends Variant implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = 1L;
+ \r
+ public static MutableVariant ofInstance(Object instance) {\r
+ Binding binding = Bindings.getBindingUnchecked( instance.getClass() );\r
+ return new MutableVariant(binding, instance);\r
+ }\r
+ \r
+ /**\r
+ * Constract a variant with a default value of empty record {}\r
+ */
+ public MutableVariant() {\r
+ binding = VoidBinding.VOID_BINDING;\r
+ value = null;\r
+ }\r
+
+ public MutableVariant(Variant v) {\r
+// assert(isValid(binding, value));\r
+ this.binding = v.getBinding();\r
+ this.value = v.getValue();\r
+ } \r
+
+ public MutableVariant(Binding binding, Object value) {
+// assert(isValid(binding, value));
+ this.binding = binding;
+ this.value = value;
+ }
+ \r
+ /**\r
+ * Set value and binding from a variant. This method takes the references, \r
+ * and does not clone the value.\r
+ * \r
+ * @param v source variant\r
+ */
+ public void setValue(Variant v) {\r
+ this.binding = v.getBinding();\r
+ this.value = v.getValue();\r
+ }\r
+
+ public void setValue(Binding binding, Object newValue) {
+// assert(isValid(binding, newValue));
+ this.binding = binding;
+ this.value = newValue;
+ }\r
+ \r
+ public void readFrom(Binding binding, Object newValue) throws BindingException {\r
+ if (binding.isImmutable()) {\r
+ this.binding = binding;\r
+ this.value = newValue;\r
+ return;\r
+ }\r
+ \r
+ if (this.binding == binding) {\r
+ binding.readFrom(binding, newValue, this.value);\r
+ } else {\r
+ try {\r
+ this.value = binding.clone( newValue );\r
+ this.binding = binding;\r
+ } catch (AdaptException e) {\r
+ throw new BindingException( e );\r
+ }\r
+ }\r
+ }
+\r
+ public MutableVariant clone() {\r
+ if (binding.isImmutable()) return new MutableVariant(binding, value);\r
+ Object newValue = Bindings.cloneUnchecked(value, binding, binding);\r
+ return new MutableVariant(binding, newValue);\r
+ }\r
+
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ Binding dataTypeBinding = Bindings.getBindingUnchecked( Datatype.class );
+ Bindings.getSerializerUnchecked( dataTypeBinding ).serialize(type());
+ Bindings.getSerializerUnchecked( binding ).serialize(value, out);
+ }
+
+ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+ Binding dataTypeBinding = Bindings.getBindingUnchecked( Datatype.class );
+ Datatype type = (Datatype) Bindings.getSerializerUnchecked( dataTypeBinding ).deserialize((InputStream)in);
+ Binding binding = Bindings.getMutableBinding(type);
+ Object value = Bindings.getSerializerUnchecked( binding ).deserialize((InputStream)in);
+ this.binding = binding;
+ this.value = value;
+ }
+
+ @SuppressWarnings("unused")
+ private void readObjectNoData() throws ObjectStreamException {
+ throw new InvalidObjectException("Don't know how to instantiate "+type()+" with no data");
+ }
+
+ public MutableVariant getComponent(ChildReference ref) throws AccessorConstructionException {\r
+ if ( ref == null ) return this;\r
+ JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);\r
+ return new MutableVariant( jo.getBinding(), jo.getObject() );\r
+ }\r
+ \r
+ public void setComponent(ChildReference ref, Binding binding, Object value) throws AccessorException, AccessorConstructionException {\r
+ if ( ref == null ) {\r
+ setValue( binding, value );\r
+ }\r
+ else {\r
+ JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);\r
+ jo.setValue( ref, binding, value );\r
+ }\r
+ }\r
+}