]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/binary/BinaryArray.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / binary / BinaryArray.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.accessor.Accessor;
24 import org.simantics.databoard.accessor.ArrayAccessor;
25 import org.simantics.databoard.accessor.StreamAccessor;
26 import org.simantics.databoard.accessor.error.AccessorConstructionException;
27 import org.simantics.databoard.accessor.error.AccessorException;
28 import org.simantics.databoard.accessor.error.ReferenceException;
29 import org.simantics.databoard.accessor.event.ArrayElementAdded;
30 import org.simantics.databoard.accessor.event.ArrayElementRemoved;
31 import org.simantics.databoard.accessor.event.Event;
32 import org.simantics.databoard.accessor.event.ValueAssigned;
33 import org.simantics.databoard.accessor.file.FileArrayAccessor;
34 import org.simantics.databoard.accessor.impl.AccessorParams;
35 import org.simantics.databoard.accessor.impl.ListenerEntry;
36 import org.simantics.databoard.accessor.interestset.ArrayInterestSet;
37 import org.simantics.databoard.accessor.interestset.InterestSet;
38 import org.simantics.databoard.accessor.reference.ChildReference;
39 import org.simantics.databoard.accessor.reference.IndexReference;
40 import org.simantics.databoard.accessor.reference.LabelReference;
41 import org.simantics.databoard.adapter.AdaptException;
42 import org.simantics.databoard.binding.ArrayBinding;
43 import org.simantics.databoard.binding.Binding;
44 import org.simantics.databoard.binding.error.BindingException;
45 import org.simantics.databoard.binding.mutable.MutableVariant;
46 import org.simantics.databoard.serialization.Serializer;
47 import org.simantics.databoard.serialization.SerializerConstructionException;
48 import org.simantics.databoard.type.ArrayType;
49 import org.simantics.databoard.type.Datatype;
50 import org.simantics.databoard.util.binary.Blob;
51 import org.simantics.databoard.util.binary.RandomAccessBinary.ByteSide;
52
53 /**
54  * Binary Array is accessor to a byte backed array of elements.
55  * <p>
56  * 
57  * Note, To increase the random access performance of the record, create sub-accessors of
58  * its fields. 
59  *
60  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
61  */
62 public class BinaryArray extends BinaryObject implements ArrayAccessor, FileArrayAccessor, ArrayAccessor.CloseableArrayAccessor, StreamAccessor {
63
64         /** Accessors to children */
65         TreeMap<Integer, java.lang.ref.Reference<BinaryObject>> children = new TreeMap<Integer, java.lang.ref.Reference<BinaryObject>>(); 
66
67         Binding cb;
68         Serializer cs;
69         Integer constantSize;
70         
71         public BinaryArray(BinaryObject parent, Blob blob, Datatype type, AccessorParams params) {
72                 super(parent, blob, type, params);
73                 ArrayType at = (ArrayType) type;
74                 cb = params.bindingScheme.getBindingUnchecked(at.componentType);
75                 cs = params.serializerScheme.getSerializerUnchecked( cb );
76                 constantSize = cs.getConstantSize();
77         }
78         
79         public ArrayType type() {
80                 return (ArrayType) type;
81         }
82         
83         
84         
85         /**
86          * Get existing sub accessor
87          * @param index
88          * @return sub-accessor or <code>null</code>
89          */
90         BinaryObject getExistingAccessor(int index)
91         {               
92                 java.lang.ref.Reference<BinaryObject> ref = children.get(index);
93                 if (ref==null) return null;
94                 BinaryObject res = (BinaryObject) ref.get();
95 //              if (res==null) children.remove(index);
96                 return res;
97         }       
98         
99         /**
100          * Get start position of a field
101          * 
102          * @param fieldIndex
103          * @return
104          * @throws AccessorException
105          */
106         long getStartPosition(int fieldIndex) throws AccessorException {
107                 if (constantSize != null) return 4L + (fieldIndex * (long) (constantSize));
108                 if (fieldIndex == 0) return 4;
109                 try {                   
110                         // sa, saIndex = getFloorExistingAccessor
111                         BinaryObject sa = null;
112                         Map.Entry<Integer, java.lang.ref.Reference<BinaryObject>> sae = children.floorEntry(fieldIndex);
113                         while (sae != null && sa == null) {
114                                 Integer key = sae.getKey();
115                                 sa = sae.getValue().get();
116                                 if (sa==null) children.remove(key); else break;
117                                 sae = children.floorEntry(key);
118                         }
119                         
120                         // Sub-accessor to the field exists
121                         if (sa!=null && sae.getKey()==fieldIndex) return sa.b.getStartPositionInSourceBinary();
122                         
123                         int si = sae==null ? 0 : sae.getKey();
124                         long pos = sae==null ? 4L : sa.b.getStartPositionInSourceBinary();
125                         b.position(pos);
126                         for (int i=si; i<fieldIndex; i++) {
127                                 cs.skip(b);
128                         }
129                         return b.position();
130                 } catch (IOException ioe) {
131                         throw new AccessorException( ioe ); 
132                 }
133         }       
134         
135         long getLength(int index, long pos) throws AccessorException {
136                 try {
137                         if (constantSize != null) return constantSize;
138                         BinaryObject sa = getExistingAccessor(index);
139                         if (sa != null) return sa.b.length();
140                         BinaryObject ni = getExistingAccessor(index+1);
141                         if (ni!=null) return ni.b.getStartPositionInSourceBinary() - pos;
142                         b.position(pos);
143                         cs.skip(b);
144                         return b.position() - pos;
145                 } catch (IOException e) {
146                         throw new AccessorException( e );
147                 }
148         }
149
150         @Override
151         public void setNoflush(int index, Binding rcb, Object rcv)
152                         throws AccessorException {
153                 assert b.isOpen();
154                 writeLock();
155                 try {
156                         
157                         // Write                        
158                         Serializer rcs = params.serializerScheme.getSerializer( rcb );
159                         long pos = getStartPosition(index);
160                         long oldSize = getLength(index, pos);
161                         long newSize = rcs.getSize(rcv, null);
162                         b.position(pos);
163                         long diff = newSize - oldSize; 
164                         if (diff>0) {
165                                 b.insertBytes( newSize - oldSize, ByteSide.Right );
166                         } else if (diff<0) { 
167                             b.removeBytes( oldSize - newSize, ByteSide.Right );
168                         }
169                         b.position(pos);
170                         rcs.serialize(b, null, rcv);
171                         
172                         // Update Blobs
173                         /*
174                         BinaryObject sa = getExistingAccessor(index);
175                         if (sa!=null && newSize != oldSize) {
176                                 sa.b.setPositionInSource(pos, newSize);
177                         }*/
178                         
179                         // Shift consecutive blobs                      
180 /*                      if (!children.isEmpty()) {
181                                 Integer lastKey = children.lastKey();
182                                 if (lastKey!=null && index+1 <= lastKey && diff!=0) {
183                                         SortedMap<Integer, Reference<BinaryObject>> pm = children.subMap(index+1, true, lastKey, true);
184                                         for (Entry<Integer, Reference<BinaryObject>> e : pm.entrySet()) {
185                                                 BinaryObject sa_ = e.getValue().get();
186                                                 if (sa_ == null) continue;
187                                                 sa_.b.setPositionInSource( sa_.b.getStartPositionInSourceBinary() + diff, sa_.b.length());
188                                         }
189                                 }
190                         }*/
191                         
192                         // Notify
193                         ListenerEntry le = listeners;
194                         while (le!=null) {                              
195                                 ArrayInterestSet is = le.getInterestSet();
196                                 if (is.inNotificationsOf(index)) {
197                                         MutableVariant newValue = null;
198                                         if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));                                        
199                                         
200                                         Event e = new ValueAssigned(new IndexReference(index), newValue);
201                                         emitEvent(le, e);
202                                 }
203                                 le = le.next;
204                         }
205                         
206                 } catch (IOException e) {
207                         throw new AccessorException(e);
208                 } catch (AdaptException e) {
209                         throw new AccessorException(e);
210                 } catch (SerializerConstructionException e) {
211                         throw new AccessorException(e);
212                 } finally {
213                         writeUnlock();
214                 }
215                                 
216         }
217                 
218         /**
219          * Set all values
220          * 
221          * @param arrayBinding
222          * @param newArray
223          */
224         @Override
225         public void setValueNoflush(Binding arrayBinding, Object newArray)
226                         throws AccessorException {
227                 assert b.isOpen();
228                 writeLock();
229                 try {
230                         // Write                        
231                         ArrayBinding rb = ((ArrayBinding)arrayBinding);
232                         Binding rcb = rb.getComponentBinding();
233                         Serializer rcs = params.serializerScheme.getSerializer( rcb );
234                         b.position(0L);                 
235                         int oldCount = b.readInt();
236                         int newCount = rb.size(newArray);                                               
237                         b.setLength( params.serializerScheme.getSerializer( rb ).getSize(newArray) );                   
238                         b.position(0L);
239                         b.writeInt(newCount);
240                         
241                         // Serialize
242                         for (int index=0; index<newCount; index++) {
243                                 //long startPos = b.position();
244                                 Object obj = rb.get(newArray, index);
245                                 rcs.serialize(b, obj);
246                                 //long endPos = b.position();
247                                 //long len = endPos - startPos;
248                                 
249                                 // update location
250                                 /*
251                                 BinaryObject sa = getExistingAccessor(index);
252                                 if (sa!=null) {
253                                         sa.b.setPositionInSource(startPos, len);
254                                 }*/
255                         }
256                         
257                         // Notify removal
258                         for (int index=oldCount-1; index>=newCount; index--) {
259                                 BinaryObject sa = getExistingAccessor(index);
260                                 if (sa!=null) {
261                                         sa.invalidatedNotification();
262                                         children.remove(index);
263                                         sa = null;
264                                 }
265                         
266                                 // Notify changes
267                                 ListenerEntry le = listeners;
268                                 while (le!=null) {                              
269                                         ArrayInterestSet is = le.getInterestSet();
270                                         if (is.inNotificationsOf(index)) {
271                                                 Event e = new ArrayElementRemoved(index);
272                                                 emitEvent(le, e);
273                                         }
274                                         le = le.next;
275                                 }
276                         }
277                         
278                         // Notify new assignment
279                         if (listeners!=null) {
280                                 for (int index=0; index<newCount; index++) {
281                                         Object cv = rb.get(newArray, index);
282                                         
283                                         // Notify changes
284                                         ListenerEntry le = listeners;
285                                         while (le!=null) {                              
286                                                 ArrayInterestSet is = le.getInterestSet();
287                                                 if (is.inNotificationsOf(index)) {                                      
288                                                         MutableVariant vv = null;
289                                                         if (is.inValues()) vv = new MutableVariant(rcb, cb.isImmutable() ? cv : rcb.clone(cv));                                 
290                                                         
291                                                         Event e = index<oldCount ? new ValueAssigned(new IndexReference(index), vv) : new ArrayElementAdded(index, vv);
292                                                         emitEvent(le, e);
293                                                 }
294                                                 le = le.next;
295                                         }                               
296                                 }
297                         }
298                         
299                 } catch (BindingException e) {
300                         throw new AccessorException(e);
301                 } catch (IOException e) {
302                         throw new AccessorException(e);
303                 } catch (AdaptException e) {
304                         throw new AccessorException(e);
305                 } catch (SerializerConstructionException e) {
306                         throw new AccessorException(e);
307                 } finally {
308                         writeUnlock();                  
309                 }
310                 
311         }
312
313         @Override
314         public void addNoflush(int index, Binding rcb, Object rcv) throws AccessorException {
315                 assert b.isOpen();
316                 writeLock();
317                 try {
318                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
319                         // Write                
320                         b.position(0L);
321                         int oldCount = b.readInt();
322                         boolean lastEntry = index == oldCount;
323                         if (index>oldCount) throw new AccessorException("Index out of range");
324                         int newCount = oldCount +1;
325                         b.position(0L);
326                         b.writeInt(newCount);
327                         
328                         long pos = getStartPosition(index);
329                         int size = rcs.getSize(rcv);
330                         b.position(pos);
331                         b.insertBytes(size, ByteSide.Left);
332                         rcs.serialize(b, null, rcv);
333                         
334                         //  Update child map keys
335                         if (!lastEntry && !children.isEmpty()) {
336                                 Integer key = children.lastKey();
337                                 while (key != null && key >= index) {
338                                         java.lang.ref.Reference<BinaryObject> value = children.remove(key);
339                                         if (value.get()!=null) children.put(key+1, value);
340                                         key = children.lowerKey(key);
341                                 }
342                         }
343                                                 
344                         // Notify Listeners
345                         ListenerEntry le = listeners;
346                         while (le!=null) {                              
347                                 ArrayInterestSet is = le.getInterestSet();
348                                 if (is.inNotifications()) {
349                                         MutableVariant newValue = null;
350                                         if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcv : rcb.clone(rcv));                                        
351                                         ArrayElementAdded e = new ArrayElementAdded(index, newValue);
352                                         emitEvent(le, e);
353                                 }
354                                 
355                                 // Update indices of interest sets
356                                 if (is.componentInterests!=null) {
357                                         Map<Integer, InterestSet> oldCis = is.componentInterests;
358                                         boolean needUpdates = false;
359                                         for (Integer i : oldCis.keySet()) {
360                                                 needUpdates |= i>=index;
361                                                 if (needUpdates) break;
362                                         }
363                                         
364                                         if (needUpdates) {
365                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
366                                                 for (Integer i : oldCis.keySet())
367                                                 {
368                                                         Integer oldKey = i;
369                                                         Integer newKey = i>=index ? i+1 : i;
370                                                         InterestSet oldValue = oldCis.get(oldKey);
371                                                         newCis.put(newKey, oldValue); 
372                                                 }
373                                                 is.componentInterests = newCis;
374                                         }
375                                 }
376                                 
377                                 // Add component interest listener
378                                 /*
379                                 boolean hadSa = getExistingAccessor(index) != null;                             
380                                 if (!hadSa) {
381                                         // Add component interest listener
382                                         InterestSet cis = is.getComponentInterest(); 
383                                         if (cis != null) {
384                                                 Accessor sa = getAccessor(index);
385                                         }                               
386                                         cis = is.getComponentInterest(index); 
387                                         if (cis != null) {
388                                                 Accessor sa = getAccessor(index);
389                                         }
390                                 }       */              
391                                 
392                                 le = le.next;
393                         }
394                         
395                 } catch (IOException e) {
396                         throw new AccessorException(e);
397                 } catch (AdaptException e) {
398                         throw new AccessorException(e);
399                 } catch (SerializerConstructionException e) {                   
400                         throw new AccessorException(e);
401                 } finally {
402                         writeUnlock();
403                 }
404         }
405
406         @Override
407         public void addNoflush(Binding binding, Object value)
408                         throws AccessorException {
409                 addNoflush(size(), binding, value);
410         }
411
412         @Override
413         public void addAllNoflush(Binding binding, Object[] values)
414                         throws AccessorException {
415                 addAllNoflush(size(), binding, values);
416         }
417
418         @Override
419         public void addAllNoflush(int index, Binding rcb, Object[] rcvs)
420                         throws AccessorException {
421                 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
422                 assert b.isOpen();
423                 writeLock();
424                 try {
425                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
426                         // Write                
427                         b.position(0L);
428                         int oldCount = b.readInt();
429                         int newCount = oldCount + rcvs.length;
430                         if (index>oldCount) throw new AccessorException("Index out of range");
431                         b.position(0L);
432                         b.writeInt(newCount);
433                         boolean lastEntry = index == oldCount;
434                         
435                         int size = 0;
436                         for (int i=0; i<rcvs.length; i++)
437                                 size += rcs.getSize(rcvs[i]);
438                         long pos = getStartPosition(index);
439                         b.position(pos);
440                         b.insertBytes(size, ByteSide.Right);
441                         
442                         b.position(pos);
443                         for (int i=0; i<rcvs.length; i++) {
444                                 Object rcv = rcvs[i];
445                                 rcs.serialize(b, rcv);                          
446                         }
447                         
448                         //  Update child map keys
449                         if (!lastEntry && !children.isEmpty()) {
450                                 Integer key = children.lastKey();
451                                 while (key!=null && key >= index) {
452                                         java.lang.ref.Reference<BinaryObject> value = children.remove(key);
453                                         if (value.get()!=null) children.put(key+rcvs.length, value);
454                                         key = children.lowerKey(key);
455                                 }
456                         }
457                                                 
458                         // Notify Listeners
459                         ListenerEntry le = listeners;
460                         while (le!=null) {                              
461                                 ArrayInterestSet is = le.getInterestSet();
462                                 if (is.inNotifications()) {
463                                         for (int i=0; i<rcvs.length; i++) {
464                                                 MutableVariant newValue = null;
465                                                 if (is.inValues()) newValue = new MutableVariant(rcb, rcb.isImmutable() ? rcvs[i] : cb.clone(rcvs[i]));                                 
466                                                 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
467                                                 emitEvent(le, e);
468                                         }
469                                 }
470                                 
471                                 // Update indices of interest sets
472                                 if (is.componentInterests!=null) {
473                                         Map<Integer, InterestSet> oldCis = is.componentInterests;
474                                         boolean needUpdates = false;
475                                         for (Integer i : oldCis.keySet()) {
476                                                 needUpdates |= i>=index;
477                                                 if (needUpdates) break;
478                                         }
479                                         
480                                         if (needUpdates) {
481                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
482                                                 for (Integer i : oldCis.keySet())
483                                                 {
484                                                         Integer oldKey = i;
485                                                         Integer newKey = i>=index ? i+rcvs.length : i;
486                                                         InterestSet oldValue = oldCis.get(oldKey);
487                                                         newCis.put(newKey, oldValue); 
488                                                 }
489                                                 is.componentInterests = newCis;
490                                         }
491                                         
492                                         // Add component interest listener
493                                         /*
494                                         for (int i = index; i<index+rcvs.length; i++) {
495                                                 boolean hadSa = getExistingAccessor(i)!=null;
496                                                 if (hadSa) continue;
497                                                  
498                                                 InterestSet cis = is.getComponentInterest(); 
499                                                 if (cis != null) {
500                                                         Accessor sa = getAccessor(i);
501                                                 }                               
502                                                 cis = is.getComponentInterest(index); 
503                                                 if (cis != null) {
504                                                         Accessor sa = getAccessor(i);
505                                                 }
506                                         }
507                                         */
508                                         
509                                 }
510                                 
511                                 le = le.next;
512                         }
513                         
514                 } catch (IOException e) {
515                         throw new AccessorException(e);
516                 } catch (AdaptException e) {
517                         throw new AccessorException(e);
518                 } catch (SerializerConstructionException e) {
519                         throw new AccessorException(e);
520                 } finally {
521                         writeUnlock();
522                 }
523         }
524
525         void addRepeatNoflush(int index, Binding rcb, Object obj, int repeatCount) throws AccessorException {
526                 if (index<0||index>size()) throw new AccessorException("Index out of bounds");
527                 assert b.isOpen();
528                 writeLock();
529                 try {
530                         Serializer rcs = params.serializerScheme.getSerializer( rcb );                  
531                         // Write                
532                         b.position(0L);
533                         int oldCount = b.readInt();
534                         int newCount = oldCount + repeatCount;
535                         if (index>oldCount) throw new AccessorException("Index out of range");
536                         b.position(0L);
537                         b.writeInt(newCount);
538                         boolean lastEntry = index == oldCount;
539                         
540                         int size = rcs.getSize(obj) * repeatCount;
541                         long pos = getStartPosition(index);
542                         b.position(pos);
543                         b.insertBytes(size, ByteSide.Right);
544                         
545                         b.position(pos);
546                         for (int i=0; i<repeatCount; i++) {
547                                 rcs.serialize(b, obj);                          
548                         }
549                         
550                         //  Update child map keys
551                         if (!lastEntry && !children.isEmpty()) {
552                                 Integer key = children.lastKey();
553                                 while (key!=null && key >= index) {
554                                         java.lang.ref.Reference<BinaryObject> value = children.remove(key);
555                                         if (value.get()!=null) children.put(key+repeatCount, value);
556                                         key = children.lowerKey(key);
557                                 }
558                         }
559                                                 
560                         // Notify Listeners
561                         ListenerEntry le = listeners;
562                         while (le!=null) {                              
563                                 ArrayInterestSet is = le.getInterestSet();
564                                 if (is.inNotifications()) {
565                                         for (int i=0; i<repeatCount; i++) {
566                                                 MutableVariant newValue = null;
567                                                 if (is.inValues()) newValue = new MutableVariant(rcb, obj/*rcb.isImmutable() ? obj : cb.clone(obj)*/);                                  
568                                                 ArrayElementAdded e = new ArrayElementAdded(index, newValue);
569                                                 emitEvent(le, e);
570                                         }
571                                 }
572                                 
573                                 // Update indices of interest sets
574                                 if (is.componentInterests!=null) {
575                                         Map<Integer, InterestSet> oldCis = is.componentInterests;
576                                         boolean needUpdates = false;
577                                         for (Integer i : oldCis.keySet()) {
578                                                 needUpdates |= i>=index;
579                                                 if (needUpdates) break;
580                                         }
581                                         
582                                         if (needUpdates) {
583                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
584                                                 for (Integer i : oldCis.keySet())
585                                                 {
586                                                         Integer oldKey = i;
587                                                         Integer newKey = i>=index ? i+repeatCount : i;
588                                                         InterestSet oldValue = oldCis.get(oldKey);
589                                                         newCis.put(newKey, oldValue); 
590                                                 }
591                                                 is.componentInterests = newCis;
592                                         }
593                                         
594                                 }
595                                 
596                                 le = le.next;
597                         }
598                         
599                 } catch (IOException e) {
600                         throw new AccessorException(e);
601                 } catch (SerializerConstructionException e) {
602                         throw new AccessorException(e);
603                 } finally {
604                         writeUnlock();
605                 }
606         }
607         
608         @Override
609         public void removeNoflush(int index, int count) throws AccessorException {
610                 assert b.isOpen();
611                 writeLock();
612                 try {
613                         // Write
614                         boolean lastEntry = index == count;
615                         b.position(0L);
616                         int oldCount = b.readInt();
617                         int newCount = oldCount - count;
618                         if (index<0||index+count>oldCount) throw new AccessorException("Index out of bounds");
619                         long pos = getStartPosition(index);                     
620                         long lastPos = getStartPosition(index+count-1);                 
621                         long lastLen = getLength(index, lastPos);
622                         long end = lastPos + lastLen;
623                         long len = end - pos;
624                         b.position(0L);
625                         b.writeInt(newCount);
626                         b.position(pos);
627                         b.removeBytes(len, ByteSide.Right);
628                         
629                         // Remove children
630                         SortedMap<Integer, java.lang.ref.Reference<BinaryObject>> sm = children.subMap(index, true, index+count, false);
631                         for (Entry<Integer, java.lang.ref.Reference<BinaryObject>> e : sm.entrySet()) {
632                             BinaryObject bo = e.getValue().get();
633                             if (bo==null) continue;
634                             bo.invalidatedNotification();                           
635                         }
636                         sm.clear();
637                         
638                         //  Update the keys of consecutive children
639                         if (!lastEntry && !children.isEmpty()) {
640                                 Integer lastKey = children.lastKey();
641                                 Integer key = children.higherKey(index);
642                                 while (key != null && key <= lastKey) {
643                                         java.lang.ref.Reference<BinaryObject> value = children.remove(key);
644                                         if (value.get()!=null) children.put(key-count, value);
645                                         key = children.higherKey(key);
646                                 }
647                         }
648                                                 
649                         // Notify Listeners
650                         ListenerEntry le = listeners;
651                         while (le!=null) {                              
652                                 ArrayInterestSet is = le.getInterestSet();
653                                 if (is.inNotifications()) {
654                                         ArrayElementRemoved e = new ArrayElementRemoved(index);
655                                         emitEvent(le, e);
656                                 }
657                                 
658                                 // Update indices of interest sets
659                                 if (is.componentInterests!=null) {
660                                         Map<Integer, InterestSet> oldCis = is.componentInterests;
661                                         boolean needUpdates = false;
662                                         for (Integer i : oldCis.keySet()) {
663                                                 needUpdates |= i>=index;
664                                                 if (needUpdates) break;
665                                         }
666                                         
667                                         if (needUpdates) {
668                                                 Map<Integer, InterestSet> newCis = new HashMap<Integer, InterestSet>(oldCis.size()); 
669                                                 for (Integer i : oldCis.keySet())
670                                                 {
671                                                         Integer oldKey = i;
672                                                         Integer newKey = i>=index ? i-1 : i;
673                                                         InterestSet oldValue = oldCis.get(oldKey);
674                                                         newCis.put(newKey, oldValue); 
675                                                 }
676                                                 is.componentInterests = newCis;
677                                         }
678                                 }                               
679                                 le = le.next;
680                         }
681                         
682                         
683                 } catch (IOException e) {
684                         throw new AccessorException( e );
685                 } finally {
686                         writeUnlock();
687                 }
688         }
689         
690         @Override
691         public Object get(int index, Binding valueBinding) throws AccessorException {
692                 assert b.isOpen();
693                 readLock();
694                 try {
695                         long pos = getStartPosition(index);
696                         b.position(pos);
697                         Serializer s = params.serializerScheme.getSerializer(valueBinding);
698                         return s.deserialize(b);
699                 } catch (IOException e) {
700                         throw new AccessorException(e);
701                 } catch (SerializerConstructionException e) {
702                         throw new AccessorException(e);
703                 } finally {
704                         readUnlock();
705                 }
706         }
707
708         @Override
709         public void get(int index, Binding valueBinding, Object dst) throws AccessorException {
710                 assert b.isOpen();
711                 readLock();
712                 try {
713                         long pos = getStartPosition(index);
714                         b.position(pos);
715                         Serializer s = params.serializerScheme.getSerializer(valueBinding);
716                         s.deserializeTo(b, dst);
717                 } catch (IOException e) {
718                         throw new AccessorException(e);
719                 } catch (SerializerConstructionException e) {
720                         throw new AccessorException(e);
721                 } finally {
722                         readUnlock();
723                 }
724         }
725
726         
727         @SuppressWarnings("unchecked")
728         @Override
729         public <T extends Accessor> T getAccessor(int index)
730                         throws AccessorConstructionException {
731                 assert b.isOpen();
732                 readLock();
733                 try {
734                         b.position(0L);
735                         int count = b.readInt();
736                         if (index<0 || index>=count) throw new ReferenceException("Element index ("+index+") out of bounds ("+count+")");
737                         
738                         // Get existing or create new
739                         BinaryObject sa = getExistingAccessor(index);
740                         if (sa==null) {
741                                 long pos = getStartPosition(index);
742                                 long len = getLength(index, pos);
743
744                                 // Instantiate correct sub accessor. 
745                                 sa = createSubAccessor(cb.type(), pos, len, params);                            
746                                 children.put(index, new WeakReference<BinaryObject>(sa) );
747
748                                 // Add component interest sets
749                                 ListenerEntry le = listeners;
750                                 while (le!=null) {                              
751                                         ArrayInterestSet is = le.getInterestSet();
752
753                                         // Generic element interest
754                                         InterestSet gis = is.getComponentInterest(); 
755                                         if (gis != null) {
756                                                 try {
757                                                         ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
758                                                         sa.addListener(le.listener, gis, childPath, le.executor);
759                                                 } catch (AccessorException e) {
760                                                         throw new AccessorConstructionException(e);
761                                                 }
762                                         }
763                                         
764                                         // Specific element interest
765                                         InterestSet cis = is.getComponentInterest(index); 
766                                         if (cis != null) {
767                                                 try {
768                                                         ChildReference childPath = ChildReference.concatenate(le.path, new IndexReference(index) );
769                                                         sa.addListener(le.listener, cis, childPath,le.executor);
770                                                 } catch (AccessorException e) {
771                                                         throw new AccessorConstructionException(e);
772                                                 }
773                                         }
774                                         
775                                         // Next listener
776                                         le = le.next;
777                                 }                               
778                                 
779                         }
780                         
781                         return (T) sa;
782                 } catch (IOException e) {
783                         throw new AccessorConstructionException(e);
784                 } catch (AccessorException e) {
785                         throw new AccessorConstructionException(e);
786                 } finally {
787                         readUnlock();
788                 }
789         }
790
791         @SuppressWarnings("unchecked")
792         @Override
793         public <T extends Accessor> T getComponent(ChildReference reference)
794                         throws AccessorConstructionException {
795                 if (reference==null) return (T) this;
796                 if (reference instanceof LabelReference) {
797                         LabelReference lr = (LabelReference) reference;
798                         try {
799                                 Integer index = new Integer( lr.label );
800                                 Accessor result = getAccessor(index);
801                                 if (reference.getChildReference() != null)
802                                         result = result.getComponent(reference.getChildReference());
803                                 return (T) result;
804                         } catch ( NumberFormatException nfe ) {
805                                 throw new ReferenceException(nfe);
806                         }                       
807                 } else if (reference instanceof IndexReference) {
808                         IndexReference ref = (IndexReference) reference;
809                         int index = ref.getIndex();
810                         Accessor result = getAccessor(index);
811                         if (reference.getChildReference() != null)
812                                 result = result.getComponent(reference.getChildReference());
813                         return (T) result;
814                 } throw new ReferenceException(reference.getClass().getName()+" is not a reference of an array");       
815         }
816         
817         @Override
818         public void getAll(Binding valueBinding, Object[] array)
819                         throws AccessorException {
820                 assert b.isOpen();
821                 readLock();
822                 try {
823                         b.position(0L);
824                         int size = b.readInt();
825                         if (size > array.length) throw new AccessorException("Argument array too short");
826                         Serializer s = params.serializerScheme.getSerializer(valueBinding);
827                         for (int i=0; i<size; i++) {
828                                 array[i] = s.deserialize(b);
829                         }
830                 } catch (IOException e) {
831                         throw new AccessorException( e );
832                 } catch (SerializerConstructionException e) {
833                         throw new AccessorException( e );
834                 } finally {
835                         readUnlock();
836                 }
837         }
838
839         @Override
840         public void getAll(Binding valueBinding, Collection<Object> values)
841                         throws AccessorException {
842                 assert b.isOpen();
843                 readLock();
844                 try {
845                         b.position(0L);
846                         int size = b.readInt();
847                         Serializer s = params.serializerScheme.getSerializer(valueBinding);
848                         for (int i=0; i<size; i++) {
849                                 values.add( s.deserialize(b) );
850                         }
851                 } catch (IOException e) {
852                         throw new AccessorException( e );
853                 } catch (SerializerConstructionException e) {
854                         throw new AccessorException( e );
855                 } finally {
856                         readUnlock();
857                 }
858         }
859         
860         @Override
861         public void setSizeNoflush(int newSize) throws AccessorException {
862                 assert b.isOpen();
863                 writeLock();
864                 try {
865                         int oldSize = size();
866
867                         // Remove instances  
868                         if (newSize<oldSize) {
869                                 remove(newSize, oldSize-newSize);
870                         }
871                                                 
872                         // Add dummy instances
873                         if (newSize>oldSize) {
874                                 Object dummy = cb.createDefault();
875                                 int count = newSize-oldSize;
876                                 addRepeatNoflush(oldSize, cb, dummy, count);
877                         }
878                         
879                 } catch (BindingException e) {
880                         throw new AccessorException( e );
881                 } finally {
882                         writeUnlock();
883                 }
884         }
885
886         @Override
887         public void setSize(int newSize) throws AccessorException {
888                 assert b.isOpen();
889                 writeLock();
890                 try {
891                         setSizeNoflush(newSize);
892                         b.flush();
893                 } catch (IOException e) {
894                         throw new AccessorException( e );
895                 } finally {
896                         writeUnlock();
897                 }
898         }
899         
900         @Override
901         public int size() throws AccessorException {
902                 assert b.isOpen();
903                 readLock();
904                 try {
905                         b.position(0L);
906                         int size = b.readInt();
907                         if (size<0) throw new AccessorException("Malformed file");
908                         return size;
909                 } catch (IOException e) {
910                         throw new AccessorException( e );
911                 } finally {
912                         readUnlock();
913                 }
914         }
915
916         @Override
917         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
918                 Event rollback = null;
919                 if (e instanceof ValueAssigned) {
920                         ValueAssigned va = (ValueAssigned) e;
921                         if (makeRollback) rollback = new ValueAssigned(cb, getValue(cb)); 
922                         setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
923                 } else          
924                 if (e instanceof ArrayElementAdded) {
925                         ArrayElementAdded aa = (ArrayElementAdded) e;
926                         addNoflush(aa.index, aa.value.getBinding(), aa.value.getValue());
927                         if (makeRollback) rollback = new ArrayElementRemoved(aa.index);
928                 } else if (e instanceof ArrayElementRemoved) {
929                         ArrayElementRemoved ar = (ArrayElementRemoved) e;
930                         if (ar.index<0 || ar.index >=size()) throw new AccessorException("Array index out of bounds");
931                         if (makeRollback) {
932                                 Object cv = get(ar.index, cb);
933                                 rollback = new ArrayElementAdded(ar.index, new MutableVariant(cb, cv));
934                         }
935                         removeNoflush(ar.index, 1);
936                 } else {
937                         throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Array");
938                 }
939                 
940                 return rollback;
941         }
942
943         
944         
945         @Override
946         public void add(Binding binding, Object value) throws AccessorException {
947                 assert b.isOpen();
948                 writeLock();
949                 try {
950                         addNoflush(binding, value);
951                         b.flush();
952                 } catch (IOException e) {
953                         throw new AccessorException( e );
954                 } finally {
955                         writeUnlock();
956                 }
957         }
958
959         @Override
960         public void add(int index, Binding binding, Object value)
961                         throws AccessorException {
962                 assert b.isOpen();
963                 writeLock();
964                 try {
965                         addNoflush(index, binding, value);
966                         b.flush();
967                 } catch (IOException e) {
968                         throw new AccessorException( e );
969                 } finally {
970                         writeUnlock();
971                 }
972         }
973
974         @Override
975         public void addAll(Binding binding, Object[] values)
976                         throws AccessorException {
977                 assert b.isOpen();
978                 writeLock();
979                 try {
980                         addAllNoflush(binding, values);
981                         b.flush();
982                 } catch (IOException e) {
983                         throw new AccessorException( e );
984                 } finally {
985                         writeUnlock();
986                 }
987         }
988
989         @Override
990         public void addAll(int index, Binding binding, Object[] values)
991                         throws AccessorException {
992                 assert b.isOpen();
993                 writeLock();
994                 try {
995                         addAllNoflush(index, binding, values);
996                         b.flush();
997                 } catch (IOException e) {
998                         throw new AccessorException( e );
999                 } finally {
1000                         writeUnlock();                  
1001                 }
1002         }
1003
1004         @Override
1005         public void remove(int index, int count) throws AccessorException {
1006                 assert b.isOpen();
1007                 writeLock();
1008                 try {
1009                         removeNoflush(index, count);
1010                         b.flush();
1011                 } catch (IOException e) {
1012                         throw new AccessorException( e );
1013                 } finally {
1014                         writeUnlock();
1015                 }
1016         }
1017
1018         @Override
1019         public void set(int index, Binding binding, Object value)
1020                         throws AccessorException {
1021                 assert b.isOpen();
1022                 writeLock();
1023                 try {
1024                         setNoflush(index, binding, value);
1025                         b.flush();
1026                 } catch (IOException e) {
1027                         throw new AccessorException(e);
1028                 } finally {
1029                         writeUnlock();
1030                 }
1031         }
1032         
1033 }
1034