]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/binary/BinaryVariableWidthStreamArray.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / binary / BinaryVariableWidthStreamArray.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
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
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.accessor.binary;
13
14 import java.io.IOException;
15 import java.lang.ref.WeakReference;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.SortedMap;
21 import java.util.TreeMap;
22
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;
55
56 /**
57  * Binary Array is accessor to a byte backed array of elements.
58  * <p>
59  * 
60  * Note, To increase the random access performance of the record, create sub-accessors of
61  * its fields. 
62  *
63  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
64  */
65 public class BinaryVariableWidthStreamArray extends BinaryObject implements ArrayAccessor, FileArrayAccessor, ArrayAccessor.CloseableArrayAccessor, StreamAccessor {
66
67         /** Accessors to children */
68         TreeMap<Integer, java.lang.ref.Reference<BinaryObject>> children = new TreeMap<Integer, java.lang.ref.Reference<BinaryObject>>(); 
69
70         Binding cb;
71         Serializer cs;
72         Integer constantSize;
73         ArrayAccessor index;
74         
75         public BinaryVariableWidthStreamArray(BinaryObject parent, Blob blob, Datatype type, AccessorParams params, ArrayAccessor index) 
76         throws AccessorConstructionException
77         {
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[]");
85                 }
86                 this.index = index;
87         }
88         
89         public ArrayType type() {
90                 return (ArrayType) type;
91         }
92         
93         /**
94          * Get existing sub accessor
95          * @param index
96          * @return sub-accessor or <code>null</code>
97          */
98         BinaryObject getExistingAccessor(int index)
99         {               
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);
104                 return res;
105         }       
106         
107         /**
108          * Get start position of a field
109          * 
110          * @param fieldIndex
111          * @return
112          * @throws AccessorException
113          */
114         long getStartPosition(int fieldIndex) throws AccessorException {
115                 int c = this.index.size();
116                 if ( fieldIndex==c )
117                         try {
118                                 return b.length();
119                         } catch (IOException e) {
120                                 throw new AccessorException( e );
121                         }
122                 if ( fieldIndex>c || fieldIndex<0 ) throw new AccessorException("Index out of bounds");
123                 return (Long) index.get(fieldIndex, Bindings.LONG);
124         }       
125         
126         long getLength(int index, long pos) throws AccessorException {
127                 int c = this.index.size();
128                 if ( index>=c || index<0 ) return 0;
129                 if ( index==c-1 ) 
130                 {
131                         try {
132                                 return b.length() - (Long) this.index.get(c-1, Bindings.LONG);
133                         } catch (IOException e) {
134                                 throw new AccessorException( e );
135                         }
136                 } else {
137                         return (Long) this.index.get(index+1, Bindings.LONG) - (Long) this.index.get(index, Bindings.LONG);
138                 }
139         }
140
141         @Override
142         public void setNoflush(int index, Binding rcb, Object rcv)
143                         throws AccessorException {
144                 assert b.isOpen();
145                 
146                 writeLock();
147                 try {
148
149                         int count = size();
150                         if ( index==count ) {
151                                 addNoflush(count, rcb, rcv);
152                                 return;
153                         }                                       
154                         
155                         // Write                        
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);
160                         b.position(pos);
161                         long diff = newSize - oldSize; 
162                         if (diff>0) {
163                                 b.insertBytes( newSize - oldSize, ByteSide.Right );
164                         } else if (diff<0) { 
165                             b.removeBytes( oldSize - newSize, ByteSide.Right );
166                         }
167                         b.position(pos);
168                         rcs.serialize(b, null, rcv);
169
170                         // Update index of the higher indices
171                         if ( diff!= 0 ) {
172                                 for (int i=index+1; i<count; i++) {
173                                         long p = (Long) this.index.get(i, Bindings.LONG);
174                                         p += diff;
175                                         this.index.set(i, Bindings.LONG, p);
176                                 }
177                         }
178                         
179                         // Update Blobs
180                         /*
181                         BinaryObject sa = getExistingAccessor(index);
182                         if (sa!=null && newSize != oldSize) {
183                                 sa.b.setPositionInSource(pos, newSize);
184                         }*/
185                         
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());
195                                         }
196                                 }
197                         }*/
198                         
199                         // Notify
200                         ListenerEntry le = listeners;
201                         while (le!=null) {                              
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));                                        
206                                         
207                                         Event e = new ValueAssigned(new IndexReference(index), newValue);
208                                         emitEvent(le, e);
209                                 }
210                                 le = le.next;
211                         }
212                         
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);
219                 } finally {
220                         writeUnlock();
221                 }
222                                 
223         }
224                 
225         /**
226          * Set all values
227          * 
228          * @param arrayBinding
229          * @param newArray
230          */
231         @Override
232         public void setValueNoflush(Binding arrayBinding, Object newArray)
233                         throws AccessorException {
234                 assert b.isOpen();
235                 writeLock();
236                 try {
237                         // Write                        
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);
245                         
246                         // Serialize
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;
254                                 
255                                 // update location
256                                 /*
257                                 BinaryObject sa = getExistingAccessor(index);
258                                 if (sa!=null) {
259                                         sa.b.setPositionInSource(startPos, len);
260                                 }*/
261                         }
262                         
263                         // Notify removal
264                         for (int index=oldCount-1; index>=newCount; index--) {
265                                 BinaryObject sa = getExistingAccessor(index);
266                                 if (sa!=null) {
267                                         sa.invalidatedNotification();
268                                         children.remove(index);
269                                         sa = null;
270                                 }
271                         
272                                 // Notify changes
273                                 ListenerEntry le = listeners;
274                                 while (le!=null) {                              
275                                         ArrayInterestSet is = le.getInterestSet();
276                                         if (is.inNotificationsOf(index)) {
277                                                 Event e = new ArrayElementRemoved(index);
278                                                 emitEvent(le, e);
279                                         }
280                                         le = le.next;
281                                 }
282                         }
283                         
284                         // Notify new assignment
285                         if (listeners!=null) {
286                                 for (int index=0; index<newCount; index++) {
287                                         Object cv = rb.get(newArray, index);
288                                         
289                                         // Notify changes
290                                         ListenerEntry le = listeners;
291                                         while (le!=null) {                              
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));                                 
296                                                         
297                                                         Event e = index<oldCount ? new ValueAssigned(new IndexReference(index), vv) : new ArrayElementAdded(index, vv);
298                                                         emitEvent(le, e);
299                                                 }
300                                                 le = le.next;
301                                         }                               
302                                 }
303                         }
304                         
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);
313                 } finally {
314                         writeUnlock();                  
315                 }
316                 
317         }
318
319         @Override
320         public void addNoflush(int index, Binding rcb, Object rcv) throws AccessorException {
321                 assert b.isOpen();
322                 writeLock();
323                 try {
324                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
325                         // Write                
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");
330                         
331                         long pos = getStartPosition(index);
332                         int size = rcs.getSize(rcv);
333                         b.position(pos);
334                         b.insertBytes(size, ByteSide.Left);
335                         rcs.serialize(b, null, rcv);
336                         
337                         this.index.add(index, Bindings.LONG, pos);
338                         
339                         for (int i=index+1; i<newCount; i++) {
340                                 long p = (Long) this.index.get(i, Bindings.LONG);
341                                 p += size;
342                                 this.index.set(i, Bindings.LONG, p);
343                         }
344                         
345                         
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);
353                                 }
354                         }
355                                                 
356                         // Notify Listeners
357                         ListenerEntry le = listeners;
358                         while (le!=null) {                              
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);
364                                         emitEvent(le, e);
365                                 }
366                                 
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;
374                                         }
375                                         
376                                         if (needUpdates) {
377                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
378                                                 for (Integer i : oldCis.keySet())
379                                                 {
380                                                         Integer oldKey = i;
381                                                         Integer newKey = i>=index ? i+1 : i;
382                                                         InterestSet oldValue = oldCis.get(oldKey);
383                                                         newCis.put(newKey, oldValue); 
384                                                 }
385                                                 is.componentInterests = newCis;
386                                         }
387                                 }
388                                 
389                                 // Add component interest listener
390                                 /*
391                                 boolean hadSa = getExistingAccessor(index) != null;                             
392                                 if (!hadSa) {
393                                         // Add component interest listener
394                                         InterestSet cis = is.getComponentInterest(); 
395                                         if (cis != null) {
396                                                 Accessor sa = getAccessor(index);
397                                         }                               
398                                         cis = is.getComponentInterest(index); 
399                                         if (cis != null) {
400                                                 Accessor sa = getAccessor(index);
401                                         }
402                                 }       */              
403                                 
404                                 le = le.next;
405                         }
406                         
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);
413                 } finally {
414                         writeUnlock();
415                 }
416         }
417
418         @Override
419         public void addNoflush(Binding binding, Object value)
420                         throws AccessorException {
421                 addNoflush(size(), binding, value);
422         }
423
424         @Override
425         public void addAllNoflush(Binding binding, Object[] values)
426                         throws AccessorException {
427                 addAllNoflush(size(), binding, values);
428         }
429
430         @Override
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");
434                 assert b.isOpen();
435                 writeLock();
436                 try {
437                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
438                         // Write                
439                         b.position(0L);
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;
445                         
446                         long size = 0;
447                         for (int i=0; i<rcvs.length; i++)
448                                 size += rcs.getSize(rcvs[i]);
449                         long pos = getStartPosition(index);
450                         b.position(pos);
451                         b.insertBytes(size, ByteSide.Right);
452
453                         long p = pos;
454                         for (int i=0; i<repeatCount; i++) {
455                                 this.index.add(index+i, Bindings.LONG, (Long) p);
456                                 p += rcs.getSize(rcvs[i]);
457                         }
458                         for (int i=index+repeatCount; i<newCount; i++) {
459                                 p = (Long) this.index.get(i, Bindings.LONG);
460                                 p += size;
461                                 this.index.set(i, Bindings.LONG, p);
462                         }
463                         
464                         b.position(pos);
465                         for (int i=0; i<rcvs.length; i++) {
466                                 Object rcv = rcvs[i];
467                                 rcs.serialize(b, rcv);                          
468                         }
469                         
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);
477                                 }
478                         }
479                                                 
480                         // Notify Listeners
481                         ListenerEntry le = listeners;
482                         while (le!=null) {                              
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);
489                                                 emitEvent(le, e);
490                                         }
491                                 }
492                                 
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;
500                                         }
501                                         
502                                         if (needUpdates) {
503                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
504                                                 for (Integer i : oldCis.keySet())
505                                                 {
506                                                         Integer oldKey = i;
507                                                         Integer newKey = i>=index ? i+rcvs.length : i;
508                                                         InterestSet oldValue = oldCis.get(oldKey);
509                                                         newCis.put(newKey, oldValue); 
510                                                 }
511                                                 is.componentInterests = newCis;
512                                         }
513                                         
514                                         // Add component interest listener
515                                         /*
516                                         for (int i = index; i<index+rcvs.length; i++) {
517                                                 boolean hadSa = getExistingAccessor(i)!=null;
518                                                 if (hadSa) continue;
519                                                  
520                                                 InterestSet cis = is.getComponentInterest(); 
521                                                 if (cis != null) {
522                                                         Accessor sa = getAccessor(i);
523                                                 }                               
524                                                 cis = is.getComponentInterest(index); 
525                                                 if (cis != null) {
526                                                         Accessor sa = getAccessor(i);
527                                                 }
528                                         }
529                                         */
530                                         
531                                 }
532                                 
533                                 le = le.next;
534                         }
535                         
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);
542                 } finally {
543                         writeUnlock();
544                 }
545         }
546
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");
549                 assert b.isOpen();
550                 writeLock();
551                 try {
552                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
553                         // Write                
554                         b.position(0L);
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;
559                         
560                         long componentSize = rcs.getSize(obj);
561                         long size = componentSize * repeatCount;
562                         long pos = getStartPosition(index);
563                         b.position(pos);
564                         b.insertBytes(size, ByteSide.Right);
565                         long p = pos;
566                         for (int i=0; i<repeatCount; i++) {
567                                 this.index.add(index+i, Bindings.LONG, (Long) p);
568                                 pos += componentSize;
569                         }
570                         for (int i=index+repeatCount; i<newCount; i++) {
571                                 p = (Long) this.index.get(i, Bindings.LONG);
572                                 p += size;
573                                 this.index.set(i, Bindings.LONG, p);
574                         }
575                         
576                         b.position(pos);
577                         for (int i=0; i<repeatCount; i++) {
578                                 rcs.serialize(b, obj);                          
579                         }
580                         
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);
588                                 }
589                         }
590                                                 
591                         // Notify Listeners
592                         ListenerEntry le = listeners;
593                         while (le!=null) {                              
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);
600                                                 emitEvent(le, e);
601                                         }
602                                 }
603                                 
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;
611                                         }
612                                         
613                                         if (needUpdates) {
614                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
615                                                 for (Integer i : oldCis.keySet())
616                                                 {
617                                                         Integer oldKey = i;
618                                                         Integer newKey = i>=index ? i+repeatCount : i;
619                                                         InterestSet oldValue = oldCis.get(oldKey);
620                                                         newCis.put(newKey, oldValue); 
621                                                 }
622                                                 is.componentInterests = newCis;
623                                         }
624                                         
625                                 }
626                                 
627                                 le = le.next;
628                         }
629                         
630                 } catch (IOException e) {
631                         throw new AccessorException(e);
632                 } catch (SerializerConstructionException e) {
633                         throw new AccessorException(e);
634                 } finally {
635                         writeUnlock();
636                 }
637         }
638         
639         @Override
640         public void removeNoflush(int index, int count) throws AccessorException {
641                 assert b.isOpen();
642                 writeLock();
643                 try {
644                         // Write
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;
654                         b.position(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);
659                                 p -= len;
660                                 this.index.set(i, Bindings.LONG, p);
661                         }
662                         
663                         // Remove children
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();                           
669                         }
670                         sm.clear();
671                         
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);
680                                 }
681                         }
682                                                 
683                         // Notify Listeners
684                         ListenerEntry le = listeners;
685                         while (le!=null) {                              
686                                 ArrayInterestSet is = le.getInterestSet();
687                                 if (is.inNotifications()) {
688                                         ArrayElementRemoved e = new ArrayElementRemoved(index);
689                                         emitEvent(le, e);
690                                 }
691                                 
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;
699                                         }
700                                         
701                                         if (needUpdates) {
702                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
703                                                 for (Integer i : oldCis.keySet())
704                                                 {
705                                                         Integer oldKey = i;
706                                                         Integer newKey = i>=index ? i-1 : i;
707                                                         InterestSet oldValue = oldCis.get(oldKey);
708                                                         newCis.put(newKey, oldValue); 
709                                                 }
710                                                 is.componentInterests = newCis;
711                                         }
712                                 }                               
713                                 le = le.next;
714                         }
715                         
716                         
717                 } catch (IOException e) {
718                         throw new AccessorException( e );
719                 } finally {
720                         writeUnlock();
721                 }
722         }
723         
724         @Override
725         public Object get(int index, Binding valueBinding) throws AccessorException {
726                 assert b.isOpen();
727                 readLock();
728                 try {
729                         long pos = getStartPosition(index);
730                         b.position(pos);
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);
737                 } finally {
738                         readUnlock();
739                 }
740         }
741
742         @Override
743         public void get(int index, Binding valueBinding, Object dst) throws AccessorException {
744                 assert b.isOpen();
745                 readLock();
746                 try {
747                         long pos = getStartPosition(index);
748                         b.position(pos);
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);
755                 } finally {
756                         readUnlock();
757                 }
758         }
759
760         
761         @SuppressWarnings("unchecked")
762         @Override
763         public <T extends Accessor> T getAccessor(int index)
764                         throws AccessorConstructionException {
765                 assert b.isOpen();
766                 readLock();
767                 try {
768                         b.position(0L);
769                         int count = b.readInt();
770                         if (index<0 || index>=count) throw new ReferenceException("Element index ("+index+") out of bounds ("+count+")");
771                         
772                         // Get existing or create new
773                         BinaryObject sa = getExistingAccessor(index);
774                         if (sa==null) {
775                                 long pos = getStartPosition(index);
776                                 long len = getLength(index, pos);
777
778                                 // Instantiate correct sub accessor. 
779                                 sa = createSubAccessor(cb.type(), pos, len, params);                            
780                                 children.put(index, new WeakReference<BinaryObject>(sa) );
781
782                                 // Add component interest sets
783                                 ListenerEntry le = listeners;
784                                 while (le!=null) {                              
785                                         ArrayInterestSet is = le.getInterestSet();
786
787                                         // Generic element interest
788                                         InterestSet gis = is.getComponentInterest(); 
789                                         if (gis != null) {
790                                                 try {
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);
795                                                 }
796                                         }
797                                         
798                                         // Specific element interest
799                                         InterestSet cis = is.getComponentInterest(index); 
800                                         if (cis != null) {
801                                                 try {
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);
806                                                 }
807                                         }
808                                         
809                                         // Next listener
810                                         le = le.next;
811                                 }                               
812                                 
813                         }
814                         
815                         return (T) sa;
816                 } catch (IOException e) {
817                         throw new AccessorConstructionException(e);
818                 } catch (AccessorException e) {
819                         throw new AccessorConstructionException(e);
820                 } finally {
821                         readUnlock();
822                 }
823         }
824
825         @SuppressWarnings("unchecked")
826         @Override
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;
832                         try {
833                                 Integer index = new Integer( lr.label );
834                                 Accessor result = getAccessor(index);
835                                 if (reference.getChildReference() != null)
836                                         result = result.getComponent(reference.getChildReference());
837                                 return (T) result;
838                         } catch ( NumberFormatException nfe ) {
839                                 throw new ReferenceException(nfe);
840                         }                       
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());
847                         return (T) result;
848                 } throw new ReferenceException(reference.getClass().getName()+" is not a reference of an array");       
849         }
850         
851         @Override
852         public void getAll(Binding valueBinding, Object[] array)
853                         throws AccessorException {
854                 assert b.isOpen();
855                 readLock();
856                 try {
857                         b.position(0L);
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);
863                         }
864                 } catch (IOException e) {
865                         throw new AccessorException( e );
866                 } catch (SerializerConstructionException e) {
867                         throw new AccessorException( e );
868                 } finally {
869                         readUnlock();
870                 }
871         }
872
873         @Override
874         public void getAll(Binding valueBinding, Collection<Object> values)
875                         throws AccessorException {
876                 assert b.isOpen();
877                 readLock();
878                 try {
879                         b.position(0L);
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) );
884                         }
885                 } catch (IOException e) {
886                         throw new AccessorException( e );
887                 } catch (SerializerConstructionException e) {
888                         throw new AccessorException( e );
889                 } finally {
890                         readUnlock();
891                 }
892         }
893         
894         @Override
895         public void setSizeNoflush(int newSize) throws AccessorException {
896                 assert b.isOpen();
897                 writeLock();
898                 try {
899                         int oldSize = size();
900
901                         // Remove instances  
902                         if (newSize<oldSize) {
903                                 remove(newSize, oldSize-newSize);
904                         }
905                                                 
906                         // Add dummy instances
907                         if (newSize>oldSize) {
908                                 Object dummy = cb.createDefault();
909                                 int count = newSize-oldSize;
910                                 addRepeatNoflush(oldSize, cb, dummy, count);
911                         }
912                         
913                 } catch (BindingException e) {
914                         throw new AccessorException( e );
915                 } finally {
916                         writeUnlock();
917                 }
918         }
919
920         @Override
921         public void setSize(int newSize) throws AccessorException {
922                 assert b.isOpen();
923                 writeLock();
924                 try {
925                         setSizeNoflush(newSize);
926                         b.flush();
927                 } catch (IOException e) {
928                         throw new AccessorException( e );
929                 } finally {
930                         writeUnlock();
931                 }
932         }
933         
934         @Override
935         public int size() throws AccessorException {
936                 assert b.isOpen();
937                 readLock();
938                 return index.size();
939         }
940
941         @Override
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());
948                 } else          
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");
956                         if (makeRollback) {
957                                 Object cv = get(ar.index, cb);
958                                 rollback = new ArrayElementAdded(ar.index, new MutableVariant(cb, cv));
959                         }
960                         removeNoflush(ar.index, 1);
961                 } else {
962                         throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Array");
963                 }
964                 
965                 return rollback;
966         }
967
968         @Override
969         public void add(Binding binding, Object value) throws AccessorException {
970                 assert b.isOpen();
971                 writeLock();
972                 try {
973                         addNoflush(binding, value);
974                         b.flush();
975                 } catch (IOException e) {
976                         throw new AccessorException( e );
977                 } finally {
978                         writeUnlock();
979                 }
980         }
981
982         @Override
983         public void add(int index, Binding binding, Object value)
984                         throws AccessorException {
985                 assert b.isOpen();
986                 writeLock();
987                 try {
988                         addNoflush(index, binding, value);
989                         b.flush();
990                 } catch (IOException e) {
991                         throw new AccessorException( e );
992                 } finally {
993                         writeUnlock();
994                 }
995         }
996
997         @Override
998         public void addAll(Binding binding, Object[] values)
999                         throws AccessorException {
1000                 assert b.isOpen();
1001                 writeLock();
1002                 try {
1003                         addAllNoflush(binding, values);
1004                         b.flush();
1005                 } catch (IOException e) {
1006                         throw new AccessorException( e );
1007                 } finally {
1008                         writeUnlock();
1009                 }
1010         }
1011
1012         @Override
1013         public void addAll(int index, Binding binding, Object[] values)
1014                         throws AccessorException {
1015                 assert b.isOpen();
1016                 writeLock();
1017                 try {
1018                         addAllNoflush(index, binding, values);
1019                         b.flush();
1020                 } catch (IOException e) {
1021                         throw new AccessorException( e );
1022                 } finally {
1023                         writeUnlock();                  
1024                 }
1025         }
1026
1027         @Override
1028         public void remove(int index, int count) throws AccessorException {
1029                 assert b.isOpen();
1030                 writeLock();
1031                 try {
1032                         removeNoflush(index, count);
1033                         b.flush();
1034                 } catch (IOException e) {
1035                         throw new AccessorException( e );
1036                 } finally {
1037                         writeUnlock();
1038                 }
1039         }
1040
1041         @Override
1042         public void set(int index, Binding binding, Object value)
1043                         throws AccessorException {
1044                 assert b.isOpen();
1045                 writeLock();
1046                 try {
1047                         setNoflush(index, binding, value);
1048                         b.flush();
1049                 } catch (IOException e) {
1050                         throw new AccessorException(e);
1051                 } finally {
1052                         writeUnlock();
1053                 }
1054         }
1055         
1056         @Override
1057         public void close() throws AccessorException {
1058                 if ( this.index instanceof CloseableAccessor ) {
1059                         CloseableAccessor ca = (CloseableAccessor) this.index;
1060                         ca.close();
1061                 }
1062                 super.close();
1063         }
1064         
1065 }
1066