1 /*******************************************************************************
2 * Copyright (c) 2010- Association for Decentralized Information Management in
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard.accessor.impl;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.LinkedList;
17 import java.util.List;
19 import java.util.concurrent.Executor;
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;
41 * Record is an accessor to a record where fields defined from a composition of
44 * Fields should not be modified while CompositeRecord is in accessor usage.
46 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
48 public class CompositeRecord implements RecordAccessor {
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;
56 public CompositeRecord() {
57 params = AccessorParams.DEFAULT;
60 public CompositeRecord(Accessor parent) {
62 params = AccessorParams.DEFAULT;
65 public CompositeRecord(Accessor parent, AccessorParams params) {
70 public void addField(String name, Accessor field) {
72 names.put(name, field);
73 type.addComponent(name, field.type());
76 public void removeField(String name) {
77 Accessor a = names.remove(name);
79 type.removeComponent(name);
88 public void addListener(Listener listener, InterestSet interestSet, ChildReference path, Executor executor) throws AccessorException {
89 RecordInterestSet is = (RecordInterestSet) interestSet;
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);
101 } catch (AccessorConstructionException e) {
102 throw new AccessorException(e);
108 public void removeListener(Listener listener) throws AccessorException {
109 for (Accessor a : fields)
110 a.removeListener(listener);
113 @SuppressWarnings("unchecked")
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);
121 @SuppressWarnings("unchecked")
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");
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);
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);
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);
152 public boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException {
154 Accessor a = getComponent(path);
155 a.setValue(binding, obj);
157 } catch (ReferenceException re) {
159 } catch (AccessorConstructionException e) {
160 throw new AccessorException(e);
165 public boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException {
167 Accessor a = getComponent(path);
168 a.getValue(binding, obj);
170 } catch (ReferenceException re) {
172 } catch (AccessorConstructionException e) {
173 throw new AccessorException(e);
177 public Object getValue(ChildReference path, Binding binding) throws AccessorException {
179 Accessor a = getComponent(path);
180 return a.getValue(binding);
181 } catch (ReferenceException re) {
183 } catch (AccessorConstructionException e) {
184 throw new AccessorException(e);
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);
197 public RecordType type() {
202 public void apply(List<Event> cs, LinkedList<Event> rollback) throws AccessorException {
204 boolean makeRollback = rollback != null;
205 ArrayList<Event> single = new ArrayList<Event>();
208 if (e.reference==null) {
209 Event rbe = applyLocal(e, makeRollback);
211 rbe.reference = e.reference;
212 rollback.addFirst( rbe );
215 Accessor sa = getComponent(e.reference);
218 Event noRefEvent = e.clone(null);
219 single.add(noRefEvent);
220 sa.apply(single, rollback);
224 } catch (AccessorConstructionException ae) {
225 throw new AccessorException(ae);
230 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
232 if (e instanceof ValueAssigned) {
233 ValueAssigned va = (ValueAssigned) e;
234 Event rollback = null;
236 Binding binding = params.bindingScheme.getBinding(type());
237 rollback = new ValueAssigned(binding, getValue(binding));
239 setValue(va.newValue.getBinding(), va.newValue.getValue());
242 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Record Type");
244 } catch (BindingConstructionException e2) {
245 throw new AccessorException( e2 );
249 @SuppressWarnings("unchecked")
251 public <T extends Accessor> T getComponent(ChildReference reference)
252 throws AccessorConstructionException {
253 if (reference==null) return (T) this;
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());
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());
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());
283 throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");
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;
293 Object values[] = new Object[rb.getComponentCount()];
295 for (int i=0; i<values.length; i++) {
296 Binding cb = rb.getComponentBinding(i);
297 Object cv = fields.get(i).getValue(cb);
301 return rb.create(values);
302 } catch (BindingException e) {
303 throw new AccessorException(e);
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;
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);
319 } catch (BindingException e) {
320 throw new AccessorException(e);
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;
332 for (int i=0; i<rb.getComponentCount(); i++) {
333 Binding cb = rb.getComponentBinding(i);
335 cv = rb.getComponent(newValue, i);
336 fields.get(i).setValue(cb, cv);
338 } catch (BindingException e) {
339 throw new AccessorException( e );