1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.binding;
14 import java.util.IdentityHashMap;
\r
15 import java.util.Set;
\r
17 import org.simantics.databoard.Bindings;
\r
18 import org.simantics.databoard.accessor.reference.ChildReference;
\r
19 import org.simantics.databoard.accessor.reference.IndexReference;
\r
20 import org.simantics.databoard.accessor.reference.LabelReference;
\r
21 import org.simantics.databoard.accessor.reference.NameReference;
\r
22 import org.simantics.databoard.adapter.AdaptException;
\r
23 import org.simantics.databoard.binding.error.BindingException;
\r
24 import org.simantics.databoard.binding.error.RuntimeBindingException;
\r
25 import org.simantics.databoard.binding.impl.BindingPrintContext;
\r
26 import org.simantics.databoard.type.UnionType;
\r
27 import org.simantics.databoard.util.IdentityPair;
\r
31 * This is a binding of Union Type and a Java Object.
34 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
36 public abstract class UnionBinding extends Binding {
38 protected Binding[] componentBindings;
40 public UnionBinding() {}
42 public UnionBinding(Binding...componentBindings) {
43 this.componentBindings = componentBindings;
47 public UnionType type() {
48 return (UnionType) type;
51 public int getComponentCount() {
52 return type().getComponentCount();
55 public Binding getComponentBinding(int tagIndex) {
\r
56 return componentBindings[tagIndex];
\r
59 public Binding getComponentBinding(String tagName) {
\r
60 return componentBindings[ type().getComponentIndex2(tagName) ];
\r
63 public Binding[] getComponentBindings() {
64 return componentBindings;
68 * Get tag number of an instance.
\r
71 * @return the tag number
\r
72 * @throws BindingException is thrown if the instance is not a tag of this union
\r
74 public abstract int getTag(Object obj) throws BindingException;
76 public abstract Object getValue(Object obj) throws BindingException;
78 public abstract Object create(int tag, Object value) throws BindingException;
\r
81 * Create a new union object with tag of default value.
\r
84 * @return new union object
\r
85 * @throws BindingException
\r
87 public Object createDefault(int tag) throws BindingException {
\r
88 Binding cb = getComponentBinding(tag);
\r
89 Object to = cb.createDefault();
\r
90 return create(tag, to);
\r
93 public Object create(String tag, Object value) throws BindingException {
94 Integer tagIndex = type().getComponentIndex(tag);
96 throw new BindingException("Union type does not have a tag " + tag + ".");
97 return create(tagIndex, value);
100 public Object createUnchecked(int tag, Object value) throws RuntimeBindingException
103 return create(tag, value);
104 } catch (BindingException e) {
105 throw new RuntimeBindingException(e);
110 public void readFrom(Binding srcBinding, Object src, Object dst)
\r
111 throws BindingException {
\r
112 UnionBinding sb = (UnionBinding) srcBinding;
\r
113 int newTag = sb.getTag(src);
\r
114 int oldTag = getTag(dst);
\r
116 // New value binding
\r
117 Binding nvb = sb.getComponentBinding(newTag);
\r
119 Object nv = sb.getValue(src);
\r
122 if (newTag==oldTag) {
\r
123 // Same tag - old value is used if possible
\r
125 // Old value binding
\r
126 Binding ovb = getComponentBinding(oldTag);
\r
128 Object ov = getValue(dst);
\r
129 ov = ovb.readFromTry(nvb, nv, ov);
\r
130 setValue(dst, oldTag, ov);
\r
133 // Different tag - old value is not used
\r
134 boolean clone = !nvb.isImmutable();
\r
135 Binding dcb = getComponentBinding(newTag);
\r
136 boolean adapt = nvb!=dcb;
\r
138 if ( !adapt && !clone) {
\r
139 setValue(dst, newTag, nv);
\r
142 // Clone or adapt value if necessary.
\r
143 Object dv = Bindings.clone(nv, nvb, dcb);
\r
144 setValue(dst, newTag, dv);
\r
145 } catch(AdaptException e) {
\r
146 throw new BindingException(e);
\r
152 if (dcb.isImmutable() || st!=dt) {
\r
154 Object dv = Bindings.clone(sv, scb, dcb);
\r
155 setValue(dst, st, dv);
\r
156 } catch(AdaptException e) {
\r
157 throw new BindingException(e);
\r
160 Object dv = getValue(dst);
\r
161 dv = dcb.readFromTry(scb, sv, dv);
\r
162 setValue(dst, st, dv);
\r
168 * Set value to an union.
169 * Throws BindingException if value cannot be written.
174 * @throws BindingException
176 public abstract void setValue(Object union, int tag, Object value) throws BindingException;
\r
179 * Set to tag with default value.
\r
183 * @throws BindingException
\r
185 public void setTag(Object union, int tag) throws BindingException {
\r
186 Binding componentBinding = getComponentBinding(tag);
\r
187 Object instance = componentBinding.createDefault();
\r
188 setValue(union, tag, instance);
\r
192 public void accept(Visitor1 v, Object obj) {
197 public <T> T accept(Visitor<T> v) {
198 return v.visit(this);
202 * Asserts the obj is valid to its UnionType.
204 * Asserts the obj using the component type
206 * @throws BindingException if obj is not valid according to the UnionType
209 public void assertInstaceIsValid(Object obj, Set<Object> validInstances) throws BindingException {
210 UnionType type = type();
211 int length = type.getComponentCount();
212 if (length==0) return;
213 int tag = getTag(obj);
214 if (tag<0 || tag>=length)
215 throw new BindingException("Instance tag ("+tag+") is out of range [0.."+(length-1)+"], faulty UnionBinding");
217 Object componentValue = getValue(obj);
218 Binding componentBinding = getComponentBindings()[tag];
219 componentBinding.assertInstaceIsValid(componentValue, validInstances);
223 public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
224 int tag = getTag(value);
225 Object element = getValue(value);
226 return tag + componentBindings[tag].deepHashValue(element, hashedObjects);
230 public int deepCompare(Object o1, Object o2,
231 Set<IdentityPair<Object, Object>> compareHistory)
232 throws BindingException {
233 Integer t1 = getTag(o1);
234 Integer t2 = getTag(o2);
235 int dif = t1.compareTo(t2);
236 if (dif!=0) return dif;
237 Object v1 = getValue(o1);
238 Object v2 = getValue(o2);
239 Binding c = getComponentBindings()[t1];
240 return c.deepCompare(v1, v2, compareHistory);
243 public void setComponentBindings(Binding[] componentBindings) {
244 this.componentBindings = componentBindings;
248 protected void toString(Object value, BindingPrintContext ctx) throws BindingException {
\r
249 int tag = getTag(value);
\r
250 ctx.b.append(type().getComponent(tag).name);
\r
252 getComponentBinding(tag).toString(getValue(value), ctx);
\r
256 public Binding getComponentBinding(ChildReference path) {
\r
257 if (path==null) return this;
\r
258 if (path instanceof IndexReference) {
\r
259 IndexReference ir = (IndexReference) path;
\r
260 return componentBindings[ir.index].getComponentBinding(path.childReference);
\r
262 if (path instanceof NameReference) {
\r
263 NameReference nr = (NameReference) path;
\r
264 return getComponentBinding( nr.name ).getComponentBinding(path.childReference);
\r
266 if (path instanceof LabelReference) {
\r
267 LabelReference lr = (LabelReference) path;
\r
269 Integer i = new Integer(lr.label);
\r
270 return getComponentBinding( i ).getComponentBinding(path.childReference);
\r
271 } catch (NumberFormatException nfe) {
\r
272 return getComponentBinding( lr.label ).getComponentBinding(path.childReference);
\r
275 throw new IllegalArgumentException();
\r
279 * Returns true if the tag of this union type can be modified
\r
281 * @return true if mutable
\r
283 public boolean isTagMutable() {
\r
288 protected boolean deepEquals(Object obj,
\r
289 Set<IdentityPair<Binding, Binding>> compareHistory) {
\r
290 if (!super.deepEquals( obj, compareHistory ))
\r
293 UnionBinding o = (UnionBinding)obj;
\r
294 if (componentBindings.length != o.componentBindings.length) return false;
\r
296 for (int i = 0; i < componentBindings.length; i++)
\r
297 if (!componentBindings[i].equals(o.componentBindings[i], compareHistory))
\r
304 public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
\r
305 int code = super.deepHashCode( hashedObjects );
\r
306 for (int i = 0; i < componentBindings.length; i++)
\r
307 code = 17 * code + componentBindings[i].hashCode(hashedObjects);
\r