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.accessor.impl;
\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
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
41 * Record is an accessor to a record where fields defined from a composition of
\r
44 * Fields should not be modified while CompositeRecord is in accessor usage.
\r
46 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
48 public class CompositeRecord implements RecordAccessor {
\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
56 public CompositeRecord() {
\r
57 params = AccessorParams.DEFAULT;
\r
60 public CompositeRecord(Accessor parent) {
\r
61 this.parent = parent;
\r
62 params = AccessorParams.DEFAULT;
\r
65 public CompositeRecord(Accessor parent, AccessorParams params) {
\r
66 this.parent = parent;
\r
67 this.params = params;
\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
76 public void removeField(String name) {
\r
77 Accessor a = names.remove(name);
\r
79 type.removeComponent(name);
\r
83 public int count() {
\r
84 return fields.size();
\r
88 public void addListener(Listener listener, InterestSet interestSet, ChildReference path, Executor executor) throws AccessorException {
\r
89 RecordInterestSet is = (RecordInterestSet) interestSet;
\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
101 } catch (AccessorConstructionException e) {
\r
102 throw new AccessorException(e);
\r
108 public void removeListener(Listener listener) throws AccessorException {
\r
109 for (Accessor a : fields)
\r
110 a.removeListener(listener);
\r
113 @SuppressWarnings("unchecked")
\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
121 @SuppressWarnings("unchecked")
\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
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
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
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
152 public boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException {
\r
154 Accessor a = getComponent(path);
\r
155 a.setValue(binding, obj);
\r
157 } catch (ReferenceException re) {
\r
159 } catch (AccessorConstructionException e) {
\r
160 throw new AccessorException(e);
\r
165 public boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException {
\r
167 Accessor a = getComponent(path);
\r
168 a.getValue(binding, obj);
\r
170 } catch (ReferenceException re) {
\r
172 } catch (AccessorConstructionException e) {
\r
173 throw new AccessorException(e);
\r
177 public Object getValue(ChildReference path, Binding binding) throws AccessorException {
\r
179 Accessor a = getComponent(path);
\r
180 return a.getValue(binding);
\r
181 } catch (ReferenceException re) {
\r
183 } catch (AccessorConstructionException e) {
\r
184 throw new AccessorException(e);
\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
197 public RecordType type() {
\r
202 public void apply(List<Event> cs, LinkedList<Event> rollback) throws AccessorException {
\r
204 boolean makeRollback = rollback != null;
\r
205 ArrayList<Event> single = new ArrayList<Event>();
\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
215 Accessor sa = getComponent(e.reference);
\r
218 Event noRefEvent = e.clone(null);
\r
219 single.add(noRefEvent);
\r
220 sa.apply(single, rollback);
\r
224 } catch (AccessorConstructionException ae) {
\r
225 throw new AccessorException(ae);
\r
230 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
\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
239 setValue(va.newValue.getBinding(), va.newValue.getValue());
\r
242 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Record Type");
\r
244 } catch (BindingConstructionException e2) {
\r
245 throw new AccessorException( e2 );
\r
249 @SuppressWarnings("unchecked")
\r
251 public <T extends Accessor> T getComponent(ChildReference reference)
\r
252 throws AccessorConstructionException {
\r
253 if (reference==null) return (T) this;
\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
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
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
283 throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");
\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
293 Object values[] = new Object[rb.getComponentCount()];
\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
301 return rb.create(values);
\r
302 } catch (BindingException e) {
\r
303 throw new AccessorException(e);
\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
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
319 } catch (BindingException e) {
\r
320 throw new AccessorException(e);
\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
332 for (int i=0; i<rb.getComponentCount(); i++) {
\r
333 Binding cb = rb.getComponentBinding(i);
\r
335 cv = rb.getComponent(newValue, i);
\r
336 fields.get(i).setValue(cb, cv);
\r
338 } catch (BindingException e) {
\r
339 throw new AccessorException( e );
\r