/******************************************************************************* * Copyright (c) 2010- Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.accessor.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; import org.simantics.databoard.accessor.Accessor; import org.simantics.databoard.accessor.RecordAccessor; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.error.ReferenceException; import org.simantics.databoard.accessor.event.Event; import org.simantics.databoard.accessor.event.ValueAssigned; import org.simantics.databoard.accessor.interestset.InterestSet; import org.simantics.databoard.accessor.interestset.RecordInterestSet; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.accessor.reference.IndexReference; import org.simantics.databoard.accessor.reference.LabelReference; import org.simantics.databoard.accessor.reference.NameReference; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.RecordBinding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.type.RecordType; /** * Record is an accessor to a record where fields defined from a composition of * other accessors. * * Fields should not be modified while CompositeRecord is in accessor usage. * * @author Toni Kalajainen */ public class CompositeRecord implements RecordAccessor { protected List fields = new ArrayList(); protected Map names = new HashMap(); protected RecordType type = new RecordType(); protected Accessor parent; protected AccessorParams params; public CompositeRecord() { params = AccessorParams.DEFAULT; } public CompositeRecord(Accessor parent) { this.parent = parent; params = AccessorParams.DEFAULT; } public CompositeRecord(Accessor parent, AccessorParams params) { this.parent = parent; this.params = params; } public void addField(String name, Accessor field) { fields.add( field ); names.put(name, field); type.addComponent(name, field.type()); } public void removeField(String name) { Accessor a = names.remove(name); fields.remove(a); type.removeComponent(name); } @Override public int count() { return fields.size(); } @Override public void addListener(Listener listener, InterestSet interestSet, ChildReference path, Executor executor) throws AccessorException { RecordInterestSet is = (RecordInterestSet) interestSet; try { if (is.componentInterests!=null) { for (int i=0; i T getFieldAccessor(int index) throws AccessorConstructionException { if (index<0 || index>=fields.size()) throw new AccessorConstructionException("Field index "+index+" does not exist"); return (T) fields.get(index); } @SuppressWarnings("unchecked") @Override public T getFieldAccessor(String fieldName) throws AccessorConstructionException { Accessor accessor = names.get(fieldName); if (accessor == null) throw new AccessorConstructionException("Field by name "+fieldName+" was not found"); return (T) accessor; } @Override public Object getFieldValue(String fieldName, Binding fieldBinding) throws AccessorException { int fieldIndex = type().getComponentIndex(fieldName); if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist"); return getFieldValue(fieldIndex, fieldBinding); } @Override public Object getFieldValue(int index, Binding fieldBinding) throws AccessorException { if (index<0 || index>=fields.size()) throw new AccessorException("Field index "+index+" does not exist"); return fields.get(index).getValue(fieldBinding); } @Override public void setFieldValue(String fieldName, Binding fieldBinding, Object value) throws AccessorException { int fieldIndex = type().getComponentIndex(fieldName); if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist"); setFieldValue(fieldIndex, fieldBinding, value); } public boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException { try { Accessor a = getComponent(path); a.setValue(binding, obj); return true; } catch (ReferenceException re) { return false; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } @Override public boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException { try { Accessor a = getComponent(path); a.getValue(binding, obj); return true; } catch (ReferenceException re) { return false; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } public Object getValue(ChildReference path, Binding binding) throws AccessorException { try { Accessor a = getComponent(path); return a.getValue(binding); } catch (ReferenceException re) { return null; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } @Override public void setFieldValue(int index, Binding fieldBinding, Object value) throws AccessorException { if (index<0 || index>=fields.size()) throw new AccessorException("Field index "+index+" does not exist"); fields.get(index).setValue(fieldBinding, value); } @Override public RecordType type() { return type; } @Override public void apply(List cs, LinkedList rollback) throws AccessorException { try { boolean makeRollback = rollback != null; ArrayList single = new ArrayList(); for (Event e : cs) { if (e.reference==null) { Event rbe = applyLocal(e, makeRollback); if (makeRollback) { rbe.reference = e.reference; rollback.addFirst( rbe ); } } else { Accessor sa = getComponent(e.reference); // Apply changes single.clear(); Event noRefEvent = e.clone(null); single.add(noRefEvent); sa.apply(single, rollback); } } } catch (AccessorConstructionException ae) { throw new AccessorException(ae); } } Event applyLocal(Event e, boolean makeRollback) throws AccessorException { try { if (e instanceof ValueAssigned) { ValueAssigned va = (ValueAssigned) e; Event rollback = null; if (makeRollback) { Binding binding = params.bindingScheme.getBinding(type()); rollback = new ValueAssigned(binding, getValue(binding)); } setValue(va.newValue.getBinding(), va.newValue.getValue()); return rollback; } else { throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Record Type"); } } catch (BindingConstructionException e2) { throw new AccessorException( e2 ); } } @SuppressWarnings("unchecked") @Override public T getComponent(ChildReference reference) throws AccessorConstructionException { if (reference==null) return (T) this; if (reference instanceof LabelReference) { LabelReference lr = (LabelReference) reference; String fieldName = lr.label; Integer index = type().getComponentIndex(fieldName); if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\""); Accessor sa = getFieldAccessor(index); if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference()); return (T) sa; } if (reference instanceof IndexReference) { IndexReference ref = (IndexReference) reference; int index = ref.getIndex(); Accessor sa = getFieldAccessor(index); if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference()); return (T) sa; } if (reference instanceof NameReference) { NameReference ref = (NameReference) reference; String fieldName = ref.getName(); Integer index = type().getComponentIndex(fieldName); if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\""); Accessor sa = getFieldAccessor(index); if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference()); return (T) sa; } throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType"); } @Override public Object getValue(Binding binding) throws AccessorException { if (!binding.type().equals(type)) throw new AccessorException("Type mismatch"); RecordBinding rb = (RecordBinding) binding; try { Object values[] = new Object[rb.getComponentCount()]; for (int i=0; i