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.binary;
14 import java.io.IOException;
15 import java.lang.ref.WeakReference;
16 import java.util.Collection;
17 import java.util.HashMap;
19 import java.util.Map.Entry;
20 import java.util.SortedMap;
21 import java.util.TreeMap;
23 import org.simantics.databoard.Bindings;
24 import org.simantics.databoard.accessor.Accessor;
25 import org.simantics.databoard.accessor.ArrayAccessor;
26 import org.simantics.databoard.accessor.CloseableAccessor;
27 import org.simantics.databoard.accessor.StreamAccessor;
28 import org.simantics.databoard.accessor.error.AccessorConstructionException;
29 import org.simantics.databoard.accessor.error.AccessorException;
30 import org.simantics.databoard.accessor.error.ReferenceException;
31 import org.simantics.databoard.accessor.event.ArrayElementAdded;
32 import org.simantics.databoard.accessor.event.ArrayElementRemoved;
33 import org.simantics.databoard.accessor.event.Event;
34 import org.simantics.databoard.accessor.event.ValueAssigned;
35 import org.simantics.databoard.accessor.file.FileArrayAccessor;
36 import org.simantics.databoard.accessor.impl.AccessorParams;
37 import org.simantics.databoard.accessor.impl.ListenerEntry;
38 import org.simantics.databoard.accessor.interestset.ArrayInterestSet;
39 import org.simantics.databoard.accessor.interestset.InterestSet;
40 import org.simantics.databoard.accessor.reference.ChildReference;
41 import org.simantics.databoard.accessor.reference.IndexReference;
42 import org.simantics.databoard.accessor.reference.LabelReference;
43 import org.simantics.databoard.adapter.AdaptException;
44 import org.simantics.databoard.binding.ArrayBinding;
45 import org.simantics.databoard.binding.Binding;
46 import org.simantics.databoard.binding.error.BindingException;
47 import org.simantics.databoard.binding.mutable.MutableVariant;
48 import org.simantics.databoard.serialization.Serializer;
49 import org.simantics.databoard.serialization.SerializerConstructionException;
50 import org.simantics.databoard.type.ArrayType;
51 import org.simantics.databoard.type.Datatype;
52 import org.simantics.databoard.type.LongType;
53 import org.simantics.databoard.util.binary.Blob;
54 import org.simantics.databoard.util.binary.RandomAccessBinary.ByteSide;
57 * Binary Array is accessor to a byte backed array of elements.
60 * Note, To increase the random access performance of the record, create sub-accessors of
63 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
65 public class BinaryVariableWidthStreamArray extends BinaryObject implements ArrayAccessor, FileArrayAccessor, ArrayAccessor.CloseableArrayAccessor, StreamAccessor {
67 /** Accessors to children */
68 TreeMap<Integer, java.lang.ref.Reference<BinaryObject>> children = new TreeMap<Integer, java.lang.ref.Reference<BinaryObject>>();
75 public BinaryVariableWidthStreamArray(BinaryObject parent, Blob blob, Datatype type, AccessorParams params, ArrayAccessor index)
76 throws AccessorConstructionException
78 super(parent, blob, type, params);
79 ArrayType at = (ArrayType) type;
80 cb = params.bindingScheme.getBindingUnchecked(at.componentType);
81 cs = params.serializerScheme.getSerializerUnchecked( cb );
82 constantSize = cs.getConstantSize();
83 if (index==null || index.type().componentType instanceof LongType == false) {
84 throw new AccessorConstructionException("Index must be Long[]");
89 public ArrayType type() {
90 return (ArrayType) type;
94 * Get existing sub accessor
96 * @return sub-accessor or <code>null</code>
98 BinaryObject getExistingAccessor(int index)
100 java.lang.ref.Reference<BinaryObject> ref = children.get(index);
101 if (ref==null) return null;
102 BinaryObject res = (BinaryObject) ref.get();
103 // if (res==null) children.remove(index);
108 * Get start position of a field
112 * @throws AccessorException
114 long getStartPosition(int fieldIndex) throws AccessorException {
115 int c = this.index.size();
119 } catch (IOException e) {
120 throw new AccessorException( e );
122 if ( fieldIndex>c || fieldIndex<0 ) throw new AccessorException("Index out of bounds");
123 return (Long) index.get(fieldIndex, Bindings.LONG);
126 long getLength(int index, long pos) throws AccessorException {
127 int c = this.index.size();
128 if ( index>=c || index<0 ) return 0;
132 return b.length() - (Long) this.index.get(c-1, Bindings.LONG);
133 } catch (IOException e) {
134 throw new AccessorException( e );
137 return (Long) this.index.get(index+1, Bindings.LONG) - (Long) this.index.get(index, Bindings.LONG);
142 public void setNoflush(int index, Binding rcb, Object rcv)
143 throws AccessorException {
150 if ( index==count ) {
151 addNoflush(count, rcb, rcv);
156 Serializer rcs = params.serializerScheme.getSerializer( rcb );
157 long pos = getStartPosition(index);
158 long oldSize = getLength(index, pos);
159 long newSize = rcs.getSize(rcv, null);
161 long diff = newSize - oldSize;
163 b.insertBytes( newSize - oldSize, ByteSide.Right );
165 b.removeBytes( oldSize - newSize, ByteSide.Right );
168 rcs.serialize(b, null, rcv);
170 // Update index of the higher indices
172 for (int i=index+1; i<count; i++) {
173 long p = (Long) this.index.get(i, Bindings.LONG);
175 this.index.set(i, Bindings.LONG, p);
181 BinaryObject sa = getExistingAccessor(index);
182 if (sa!=null && newSize != oldSize) {
183 sa.b.setPositionInSource(pos, newSize);
186 // Shift consecutive blobs
187 /* if (!children.isEmpty()) {
188 Integer lastKey = children.lastKey();
189 if (lastKey!=null && index+1 <= lastKey && diff!=0) {
190 SortedMap<Integer, Reference<BinaryObject>> pm = children.subMap(index+1, true, lastKey, true);
191 for (Entry<Integer, Reference<BinaryObject>> e : pm.entrySet()) {
192 BinaryObject sa_ = e.getValue().get();
193 if (sa_ == null) continue;
194 sa_.b.setPositionInSource( sa_.b.getStartPositionInSourceBinary() + diff, sa_.b.length());
200 ListenerEntry le = listeners;
202 ArrayInterestSet is = le.getInterestSet();
203 if (is.inNotificationsOf(index)) {
204 MutableVariant newValue = null;
205 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));
207 Event e = new ValueAssigned(new IndexReference(index), newValue);
213 } catch (IOException e) {
214 throw new AccessorException(e);
215 } catch (AdaptException e) {
216 throw new AccessorException(e);
217 } catch (SerializerConstructionException e) {
218 throw new AccessorException(e);
228 * @param arrayBinding
232 public void setValueNoflush(Binding arrayBinding, Object newArray)
233 throws AccessorException {
238 ArrayBinding rb = ((ArrayBinding)arrayBinding);
239 Binding rcb = rb.getComponentBinding();
240 Serializer rcs = params.serializerScheme.getSerializer( rcb );
241 int oldCount = index.size();
242 int newCount = rb.size(newArray);
243 b.setLength( params.serializerScheme.getSerializer( rb ).getSize(newArray) );
244 index.setSize(newCount);
247 for (int index=0; index<newCount; index++) {
248 //long startPos = b.position();
249 Object obj = rb.get(newArray, index);
250 this.index.set(index, Bindings.LONG, b.position());
251 rcs.serialize(b, obj);
252 //long endPos = b.position();
253 //long len = endPos - startPos;
257 BinaryObject sa = getExistingAccessor(index);
259 sa.b.setPositionInSource(startPos, len);
264 for (int index=oldCount-1; index>=newCount; index--) {
265 BinaryObject sa = getExistingAccessor(index);
267 sa.invalidatedNotification();
268 children.remove(index);
273 ListenerEntry le = listeners;
275 ArrayInterestSet is = le.getInterestSet();
276 if (is.inNotificationsOf(index)) {
277 Event e = new ArrayElementRemoved(index);
284 // Notify new assignment
285 if (listeners!=null) {
286 for (int index=0; index<newCount; index++) {
287 Object cv = rb.get(newArray, index);
290 ListenerEntry le = listeners;
292 ArrayInterestSet is = le.getInterestSet();
293 if (is.inNotificationsOf(index)) {
294 MutableVariant vv = null;
295 if (is.inValues()) vv = new MutableVariant(rcb, cb.isImmutable() ? cv : rcb.clone(cv));
297 Event e = index<oldCount ? new ValueAssigned(new IndexReference(index), vv) : new ArrayElementAdded(index, vv);
305 } catch (BindingException e) {
306 throw new AccessorException(e);
307 } catch (IOException e) {
308 throw new AccessorException(e);
309 } catch (AdaptException e) {
310 throw new AccessorException(e);
311 } catch (SerializerConstructionException e) {
312 throw new AccessorException(e);
320 public void addNoflush(int index, Binding rcb, Object rcv) throws AccessorException {
324 Serializer rcs = params.serializerScheme.getSerializer( rcb );
326 int oldCount = this.index.size();
327 int newCount = oldCount+1;
328 boolean lastEntry = index == oldCount;
329 if (index>oldCount) throw new AccessorException("Index out of range");
331 long pos = getStartPosition(index);
332 int size = rcs.getSize(rcv);
334 b.insertBytes(size, ByteSide.Left);
335 rcs.serialize(b, null, rcv);
337 this.index.add(index, Bindings.LONG, pos);
339 for (int i=index+1; i<newCount; i++) {
340 long p = (Long) this.index.get(i, Bindings.LONG);
342 this.index.set(i, Bindings.LONG, p);
346 // Update child map keys
347 if (!lastEntry && !children.isEmpty()) {
348 Integer key = children.lastKey();
349 while (key != null && key >= index) {
350 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
351 if (value.get()!=null) children.put(key+1, value);
352 key = children.lowerKey(key);
357 ListenerEntry le = listeners;
359 ArrayInterestSet is = le.getInterestSet();
360 if (is.inNotifications()) {
361 MutableVariant newValue = null;
362 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));
363 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
367 // Update indices of interest sets
368 if (is.componentInterests!=null) {
369 Map<Integer, InterestSet> oldCis = is.componentInterests;
370 boolean needUpdates = false;
371 for (Integer i : oldCis.keySet()) {
372 needUpdates |= i>=index;
373 if (needUpdates) break;
377 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
378 for (Integer i : oldCis.keySet())
381 Integer newKey = i>=index ? i+1 : i;
382 InterestSet oldValue = oldCis.get(oldKey);
383 newCis.put(newKey, oldValue);
385 is.componentInterests = newCis;
389 // Add component interest listener
391 boolean hadSa = getExistingAccessor(index) != null;
393 // Add component interest listener
394 InterestSet cis = is.getComponentInterest();
396 Accessor sa = getAccessor(index);
398 cis = is.getComponentInterest(index);
400 Accessor sa = getAccessor(index);
407 } catch (IOException e) {
408 throw new AccessorException(e);
409 } catch (AdaptException e) {
410 throw new AccessorException(e);
411 } catch (SerializerConstructionException e) {
412 throw new AccessorException(e);
419 public void addNoflush(Binding binding, Object value)
420 throws AccessorException {
421 addNoflush(size(), binding, value);
425 public void addAllNoflush(Binding binding, Object[] values)
426 throws AccessorException {
427 addAllNoflush(size(), binding, values);
431 public void addAllNoflush(int index, Binding rcb, Object[] rcvs)
432 throws AccessorException {
433 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
437 Serializer rcs = params.serializerScheme.getSerializer( rcb );
440 int repeatCount = rcvs.length;
441 int oldCount = b.readInt();
442 int newCount = oldCount + rcvs.length;
443 if (index>oldCount) throw new AccessorException("Index out of range");
444 boolean lastEntry = index == oldCount;
447 for (int i=0; i<rcvs.length; i++)
448 size += rcs.getSize(rcvs[i]);
449 long pos = getStartPosition(index);
451 b.insertBytes(size, ByteSide.Right);
454 for (int i=0; i<repeatCount; i++) {
455 this.index.add(index+i, Bindings.LONG, (Long) p);
456 p += rcs.getSize(rcvs[i]);
458 for (int i=index+repeatCount; i<newCount; i++) {
459 p = (Long) this.index.get(i, Bindings.LONG);
461 this.index.set(i, Bindings.LONG, p);
465 for (int i=0; i<rcvs.length; i++) {
466 Object rcv = rcvs[i];
467 rcs.serialize(b, rcv);
470 // Update child map keys
471 if (!lastEntry && !children.isEmpty()) {
472 Integer key = children.lastKey();
473 while (key!=null && key >= index) {
474 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
475 if (value.get()!=null) children.put(key+rcvs.length, value);
476 key = children.lowerKey(key);
481 ListenerEntry le = listeners;
483 ArrayInterestSet is = le.getInterestSet();
484 if (is.inNotifications()) {
485 for (int i=0; i<rcvs.length; i++) {
486 MutableVariant newValue = null;
487 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcvs[i] : cb.clone(rcvs[i]));
488 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
493 // Update indices of interest sets
494 if (is.componentInterests!=null) {
495 Map<Integer, InterestSet> oldCis = is.componentInterests;
496 boolean needUpdates = false;
497 for (Integer i : oldCis.keySet()) {
498 needUpdates |= i>=index;
499 if (needUpdates) break;
503 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
504 for (Integer i : oldCis.keySet())
507 Integer newKey = i>=index ? i+rcvs.length : i;
508 InterestSet oldValue = oldCis.get(oldKey);
509 newCis.put(newKey, oldValue);
511 is.componentInterests = newCis;
514 // Add component interest listener
516 for (int i = index; i<index+rcvs.length; i++) {
517 boolean hadSa = getExistingAccessor(i)!=null;
520 InterestSet cis = is.getComponentInterest();
522 Accessor sa = getAccessor(i);
524 cis = is.getComponentInterest(index);
526 Accessor sa = getAccessor(i);
536 } catch (IOException e) {
537 throw new AccessorException(e);
538 } catch (AdaptException e) {
539 throw new AccessorException(e);
540 } catch (SerializerConstructionException e) {
541 throw new AccessorException(e);
547 void addRepeatNoflush(int index, Binding rcb, Object obj, int repeatCount) throws AccessorException {
548 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
552 Serializer rcs = params.serializerScheme.getSerializer( rcb );
555 int oldCount = this.index.size();
556 int newCount = oldCount + repeatCount;
557 if (index>oldCount) throw new AccessorException("Index out of range");
558 boolean lastEntry = index == oldCount;
560 long componentSize = rcs.getSize(obj);
561 long size = componentSize * repeatCount;
562 long pos = getStartPosition(index);
564 b.insertBytes(size, ByteSide.Right);
566 for (int i=0; i<repeatCount; i++) {
567 this.index.add(index+i, Bindings.LONG, (Long) p);
568 pos += componentSize;
570 for (int i=index+repeatCount; i<newCount; i++) {
571 p = (Long) this.index.get(i, Bindings.LONG);
573 this.index.set(i, Bindings.LONG, p);
577 for (int i=0; i<repeatCount; i++) {
578 rcs.serialize(b, obj);
581 // Update child map keys
582 if (!lastEntry && !children.isEmpty()) {
583 Integer key = children.lastKey();
584 while (key!=null && key >= index) {
585 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
586 if (value.get()!=null) children.put(key+repeatCount, value);
587 key = children.lowerKey(key);
592 ListenerEntry le = listeners;
594 ArrayInterestSet is = le.getInterestSet();
595 if (is.inNotifications()) {
596 for (int i=0; i<repeatCount; i++) {
597 MutableVariant newValue = null;
598 if (is.inValues()) newValue = new MutableVariant(rcb, obj/*rcb.isImmutable() ? obj : cb.clone(obj)*/);
599 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
604 // Update indices of interest sets
605 if (is.componentInterests!=null) {
606 Map<Integer, InterestSet> oldCis = is.componentInterests;
607 boolean needUpdates = false;
608 for (Integer i : oldCis.keySet()) {
609 needUpdates |= i>=index;
610 if (needUpdates) break;
614 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
615 for (Integer i : oldCis.keySet())
618 Integer newKey = i>=index ? i+repeatCount : i;
619 InterestSet oldValue = oldCis.get(oldKey);
620 newCis.put(newKey, oldValue);
622 is.componentInterests = newCis;
630 } catch (IOException e) {
631 throw new AccessorException(e);
632 } catch (SerializerConstructionException e) {
633 throw new AccessorException(e);
640 public void removeNoflush(int index, int count) throws AccessorException {
645 boolean lastEntry = index == count;
646 int oldCount = this.index.size();
647 int newCount = oldCount - count;
648 if (index<0||index+count>oldCount) throw new AccessorException("Index out of bounds");
649 long pos = getStartPosition(index);
650 long lastPos = getStartPosition(index+count-1);
651 long lastLen = getLength(index, lastPos);
652 long end = lastPos + lastLen;
653 long len = end - pos;
655 b.removeBytes(len, ByteSide.Right);
656 this.index.remove(index, count);
657 for (int i=index; i<newCount; i++) {
658 long p = (Long) this.index.get(i, Bindings.LONG);
660 this.index.set(i, Bindings.LONG, p);
664 SortedMap<Integer, java.lang.ref.Reference<BinaryObject>> sm = children.subMap(index, true, index+count, false);
665 for (Entry<Integer, java.lang.ref.Reference<BinaryObject>> e : sm.entrySet()) {
666 BinaryObject bo = e.getValue().get();
667 if (bo==null) continue;
668 bo.invalidatedNotification();
672 // Update the keys of consecutive children
673 if (!lastEntry && !children.isEmpty()) {
674 Integer lastKey = children.lastKey();
675 Integer key = children.higherKey(index);
676 while (key != null && key <= lastKey) {
677 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
678 if (value.get()!=null) children.put(key-count, value);
679 key = children.higherKey(key);
684 ListenerEntry le = listeners;
686 ArrayInterestSet is = le.getInterestSet();
687 if (is.inNotifications()) {
688 ArrayElementRemoved e = new ArrayElementRemoved(index);
692 // Update indices of interest sets
693 if (is.componentInterests!=null) {
694 Map<Integer, InterestSet> oldCis = is.componentInterests;
695 boolean needUpdates = false;
696 for (Integer i : oldCis.keySet()) {
697 needUpdates |= i>=index;
698 if (needUpdates) break;
702 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
703 for (Integer i : oldCis.keySet())
706 Integer newKey = i>=index ? i-1 : i;
707 InterestSet oldValue = oldCis.get(oldKey);
708 newCis.put(newKey, oldValue);
710 is.componentInterests = newCis;
717 } catch (IOException e) {
718 throw new AccessorException( e );
725 public Object get(int index, Binding valueBinding) throws AccessorException {
729 long pos = getStartPosition(index);
731 Serializer s = params.serializerScheme.getSerializer(valueBinding);
732 return s.deserialize(b);
733 } catch (IOException e) {
734 throw new AccessorException(e);
735 } catch (SerializerConstructionException e) {
736 throw new AccessorException(e);
743 public void get(int index, Binding valueBinding, Object dst) throws AccessorException {
747 long pos = getStartPosition(index);
749 Serializer s = params.serializerScheme.getSerializer(valueBinding);
750 s.deserializeTo(b, dst);
751 } catch (IOException e) {
752 throw new AccessorException(e);
753 } catch (SerializerConstructionException e) {
754 throw new AccessorException(e);
761 @SuppressWarnings("unchecked")
763 public <T extends Accessor> T getAccessor(int index)
764 throws AccessorConstructionException {
769 int count = b.readInt();
770 if (index<0 || index>=count) throw new ReferenceException("Element index ("+index+") out of bounds ("+count+")");
772 // Get existing or create new
773 BinaryObject sa = getExistingAccessor(index);
775 long pos = getStartPosition(index);
776 long len = getLength(index, pos);
778 // Instantiate correct sub accessor.
779 sa = createSubAccessor(cb.type(), pos, len, params);
780 children.put(index, new WeakReference<BinaryObject>(sa) );
782 // Add component interest sets
783 ListenerEntry le = listeners;
785 ArrayInterestSet is = le.getInterestSet();
787 // Generic element interest
788 InterestSet gis = is.getComponentInterest();
791 ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
792 sa.addListener(le.listener, gis, childPath, le.executor);
793 } catch (AccessorException e) {
794 throw new AccessorConstructionException(e);
798 // Specific element interest
799 InterestSet cis = is.getComponentInterest(index);
802 ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
803 sa.addListener(le.listener, cis, childPath,le.executor);
804 } catch (AccessorException e) {
805 throw new AccessorConstructionException(e);
816 } catch (IOException e) {
817 throw new AccessorConstructionException(e);
818 } catch (AccessorException e) {
819 throw new AccessorConstructionException(e);
825 @SuppressWarnings("unchecked")
827 public <T extends Accessor> T getComponent(ChildReference reference)
828 throws AccessorConstructionException {
829 if (reference==null) return (T) this;
830 if (reference instanceof LabelReference) {
831 LabelReference lr = (LabelReference) reference;
833 Integer index = new Integer( lr.label );
834 Accessor result = getAccessor(index);
835 if (reference.getChildReference() != null)
836 result = result.getComponent(reference.getChildReference());
838 } catch ( NumberFormatException nfe ) {
839 throw new ReferenceException(nfe);
841 } else if (reference instanceof IndexReference) {
842 IndexReference ref = (IndexReference) reference;
843 int index = ref.getIndex();
844 Accessor result = getAccessor(index);
845 if (reference.getChildReference() != null)
846 result = result.getComponent(reference.getChildReference());
848 } throw new ReferenceException(reference.getClass().getName()+" is not a reference of an array");
852 public void getAll(Binding valueBinding, Object[] array)
853 throws AccessorException {
858 int size = b.readInt();
859 if (size > array.length) throw new AccessorException("Argument array too short");
860 Serializer s = params.serializerScheme.getSerializer(valueBinding);
861 for (int i=0; i<size; i++) {
862 array[i] = s.deserialize(b);
864 } catch (IOException e) {
865 throw new AccessorException( e );
866 } catch (SerializerConstructionException e) {
867 throw new AccessorException( e );
874 public void getAll(Binding valueBinding, Collection<Object> values)
875 throws AccessorException {
880 int size = b.readInt();
881 Serializer s = params.serializerScheme.getSerializer(valueBinding);
882 for (int i=0; i<size; i++) {
883 values.add( s.deserialize(b) );
885 } catch (IOException e) {
886 throw new AccessorException( e );
887 } catch (SerializerConstructionException e) {
888 throw new AccessorException( e );
895 public void setSizeNoflush(int newSize) throws AccessorException {
899 int oldSize = size();
902 if (newSize<oldSize) {
903 remove(newSize, oldSize-newSize);
906 // Add dummy instances
907 if (newSize>oldSize) {
908 Object dummy = cb.createDefault();
909 int count = newSize-oldSize;
910 addRepeatNoflush(oldSize, cb, dummy, count);
913 } catch (BindingException e) {
914 throw new AccessorException( e );
921 public void setSize(int newSize) throws AccessorException {
925 setSizeNoflush(newSize);
927 } catch (IOException e) {
928 throw new AccessorException( e );
935 public int size() throws AccessorException {
942 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
943 Event rollback = null;
944 if (e instanceof ValueAssigned) {
945 ValueAssigned va = (ValueAssigned) e;
946 if (makeRollback) rollback = new ValueAssigned(cb, getValue(cb));
947 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
949 if (e instanceof ArrayElementAdded) {
950 ArrayElementAdded aa = (ArrayElementAdded) e;
951 addNoflush(aa.index, aa.value.getBinding(), aa.value.getValue());
952 if (makeRollback) rollback = new ArrayElementRemoved(aa.index);
953 } else if (e instanceof ArrayElementRemoved) {
954 ArrayElementRemoved ar = (ArrayElementRemoved) e;
955 if (ar.index<0 || ar.index >=size()) throw new AccessorException("Array index out of bounds");
957 Object cv = get(ar.index, cb);
958 rollback = new ArrayElementAdded(ar.index, new MutableVariant(cb, cv));
960 removeNoflush(ar.index, 1);
962 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Array");
969 public void add(Binding binding, Object value) throws AccessorException {
973 addNoflush(binding, value);
975 } catch (IOException e) {
976 throw new AccessorException( e );
983 public void add(int index, Binding binding, Object value)
984 throws AccessorException {
988 addNoflush(index, binding, value);
990 } catch (IOException e) {
991 throw new AccessorException( e );
998 public void addAll(Binding binding, Object[] values)
999 throws AccessorException {
1003 addAllNoflush(binding, values);
1005 } catch (IOException e) {
1006 throw new AccessorException( e );
1013 public void addAll(int index, Binding binding, Object[] values)
1014 throws AccessorException {
1018 addAllNoflush(index, binding, values);
1020 } catch (IOException e) {
1021 throw new AccessorException( e );
1028 public void remove(int index, int count) throws AccessorException {
1032 removeNoflush(index, count);
1034 } catch (IOException e) {
1035 throw new AccessorException( e );
1042 public void set(int index, Binding binding, Object value)
1043 throws AccessorException {
1047 setNoflush(index, binding, value);
1049 } catch (IOException e) {
1050 throw new AccessorException(e);
1057 public void close() throws AccessorException {
1058 if ( this.index instanceof CloseableAccessor ) {
1059 CloseableAccessor ca = (CloseableAccessor) this.index;