/******************************************************************************* * Copyright (c) 2010 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.binding.mutable; import java.io.IOException; import java.io.InputStream; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; import org.simantics.databoard.Accessors; import org.simantics.databoard.Bindings; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.java.JavaObject; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.reflection.VoidBinding; import org.simantics.databoard.type.Datatype; /** * 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. * * @see MutableVariantBinding is binding for Variant-class * @author Toni Kalajainen */ public class MutableVariant extends Variant implements Serializable, Cloneable { private static final long serialVersionUID = 1L; public static MutableVariant ofInstance(Object instance) { Binding binding = Bindings.getBindingUnchecked( instance.getClass() ); return new MutableVariant(binding, instance); } /** * Constract a variant with a default value of empty record {} */ public MutableVariant() { binding = VoidBinding.VOID_BINDING; value = null; } public MutableVariant(Variant v) { // assert(isValid(binding, value)); this.binding = v.getBinding(); this.value = v.getValue(); } public MutableVariant(Binding binding, Object value) { // assert(isValid(binding, value)); this.binding = binding; this.value = value; } /** * Set value and binding from a variant. This method takes the references, * and does not clone the value. * * @param v source variant */ public void setValue(Variant v) { this.binding = v.getBinding(); this.value = v.getValue(); } public void setValue(Binding binding, Object newValue) { // assert(isValid(binding, newValue)); this.binding = binding; this.value = newValue; } public void readFrom(Binding binding, Object newValue) throws BindingException { if (binding.isImmutable()) { this.binding = binding; this.value = newValue; return; } if (this.binding == binding) { binding.readFrom(binding, newValue, this.value); } else { try { this.value = binding.clone( newValue ); this.binding = binding; } catch (AdaptException e) { throw new BindingException( e ); } } } public MutableVariant clone() { if (binding.isImmutable()) return new MutableVariant(binding, value); Object newValue = Bindings.cloneUnchecked(value, binding, binding); return new MutableVariant(binding, newValue); } 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 { if ( ref == null ) return this; JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref); return new MutableVariant( jo.getBinding(), jo.getObject() ); } public void setComponent(ChildReference ref, Binding binding, Object value) throws AccessorException, AccessorConstructionException { if ( ref == null ) { setValue( binding, value ); } else { JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref); jo.setValue( ref, binding, value ); } } }