]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/UnionBinding.java
Use type reflection tools from databoard in objmap2.
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / UnionBinding.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
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
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.binding;
13
14 import java.util.IdentityHashMap;
15 import java.util.Set;
16
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.LabelReference;
21 import org.simantics.databoard.accessor.reference.NameReference;
22 import org.simantics.databoard.adapter.AdaptException;
23 import org.simantics.databoard.binding.error.BindingException;
24 import org.simantics.databoard.binding.error.RuntimeBindingException;
25 import org.simantics.databoard.binding.impl.BindingPrintContext;
26 import org.simantics.databoard.type.UnionType;
27 import org.simantics.databoard.util.IdentityPair;
28
29
30 /**
31  * This is a binding of Union Type and a Java Object.
32  *
33  * @see UnionType
34  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
35  */
36 public abstract class UnionBinding extends Binding {
37                 
38     protected Binding[] componentBindings;
39     
40     public UnionBinding() {}
41     
42     public UnionBinding(Binding...componentBindings) {
43         this.componentBindings = componentBindings;
44     }
45     
46     @Override
47     public UnionType type() {
48         return (UnionType) type;
49     }
50     
51     public int getComponentCount() {
52         return type().getComponentCount();
53     }
54     
55     public Binding getComponentBinding(int tagIndex) {
56         return componentBindings[tagIndex];
57     }
58     
59     public Binding getComponentBinding(String tagName) {
60         return componentBindings[ type().getComponentIndex2(tagName) ];
61     }
62     
63     public Binding[] getComponentBindings() {
64         return componentBindings;
65     }    
66         
67     /**
68      * Get tag number of an instance.
69      * 
70      * @param obj
71      * @return the tag number
72      * @throws BindingException is thrown if the instance is not a tag of this union
73      */
74         public abstract int getTag(Object obj) throws BindingException;
75         
76         public abstract Object getValue(Object obj) throws BindingException;
77         
78         public abstract Object create(int tag, Object value) throws BindingException;
79         
80         /**
81          * Create a new union object with tag of default value.
82          * 
83          * @param tag
84          * @return new union object
85          * @throws BindingException
86          */
87         public Object createDefault(int tag) throws BindingException {
88                 Binding cb = getComponentBinding(tag);
89                 Object to = cb.createDefault();
90                 return create(tag, to);
91         }
92         
93         public Object create(String tag, Object value) throws BindingException {
94                 Integer tagIndex = type().getComponentIndex(tag);
95                 if(tagIndex == null)
96                         throw new BindingException("Union type does not have a tag " + tag + ".");
97                 return create(tagIndex, value);
98         }
99         
100         public Object createUnchecked(int tag, Object value) throws RuntimeBindingException
101         {
102                 try {
103                         return create(tag, value);
104                 } catch (BindingException e) {
105                         throw new RuntimeBindingException(e);
106                 }
107         }
108
109         @Override
110         public void readFrom(Binding srcBinding, Object src, Object dst)
111                         throws BindingException {
112                 UnionBinding sb = (UnionBinding) srcBinding;
113                 int newTag = sb.getTag(src);
114                 int oldTag = getTag(dst);
115                 
116                 // New value binding
117                 Binding nvb = sb.getComponentBinding(newTag);
118                 // New value
119                 Object nv = sb.getValue(src);
120                 
121                 // Same tag
122                 if (newTag==oldTag) {
123                         // Same tag - old value is used if possible
124                         
125                         // Old value binding
126                         Binding ovb = getComponentBinding(oldTag);
127                         
128                         Object ov = getValue(dst);
129                         ov = ovb.readFromTry(nvb, nv, ov);
130                         setValue(dst, oldTag, ov);
131                         
132                 } else {
133                         // Different tag - old value is not used
134                         boolean clone = !nvb.isImmutable();
135                         Binding dcb = getComponentBinding(newTag);
136                         boolean adapt = nvb!=dcb;
137                         
138                         if ( !adapt && !clone) {
139                                 setValue(dst, newTag, nv);
140                         } else {
141                                 try {
142                                         // Clone or adapt value if necessary.
143                                         Object dv = Bindings.clone(nv, nvb, dcb);
144                                         setValue(dst, newTag, dv);
145                                 } catch(AdaptException e) {
146                                         throw new BindingException(e);
147                                 }                               
148                         }
149                 }
150                 
151                 /*
152                 if (dcb.isImmutable() || st!=dt) {
153                         try {
154                                 Object dv = Bindings.clone(sv, scb, dcb);
155                                 setValue(dst, st, dv);
156                         } catch(AdaptException e) {
157                                 throw new BindingException(e);
158                         }
159                 } else {
160                         Object dv = getValue(dst);
161                         dv = dcb.readFromTry(scb, sv, dv);
162                         setValue(dst, st, dv);
163                 }
164                 */
165         }
166         
167     /**
168      * Set value to an union.
169      * Throws BindingException if value cannot be written.
170      * 
171      * @param union
172      * @param tag
173      * @param value
174      * @throws BindingException
175      */
176         public abstract void setValue(Object union, int tag, Object value) throws BindingException;
177         
178         /**
179          * Set to tag with default value.
180          * 
181          * @param union
182          * @param tag
183          * @throws BindingException
184          */
185         public void setTag(Object union, int tag) throws BindingException {
186                 Binding componentBinding = getComponentBinding(tag);
187                 Object instance = componentBinding.createDefault();
188                 setValue(union, tag, instance);
189         }
190         
191     @Override
192     public void accept(Visitor1 v, Object obj) {
193         v.visit(this, obj);        
194     }
195     
196     @Override
197     public <T> T accept(Visitor<T> v) {
198         return v.visit(this);
199     }
200
201     /**
202      * Asserts the obj is valid to its UnionType.
203      * 
204      * Asserts the obj using the component type
205      * 
206      * @throws BindingException if obj is not valid according to the UnionType
207      */
208     @Override
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");
216         
217         Object componentValue = getValue(obj);
218         Binding componentBinding = getComponentBindings()[tag];
219         componentBinding.assertInstaceIsValid(componentValue, validInstances);
220     }
221
222     @Override
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);
227     }
228
229         @Override
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);           
241         }
242
243         public void setComponentBindings(Binding[] componentBindings) {
244                 this.componentBindings = componentBindings;
245         }
246
247         @Override
248         protected void toString(Object value, BindingPrintContext ctx) throws BindingException {
249                 int tag = getTag(value);
250                 ctx.b.append(type().getComponent(tag).name);
251                 ctx.b.append(' ');
252                 getComponentBinding(tag).toString(getValue(value), ctx);
253         }
254         
255         @Override
256         public Binding getComponentBinding(ChildReference path) {
257                 if (path==null) return this;
258                 if (path instanceof IndexReference) {
259                         IndexReference ir = (IndexReference) path;
260                         return componentBindings[ir.index].getComponentBinding(path.childReference);
261                 }
262                 if (path instanceof NameReference) {
263                         NameReference nr = (NameReference) path;
264                         return getComponentBinding( nr.name ).getComponentBinding(path.childReference);
265                 }
266                 if (path instanceof LabelReference) {
267                         LabelReference lr = (LabelReference) path;                      
268                         try {
269                                 Integer i = new Integer(lr.label);
270                                 return getComponentBinding( i ).getComponentBinding(path.childReference);
271                         } catch (NumberFormatException nfe) {
272                                 return getComponentBinding( lr.label ).getComponentBinding(path.childReference);
273                         }
274                 }
275                 throw new IllegalArgumentException();
276         }       
277         
278         /**
279          * Returns true if the tag of this union type can be modified
280          *  
281          * @return true if mutable
282          */
283         public boolean isTagMutable() {
284                 return true;
285         }
286
287         @Override
288         protected boolean deepEquals(Object obj,
289                         Set<IdentityPair<Binding, Binding>> compareHistory) {
290             if (!super.deepEquals( obj, compareHistory ))
291                 return false;
292             
293                 UnionBinding o = (UnionBinding)obj;
294                 if (componentBindings.length != o.componentBindings.length) return false;
295                 
296                 for (int i = 0; i < componentBindings.length; i++)
297                         if (!componentBindings[i].equals(o.componentBindings[i], compareHistory))
298                                 return false;
299                 
300                 return true;
301         }
302         
303         @Override
304         public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
305                 int code = super.deepHashCode( hashedObjects );
306                 for (int i = 0; i < componentBindings.length; i++)
307                         code = 17 * code + componentBindings[i].hashCode(hashedObjects);
308                 return code;
309         }
310 }