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;
14 import java.util.IdentityHashMap;
17 import org.simantics.databoard.Bindings;
18 import org.simantics.databoard.accessor.reference.ChildReference;
19 import org.simantics.databoard.accessor.reference.IndexReference;
20 import org.simantics.databoard.accessor.reference.KeyReference;
21 import org.simantics.databoard.accessor.reference.LabelReference;
22 import org.simantics.databoard.accessor.reference.NameReference;
23 import org.simantics.databoard.adapter.AdaptException;
24 import org.simantics.databoard.binding.error.BindingException;
25 import org.simantics.databoard.binding.error.RuntimeBindingException;
26 import org.simantics.databoard.binding.impl.BindingPrintContext;
27 import org.simantics.databoard.type.OptionalType;
28 import org.simantics.databoard.util.IdentityPair;
32 * This is a binding of Optional Type and a Java Object.
35 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
37 public abstract class OptionalBinding extends Binding {
39 public Binding componentBinding;
41 public OptionalBinding(OptionalType type, Binding componentBinding) {
42 this.componentBinding = componentBinding;
46 public OptionalBinding(Binding componentBinding) {
47 this.componentBinding = componentBinding;
48 this.type = new OptionalType(componentBinding.type());
52 public OptionalType type() {
53 return (OptionalType) type;
57 * Create result with no value
61 public abstract Object createNoValue() throws BindingException;
64 * Create result with a value
67 * @return argument that contains a value
69 public abstract Object createValue(Object value) throws BindingException;
73 * Tests whether arg contains a value
76 * @return true if arg contained a value
78 public abstract boolean hasValue(Object arg) throws BindingException;
81 * Get the non-null value, the arg did not contain a value,
82 * BindingException is thrown.
84 * @param arg argument that contains a value
85 * @return the composite value
86 * @throws BindingException
88 public abstract Object getValue(Object arg) throws BindingException;
90 public abstract void setValue(Object optional, Object componentValue) throws BindingException;
92 public abstract void setNoValue(Object optional) throws BindingException;
94 public abstract boolean isInstance(Object obj);
96 public Binding getComponentBinding() {
97 return componentBinding;
101 public void readFrom(Binding srcBinding, Object src, Object dst)
102 throws BindingException {
103 OptionalBinding sb = (OptionalBinding) srcBinding;
104 if (sb.hasValue(src)) {
105 Binding dcb = getComponentBinding();
106 Binding scb = sb.getComponentBinding();
107 Object scv = sb.getValue(src);
108 if (dcb.isImmutable() || !hasValue(dst)) {
110 Object v = Bindings.clone(scv, scb, dcb);
111 v = dcb.readFromTry(scb, scv, v);
113 } catch (AdaptException e) {
114 throw new BindingException(e);
117 Object v = getValue(src);
118 v = dcb.readFromTry(scb, scv, v);
127 public void accept(Visitor1 v, Object obj) {
132 public <T> T accept(Visitor<T> v) {
133 return v.visit(this);
137 * Assert tje obj is a correct instance.
138 * Assert the obj is valid also according to the component binding.
141 public void assertInstaceIsValid(Object obj, Set<Object> validInstances) throws BindingException {
142 if (!hasValue(obj)) return;
143 Object componentValue = getValue(obj);
144 componentBinding.assertInstaceIsValid(componentValue, validInstances);
148 public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
149 return hasValue(value) ? componentBinding.deepHashValue( getValue(value), hashedObjects ) : 0;
153 public int deepCompare(Object o1, Object o2, Set<IdentityPair<Object, Object>> compareHistory) throws BindingException
155 Boolean h1 = hasValue(o1);
156 Boolean h2 = hasValue(o2);
157 if (!h1 && !h2) return 0;
158 int dif = h1.compareTo(h2);
159 if (dif!=0) return dif;
161 Binding c = getComponentBinding();
162 Object v1 = getValue(o1);
163 Object v2 = getValue(o2);
164 return c.deepCompare(v1, v2, compareHistory);
167 public Object createNoValueUnchecked() throws RuntimeBindingException {
169 return createNoValue();
170 } catch (BindingException e) {
171 throw new RuntimeBindingException(e);
175 public Object createValueUnchecked(Object value)
176 throws RuntimeBindingException {
178 return createValue(value);
179 } catch (BindingException e) {
180 throw new RuntimeBindingException(e);
184 public boolean hasValueUnchecked(Object arg) throws RuntimeBindingException {
186 return hasValue(arg);
187 } catch (BindingException e) {
188 throw new RuntimeBindingException(e);
193 protected void toString(Object value, BindingPrintContext ctx) throws BindingException {
194 if(hasValue(value)) {
195 getComponentBinding().toString(getValue(value), ctx);
197 ctx.b.append("null");
202 public Binding getComponentBinding(ChildReference path) {
203 if (path==null) return this;
204 if (path instanceof KeyReference) throw new IllegalArgumentException("KeyReference is not supported in OptionalType");
205 if (path instanceof NameReference) throw new IllegalArgumentException("NameReference is not supported in OptionalType");
206 if (path instanceof IndexReference && ((IndexReference) path).index!=0) throw new IllegalArgumentException("Index out of bounds");
207 if (path instanceof LabelReference && !((LabelReference) path).label.equals("v")) throw new IllegalArgumentException("Unknown label");
208 return componentBinding.getComponentBinding(path.childReference);
212 public int getComponentCount() {
217 public Binding getComponentBinding(int index) {
218 if (index==0) return componentBinding;
219 throw new IllegalArgumentException();
223 protected boolean deepEquals(Object obj,
224 Set<IdentityPair<Binding, Binding>> compareHistory) {
225 return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((OptionalBinding) obj).componentBinding, compareHistory);
229 public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
230 return super.deepHashCode( hashedObjects ) + componentBinding.hashCode(hashedObjects);