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