1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 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.binary;
\r
14 import java.io.IOException;
\r
15 import java.lang.ref.WeakReference;
\r
16 import java.util.Collection;
\r
17 import java.util.HashMap;
\r
18 import java.util.Map;
\r
19 import java.util.Map.Entry;
\r
20 import java.util.SortedMap;
\r
21 import java.util.TreeMap;
\r
23 import org.simantics.databoard.accessor.Accessor;
\r
24 import org.simantics.databoard.accessor.ArrayAccessor;
\r
25 import org.simantics.databoard.accessor.CloseableAccessor;
\r
26 import org.simantics.databoard.accessor.StreamAccessor;
\r
27 import org.simantics.databoard.accessor.error.AccessorConstructionException;
\r
28 import org.simantics.databoard.accessor.error.AccessorException;
\r
29 import org.simantics.databoard.accessor.error.ReferenceException;
\r
30 import org.simantics.databoard.accessor.event.ArrayElementAdded;
\r
31 import org.simantics.databoard.accessor.event.ArrayElementRemoved;
\r
32 import org.simantics.databoard.accessor.event.Event;
\r
33 import org.simantics.databoard.accessor.event.ValueAssigned;
\r
34 import org.simantics.databoard.accessor.file.FileArrayAccessor;
\r
35 import org.simantics.databoard.accessor.impl.AccessorParams;
\r
36 import org.simantics.databoard.accessor.impl.ListenerEntry;
\r
37 import org.simantics.databoard.accessor.interestset.ArrayInterestSet;
\r
38 import org.simantics.databoard.accessor.interestset.InterestSet;
\r
39 import org.simantics.databoard.accessor.reference.ChildReference;
\r
40 import org.simantics.databoard.accessor.reference.IndexReference;
\r
41 import org.simantics.databoard.accessor.reference.LabelReference;
\r
42 import org.simantics.databoard.adapter.AdaptException;
\r
43 import org.simantics.databoard.binding.ArrayBinding;
\r
44 import org.simantics.databoard.binding.Binding;
\r
45 import org.simantics.databoard.binding.error.BindingException;
\r
46 import org.simantics.databoard.binding.mutable.MutableVariant;
\r
47 import org.simantics.databoard.serialization.Serializer;
\r
48 import org.simantics.databoard.serialization.SerializerConstructionException;
\r
49 import org.simantics.databoard.type.ArrayType;
\r
50 import org.simantics.databoard.type.Datatype;
\r
51 import org.simantics.databoard.util.binary.Blob;
\r
52 import org.simantics.databoard.util.binary.RandomAccessBinary.ByteSide;
\r
55 * Stream Array is accessor to an array where values can be added to
\r
56 * the end, and where element size is constant.
\r
59 * The Binary format is different from the normal array format, there is no size
\r
60 * integer at the beginning of the binary data. Instead the size is derieved
\r
61 * from the size of the binary data by dividing byte size with element size.
\r
62 * Therefore, the element size must be constant.
\r
64 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
66 public class BinaryStreamArray extends BinaryObject implements ArrayAccessor, FileArrayAccessor, CloseableAccessor, ArrayAccessor.CloseableArrayAccessor, StreamAccessor {
\r
68 /** Accessors to children */
\r
69 TreeMap<Integer, java.lang.ref.Reference<BinaryObject>> children = new TreeMap<Integer, java.lang.ref.Reference<BinaryObject>>();
\r
71 /** Element Binding */
\r
73 /** Element Serializer */
\r
78 public BinaryStreamArray(BinaryObject parent, Blob blob, Datatype type, AccessorParams params)
\r
79 throws AccessorException
\r
81 super(parent, blob, type, params);
\r
82 ArrayType at = (ArrayType) type;
\r
83 cb = params.bindingScheme.getBindingUnchecked(at.componentType);
\r
84 cs = params.serializerScheme.getSerializerUnchecked( cb );
\r
85 Integer elementConstantSize = cs.getConstantSize();
\r
86 if (elementConstantSize == null) {
\r
87 throw new AccessorException("The size in an element of an AppendableArray must be constant.");
\r
89 elementSize = elementConstantSize;
\r
92 public ArrayType type() {
\r
93 return (ArrayType) type;
\r
98 * Get existing sub accessor
\r
100 * @return sub-accessor or <code>null</code>
\r
102 BinaryObject getExistingAccessor(int index)
\r
104 java.lang.ref.Reference<BinaryObject> ref = children.get(index);
\r
105 if (ref==null) return null;
\r
106 BinaryObject res = (BinaryObject) ref.get();
\r
107 // if (res==null) children.remove(index);
\r
112 * Get start position of a field
\r
114 * @param fieldIndex
\r
116 * @throws AccessorException
\r
118 long getStartPosition(int fieldIndex) throws AccessorException {
\r
119 return fieldIndex * (long) (elementSize);
\r
122 long getLength(int index, long pos) throws AccessorException {
\r
123 return elementSize;
\r
127 public void setNoflush(int index, Binding rcb, Object rcv)
\r
128 throws AccessorException {
\r
134 Serializer rcs = params.serializerScheme.getSerializer( rcb );
\r
135 long pos = getStartPosition(index);
\r
137 rcs.serialize(b, null, rcv);
\r
140 ListenerEntry le = listeners;
\r
141 while (le!=null) {
\r
142 ArrayInterestSet is = le.getInterestSet();
\r
143 if (is.inNotificationsOf(index)) {
\r
144 MutableVariant newValue = null;
\r
145 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));
\r
147 Event e = new ValueAssigned(new IndexReference(index), newValue);
\r
153 } catch (IOException e) {
\r
154 throw new AccessorException(e);
\r
155 } catch (AdaptException e) {
\r
156 throw new AccessorException(e);
\r
157 } catch (SerializerConstructionException e) {
\r
158 throw new AccessorException(e);
\r
168 * @param arrayBinding
\r
172 public void setValueNoflush(Binding arrayBinding, Object newArray)
\r
173 throws AccessorException {
\r
178 ArrayBinding rb = ((ArrayBinding)arrayBinding);
\r
179 Binding rcb = rb.getComponentBinding();
\r
180 Serializer rcs = params.serializerScheme.getSerializer( rcb );
\r
181 int oldCount = _size();
\r
182 int newCount = rb.size(newArray);
\r
183 b.setLength( newCount * elementSize );
\r
187 for (int index=0; index<newCount; index++) {
\r
188 Object obj = rb.get(newArray, index);
\r
189 rcs.serialize(b, obj);
\r
193 for (int index=oldCount-1; index>=newCount; index--) {
\r
194 BinaryObject sa = getExistingAccessor(index);
\r
196 sa.invalidatedNotification();
\r
197 children.remove(index);
\r
202 ListenerEntry le = listeners;
\r
203 while (le!=null) {
\r
204 ArrayInterestSet is = le.getInterestSet();
\r
205 if (is.inNotificationsOf(index)) {
\r
206 Event e = new ArrayElementRemoved(index);
\r
213 // Notify new assignment
\r
214 if (listeners!=null) {
\r
215 for (int index=0; index<newCount; index++) {
\r
216 Object cv = rb.get(newArray, index);
\r
219 ListenerEntry le = listeners;
\r
220 while (le!=null) {
\r
221 ArrayInterestSet is = le.getInterestSet();
\r
222 if (is.inNotificationsOf(index)) {
\r
223 MutableVariant vv = null;
\r
224 if (is.inValues()) vv = new MutableVariant(rcb, cb.isImmutable() ? cv : rcb.clone(cv));
\r
226 Event e = index<oldCount ? new ValueAssigned(new IndexReference(index), vv) : new ArrayElementAdded(index, vv);
\r
234 } catch (BindingException e) {
\r
235 throw new AccessorException(e);
\r
236 } catch (IOException e) {
\r
237 throw new AccessorException(e);
\r
238 } catch (AdaptException e) {
\r
239 throw new AccessorException(e);
\r
240 } catch (SerializerConstructionException e) {
\r
241 throw new AccessorException(e);
\r
249 public void addNoflush(int index, Binding rcb, Object rcv) throws AccessorException {
\r
253 Serializer rcs = params.serializerScheme.getSerializer( rcb );
\r
255 int oldCount = _size();
\r
256 boolean lastEntry = index == oldCount;
\r
257 if (index>oldCount) throw new AccessorException("Index out of range");
\r
259 long pos = getStartPosition(index);
\r
261 b.insertBytes(elementSize, ByteSide.Left);
\r
262 rcs.serialize(b, null, rcv);
\r
264 // Update child map keys
\r
265 if (!lastEntry && !children.isEmpty()) {
\r
266 Integer key = children.lastKey();
\r
267 while (key != null && key >= index) {
\r
268 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
\r
269 if (value.get()!=null) children.put(key+1, value);
\r
270 key = children.lowerKey(key);
\r
274 // Notify Listeners
\r
275 ListenerEntry le = listeners;
\r
276 while (le!=null) {
\r
277 ArrayInterestSet is = le.getInterestSet();
\r
278 if (is.inNotifications()) {
\r
279 MutableVariant newValue = null;
\r
280 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));
\r
281 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
\r
285 // Update indices of interest sets
\r
286 if (is.componentInterests!=null) {
\r
287 Map<Integer, InterestSet> oldCis = is.componentInterests;
\r
288 boolean needUpdates = false;
\r
289 for (Integer i : oldCis.keySet()) {
\r
290 needUpdates |= i>=index;
\r
291 if (needUpdates) break;
\r
295 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
\r
296 for (Integer i : oldCis.keySet())
\r
298 Integer oldKey = i;
\r
299 Integer newKey = i>=index ? i+1 : i;
\r
300 InterestSet oldValue = oldCis.get(oldKey);
\r
301 newCis.put(newKey, oldValue);
\r
303 is.componentInterests = newCis;
\r
310 } catch (IOException e) {
\r
311 throw new AccessorException(e);
\r
312 } catch (AdaptException e) {
\r
313 throw new AccessorException(e);
\r
314 } catch (SerializerConstructionException e) {
\r
315 throw new AccessorException(e);
\r
322 public void addNoflush(Binding binding, Object value)
\r
323 throws AccessorException {
\r
324 addNoflush(_size(), binding, value);
\r
328 public void addAllNoflush(Binding binding, Object[] values)
\r
329 throws AccessorException {
\r
330 addAllNoflush(size(), binding, values);
\r
334 public void addAllNoflush(int index, Binding rcb, Object[] rcvs)
\r
335 throws AccessorException {
\r
336 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
\r
340 Serializer rcs = params.serializerScheme.getSerializer( rcb );
\r
343 int oldCount = b.readInt();
\r
344 int newCount = oldCount + rcvs.length;
\r
345 if (index>oldCount) throw new AccessorException("Index out of range");
\r
347 b.writeInt(newCount);
\r
348 boolean lastEntry = index == oldCount;
\r
351 for (int i=0; i<rcvs.length; i++)
\r
352 size += rcs.getSize(rcvs[i]);
\r
353 long pos = getStartPosition(index);
\r
355 b.insertBytes(size, ByteSide.Right);
\r
358 for (int i=0; i<rcvs.length; i++) {
\r
359 Object rcv = rcvs[i];
\r
360 rcs.serialize(b, rcv);
\r
363 // Update child map keys
\r
364 if (!lastEntry && !children.isEmpty()) {
\r
365 Integer key = children.lastKey();
\r
366 while (key!=null && key >= index) {
\r
367 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
\r
368 if (value.get()!=null) children.put(key+rcvs.length, value);
\r
369 key = children.lowerKey(key);
\r
373 // Notify Listeners
\r
374 ListenerEntry le = listeners;
\r
375 while (le!=null) {
\r
376 ArrayInterestSet is = le.getInterestSet();
\r
377 if (is.inNotifications()) {
\r
378 for (int i=0; i<rcvs.length; i++) {
\r
379 MutableVariant newValue = null;
\r
380 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcvs[i] : cb.clone(rcvs[i]));
\r
381 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
\r
386 // Update indices of interest sets
\r
387 if (is.componentInterests!=null) {
\r
388 Map<Integer, InterestSet> oldCis = is.componentInterests;
\r
389 boolean needUpdates = false;
\r
390 for (Integer i : oldCis.keySet()) {
\r
391 needUpdates |= i>=index;
\r
392 if (needUpdates) break;
\r
396 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
\r
397 for (Integer i : oldCis.keySet())
\r
399 Integer oldKey = i;
\r
400 Integer newKey = i>=index ? i+rcvs.length : i;
\r
401 InterestSet oldValue = oldCis.get(oldKey);
\r
402 newCis.put(newKey, oldValue);
\r
404 is.componentInterests = newCis;
\r
407 // Add component interest listener
\r
409 for (int i = index; i<index+rcvs.length; i++) {
\r
410 boolean hadSa = getExistingAccessor(i)!=null;
\r
411 if (hadSa) continue;
\r
413 InterestSet cis = is.getComponentInterest();
\r
415 Accessor sa = getAccessor(i);
\r
417 cis = is.getComponentInterest(index);
\r
419 Accessor sa = getAccessor(i);
\r
429 } catch (IOException e) {
\r
430 throw new AccessorException(e);
\r
431 } catch (AdaptException e) {
\r
432 throw new AccessorException(e);
\r
433 } catch (SerializerConstructionException e) {
\r
434 throw new AccessorException(e);
\r
440 void addRepeatNoflush(int index, Binding rcb, Object obj, int repeatCount) throws AccessorException {
\r
441 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
\r
445 Serializer rcs = params.serializerScheme.getSerializer( rcb );
\r
447 int oldCount = _size();
\r
448 int newCount = oldCount + repeatCount;
\r
449 if (index>oldCount) throw new AccessorException("Index out of range");
\r
451 b.writeInt(newCount);
\r
452 boolean lastEntry = index == oldCount;
\r
454 int size = rcs.getSize(obj) * repeatCount;
\r
455 long pos = getStartPosition(index);
\r
457 b.insertBytes(size, ByteSide.Right);
\r
460 for (int i=0; i<repeatCount; i++) {
\r
461 rcs.serialize(b, obj);
\r
464 // Update child map keys
\r
465 if (!lastEntry && !children.isEmpty()) {
\r
466 Integer key = children.lastKey();
\r
467 while (key!=null && key >= index) {
\r
468 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
\r
469 if (value.get()!=null) children.put(key+repeatCount, value);
\r
470 key = children.lowerKey(key);
\r
474 // Notify Listeners
\r
475 ListenerEntry le = listeners;
\r
476 while (le!=null) {
\r
477 ArrayInterestSet is = le.getInterestSet();
\r
478 if (is.inNotifications()) {
\r
479 for (int i=0; i<repeatCount; i++) {
\r
480 MutableVariant newValue = null;
\r
481 if (is.inValues()) newValue = new MutableVariant(rcb, obj/*rcb.isImmutable() ? obj : cb.clone(obj)*/);
\r
482 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
\r
487 // Update indices of interest sets
\r
488 if (is.componentInterests!=null) {
\r
489 Map<Integer, InterestSet> oldCis = is.componentInterests;
\r
490 boolean needUpdates = false;
\r
491 for (Integer i : oldCis.keySet()) {
\r
492 needUpdates |= i>=index;
\r
493 if (needUpdates) break;
\r
497 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
\r
498 for (Integer i : oldCis.keySet())
\r
500 Integer oldKey = i;
\r
501 Integer newKey = i>=index ? i+repeatCount : i;
\r
502 InterestSet oldValue = oldCis.get(oldKey);
\r
503 newCis.put(newKey, oldValue);
\r
505 is.componentInterests = newCis;
\r
513 } catch (IOException e) {
\r
514 throw new AccessorException(e);
\r
515 } catch (SerializerConstructionException e) {
\r
516 throw new AccessorException(e);
\r
523 public void removeNoflush(int index, int count) throws AccessorException {
\r
528 boolean lastEntry = index == count;
\r
529 int oldCount = _size();
\r
530 if (index<0||index+count>oldCount) throw new AccessorException("Index out of bounds");
\r
531 long pos = getStartPosition(index);
\r
532 long lastPos = getStartPosition(index+count-1);
\r
533 long lastLen = getLength(index, lastPos);
\r
534 long end = lastPos + lastLen;
\r
535 long len = end - pos;
\r
537 b.removeBytes(len, ByteSide.Right);
\r
540 SortedMap<Integer, java.lang.ref.Reference<BinaryObject>> sm = children.subMap(index, true, index+count, false);
\r
541 for (Entry<Integer, java.lang.ref.Reference<BinaryObject>> e : sm.entrySet()) {
\r
542 BinaryObject bo = e.getValue().get();
\r
543 if (bo==null) continue;
\r
544 bo.invalidatedNotification();
\r
548 // Update the keys of consecutive children
\r
549 if (!lastEntry && !children.isEmpty()) {
\r
550 Integer lastKey = children.lastKey();
\r
551 Integer key = children.higherKey(index);
\r
552 while (key != null && key <= lastKey) {
\r
553 java.lang.ref.Reference<BinaryObject> value = children.remove(key);
\r
554 if (value.get()!=null) children.put(key-count, value);
\r
555 key = children.higherKey(key);
\r
559 // Notify Listeners
\r
560 ListenerEntry le = listeners;
\r
561 while (le!=null) {
\r
562 ArrayInterestSet is = le.getInterestSet();
\r
563 if (is.inNotifications()) {
\r
564 ArrayElementRemoved e = new ArrayElementRemoved(index);
\r
568 // Update indices of interest sets
\r
569 if (is.componentInterests!=null) {
\r
570 Map<Integer, InterestSet> oldCis = is.componentInterests;
\r
571 boolean needUpdates = false;
\r
572 for (Integer i : oldCis.keySet()) {
\r
573 needUpdates |= i>=index;
\r
574 if (needUpdates) break;
\r
578 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size());
\r
579 for (Integer i : oldCis.keySet())
\r
581 Integer oldKey = i;
\r
582 Integer newKey = i>=index ? i-1 : i;
\r
583 InterestSet oldValue = oldCis.get(oldKey);
\r
584 newCis.put(newKey, oldValue);
\r
586 is.componentInterests = newCis;
\r
593 } catch (IOException e) {
\r
594 throw new AccessorException( e );
\r
601 public Object get(int index, Binding valueBinding) throws AccessorException {
\r
605 long pos = getStartPosition(index);
\r
607 Serializer s = params.serializerScheme.getSerializer(valueBinding);
\r
608 return s.deserialize(b);
\r
609 } catch (IOException e) {
\r
610 throw new AccessorException(e);
\r
611 } catch (SerializerConstructionException e) {
\r
612 throw new AccessorException(e);
\r
619 public void get(int index, Binding valueBinding, Object dst) throws AccessorException {
\r
623 long pos = getStartPosition(index);
\r
625 Serializer s = params.serializerScheme.getSerializer(valueBinding);
\r
626 s.deserializeTo(b, dst);
\r
627 } catch (IOException e) {
\r
628 throw new AccessorException(e);
\r
629 } catch (SerializerConstructionException e) {
\r
630 throw new AccessorException(e);
\r
637 @SuppressWarnings("unchecked")
\r
639 public <T extends Accessor> T getAccessor(int index)
\r
640 throws AccessorConstructionException {
\r
644 int count = _size();
\r
645 if (index<0 || index>=count) throw new ReferenceException("Element index ("+index+") out of bounds ("+count+")");
\r
647 // Get existing or create new
\r
648 BinaryObject sa = getExistingAccessor(index);
\r
650 long pos = getStartPosition(index);
\r
651 long len = getLength(index, pos);
\r
653 // Instantiate correct sub accessor.
\r
654 sa = createSubAccessor(cb.type(), pos, len, params);
\r
655 children.put(index, new WeakReference<BinaryObject>(sa) );
\r
657 // Add component interest sets
\r
658 ListenerEntry le = listeners;
\r
659 while (le!=null) {
\r
660 ArrayInterestSet is = le.getInterestSet();
\r
662 // Generic element interest
\r
663 InterestSet gis = is.getComponentInterest();
\r
666 ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
\r
667 sa.addListener(le.listener, gis, childPath, le.executor);
\r
668 } catch (AccessorException e) {
\r
669 throw new AccessorConstructionException(e);
\r
673 // Specific element interest
\r
674 InterestSet cis = is.getComponentInterest(index);
\r
677 ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
\r
678 sa.addListener(le.listener, cis, childPath,le.executor);
\r
679 } catch (AccessorException e) {
\r
680 throw new AccessorConstructionException(e);
\r
691 } catch (AccessorException e) {
\r
692 throw new AccessorConstructionException(e);
\r
698 @SuppressWarnings("unchecked")
\r
700 public <T extends Accessor> T getComponent(ChildReference reference)
\r
701 throws AccessorConstructionException {
\r
702 if (reference==null) return (T) this;
\r
703 if (reference instanceof LabelReference) {
\r
704 LabelReference lr = (LabelReference) reference;
\r
706 Integer index = new Integer( lr.label );
\r
707 Accessor result = getAccessor(index);
\r
708 if (reference.getChildReference() != null)
\r
709 result = result.getComponent(reference.getChildReference());
\r
711 } catch ( NumberFormatException nfe ) {
\r
712 throw new ReferenceException(nfe);
\r
714 } else if (reference instanceof IndexReference) {
\r
715 IndexReference ref = (IndexReference) reference;
\r
716 int index = ref.getIndex();
\r
717 Accessor result = getAccessor(index);
\r
718 if (reference.getChildReference() != null)
\r
719 result = result.getComponent(reference.getChildReference());
\r
721 } throw new ReferenceException(reference.getClass().getName()+" is not a reference of an array");
\r
725 public void getAll(Binding valueBinding, Object[] array)
\r
726 throws AccessorException {
\r
730 int size = _size();
\r
731 if (size > array.length) throw new AccessorException("Argument array too short");
\r
732 Serializer s = params.serializerScheme.getSerializer(valueBinding);
\r
734 for (int i=0; i<size; i++) {
\r
735 array[i] = s.deserialize(b);
\r
737 } catch (IOException e) {
\r
738 throw new AccessorException( e );
\r
739 } catch (SerializerConstructionException e) {
\r
740 throw new AccessorException( e );
\r
747 public void getAll(Binding valueBinding, Collection<Object> values)
\r
748 throws AccessorException {
\r
753 int size = _size();
\r
754 Serializer s = params.serializerScheme.getSerializer(valueBinding);
\r
755 for (int i=0; i<size; i++) {
\r
756 values.add( s.deserialize(b) );
\r
758 } catch (IOException e) {
\r
759 throw new AccessorException( e );
\r
760 } catch (SerializerConstructionException e) {
\r
761 throw new AccessorException( e );
\r
768 public void setSizeNoflush(int newSize) throws AccessorException {
\r
772 int oldSize = _size();
\r
774 // Remove instances
\r
775 if (newSize<oldSize) {
\r
776 remove(newSize, oldSize-newSize);
\r
779 // Add dummy instances
\r
780 if (newSize>oldSize) {
\r
781 Object dummy = cb.createDefault();
\r
782 int count = newSize-oldSize;
\r
783 addRepeatNoflush(oldSize, cb, dummy, count);
\r
786 } catch (BindingException e) {
\r
787 throw new AccessorException( e );
\r
794 public void setSize(int newSize) throws AccessorException {
\r
798 setSizeNoflush(newSize);
\r
800 } catch (IOException e) {
\r
801 throw new AccessorException( e );
\r
808 public int size() throws AccessorException {
\r
812 return (int) ( b.length() / elementSize );
\r
813 } catch (IOException e) {
\r
814 throw new AccessorException( e );
\r
820 private int _size() throws AccessorException {
\r
822 return (int) ( b.length() / elementSize );
\r
823 } catch (IOException e) {
\r
824 throw new AccessorException( e );
\r
829 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
\r
830 Event rollback = null;
\r
831 if (e instanceof ValueAssigned) {
\r
832 ValueAssigned va = (ValueAssigned) e;
\r
833 if (makeRollback) rollback = new ValueAssigned(cb, getValue(cb));
\r
834 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
\r
836 if (e instanceof ArrayElementAdded) {
\r
837 ArrayElementAdded aa = (ArrayElementAdded) e;
\r
838 addNoflush(aa.index, aa.value.getBinding(), aa.value.getValue());
\r
839 if (makeRollback) rollback = new ArrayElementRemoved(aa.index);
\r
840 } else if (e instanceof ArrayElementRemoved) {
\r
841 ArrayElementRemoved ar = (ArrayElementRemoved) e;
\r
842 if (ar.index<0 || ar.index >=size()) throw new AccessorException("Array index out of bounds");
\r
843 if (makeRollback) {
\r
844 Object cv = get(ar.index, cb);
\r
845 rollback = new ArrayElementAdded(ar.index, new MutableVariant(cb, cv));
\r
847 removeNoflush(ar.index, 1);
\r
849 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Array");
\r
858 public void add(Binding binding, Object value) throws AccessorException {
\r
862 addNoflush(binding, value);
\r
864 } catch (IOException e) {
\r
865 throw new AccessorException( e );
\r
872 public void add(int index, Binding binding, Object value)
\r
873 throws AccessorException {
\r
877 addNoflush(index, binding, value);
\r
879 } catch (IOException e) {
\r
880 throw new AccessorException( e );
\r
887 public void addAll(Binding binding, Object[] values)
\r
888 throws AccessorException {
\r
892 addAllNoflush(binding, values);
\r
894 } catch (IOException e) {
\r
895 throw new AccessorException( e );
\r
902 public void addAll(int index, Binding binding, Object[] values)
\r
903 throws AccessorException {
\r
907 addAllNoflush(index, binding, values);
\r
909 } catch (IOException e) {
\r
910 throw new AccessorException( e );
\r
917 public void remove(int index, int count) throws AccessorException {
\r
921 removeNoflush(index, count);
\r
923 } catch (IOException e) {
\r
924 throw new AccessorException( e );
\r
931 public void set(int index, Binding binding, Object value)
\r
932 throws AccessorException {
\r
936 setNoflush(index, binding, value);
\r
938 } catch (IOException e) {
\r
939 throw new AccessorException(e);
\r