]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/UnionBinding.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / UnionBinding.java
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\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
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.binding;
13
14 import java.util.IdentityHashMap;\r
15 import java.util.Set;\r
16 \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
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) {\r
56         return componentBindings[tagIndex];\r
57     }\r
58     \r
59     public Binding getComponentBinding(String tagName) {\r
60         return componentBindings[ type().getComponentIndex2(tagName) ];\r
61     }\r
62     \r
63     public Binding[] getComponentBindings() {
64         return componentBindings;
65     }    
66         \r
67     /**\r
68      * Get tag number of an instance.\r
69      * \r
70      * @param obj\r
71      * @return the tag number\r
72      * @throws BindingException is thrown if the instance is not a tag of this union\r
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;\r
79         \r
80         /**\r
81          * Create a new union object with tag of default value.\r
82          * \r
83          * @param tag\r
84          * @return new union object\r
85          * @throws BindingException\r
86          */\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
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 \r
109         @Override\r
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
115                 \r
116                 // New value binding\r
117                 Binding nvb = sb.getComponentBinding(newTag);\r
118                 // New value\r
119                 Object nv = sb.getValue(src);\r
120                 \r
121                 // Same tag\r
122                 if (newTag==oldTag) {\r
123                         // Same tag - old value is used if possible\r
124                         \r
125                         // Old value binding\r
126                         Binding ovb = getComponentBinding(oldTag);\r
127                         \r
128                         Object ov = getValue(dst);\r
129                         ov = ovb.readFromTry(nvb, nv, ov);\r
130                         setValue(dst, oldTag, ov);\r
131                         \r
132                 } else {\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
137                         \r
138                         if ( !adapt && !clone) {\r
139                                 setValue(dst, newTag, nv);\r
140                         } else {\r
141                                 try {\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
147                                 }                               \r
148                         }\r
149                 }\r
150                 \r
151                 /*\r
152                 if (dcb.isImmutable() || st!=dt) {\r
153                         try {\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
158                         }\r
159                 } else {\r
160                         Object dv = getValue(dst);\r
161                         dv = dcb.readFromTry(scb, sv, dv);\r
162                         setValue(dst, st, dv);\r
163                 }\r
164                 */\r
165         }\r
166         \r
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;\r
177         \r
178         /**\r
179          * Set to tag with default value.\r
180          * \r
181          * @param union\r
182          * @param tag\r
183          * @throws BindingException\r
184          */\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
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 \r
247         @Override\r
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
251                 ctx.b.append(' ');\r
252                 getComponentBinding(tag).toString(getValue(value), ctx);\r
253         }\r
254         \r
255         @Override\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
261                 }\r
262                 if (path instanceof NameReference) {\r
263                         NameReference nr = (NameReference) path;\r
264                         return getComponentBinding( nr.name ).getComponentBinding(path.childReference);\r
265                 }\r
266                 if (path instanceof LabelReference) {\r
267                         LabelReference lr = (LabelReference) path;                      \r
268                         try {\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
273                         }\r
274                 }\r
275                 throw new IllegalArgumentException();\r
276         }       \r
277         \r
278         /**\r
279          * Returns true if the tag of this union type can be modified\r
280          *  \r
281          * @return true if mutable\r
282          */\r
283         public boolean isTagMutable() {\r
284                 return true;\r
285         }\r
286 \r
287         @Override\r
288         protected boolean deepEquals(Object obj,\r
289                         Set<IdentityPair<Binding, Binding>> compareHistory) {\r
290             if (!super.deepEquals( obj, compareHistory ))\r
291                 return false;\r
292             \r
293                 UnionBinding o = (UnionBinding)obj;\r
294                 if (componentBindings.length != o.componentBindings.length) return false;\r
295                 \r
296                 for (int i = 0; i < componentBindings.length; i++)\r
297                         if (!componentBindings[i].equals(o.componentBindings[i], compareHistory))\r
298                                 return false;\r
299                 \r
300                 return true;\r
301         }\r
302         \r
303         @Override\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
308                 return code;\r
309         }\r
310 }