X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fbinding%2FUnionBinding.java;fp=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fbinding%2FUnionBinding.java;h=6934c8ac5234b381b4687e57494143c178ba2d9f;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/UnionBinding.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/UnionBinding.java new file mode 100644 index 000000000..6934c8ac5 --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/UnionBinding.java @@ -0,0 +1,310 @@ +/******************************************************************************* + * 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; + +import java.util.IdentityHashMap; +import java.util.Set; + +import org.simantics.databoard.Bindings; +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.accessor.reference.IndexReference; +import org.simantics.databoard.accessor.reference.LabelReference; +import org.simantics.databoard.accessor.reference.NameReference; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.binding.error.RuntimeBindingException; +import org.simantics.databoard.binding.impl.BindingPrintContext; +import org.simantics.databoard.type.UnionType; +import org.simantics.databoard.util.IdentityPair; + + +/** + * This is a binding of Union Type and a Java Object. + * + * @see UnionType + * @author Toni Kalajainen + */ +public abstract class UnionBinding extends Binding { + + protected Binding[] componentBindings; + + public UnionBinding() {} + + public UnionBinding(Binding...componentBindings) { + this.componentBindings = componentBindings; + } + + @Override + public UnionType type() { + return (UnionType) type; + } + + public int getComponentCount() { + return type().getComponentCount(); + } + + public Binding getComponentBinding(int tagIndex) { + return componentBindings[tagIndex]; + } + + public Binding getComponentBinding(String tagName) { + return componentBindings[ type().getComponentIndex2(tagName) ]; + } + + public Binding[] getComponentBindings() { + return componentBindings; + } + + /** + * Get tag number of an instance. + * + * @param obj + * @return the tag number + * @throws BindingException is thrown if the instance is not a tag of this union + */ + public abstract int getTag(Object obj) throws BindingException; + + public abstract Object getValue(Object obj) throws BindingException; + + public abstract Object create(int tag, Object value) throws BindingException; + + /** + * Create a new union object with tag of default value. + * + * @param tag + * @return new union object + * @throws BindingException + */ + public Object createDefault(int tag) throws BindingException { + Binding cb = getComponentBinding(tag); + Object to = cb.createDefault(); + return create(tag, to); + } + + public Object create(String tag, Object value) throws BindingException { + Integer tagIndex = type().getComponentIndex(tag); + if(tagIndex == null) + throw new BindingException("Union type does not have a tag " + tag + "."); + return create(tagIndex, value); + } + + public Object createUnchecked(int tag, Object value) throws RuntimeBindingException + { + try { + return create(tag, value); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + @Override + public void readFrom(Binding srcBinding, Object src, Object dst) + throws BindingException { + UnionBinding sb = (UnionBinding) srcBinding; + int newTag = sb.getTag(src); + int oldTag = getTag(dst); + + // New value binding + Binding nvb = sb.getComponentBinding(newTag); + // New value + Object nv = sb.getValue(src); + + // Same tag + if (newTag==oldTag) { + // Same tag - old value is used if possible + + // Old value binding + Binding ovb = getComponentBinding(oldTag); + + Object ov = getValue(dst); + ov = ovb.readFromTry(nvb, nv, ov); + setValue(dst, oldTag, ov); + + } else { + // Different tag - old value is not used + boolean clone = !nvb.isImmutable(); + Binding dcb = getComponentBinding(newTag); + boolean adapt = nvb!=dcb; + + if ( !adapt && !clone) { + setValue(dst, newTag, nv); + } else { + try { + // Clone or adapt value if necessary. + Object dv = Bindings.clone(nv, nvb, dcb); + setValue(dst, newTag, dv); + } catch(AdaptException e) { + throw new BindingException(e); + } + } + } + + /* + if (dcb.isImmutable() || st!=dt) { + try { + Object dv = Bindings.clone(sv, scb, dcb); + setValue(dst, st, dv); + } catch(AdaptException e) { + throw new BindingException(e); + } + } else { + Object dv = getValue(dst); + dv = dcb.readFromTry(scb, sv, dv); + setValue(dst, st, dv); + } + */ + } + + /** + * Set value to an union. + * Throws BindingException if value cannot be written. + * + * @param union + * @param tag + * @param value + * @throws BindingException + */ + public abstract void setValue(Object union, int tag, Object value) throws BindingException; + + /** + * Set to tag with default value. + * + * @param union + * @param tag + * @throws BindingException + */ + public void setTag(Object union, int tag) throws BindingException { + Binding componentBinding = getComponentBinding(tag); + Object instance = componentBinding.createDefault(); + setValue(union, tag, instance); + } + + @Override + public void accept(Visitor1 v, Object obj) { + v.visit(this, obj); + } + + @Override + public T accept(Visitor v) { + return v.visit(this); + } + + /** + * Asserts the obj is valid to its UnionType. + * + * Asserts the obj using the component type + * + * @throws BindingException if obj is not valid according to the UnionType + */ + @Override + public void assertInstaceIsValid(Object obj, Set validInstances) throws BindingException { + UnionType type = type(); + int length = type.getComponentCount(); + if (length==0) return; + int tag = getTag(obj); + if (tag<0 || tag>=length) + throw new BindingException("Instance tag ("+tag+") is out of range [0.."+(length-1)+"], faulty UnionBinding"); + + Object componentValue = getValue(obj); + Binding componentBinding = getComponentBindings()[tag]; + componentBinding.assertInstaceIsValid(componentValue, validInstances); + } + + @Override + public int deepHashValue(Object value, IdentityHashMap hashedObjects) throws BindingException { + int tag = getTag(value); + Object element = getValue(value); + return tag + componentBindings[tag].deepHashValue(element, hashedObjects); + } + + @Override + public int deepCompare(Object o1, Object o2, + Set> compareHistory) + throws BindingException { + Integer t1 = getTag(o1); + Integer t2 = getTag(o2); + int dif = t1.compareTo(t2); + if (dif!=0) return dif; + Object v1 = getValue(o1); + Object v2 = getValue(o2); + Binding c = getComponentBindings()[t1]; + return c.deepCompare(v1, v2, compareHistory); + } + + public void setComponentBindings(Binding[] componentBindings) { + this.componentBindings = componentBindings; + } + + @Override + protected void toString(Object value, BindingPrintContext ctx) throws BindingException { + int tag = getTag(value); + ctx.b.append(type().getComponent(tag).name); + ctx.b.append(' '); + getComponentBinding(tag).toString(getValue(value), ctx); + } + + @Override + public Binding getComponentBinding(ChildReference path) { + if (path==null) return this; + if (path instanceof IndexReference) { + IndexReference ir = (IndexReference) path; + return componentBindings[ir.index].getComponentBinding(path.childReference); + } + if (path instanceof NameReference) { + NameReference nr = (NameReference) path; + return getComponentBinding( nr.name ).getComponentBinding(path.childReference); + } + if (path instanceof LabelReference) { + LabelReference lr = (LabelReference) path; + try { + Integer i = new Integer(lr.label); + return getComponentBinding( i ).getComponentBinding(path.childReference); + } catch (NumberFormatException nfe) { + return getComponentBinding( lr.label ).getComponentBinding(path.childReference); + } + } + throw new IllegalArgumentException(); + } + + /** + * Returns true if the tag of this union type can be modified + * + * @return true if mutable + */ + public boolean isTagMutable() { + return true; + } + + @Override + protected boolean deepEquals(Object obj, + Set> compareHistory) { + if (!super.deepEquals( obj, compareHistory )) + return false; + + UnionBinding o = (UnionBinding)obj; + if (componentBindings.length != o.componentBindings.length) return false; + + for (int i = 0; i < componentBindings.length; i++) + if (!componentBindings[i].equals(o.componentBindings[i], compareHistory)) + return false; + + return true; + } + + @Override + public int deepHashCode(IdentityHashMap hashedObjects) { + int code = super.deepHashCode( hashedObjects ); + for (int i = 0; i < componentBindings.length; i++) + code = 17 * code + componentBindings[i].hashCode(hashedObjects); + return code; + } +}