/******************************************************************************* * 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.KeyReference; 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.OptionalType; import org.simantics.databoard.util.IdentityPair; /** * This is a binding of Optional Type and a Java Object. * * @see OptionalType * @author Toni Kalajainen */ public abstract class OptionalBinding extends Binding { public Binding componentBinding; public OptionalBinding(OptionalType type, Binding componentBinding) { this.componentBinding = componentBinding; this.type = type; } public OptionalBinding(Binding componentBinding) { this.componentBinding = componentBinding; this.type = new OptionalType(componentBinding.type()); } @Override public OptionalType type() { return (OptionalType) type; } /** * Create result with no value * * @return no value */ public abstract Object createNoValue() throws BindingException; /** * Create result with a value * * @param value * @return argument that contains a value */ public abstract Object createValue(Object value) throws BindingException; /** * Tests whether arg contains a value * * @param arg * @return true if arg contained a value */ public abstract boolean hasValue(Object arg) throws BindingException; /** * Get the non-null value, the arg did not contain a value, * BindingException is thrown. * * @param arg argument that contains a value * @return the composite value * @throws BindingException */ public abstract Object getValue(Object arg) throws BindingException; public abstract void setValue(Object optional, Object componentValue) throws BindingException; public abstract void setNoValue(Object optional) throws BindingException; public abstract boolean isInstance(Object obj); public Binding getComponentBinding() { return componentBinding; } @Override public void readFrom(Binding srcBinding, Object src, Object dst) throws BindingException { OptionalBinding sb = (OptionalBinding) srcBinding; if (sb.hasValue(src)) { Binding dcb = getComponentBinding(); Binding scb = sb.getComponentBinding(); Object scv = sb.getValue(src); if (dcb.isImmutable() || !hasValue(dst)) { try { Object v = Bindings.clone(scv, scb, dcb); v = dcb.readFromTry(scb, scv, v); setValue(dst, v); } catch (AdaptException e) { throw new BindingException(e); } } else { Object v = getValue(src); v = dcb.readFromTry(scb, scv, v); setValue(dst, v); } } else { setNoValue(dst); } } @Override public void accept(Visitor1 v, Object obj) { v.visit(this, obj); } @Override public T accept(Visitor v) { return v.visit(this); } /** * Assert tje obj is a correct instance. * Assert the obj is valid also according to the component binding. */ @Override public void assertInstaceIsValid(Object obj, Set validInstances) throws BindingException { if (!hasValue(obj)) return; Object componentValue = getValue(obj); componentBinding.assertInstaceIsValid(componentValue, validInstances); } @Override public int deepHashValue(Object value, IdentityHashMap hashedObjects) throws BindingException { return hasValue(value) ? componentBinding.deepHashValue( getValue(value), hashedObjects ) : 0; } @Override public int deepCompare(Object o1, Object o2, Set> compareHistory) throws BindingException { Boolean h1 = hasValue(o1); Boolean h2 = hasValue(o2); if (!h1 && !h2) return 0; int dif = h1.compareTo(h2); if (dif!=0) return dif; Binding c = getComponentBinding(); Object v1 = getValue(o1); Object v2 = getValue(o2); return c.deepCompare(v1, v2, compareHistory); } public Object createNoValueUnchecked() throws RuntimeBindingException { try { return createNoValue(); } catch (BindingException e) { throw new RuntimeBindingException(e); } } public Object createValueUnchecked(Object value) throws RuntimeBindingException { try { return createValue(value); } catch (BindingException e) { throw new RuntimeBindingException(e); } } public boolean hasValueUnchecked(Object arg) throws RuntimeBindingException { try { return hasValue(arg); } catch (BindingException e) { throw new RuntimeBindingException(e); } } @Override protected void toString(Object value, BindingPrintContext ctx) throws BindingException { if(hasValue(value)) { getComponentBinding().toString(getValue(value), ctx); } else { ctx.b.append("null"); } } @Override public Binding getComponentBinding(ChildReference path) { if (path==null) return this; if (path instanceof KeyReference) throw new IllegalArgumentException("KeyReference is not supported in OptionalType"); if (path instanceof NameReference) throw new IllegalArgumentException("NameReference is not supported in OptionalType"); if (path instanceof IndexReference && ((IndexReference) path).index!=0) throw new IllegalArgumentException("Index out of bounds"); if (path instanceof LabelReference && !((LabelReference) path).label.equals("v")) throw new IllegalArgumentException("Unknown label"); return componentBinding.getComponentBinding(path.childReference); } @Override public int getComponentCount() { return 1; } @Override public Binding getComponentBinding(int index) { if (index==0) return componentBinding; throw new IllegalArgumentException(); } @Override protected boolean deepEquals(Object obj, Set> compareHistory) { return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((OptionalBinding) obj).componentBinding, compareHistory); } @Override public int deepHashCode(IdentityHashMap hashedObjects) { return super.deepHashCode( hashedObjects ) + componentBinding.hashCode(hashedObjects); } }