]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/impl/CompositeRecord.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / impl / CompositeRecord.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.accessor.impl;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.HashMap;\r
16 import java.util.LinkedList;\r
17 import java.util.List;\r
18 import java.util.Map;\r
19 import java.util.concurrent.Executor;\r
20 \r
21 import org.simantics.databoard.accessor.Accessor;\r
22 import org.simantics.databoard.accessor.RecordAccessor;\r
23 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
24 import org.simantics.databoard.accessor.error.AccessorException;\r
25 import org.simantics.databoard.accessor.error.ReferenceException;\r
26 import org.simantics.databoard.accessor.event.Event;\r
27 import org.simantics.databoard.accessor.event.ValueAssigned;\r
28 import org.simantics.databoard.accessor.interestset.InterestSet;\r
29 import org.simantics.databoard.accessor.interestset.RecordInterestSet;\r
30 import org.simantics.databoard.accessor.reference.ChildReference;\r
31 import org.simantics.databoard.accessor.reference.IndexReference;\r
32 import org.simantics.databoard.accessor.reference.LabelReference;\r
33 import org.simantics.databoard.accessor.reference.NameReference;\r
34 import org.simantics.databoard.binding.Binding;\r
35 import org.simantics.databoard.binding.RecordBinding;\r
36 import org.simantics.databoard.binding.error.BindingConstructionException;\r
37 import org.simantics.databoard.binding.error.BindingException;\r
38 import org.simantics.databoard.type.RecordType;\r
39 \r
40 /**\r
41  * Record is an accessor to a record where fields defined from a composition of\r
42  * other accessors.\r
43  * \r
44  * Fields should not be modified while CompositeRecord is in accessor usage.  \r
45  *\r
46  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
47  */\r
48 public class CompositeRecord implements RecordAccessor {\r
49 \r
50         protected List<Accessor> fields = new ArrayList<Accessor>();\r
51         protected Map<String, Accessor> names = new HashMap<String, Accessor>();\r
52         protected RecordType type = new RecordType();\r
53         protected Accessor parent;\r
54         protected AccessorParams params;\r
55         \r
56         public CompositeRecord() {\r
57                 params = AccessorParams.DEFAULT;\r
58         }\r
59         \r
60         public CompositeRecord(Accessor parent) {\r
61                 this.parent = parent;\r
62                 params = AccessorParams.DEFAULT;\r
63         }\r
64         \r
65         public CompositeRecord(Accessor parent, AccessorParams params) {\r
66                 this.parent = parent;\r
67                 this.params = params;\r
68         }\r
69         \r
70         public void addField(String name, Accessor field) {\r
71                 fields.add( field );\r
72                 names.put(name, field);\r
73                 type.addComponent(name, field.type());\r
74         }\r
75         \r
76         public void removeField(String name) {\r
77                 Accessor a = names.remove(name);\r
78                 fields.remove(a);\r
79                 type.removeComponent(name);\r
80         }\r
81 \r
82         @Override\r
83         public int count() {\r
84                 return fields.size();\r
85         }\r
86 \r
87         @Override\r
88         public void addListener(Listener listener, InterestSet interestSet, ChildReference path, Executor executor) throws AccessorException {\r
89                 RecordInterestSet is = (RecordInterestSet) interestSet;\r
90 \r
91                 try {\r
92                         if (is.componentInterests!=null) {\r
93                                 for (int i=0; i<count(); i++) {\r
94                                         InterestSet cis = is.getComponentInterest(i);\r
95                                         if (cis==null) continue;\r
96                                         ChildReference childPath = ChildReference.concatenate(path, new IndexReference(i) );\r
97                                         Accessor ca = getFieldAccessor(i);\r
98                                         ca.addListener(listener, cis, childPath, executor);                             \r
99                                 }\r
100                         }\r
101                 } catch (AccessorConstructionException e) {\r
102                         throw new AccessorException(e);\r
103                 }\r
104                 \r
105         }\r
106         \r
107         @Override\r
108         public void removeListener(Listener listener) throws AccessorException {\r
109                 for (Accessor a : fields)\r
110                         a.removeListener(listener);             \r
111         }\r
112         \r
113         @SuppressWarnings("unchecked")\r
114         @Override\r
115         public <T extends Accessor> T getFieldAccessor(int index) throws AccessorConstructionException {\r
116                 if (index<0 || index>=fields.size()) \r
117                         throw new AccessorConstructionException("Field index "+index+" does not exist");                \r
118                 return (T) fields.get(index);\r
119         }\r
120 \r
121         @SuppressWarnings("unchecked")\r
122         @Override\r
123         public <T extends Accessor> T getFieldAccessor(String fieldName) throws AccessorConstructionException {\r
124                 Accessor accessor = names.get(fieldName);\r
125                 if (accessor == null) \r
126                         throw new AccessorConstructionException("Field by name "+fieldName+" was not found");\r
127                 return (T) accessor;\r
128         }\r
129 \r
130         @Override\r
131         public Object getFieldValue(String fieldName, Binding fieldBinding)\r
132                         throws AccessorException {\r
133                 int fieldIndex = type().getComponentIndex(fieldName);\r
134                 if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist");            \r
135                 return getFieldValue(fieldIndex, fieldBinding);\r
136         }\r
137         \r
138         @Override\r
139         public Object getFieldValue(int index, Binding fieldBinding) throws AccessorException {\r
140                 if (index<0 || index>=fields.size()) \r
141                         throw new AccessorException("Field index "+index+" does not exist");\r
142                 return fields.get(index).getValue(fieldBinding);\r
143         }\r
144 \r
145         @Override\r
146         public void setFieldValue(String fieldName, Binding fieldBinding, Object value) throws AccessorException {\r
147                 int fieldIndex = type().getComponentIndex(fieldName);\r
148                 if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist");\r
149                 setFieldValue(fieldIndex, fieldBinding, value);\r
150         }\r
151         \r
152         public boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException {\r
153                 try {\r
154                         Accessor a = getComponent(path);\r
155                         a.setValue(binding, obj);\r
156                         return true;\r
157                 } catch (ReferenceException re) {\r
158                         return false;\r
159                 } catch (AccessorConstructionException e) {\r
160                         throw new AccessorException(e);\r
161                 }\r
162         }\r
163         \r
164         @Override\r
165         public boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException {\r
166                 try {\r
167                         Accessor a = getComponent(path);\r
168                         a.getValue(binding, obj);\r
169                         return true;\r
170                 } catch (ReferenceException re) {\r
171                         return false;\r
172                 } catch (AccessorConstructionException e) {\r
173                         throw new AccessorException(e);\r
174                 }\r
175         }       \r
176         \r
177         public Object getValue(ChildReference path, Binding binding) throws AccessorException {\r
178                 try {\r
179                         Accessor a = getComponent(path);\r
180                         return a.getValue(binding);\r
181                 } catch (ReferenceException re) {\r
182                         return null;\r
183                 } catch (AccessorConstructionException e) {\r
184                         throw new AccessorException(e);\r
185                 }\r
186         }\r
187         \r
188         @Override\r
189         public void setFieldValue(int index, Binding fieldBinding, Object value)\r
190                         throws AccessorException {\r
191                 if (index<0 || index>=fields.size()) \r
192                         throw new AccessorException("Field index "+index+" does not exist");\r
193                 fields.get(index).setValue(fieldBinding, value);\r
194         }\r
195 \r
196         @Override\r
197         public RecordType type() {              \r
198                 return type;\r
199         }\r
200 \r
201         @Override\r
202         public void apply(List<Event> cs, LinkedList<Event> rollback) throws AccessorException {\r
203                 try {\r
204                         boolean makeRollback = rollback != null;\r
205                         ArrayList<Event> single = new ArrayList<Event>();\r
206                         \r
207                         for (Event e : cs) {\r
208                                 if (e.reference==null) {\r
209                                         Event rbe = applyLocal(e, makeRollback);\r
210                                         if (makeRollback) {\r
211                                                 rbe.reference = e.reference;\r
212                                                 rollback.addFirst( rbe );\r
213                                         }                                       \r
214                                 } else {\r
215                                         Accessor sa = getComponent(e.reference);\r
216                                         // Apply changes\r
217                                         single.clear();\r
218                                         Event noRefEvent = e.clone(null);\r
219                                         single.add(noRefEvent);\r
220                                         sa.apply(single, rollback);\r
221                                 }\r
222                         }\r
223                         \r
224                 } catch (AccessorConstructionException ae) {\r
225                         throw new AccessorException(ae);\r
226                 }\r
227                 \r
228         }       \r
229 \r
230         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {\r
231                 try {\r
232                         if (e instanceof ValueAssigned) {\r
233                                 ValueAssigned va = (ValueAssigned) e;\r
234                                 Event rollback = null;\r
235                                 if (makeRollback) {\r
236                                         Binding binding = params.bindingScheme.getBinding(type());\r
237                                         rollback = new ValueAssigned(binding, getValue(binding));                               \r
238                                 }\r
239                                 setValue(va.newValue.getBinding(), va.newValue.getValue());\r
240                                 return rollback;\r
241                         } else {\r
242                                 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Record Type");                          \r
243                         }\r
244                 } catch (BindingConstructionException e2) {\r
245                         throw new AccessorException( e2 );\r
246                 }\r
247         }               \r
248 \r
249         @SuppressWarnings("unchecked")\r
250         @Override\r
251         public <T extends Accessor> T getComponent(ChildReference reference)\r
252                         throws AccessorConstructionException {\r
253                 if (reference==null) return (T) this;\r
254                 \r
255                 if (reference instanceof LabelReference) {\r
256                         LabelReference lr = (LabelReference) reference;\r
257                         String fieldName = lr.label;\r
258                         Integer index = type().getComponentIndex(fieldName);\r
259                         if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");\r
260                         Accessor sa = getFieldAccessor(index);\r
261                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());\r
262                         return (T) sa;                  \r
263                 }               \r
264                 \r
265                 if (reference instanceof IndexReference) {\r
266                         IndexReference ref = (IndexReference) reference;\r
267                         int index = ref.getIndex();\r
268                         Accessor sa = getFieldAccessor(index);\r
269                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());\r
270                         return (T) sa;\r
271                 } \r
272                 \r
273                 if (reference instanceof NameReference) {\r
274                         NameReference ref = (NameReference) reference;\r
275                         String fieldName = ref.getName();\r
276                         Integer index = type().getComponentIndex(fieldName);\r
277                         if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");\r
278                         Accessor sa = getFieldAccessor(index);\r
279                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());\r
280                         return (T) sa;                  \r
281                 } \r
282                 \r
283                 throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");              \r
284         }\r
285 \r
286         @Override\r
287         public Object getValue(Binding binding) throws AccessorException {\r
288                 if (!binding.type().equals(type))\r
289                         throw new AccessorException("Type mismatch");\r
290                 RecordBinding rb = (RecordBinding) binding;\r
291 \r
292                 try {\r
293                         Object values[] = new Object[rb.getComponentCount()];\r
294                         \r
295                         for (int i=0; i<values.length; i++) {\r
296                                 Binding cb = rb.getComponentBinding(i);\r
297                                 Object cv = fields.get(i).getValue(cb);\r
298                                 values[i] = cv;\r
299                         }\r
300                         \r
301                         return rb.create(values);\r
302                 } catch (BindingException e) {\r
303                         throw new AccessorException(e);\r
304                 }\r
305         }\r
306         \r
307         @Override\r
308         public void getValue(Binding dstBinding, Object dst) throws AccessorException {\r
309                 if (!dstBinding.type().equals(type)) throw new AccessorException("Type mismatch");\r
310                 RecordBinding db = (RecordBinding) dstBinding;\r
311                 \r
312                 try {\r
313                         for (int i=0; i<db.getComponentCount(); i++) {\r
314                                 Object c = db.getComponent(dst, i);\r
315                                 Binding dcb = db.getComponentBinding(i);\r
316                                 fields.get(i).getValue(dcb, c);\r
317                                 db.setComponent(dst, i, c);\r
318                         }\r
319                 } catch (BindingException e) {\r
320                         throw new AccessorException(e);\r
321                 }\r
322         }\r
323 \r
324         @Override\r
325         public void setValue(Binding binding, Object newValue)\r
326                         throws AccessorException {\r
327                 if (!binding.type().equals(type))\r
328                         throw new AccessorException("Type mismatch");\r
329                 RecordBinding rb = (RecordBinding) binding;\r
330 \r
331                 try {\r
332                         for (int i=0; i<rb.getComponentCount(); i++) {\r
333                                 Binding cb = rb.getComponentBinding(i);\r
334                                 Object cv;\r
335                                 cv = rb.getComponent(newValue, i);\r
336                                 fields.get(i).setValue(cb, cv);\r
337                         }\r
338                 } catch (BindingException e) {\r
339                         throw new AccessorException( e );\r
340                 }                       \r
341         }\r
342 \r
343         \r
344 }\r
345 \r