1 /*******************************************************************************
2 * Copyright (c) 2010 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard.binding.mutable;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.InvalidObjectException;
17 import java.io.ObjectStreamException;
18 import java.io.Serializable;
20 import org.simantics.databoard.Accessors;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.databoard.accessor.error.AccessorConstructionException;
23 import org.simantics.databoard.accessor.error.AccessorException;
24 import org.simantics.databoard.accessor.java.JavaObject;
25 import org.simantics.databoard.accessor.reference.ChildReference;
26 import org.simantics.databoard.adapter.AdaptException;
27 import org.simantics.databoard.binding.Binding;
28 import org.simantics.databoard.binding.error.BindingException;
29 import org.simantics.databoard.binding.reflection.VoidBinding;
30 import org.simantics.databoard.type.Datatype;
33 * MutableVariant is a container to a data value of any type.
34 * The value and type can be changed.
36 * MutableVariant is hash-equals-comparable, even variants of bindings (and types).
37 * The hash function and comparison rules are defined in the manual.
39 * @see MutableVariantBinding is binding for Variant-class
40 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
42 public class MutableVariant extends Variant implements Serializable, Cloneable {
44 private static final long serialVersionUID = 1L;
46 public static MutableVariant ofInstance(Object instance) {
47 Binding binding = Bindings.getBindingUnchecked( instance.getClass() );
48 return new MutableVariant(binding, instance);
52 * Constract a variant with a default value of empty record {}
54 public MutableVariant() {
55 binding = VoidBinding.VOID_BINDING;
59 public MutableVariant(Variant v) {
60 // assert(isValid(binding, value));
61 this.binding = v.getBinding();
62 this.value = v.getValue();
65 public MutableVariant(Binding binding, Object value) {
66 // assert(isValid(binding, value));
67 this.binding = binding;
72 * Set value and binding from a variant. This method takes the references,
73 * and does not clone the value.
75 * @param v source variant
77 public void setValue(Variant v) {
78 this.binding = v.getBinding();
79 this.value = v.getValue();
82 public void setValue(Binding binding, Object newValue) {
83 // assert(isValid(binding, newValue));
84 this.binding = binding;
85 this.value = newValue;
88 public void readFrom(Binding binding, Object newValue) throws BindingException {
89 if (binding.isImmutable()) {
90 this.binding = binding;
91 this.value = newValue;
95 if (this.binding == binding) {
96 binding.readFrom(binding, newValue, this.value);
99 this.value = binding.clone( newValue );
100 this.binding = binding;
101 } catch (AdaptException e) {
102 throw new BindingException( e );
107 public MutableVariant clone() {
108 if (binding.isImmutable()) return new MutableVariant(binding, value);
109 Object newValue = Bindings.cloneUnchecked(value, binding, binding);
110 return new MutableVariant(binding, newValue);
113 private void writeObject(java.io.ObjectOutputStream out) throws IOException {
114 Binding dataTypeBinding = Bindings.getBindingUnchecked( Datatype.class );
115 Bindings.getSerializerUnchecked( dataTypeBinding ).serialize(type());
116 Bindings.getSerializerUnchecked( binding ).serialize(value, out);
119 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
120 Binding dataTypeBinding = Bindings.getBindingUnchecked( Datatype.class );
121 Datatype type = (Datatype) Bindings.getSerializerUnchecked( dataTypeBinding ).deserialize((InputStream)in);
122 Binding binding = Bindings.getMutableBinding(type);
123 Object value = Bindings.getSerializerUnchecked( binding ).deserialize((InputStream)in);
124 this.binding = binding;
128 @SuppressWarnings("unused")
129 private void readObjectNoData() throws ObjectStreamException {
130 throw new InvalidObjectException("Don't know how to instantiate "+type()+" with no data");
133 public MutableVariant getComponent(ChildReference ref) throws AccessorConstructionException {
134 if ( ref == null ) return this;
135 JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);
136 return new MutableVariant( jo.getBinding(), jo.getObject() );
139 public void setComponent(ChildReference ref, Binding binding, Object value) throws AccessorException, AccessorConstructionException {
141 setValue( binding, value );
144 JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);
145 jo.setValue( ref, binding, value );