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