]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/binary/BinaryMap.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / binary / BinaryMap.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.SoftReference;
16 import java.util.Map;
17 import java.util.TreeMap;
18 import java.util.concurrent.Executor;
19
20 import org.simantics.databoard.accessor.Accessor;
21 import org.simantics.databoard.accessor.MapAccessor;
22 import org.simantics.databoard.accessor.error.AccessorConstructionException;
23 import org.simantics.databoard.accessor.error.AccessorException;
24 import org.simantics.databoard.accessor.error.ReferenceException;
25 import org.simantics.databoard.accessor.event.Event;
26 import org.simantics.databoard.accessor.event.MapEntryAdded;
27 import org.simantics.databoard.accessor.event.MapEntryRemoved;
28 import org.simantics.databoard.accessor.event.ValueAssigned;
29 import org.simantics.databoard.accessor.file.FileMapAccessor;
30 import org.simantics.databoard.accessor.impl.AccessorParams;
31 import org.simantics.databoard.accessor.impl.ListenerEntry;
32 import org.simantics.databoard.accessor.interestset.InterestSet;
33 import org.simantics.databoard.accessor.interestset.MapInterestSet;
34 import org.simantics.databoard.accessor.reference.ChildReference;
35 import org.simantics.databoard.accessor.reference.KeyReference;
36 import org.simantics.databoard.accessor.reference.LabelReference;
37 import org.simantics.databoard.adapter.AdaptException;
38 import org.simantics.databoard.adapter.Adapter;
39 import org.simantics.databoard.adapter.AdapterConstructionException;
40 import org.simantics.databoard.binding.ArrayBinding;
41 import org.simantics.databoard.binding.Binding;
42 import org.simantics.databoard.binding.MapBinding;
43 import org.simantics.databoard.binding.error.BindingConstructionException;
44 import org.simantics.databoard.binding.error.BindingException;
45 import org.simantics.databoard.binding.mutable.MutableVariant;
46 import org.simantics.databoard.parser.repository.DataTypeSyntaxError;
47 import org.simantics.databoard.parser.repository.DataValueRepository;
48 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
49 import org.simantics.databoard.serialization.SerializationException;
50 import org.simantics.databoard.serialization.Serializer;
51 import org.simantics.databoard.serialization.SerializerConstructionException;
52 import org.simantics.databoard.type.Datatype;
53 import org.simantics.databoard.type.MapType;
54 import org.simantics.databoard.util.binary.Blob;
55 import org.simantics.databoard.util.binary.RandomAccessBinary.ByteSide;
56
57 /**
58  * BinaryMap is accessor to a map structure in a file or byte memory.
59  * <p> (Fixed sized entries)
60  * If the size of an entry is constant, then the implementation uses binary 
61  * search for random access operations O(log(n)). 
62  * 
63  * <p> (Variable sized entries)
64  * If the size is variable, for example the key or value is string, then the 
65  * implementation does sequential search for all operations, which is very 
66  * slow O(n). To improve performance, an index is built in memory as the file
67  * is read. To conserve memory, the index is held with SoftReference. So, 
68  * the performance remains good if lots of operations are done within a short
69  * time period.
70  * 
71  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
72  */
73 public class BinaryMap extends BinaryObject implements MapAccessor, FileMapAccessor {
74
75         /** Accessors to children */
76         TreeMap<Object, java.lang.ref.Reference<BinaryObject>> children;
77         
78         Binding kb;
79         Binding vb;
80         Serializer ks;
81         Serializer vs;
82         
83         /** Entry size, constant */
84         Integer constantSize;
85         
86         Index index;
87         boolean indexing = false;
88         
89         public BinaryMap(BinaryObject parent, Blob blob, Datatype type, AccessorParams params) {
90                 super(parent, blob, type, params);
91                 MapType mt = (MapType) type;
92                 kb = params.bindingScheme.getBindingUnchecked( mt.keyType );
93                 vb = params.bindingScheme.getBindingUnchecked( mt.valueType );
94                 ks = params.serializerScheme.getSerializerUnchecked( kb );
95                 vs = params.serializerScheme.getSerializerUnchecked( vb );
96                 children = new TreeMap<Object, java.lang.ref.Reference<BinaryObject>>(kb);
97                 
98                 if (ks.getConstantSize()!=null && vs.getConstantSize()!=null)  {
99                         constantSize = ks.getConstantSize() + vs.getConstantSize();
100                         index = new Constant();
101                 } else {
102                         index = new Sequential();
103                 }
104         } 
105         
106         // Get existing accessor
107         BinaryObject getChild(Object key)
108         {
109                 java.lang.ref.Reference<BinaryObject> ref = children.get(key);
110                 if (ref==null) return null;
111                 BinaryObject result = ref.get();
112                 if (result==null) {
113                         children.remove(key);
114                         return null;
115                 }
116                 return result;
117         }               
118         
119         Entry floorChildEntry(Object key) throws IOException, SerializationException, BindingException {
120                 if (ks.getConstantSize()==null) return null;
121                 BinaryObject sa = getChild(key);
122                 // Exact match
123                 if (sa!=null) {
124                         if (ks.getConstantSize()==null) return null;
125                         long valuePos = sa.b.getStartPositionInSourceBinary();
126                         long keyPos = valuePos - ks.getConstantSize();
127                         return new Entry(key, keyPos, sa);
128                 }
129                 return lowerChildEntry(key);
130         }
131
132         Entry lowerChildEntry(Object key) throws IOException, SerializationException, BindingException {
133                 if (ks.getConstantSize()==null) return null;
134                 Map.Entry<Object, java.lang.ref.Reference<BinaryObject>> e = children.lowerEntry(key);
135                 while (e != null) {
136                         key = e.getKey();
137                         BinaryObject sa = e.getValue().get();
138                         if (sa!=null) {
139                                 long valuePos = sa.b.getStartPositionInSourceBinary();
140                                 long keyPos = valuePos - ks.getConstantSize();
141                                 return new Entry(key, keyPos, sa);
142                         } else {
143                                 children.remove(e.getKey());
144                         }
145                         e = children.lowerEntry(key);
146                 }
147                 return null;
148         }
149
150         Entry lastChildEntry() throws IOException, SerializationException, BindingException {
151                 if (ks.getConstantSize()==null) return null;
152                 Map.Entry<Object, java.lang.ref.Reference<BinaryObject>> e = children.lastEntry();
153                 while (e != null) {
154                         Object key = e.getKey();
155                         BinaryObject sa = e.getValue().get();
156                         if (sa!=null) {
157                                 long valuePos = sa.b.getStartPositionInSourceBinary();
158                                 long keyPos = valuePos - ks.getConstantSize();
159                                 return new Entry(key, keyPos, sa);
160                         } else {
161                                 children.remove(key);
162                         }
163                         e = children.lowerEntry(key);
164                 }
165                 return null;
166         }
167         
168         Entry higherChildEntry(Object key) throws IOException, SerializationException, BindingException {
169                 if (ks.getConstantSize()==null) return null;
170                 Map.Entry<Object, java.lang.ref.Reference<BinaryObject>> e = children.higherEntry(key);
171                 while (e != null) {
172                         key = e.getKey();
173                         BinaryObject sa = e.getValue().get();
174                         if (sa!=null) {
175                                 long valuePos = sa.b.getStartPositionInSourceBinary();
176                                 long keyPos = valuePos - ks.getConstantSize();
177                                 return new Entry(key, keyPos, sa);
178                         } else {
179                                 children.remove(key);
180                         }
181                         e = children.higherEntry(key);
182                 }
183                 return null;
184         }
185
186         Entry ceilingChildEntry(Object key) throws IOException, SerializationException, BindingException {
187                 if (ks.getConstantSize()==null) return null;
188                 BinaryObject sa = getChild(key);
189                 // Exact match
190                 if (sa!=null) {
191                         long valuePos = sa.b.getStartPositionInSourceBinary();
192                         long keyPos = valuePos - ks.getConstantSize();
193                         return new Entry(key, keyPos, sa);
194                 }
195                 return higherChildEntry(key);
196         }
197         
198         Entry getEntryAt(long pos) throws SerializationException, IOException, BindingException {
199                 Object k = getKeyAt(pos);
200                 if (k==null) return null;
201                 return new Entry(k, pos, getChild(k));
202         }
203         
204         Object getKeyAt(long pos) throws SerializationException, IOException, BindingException {
205                 if (pos<4L) return null;
206                 if (pos>=b.length()) return null;
207                 b.position(pos);
208                 Object k = ks.deserialize(b, null);
209                 return k;
210         }       
211         
212         @Override
213         public MapType type() {
214                 return (MapType) type;
215         }
216
217         @Override
218         public void clear() throws AccessorException {
219                 assert b.isOpen();
220                 writeLock();
221                 try {
222                         clearNoflush();
223                         b.flush();
224                 } catch (IOException e) {
225                         throw new AccessorException( e );
226                 } finally {
227                         writeUnlock();
228                 }
229         }       
230
231         @Override
232         public int size() throws AccessorException {
233                 assert b.isOpen();
234                 readLock();
235                 try {
236                         if (constantSize != null) return (int) ((b.length()-4) / constantSize);
237                         b.position(0L);
238                         return b.readInt();
239                 } catch (IOException e) {
240                         throw new AccessorException( e );
241                 } finally {
242                         readUnlock();
243                 }
244         }       
245
246         @Override
247         public boolean containsKey(Binding keyBinding, Object key)
248                         throws AccessorException {
249                 assert b.isOpen();
250                 readLock();
251                 try {
252                         Object lk = adapt(key, keyBinding, kb);
253                         Entry e = index.getKey(lk);
254                         return e != null;
255                 } catch (AdaptException e) {
256                         throw new AccessorException(e);
257                 } catch (AdapterConstructionException e) {
258                         throw new AccessorException(e);
259                 } finally {
260                         readUnlock();
261                 }
262         }
263
264         @Override
265         public boolean containsValue(Binding valueBinding, Object value)
266                         throws AccessorException {              
267                 assert b.isOpen();
268                 readLock();
269                 try {
270                         Serializer vs = params.serializerScheme.getSerializer( valueBinding );
271                         b.position(0L);
272                         int count = b.readInt();
273                         for (int i=0; i<count; i++) {
274                                 ks.skip(b);
275                                 Object v = vs.deserialize(b, null);
276                                 if (valueBinding.equals(v, value)) return true;
277                         }
278                 } catch (IOException e) {
279                         throw new AccessorException(e);
280                 } catch (SerializerConstructionException e) {
281                         throw new AccessorException(e);
282                 } finally {
283                         readUnlock();
284                 }
285                 return false;
286         }
287
288         @Override
289         public Object get(Binding keyBinding, Object key, Binding valueBinding)
290                         throws AccessorException {
291                 assert b.isOpen();
292                 readLock();
293                 try {
294                         Object lk = adapt(key, keyBinding, kb);
295                         Entry e = index.getKey(lk);
296                         if (e==null) return null;
297                         b.position(e.pos);
298                         ks.skip(b, null);
299                         Object value = params.serializerScheme.getSerializer( valueBinding ).deserialize(b, null);                      
300                         return value;
301                 } catch (AdaptException e1) {
302                         throw new AccessorException(e1);
303                 } catch (IOException e) {
304                         throw new AccessorException(e);
305                 } catch (RuntimeSerializerConstructionException e) {
306                         throw new AccessorException(e);
307                 } catch (AdapterConstructionException e) {
308                         throw new AccessorException(e);
309                 } catch (SerializerConstructionException e) {
310                         throw new AccessorException(e);
311                 } finally {
312                         readUnlock();
313                 }
314         }
315
316         @Override
317         public void getAll(Binding keyBinding, Binding valueBinding,
318                         Map<Object, Object> to) throws AccessorException {
319                 assert b.isOpen();
320                 readLock();
321                 try {
322                         Adapter ka = params.adapterScheme.getAdapter(kb, keyBinding, true, false);
323                         Adapter va = params.adapterScheme.getAdapter(vb, valueBinding, true, false);
324                         b.position(0L);
325                         int count = b.readInt();
326                         for (int i=0; i<count; i++) {
327                                 Object k = ks.deserialize(b, null);
328                                 Object v = vs.deserialize(b, null);
329                                 k = ka.adapt(k);
330                                 v = va.adapt(v);
331                                 to.put(k, v);
332                         }                       
333                         
334                 } catch (IOException e) {
335                         throw new AccessorException(e);
336                 } catch (AdapterConstructionException e) {
337                         throw new AccessorException(e);
338                 } catch (AdaptException e) {
339                         throw new AccessorException(e);
340                 } finally {
341                         readUnlock();
342                 }
343                 
344         }
345
346         @Override
347         public void getAll(Binding keyBinding, Binding valueBinding, Object[] keys,
348                         Object[] values) throws AccessorException {
349                 assert b.isOpen();
350                 readLock();
351                 try {
352                         Adapter ka = params.adapterScheme.getAdapter(kb, keyBinding, true, false);
353                         Adapter va = params.adapterScheme.getAdapter(vb, valueBinding, true, false);
354                         b.position(0L);
355                         int count = b.readInt();
356                         if (count>keys.length) throw new AccessorException("keys array too short");
357                         if (count>values.length) throw new AccessorException("values array too short");
358                         for (int i=0; i<count; i++) {
359                                 Object k = ks.deserialize(b, null);
360                                 Object v = vs.deserialize(b, null);
361                                 k = ka.adapt(k);
362                                 v = va.adapt(v);
363                                 keys[i] = k;
364                                 values[i] = v;
365                         }                       
366                         
367                 } catch (IOException e) {
368                         throw new AccessorException(e);
369                 } catch (AdapterConstructionException e) {
370                         throw new AccessorException(e);
371                 } catch (AdaptException e) {
372                         throw new AccessorException(e);
373                 } finally {
374                         readUnlock();
375                 }
376                 
377         }
378         
379         @Override
380         public int count(Binding keyBinding, Object from, boolean fromInclusive,
381                         Object end, boolean endInclusive) throws AccessorException {
382                 assert b.isOpen();
383                 readLock();
384                 try {
385                         Object lf = params.adapterScheme.adapt(from, keyBinding, kb);
386                         Object le = params.adapterScheme.adapt(end, keyBinding, kb);
387                         
388                         Entry fromEntry = fromInclusive ? index.ceiling(lf) : index.higher(lf);
389                         Entry endEntry  = endInclusive  ? index.floor(le)   : index.lower(le);
390                         if (endEntry==null || fromEntry == null) return 0;
391
392                         if (fromEntry.pos>endEntry.pos) return 0;
393                         if (fromEntry.pos==endEntry.pos) return 1;
394                                                 
395                         if (constantSize != null) {
396                                 return (int) ((endEntry.pos-fromEntry.pos)/constantSize)+1;
397                         }
398                         
399                         int result = 1;
400                         b.position(fromEntry.pos);
401                         while (b.position()<endEntry.pos) {
402                                 ks.skip(b);
403                                 vs.skip(b);
404                                 result++;
405                         }
406                         return result;                  
407                 } catch (IOException e) {
408                         throw new AccessorException(e);
409                 } catch (AdaptException e) {
410                         throw new AccessorException(e);
411                 } finally {
412                         readUnlock();
413                 }
414         }
415         
416         @Override
417         public int getEntries(Binding keyBinding, Object from,
418                         boolean fromInclusive, Object end, boolean endInclusive,
419                         ArrayBinding keyArrayBinding, Object keysArray,
420                         ArrayBinding valueArrayBinding, Object valueArray, int limit)
421                         throws AccessorException {
422                 assert b.isOpen();
423                 readLock();
424                 try {
425                         Object lf = params.adapterScheme.adapt(from, keyBinding, kb);
426                         Object le = params.adapterScheme.adapt(end, keyBinding, kb);
427                         
428                         Entry fromEntry = fromInclusive ? index.ceiling(lf) : index.higher(lf);
429                         Entry endEntry  = endInclusive  ? index.floor(le)   : index.lower(le);
430                         if (endEntry==null || fromEntry == null) return 0;
431                         
432                         // Requester's Key & Value Binding
433                         Binding rkb   = keyArrayBinding.getComponentBinding();
434                         Binding rvb   = valueArrayBinding.getComponentBinding();
435                         
436                         // Local Key & Value type & bindings
437                         Datatype lkt  = type().keyType;
438                         Datatype lvt  = type().valueType;
439                         
440                         boolean adaptKey   = !rkb.type().equals(lkt);
441                         boolean adaptValue = !rvb.type().equals(lvt);
442                         
443                         Serializer ks, vs;
444                         Adapter ka = null, va = null;
445                         
446                         if (adaptKey) {
447                                 Binding lkb   = params.bindingScheme.getBinding( lkt );
448                                 ka = params.adapterScheme.getAdapter( lkb, rkb, true, false);
449                                 ks = params.serializerScheme.getSerializer( lkb );
450                         } else {
451                                 ks = params.serializerScheme.getSerializer( rkb );                              
452                         }
453                         
454                         if (adaptValue) {
455                                 Binding lvb   = params.bindingScheme.getBinding( lvt );
456                                 va = params.adapterScheme.getAdapter( lvb, rvb, true, false);
457                                 vs = params.serializerScheme.getSerializer( lvb );
458                         } else {
459                                 vs = params.serializerScheme.getSerializer( rvb );
460                         }                       
461                         
462                         int i = 0;
463                         int kac = keyArrayBinding.size( keysArray );
464                         int vac = valueArrayBinding.size( valueArray ); 
465                         b.position(fromEntry.pos);
466                         while (b.position()<=endEntry.pos) {
467                                 if (limit>=0 && i>=limit) break;
468                                 Object key = ks.deserialize(b);
469                                 if (adaptKey) key = ka.adapt(key);
470                                 Object value = vs.deserialize(b);
471                                 if (adaptValue) value = va.adapt(value);
472                                 
473                                 if (i<kac) keyArrayBinding.set(keysArray, i, key); else keyArrayBinding.add(keysArray, i, key);
474                                 if (i<vac) valueArrayBinding.set(valueArray, i, value); else valueArrayBinding.add(valueArray, i, value);
475                                 
476                                 i++;
477                         }
478                         return i;                       
479                 } catch (IOException e) {
480                         throw new AccessorException(e);
481                 } catch (AdaptException e) {
482                         throw new AccessorException(e);
483                 } catch (SerializerConstructionException e) {
484                         throw new AccessorException(e);
485                 } catch (BindingException e) {
486                         throw new AccessorException(e);
487                 } catch (BindingConstructionException e) {
488                         throw new AccessorException(e);
489                 } catch (AdapterConstructionException e) {
490                         throw new AccessorException(e);
491                 } finally {
492                         readUnlock();
493                 }
494         }       
495
496         @Override
497         public Object getCeilingKey(Binding keyBinding, Object key)
498                         throws AccessorException {
499                 assert b.isOpen();
500                 readLock();
501                 try {
502                         Object lk = adapt(key, keyBinding, kb);
503                         if (ks.getConstantSize()!=null) {
504                                 if (getChild(lk)!=null) return key;
505                         }
506                         Entry e = index.ceiling(lk);
507                         if (e==null) return null;
508                         return adapt(e.key, kb, keyBinding);
509                 } catch (AdaptException e1) {
510                         throw new AccessorException( e1 );
511                 } catch (AdapterConstructionException e) {
512                         throw new AccessorException( e );
513                 } finally {
514                         readUnlock();
515                 }
516         }
517
518         @Override
519         public Object getFirstKey(Binding keyBinding) throws AccessorException {
520                 assert b.isOpen();
521                 readLock();
522                 try {
523                         b.position(0L);
524                         int count = b.readInt();
525                         if (count==0) return null;
526                         return params.serializerScheme.getSerializer( keyBinding ).deserialize(b);
527                 } catch (RuntimeSerializerConstructionException e) {
528                         throw new AccessorException(e);
529                 } catch (IOException e) {
530                         throw new AccessorException(e);
531                 } catch (SerializerConstructionException e) {
532                         throw new AccessorException(e);
533                 } finally {
534                         readUnlock();
535                 }
536         }
537
538         @Override
539         public Object getFloorKey(Binding keyBinding, Object key)
540                         throws AccessorException {
541                 assert b.isOpen();
542                 readLock();
543                 try {
544                         Object lk = adapt(key, keyBinding, kb);
545                         if (ks.getConstantSize()!=null) {
546                                 // See if we get exact match
547                                 if (getChild(lk)!=null) return key;
548                         }
549                         Entry e = index.floor(lk);
550                         if (e==null) return null;
551                         return adapt(e.key, kb, keyBinding);
552                 } catch (AdaptException e1) {
553                         throw new AccessorException( e1 );
554                 } catch (AdapterConstructionException e) {
555                         throw new AccessorException( e );
556                 } finally {
557                         readUnlock();
558                 }
559         }
560
561         @Override
562         public Object getHigherKey(Binding keyBinding, Object key)
563                         throws AccessorException {
564                 assert b.isOpen();
565                 readLock();
566                 try {
567                         Object lk = adapt(key, keyBinding, kb);
568                         Entry e = index.higher(lk);
569                         if (e==null) return null;
570                         return adapt(e.key, kb, keyBinding);
571                 } catch (AdaptException e1) {
572                         throw new AccessorException( e1 );
573                 } catch (AdapterConstructionException e) {
574                         throw new AccessorException( e );
575                 } finally {
576                         readUnlock();
577                 }
578         }
579
580         @Override
581         public Object[] getKeys(Binding keyBinding) throws AccessorException {
582                 assert b.isOpen();
583                 readLock();
584                 try {
585                         Adapter ka = params.adapterScheme.getAdapter(kb, keyBinding, true, false);
586                         b.position(0L);
587                         int count = b.readInt();
588                         Object[] result = new Object[ count ];
589                         for (int i=0; i<count; i++) {
590                                 Object k = ks.deserialize(b, null);
591                                 vs.skip(b, null);
592                                 k = ka.adapt(k);
593                                 result[i] = k;
594                         }                       
595                         return result;                  
596                 } catch (IOException e) {
597                         throw new AccessorException(e);
598                 } catch (AdapterConstructionException e) {
599                         throw new AccessorException(e);
600                 } catch (AdaptException e) {
601                         throw new AccessorException(e);
602                 } finally {
603                         readUnlock();
604                 }
605         }
606
607         @Override
608         public Object getLastKey(Binding keyBinding) throws AccessorException {
609                 assert b.isOpen();
610                 readLock();
611                 try {
612                         Entry e = index.last();
613                         if (e==null) return null;
614                         return adapt(e.key, kb, keyBinding);
615                 } catch (AdaptException e1) {
616                         throw new AccessorException( e1 );
617                 } catch (AdapterConstructionException e) {
618                         throw new AccessorException( e );
619                 } finally {
620                         readUnlock();
621                 }
622         }
623
624         @Override
625         public Object getLowerKey(Binding keyBinding, Object key)
626                         throws AccessorException {
627                 assert b.isOpen();
628                 readLock();
629                 try {
630                         Object lk = adapt(key, keyBinding, kb);
631                         Entry e = index.lower(lk);
632                         if (e==null) return null;
633                         return adapt(e.key, kb, keyBinding);
634                 } catch (AdaptException e1) {
635                         throw new AccessorException( e1 );
636                 } catch (AdapterConstructionException e) {
637                         throw new AccessorException( e );
638                 } finally {
639                         readUnlock();
640                 }
641         }
642
643
644         @SuppressWarnings("unchecked")
645         @Override
646         public <T extends Accessor> T getComponent(ChildReference reference)
647                         throws AccessorConstructionException {
648                 if (reference==null) return (T) this;
649                 
650                 if (reference instanceof LabelReference) {
651                         LabelReference lr = (LabelReference) reference;
652                         try {
653                                 DataValueRepository rep = new DataValueRepository(); 
654                                 kb.parseValue(lr.label, rep);
655                                 Object value = rep.get( rep.getValueNames().iterator().next() );
656                                 
657                                 Accessor result = (T) getValueAccessor(kb, value);
658                                 if (reference.getChildReference() != null)
659                                         result = result.getComponent(reference.getChildReference());
660                                 return (T) result;                      
661                         } catch ( BindingException e1 ) {
662                                 throw new ReferenceException(e1);                               
663                         } catch ( DataTypeSyntaxError e2 ) {
664                                 throw new ReferenceException(e2);                               
665                         }                       
666                 } else          
667                 if (reference instanceof KeyReference) {
668                         KeyReference ref = (KeyReference) reference;
669                         Accessor result = getValueAccessor(ref.key.getBinding(), ref.key.getValue());
670                         if (reference.getChildReference() != null)
671                                 result = result.getComponent(reference.getChildReference());
672                         return (T) result;                      
673                 } throw new ReferenceException(reference.getClass().getName()+" is not a reference of a map");  
674         }
675         
676         @SuppressWarnings("unchecked")
677         @Override
678         public <T extends Accessor> T getValueAccessor(Binding keyBinding,
679                         Object key) throws AccessorConstructionException {
680                 
681                 assert b.isOpen();
682                 readLock();
683                 try {                   
684                         Object rk = key;
685                         Object lk = params.adapterScheme.getAdapter(keyBinding, kb, true, true).adapt(rk);
686                         
687                         BinaryObject sa = getChild(lk);
688                         if (sa!=null) return (T) sa;
689                         
690                         Entry e = index.getKey(lk);
691                         if (e == null) throw new AccessorConstructionException("Map doesn't contain the requested element");
692                         
693                         long valuePos;
694                         if (ks.getConstantSize()!=null) {
695                                 valuePos = e.pos + ks.getConstantSize();
696                         } else {
697                                 b.position(e.pos);
698                                 ks.skip(b, null);
699                                 valuePos = b.position();
700                         }
701                         
702                         long valueSize;
703                         if (vs.getConstantSize()!=null) {
704                                 valueSize = vs.getConstantSize();
705                         } else {
706                                 b.position(valuePos);
707                                 vs.skip(b, null);
708                                 valueSize = b.position() - valuePos;
709                         }
710                         
711                         // Instantiate correct sub accessor. 
712                         sa = createSubAccessor(vb.type(), valuePos, valueSize, params);
713                         children.put(lk, new SoftReference<BinaryObject>(sa));
714                                 
715                         // Add component interest sets
716                         if (listeners!=null) {
717                                 MutableVariant kv = new MutableVariant(kb, lk);
718                                 ListenerEntry le = listeners;
719                                 while (le!=null) {                              
720                                         MapInterestSet is = le.getInterestSet();
721         
722                                         // Generic element interest
723                                         InterestSet gis = is.getComponentInterest(); 
724                                         if (gis != null) {
725                                                 try {
726                                                         ChildReference childPath = ChildReference.concatenate(le.path, new KeyReference(kv) );
727                                                         sa.addListener(le.listener, gis, childPath, le.executor);
728                                                 } catch (AccessorException e1) {
729                                                         throw new AccessorConstructionException(e1);
730                                                 }
731                                         }
732                                                 
733                                         // Specific element interest
734                                         InterestSet cis = is.getComponentInterest(kv); 
735                                         if (cis != null) {
736                                                 try {
737                                                         ChildReference childPath = ChildReference.concatenate(le.path, new KeyReference(kv) );
738                                                         sa.addListener(le.listener, cis, childPath, le.executor );
739                                                 } catch (AccessorException e1) {
740                                                         throw new AccessorConstructionException(e1);
741                                                 }
742                                         }
743                                                 
744                                         // Next listener
745                                         le = le.next;
746                                 }
747                         }
748                         
749                         return (T) sa;
750                 } catch (AdaptException e) {
751                         throw new AccessorConstructionException(e);
752                 } catch (AdapterConstructionException e) {
753                         throw new AccessorConstructionException(e);
754                 } catch (IOException e) {
755                         throw new AccessorConstructionException(e);
756                 } catch (AccessorException e) {
757                         throw new AccessorConstructionException(e);
758                 } finally {
759                         readUnlock();
760                 }
761         }
762         
763         @Override
764         public Object[] getValues(Binding valueBinding) throws AccessorException {
765                 assert b.isOpen();
766                 readLock();
767                 try {
768                         Serializer rvs = params.serializerScheme.getSerializer(valueBinding);
769                         b.position(0L);
770                         int count = b.readInt();
771                         Object[] result = new Object[ count ];
772                         for (int i=0; i<result.length; i++) {
773                                 ks.skip(b, null);
774                                 result[i] = rvs.deserialize(b, null);
775                         }
776                         return result;
777                 } catch (IOException e) {
778                         throw new AccessorException( e );
779                 } catch (SerializerConstructionException e) {
780                         throw new AccessorException( e );
781                 } finally {
782                         readUnlock();
783                 }
784         }
785
786         @Override
787         public void setValueNoflush(Binding binding, Object mapValue)
788                         throws AccessorException {              
789                 assert b.isOpen();
790                 MapBinding mb = (MapBinding) binding;
791                 if (children.isEmpty() && listeners==null) {
792                         writeLock();
793                         try {
794                                 // Write
795                                 Serializer s = params.serializerScheme.getSerializer( mb );
796                                 int size = s.getSize(mapValue, null);
797                                 b.setLength(size);
798                                 b.position(0L);
799                                 // Write all at once
800                                 s.serialize(b, null, mapValue);                 
801                         } catch (IOException e) {
802                                 throw new AccessorException( e );
803                         } catch (SerializerConstructionException e) {
804                                 throw new AccessorException( e );
805                         } finally {
806                                 writeUnlock();
807                         }
808                 } else {
809
810                         writeLock();
811                         try {
812                                 int nc = mb.size(mapValue);
813                                 Object nks[] = new Object[nc];
814                                 Object nvs[] = new Object[nc];
815                                 mb.getAll(mapValue, nks, nvs);
816                                 setAllNoflush(mb.getKeyBinding(), mb.getValueBinding(), nks, nvs);
817                         } catch (BindingException e) {
818                                 throw new AccessorException(e);
819                         } finally {
820                                 writeUnlock();
821                         }
822                         
823                 }
824         }
825         
826
827         @Override
828         public void clearNoflush() throws AccessorException {
829                 assert b.isOpen();
830                 writeLock();
831                 try {
832                         boolean hasListeners = listeners!=null;
833                         Object[] keys = hasListeners ? getKeys(kb) : null; 
834                         
835                         // Write
836                         b.position(0L);
837                         b.writeInt(0);
838                         b.setLength(4);
839                                                 
840                         // Disconnect sub-accessor
841                         for (java.lang.ref.Reference<BinaryObject> ref : children.values()) {
842                                 BinaryObject sa = ref.get();
843                                 if (sa==null) continue;
844                                 sa.invalidatedNotification();
845                         }
846                         children.clear();
847                         
848                         // Notify Listeners
849                         ListenerEntry le = listeners;
850                         while (le!=null) {                              
851                                 MapInterestSet is = le.getInterestSet();
852                                 for (Object key : keys) {
853                                         MutableVariant var = new MutableVariant(kb, key);
854                                         if (is.inNotificationsOf(var)) {
855                                                 MapEntryRemoved e = new MapEntryRemoved(var); 
856                                                 emitEvent(le, e);
857                                         }
858                                 }
859                                                                 
860                                 le = le.next;
861                         }               
862                         
863                 } catch (IOException e) {
864                         throw new AccessorException( e );
865                 } finally {
866                         writeUnlock();
867                 }
868                 
869         }
870
871         @Override
872         public void putAllNoflush(Binding keyBinding, Binding valueBinding,
873                         Map<Object, Object> from) throws AccessorException {
874                 int nc = from.size();
875                 Object[] nks = new Object[ nc ];
876                 Object[] nvs = new Object[ nc ];                
877             int i=0;
878             for (Map.Entry<Object, Object> e : from.entrySet()) {
879                 nks[i] = e.getKey();
880                 nvs[i] = e.getValue();
881                 i++;
882             }
883                 putAllNoflush(keyBinding, valueBinding, nks, nvs);
884         }
885
886         @Override
887         public void putAllNoflush(Binding kb, Binding vb,
888                         Object[] nks, Object[] nvs) throws AccessorException {
889                 int c = nks.length;
890                 int newItemsCount = 0;
891                 for (int i=0; i<c; i++) {
892                         boolean hadPreviousValue = _putNoflush(kb, nks[i], vb, nvs[i]);
893                         if (!hadPreviousValue) newItemsCount++;
894                 }
895
896                 if (newItemsCount>0) {
897                         assert b.isOpen();
898                         writeLock();
899                         try {
900                                 b.position(0L);
901                                 int oldCount = b.readInt();
902                                 b.position(0L);
903                                 b.writeInt( oldCount + newItemsCount);                  
904                         } catch (IOException e) {
905                                 throw new AccessorException(e);
906                         } finally {
907                                 writeUnlock();
908                         }
909                 }
910         
911         }
912         
913         public void setAllNoflush(Binding kb, Binding vb,
914                         Object[] nks, Object[] nvs) throws AccessorException {
915                 assert b.isOpen();
916                 writeLock();
917                 try {
918                         Serializer ks = params.serializerScheme.getSerializer( kb );
919                         Serializer vs = params.serializerScheme.getSerializer( vb );
920                         int nc = nks.length;
921                         // Generate removed, assigned and added events
922                         if (listeners!=null) {
923                                 
924                                 b.position(4L);                 
925                                 int ni = 0;
926                                 
927                                 // New and Old map lowest Keys 
928                                 Object nk = nks.length>0 ? nks[0] : null;
929                                 Object ok = b.length()<=4 ? null : ks.deserialize(b, null);
930                                 
931                                 while (nk!=null || ok!=null) {
932                                         int c = 0;
933                                         if (nk==null) {
934                                                 c = -1;
935                                         } else if (ok==null) {
936                                                 c= 1;
937                                         } else c = kb.compare(ok, nk);
938                                         if (c==0) {
939                                                 // old key == new key
940                                                 // Assigned new value
941                                                 MutableVariant kv = new MutableVariant(kb, kb.isImmutable() ? nk : kb.clone(nk));
942                                                 ListenerEntry le = listeners;
943                                                 while (le!=null) {                              
944                                                         MapInterestSet is = le.getInterestSet();
945                                                         if (is.inNotificationsOf(kv)) {
946                                                                 MutableVariant vv = null;
947                                                                 if (is.inValuesOf(kv)) {
948                                                                         Object nv = vb.isImmutable() ? nvs[ni] : vb.clone(nvs[ni]);
949                                                                         vv = new MutableVariant(vb, nv);                                                                        
950                                                                 }
951                                                                 Event e = new ValueAssigned( new KeyReference( kv ), vv);
952                                                                 emitEvent(le, e);
953                                                         }
954                                                         le = le.next;
955                                                 }
956                                                 // Move new pointer
957                                                 ni++;
958                                                 nk = ni<nks.length ? nks[ni] : null;
959                                                 // Move old pointer
960                                                 vs.skip(b, null);
961                                                 ok = b.position()<b.length() ? ks.deserialize(b, null) : null;                                                  
962                                         } 
963                                         
964                                         else if (c<0) {
965                                                 // old key < new key
966                                                 MutableVariant kv = new MutableVariant(kb, kb.isImmutable() ? ok : kb.clone(ok));
967                                                 ListenerEntry le = listeners;
968                                                 while (le!=null) {                              
969                                                         MapInterestSet is = le.getInterestSet();
970                                                         if (is.inNotificationsOf(kv)) {                                                         
971                                                                 MapEntryRemoved e = new MapEntryRemoved(kv);
972                                                                 emitEvent(le, e);
973                                                         }
974                                                         le = le.next;
975                                                 }                                               
976                                                 // Move old pointer
977                                                 vs.skip(b, null);
978                                                 ok = b.position()<b.length() ? ks.deserialize(b, null) : null;                                                  
979                                         }
980                                         
981                                         else if (c>0) {
982                                                 // new key < old key
983                                                 MutableVariant kv = new MutableVariant(kb, kb.isImmutable() ? nk : kb.clone(nk));
984
985                                                 if (listeners!=null) {
986                                                         Object nv = null;
987                                                         ListenerEntry le = listeners;
988                                                         while (le!=null) {                              
989                                                                 MapInterestSet is = le.getInterestSet();
990                                                                 if (is.inNotificationsOf(kv)) {                                                         
991                                                                         MutableVariant vv = null;
992                                                                         if (is.inValuesOf(kv)) {
993                                                                                 if (nv==null) {
994                                                                                         nv = vb.clone( nvs[ni] );
995                                                                                 }
996                                                                                 vv = new MutableVariant(vb, nv);
997                                                                         }
998                                                                         MapEntryAdded e = new MapEntryAdded(kv, vv);
999                                                                         emitEvent(le, e);
1000                                                                 }
1001                                                                 le = le.next;
1002                                                         }
1003                                                 }
1004                                                 
1005                                                 // Move new pointer
1006                                                 ni++;
1007                                                 nk = ni<nks.length ? nks[ni] : null;
1008                                         }
1009                                 }
1010                                 
1011                         }
1012                         
1013                         // Calc Size
1014                         long size = 4;                  
1015                         if (ks.getConstantSize()!=null) {
1016                                 size += ((long)nc) * ks.getConstantSize();
1017                         } else {
1018                                 for (int i=0; i<nc; i++) size += ks.getSize(nks[i], null);
1019                                 
1020                         }
1021                         if (vs.getConstantSize()!=null) {
1022                                 size += ((long)nc) * vs.getConstantSize();
1023                         } else {
1024                                 for (int i=0; i<nc; i++) size += vs.getSize(nvs[i], null);
1025                                 
1026                         }
1027                         b.setLength(size);                      
1028                         
1029                         // Write entry by entry and update positions of children
1030                         b.position(0L);
1031                         b.writeInt(nc);
1032                         for (int i=0; i<nc; i++) {
1033                                 Object nk = nks[i];
1034                                 Object nv = nvs[i];
1035                                 long startPos = b.position();
1036                                 ks.serialize(b, null, nk);
1037                                 vs.serialize(b, null, nv);
1038                                 long endPos = b.position();
1039                                 long len = endPos - startPos;
1040                                 Object lk = params.adapterScheme.adapt(nk, kb, this.kb);
1041                                 BinaryObject sa = getChild(lk);
1042                                 if (sa!=null) sa.b.setPositionInSource(startPos, len);                                  
1043                         }
1044                                 
1045                         
1046                 } catch (IOException e) {
1047                         throw new AccessorException(e);
1048                 } catch (AdaptException e) {
1049                         throw new AccessorException(e);
1050                 } catch (SerializerConstructionException e) {
1051                         throw new AccessorException(e);
1052                 } finally {
1053                         writeUnlock();
1054                 }
1055         }
1056
1057         
1058         @Override
1059         public void putNoflush(Binding kb, Object key,
1060                         Binding vb, Object value) throws AccessorException {
1061                 assert b.isOpen();
1062                 writeLock();
1063                 try {
1064                         boolean hadPreviousEntry = _putNoflush(kb, key, vb, value);
1065                 
1066                         if (!hadPreviousEntry) {
1067                                 b.position(0L);
1068                                 int oldCount = b.readInt();
1069                                 b.position(0L);
1070                                 b.writeInt( oldCount + 1);                      
1071                         }
1072                 } catch (IOException e) {
1073                         throw new AccessorException(e);
1074                 } catch (RuntimeSerializerConstructionException e) {
1075                         throw new AccessorException(e);
1076                 } finally {
1077                         writeUnlock();
1078                 }
1079         }
1080         
1081         /**
1082          * Put an entry. Does not update size.
1083          * 
1084          * @param kb
1085          * @param key
1086          * @param vb
1087          * @param value
1088          * @return true if previous entry existed
1089          * @throws AccessorException
1090          */
1091         private boolean _putNoflush(Binding kb, Object key,
1092                         Binding vb, Object value) throws AccessorException {
1093                 writeLock();
1094                 try {
1095                         Object lk = adapt(key, kb, this.kb);
1096                         long insertPos = index.getInsertPos(lk);
1097                         Serializer ks = params.serializerScheme.getSerializer( kb );
1098                         Serializer vs = params.serializerScheme.getSerializer( vb );                    
1099                         long newSize = ks.getSize(key, null) + vs.getSize(value, null);
1100                         
1101                         if (insertPos<0) {                              
1102                                 // Insert new entry
1103                                 // Write
1104                                 long pos = -insertPos;
1105                                 b.position(pos);
1106                                 b.insertBytes(newSize, ByteSide.Neither);
1107                                 b.position(pos);
1108                                 ks.serialize(b, null, key);
1109                                 vs.serialize(b, null, value);
1110                                 
1111                                 // Key variant
1112                                 MutableVariant kv = new MutableVariant(this.kb, lk);
1113                                 
1114                                 // Notify Listeners
1115                                 ListenerEntry le = listeners;
1116                                 while (le!=null) {                              
1117                                         MapInterestSet is = le.getInterestSet();
1118                                         if (is.inNotificationsOf(kv)) {
1119                                                 
1120                                                 MutableVariant vv = null;
1121                                                 if (is.inValuesOf(kv)) vv = new MutableVariant(vb, vb.isImmutable() ? value : vb.clone(value));
1122                                                 
1123                                                 // Notify about new entry
1124                                                 MapEntryAdded e = new MapEntryAdded(kv, vv);
1125                                                 emitEvent(le, e);
1126                                         }
1127                                         
1128                                         le = le.next;
1129                                 }
1130                                 
1131                                 // Optimization for sequential write
1132                                 // Create sub accessor for the last entry
1133                                 if (insertPos==b.length() && constantSize==null) {
1134                                         BinaryObject sa = getChild(lk);
1135                                         if (sa==null) {
1136                                                 // Instantiate correct sub accessor. 
1137                                                 try {
1138                                                         sa = createSubAccessor(vb.type(), pos, newSize, params);
1139                                                         children.put(lk, new SoftReference<BinaryObject>(sa));
1140                                                 } catch (AccessorConstructionException e1) {
1141                                                 }
1142                                         }
1143                                 }
1144                                 
1145                                 return false;
1146                         }
1147                         
1148                         // Replace previous entry                       
1149                         // Write
1150                         Entry e = new Entry(lk, insertPos, null);
1151                         long pos = insertPos;
1152                         long oldSize = index.size(e);
1153                         
1154                         if (oldSize<newSize) {
1155                                 b.position(pos);
1156                                 b.insertBytes(newSize - oldSize, ByteSide.Right);
1157                         } else if (newSize<oldSize) {
1158                                 b.position(pos);
1159                                 b.removeBytes(oldSize - newSize, ByteSide.Right);
1160                         }
1161                         
1162                         b.position(pos);
1163                         ks.serialize(b, null, key);
1164                         vs.serialize(b, null, value);
1165                                                 
1166                         // Notify Listeners
1167                         ListenerEntry le = listeners;
1168                         if (listeners!=null) {
1169                                 MutableVariant kv = new MutableVariant(kb, lk);
1170                                 while (le!=null) {                              
1171                                         MapInterestSet is = le.getInterestSet();
1172                                         if (is.inNotificationsOf(kv)) {
1173                                                 
1174                                                 MutableVariant vv = null;
1175                                                 if (is.inValuesOf(kv)) vv = new MutableVariant(vb, vb.isImmutable() ? value : vb.clone(value));
1176                                                 
1177                                                 // Notify about new entry
1178                                                 Event ev = new ValueAssigned( new KeyReference(kv), vv);
1179                                                 emitEvent(le, ev);
1180                                         }
1181                                         
1182                                         le = le.next;
1183                                 }
1184                         }
1185
1186                         // Update child
1187 //                      BinaryObject sa = getChild(lk);                         
1188 //                      if (sa!=null) {
1189 //                              sa.b.setPositionInSource(pos, newSize);
1190 //                      }
1191                         
1192                         return true;
1193                         
1194                 } catch (AdaptException e1) {
1195                         throw new AccessorException(e1);
1196                 } catch (IOException e) {
1197                         throw new AccessorException(e);
1198                 } catch (RuntimeSerializerConstructionException e) {
1199                         throw new AccessorException(e);
1200                 } catch (AdapterConstructionException e) {
1201                         throw new AccessorException(e);
1202                 } catch (SerializerConstructionException e) {
1203                         throw new AccessorException(e);
1204                 } finally {
1205                         writeUnlock();
1206                 }
1207                 
1208         }
1209
1210         @Override
1211         public void removeNoflush(Binding keyBinding, Object key)
1212                         throws AccessorException {
1213                 assert b.isOpen();
1214                 writeLock();
1215                 try {
1216                         Object lk = params.adapterScheme.getAdapter(keyBinding, kb, true, listeners!=null).adapt(key);
1217                         Entry e = index.getKey(lk);
1218                         if (e==null) return;
1219                         // Write
1220                         int oldSize = size();
1221                         b.position(0L);
1222                         b.writeInt( oldSize - 1 );
1223                         long size = index.size(e);
1224                         b.position(e.pos);
1225                         b.removeBytes(size, ByteSide.Right);
1226                         
1227                         // Disconnect sub-accessor
1228                         BinaryObject sa = getChild(lk);
1229                         // Notify about disconnection of sub-accessor
1230                         if (sa!=null) {
1231                                 sa.invalidatedNotification();
1232                                 children.remove(lk);
1233                         }                               
1234                         
1235                         // Notify Listeners
1236                         if (listeners!=null) {
1237                                 MutableVariant var = new MutableVariant(kb, lk);
1238                                 ListenerEntry le = listeners;
1239                                 while (le!=null) {                              
1240                                         MapInterestSet is = le.getInterestSet();                                
1241                                         if (is.inNotificationsOf(var)) {
1242                                                 MapEntryRemoved e2 = new MapEntryRemoved(var); 
1243                                                 emitEvent(le, e2);
1244                                         }
1245                                                                         
1246                                         le = le.next;
1247                                 }               
1248                         }
1249                         
1250                 } catch (IOException e) {
1251                         throw new AccessorException(e);
1252                 } catch (AdaptException e) {
1253                         throw new AccessorException(e);
1254                 } catch (AdapterConstructionException e) {
1255                         throw new AccessorException(e);
1256                 } finally {
1257                         writeUnlock();
1258                 }
1259         }
1260         
1261         
1262         @Override
1263         public void addListener(Listener listener, InterestSet interestSet,
1264                         ChildReference path, Executor executor) throws AccessorException {
1265                 super.addListener(listener, interestSet, path, executor);
1266                 MapInterestSet is = (MapInterestSet) interestSet;
1267
1268                 for (Object key : children.keySet()) {
1269                         BinaryObject sa = getChild(key);
1270                         if (sa==null) continue;
1271                         
1272                         MutableVariant vkey = new MutableVariant(kb, key);
1273                         InterestSet cis = is.getComponentInterest();
1274                         if (cis!=null) {
1275                                 ChildReference childPath = ChildReference.concatenate( path, new KeyReference(vkey) );
1276                                 sa.addListener(listener, cis, childPath, executor);                             
1277                         }
1278                         cis = is.getComponentInterest( vkey );
1279                         if (cis!=null) {
1280                                 ChildReference childPath = ChildReference.concatenate( path, new KeyReference(vkey) );
1281                                 sa.addListener(listener, cis, childPath, executor);                             
1282                         }
1283                 }               
1284         }               
1285         
1286         @Override
1287         public void removeListener(Listener listener) throws AccessorException {
1288                 ListenerEntry e = detachListener(listener);
1289                 if (e==null) return;
1290                 MapInterestSet is = (MapInterestSet) e.interestSet;
1291                 
1292                 for (Map.Entry<Object, java.lang.ref.Reference<BinaryObject>> entry : children.entrySet()) {
1293                         BinaryObject sa = entry.getValue().get();
1294                         if (sa==null) continue;
1295                         Object key = entry.getKey();
1296                         
1297                         MutableVariant vkey = new MutableVariant(kb, key);
1298                         InterestSet cis = is.getComponentInterest();
1299                         if (cis!=null) {
1300                                 sa.removeListener(listener);                            
1301                         }
1302                         cis = is.getComponentInterest( vkey );
1303                         if (cis!=null) {
1304                                 sa.removeListener(listener);                            
1305                         }
1306                 }
1307                 
1308         }
1309         
1310         @Override
1311         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
1312                 Event rollback = null;
1313                 
1314                 if (e instanceof ValueAssigned) {
1315                         try {
1316                                 ValueAssigned va = (ValueAssigned) e;
1317                                 if (makeRollback) {
1318                                         Binding binding = params.bindingScheme.getBinding(type());
1319                                         rollback = new ValueAssigned(binding, getValue(binding));                               
1320                                 }
1321                                 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
1322                                 return rollback;
1323                         } catch (BindingConstructionException e1) {
1324                                 throw new AccessorException( e1 );
1325                         }
1326                 } else if (e instanceof MapEntryAdded) {
1327                         MapEntryAdded ea = (MapEntryAdded) e;
1328                         if (ea.key==null) throw new AccessorException("Cannot apply entry added event because key is missing");
1329                         if (ea.value==null) throw new AccessorException("Cannot apply entry added event because value is missing");
1330                         boolean hadValue = containsKey(ea.key.getBinding(), ea.key.getValue());
1331                         if (hadValue) throw new AccessorException("Could not add entry to key that already existed");
1332                         
1333                         if (makeRollback) {                             
1334                                 rollback = new MapEntryRemoved( ea.key );
1335                         }
1336                         
1337                         putNoflush(ea.key.getBinding(), ea.key.getValue(), ea.value.getBinding(), ea.value.getValue());
1338                         return rollback;
1339                         
1340                 } else if (e instanceof MapEntryRemoved) {
1341                         MapEntryRemoved er = (MapEntryRemoved) e;
1342                         
1343                         if (makeRollback) {
1344                                 boolean hadValue = containsKey(er.key.getBinding(), er.key.getValue());
1345                                 
1346                                 if (hadValue) {                         
1347                                         Object oldValueObj = get(er.key.getBinding(), er.key.getValue(), vb);
1348                                         MutableVariant oldKey = er.key;
1349                                         MutableVariant oldValue = new MutableVariant(vb, oldValueObj);
1350                                         rollback = new MapEntryAdded(oldKey, oldValue);
1351                                 } else {
1352                                         rollback = new MapEntryRemoved( er.key.clone() );
1353                                 }
1354                         }
1355                         
1356                         removeNoflush( er.key.getBinding(), er.key.getValue() );
1357                         return rollback;
1358                         
1359                 } else {
1360                         throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Map Type");
1361                 }               
1362         }
1363
1364         
1365         
1366         @Override
1367         public void put(Binding keyBinding, Object key, Binding valueBinding,
1368                         Object value) throws AccessorException {
1369                 assert b.isOpen();
1370                 writeLock();
1371                 try {
1372                         putNoflush(keyBinding, key, valueBinding, value);
1373                         b.flush();
1374                 } catch (IOException e) {
1375                         throw new AccessorException(e);
1376                 } finally {
1377                         writeUnlock();
1378                 }
1379         }
1380
1381         @Override
1382         public void putAll(Binding keyBinding, Binding valueBinding,
1383                         Map<Object, Object> from) throws AccessorException {
1384                 assert b.isOpen();
1385                 writeLock();
1386                 try {
1387                         putAllNoflush(keyBinding, valueBinding, from);
1388                         b.flush();
1389                 } catch (IOException e) {
1390                         throw new AccessorException(e);
1391                 } finally {
1392                         writeUnlock();
1393                 }
1394         }
1395
1396         @Override
1397         public void putAll(Binding keyBinding, Binding valueBinding, Object[] keys,
1398                         Object[] values) throws AccessorException {
1399                 assert b.isOpen();
1400                 writeLock();
1401                 try {
1402                         putAllNoflush(keyBinding, valueBinding, keys, values);
1403                         b.flush();
1404                 } catch (IOException e) {
1405                         throw new AccessorException(e);
1406                 } finally {
1407                         writeUnlock();
1408                 }
1409         }
1410
1411         @Override
1412         public void remove(Binding keyBinding, Object key) throws AccessorException {
1413                 assert b.isOpen();
1414                 writeLock();
1415                 try {
1416                         removeNoflush(keyBinding, key);         
1417                         b.flush();
1418                 } catch (IOException e) {
1419                         throw new AccessorException(e);
1420                 } finally {
1421                         writeUnlock();
1422                 }
1423         }
1424         
1425         
1426         /** Interface for a search structure */
1427         abstract class Index {
1428                 /**
1429                  * Get insert pos
1430                  * @param key
1431                  * @return if >0 position of existing entry of same key, <0 insertion position 
1432                  * @throws AccessorException 
1433                  */
1434                 abstract long getInsertPos(Object key) throws AccessorException;
1435
1436                 abstract Entry getKey(Object key) throws AccessorException;             
1437                 abstract Entry floor(Object key) throws AccessorException;
1438                 abstract Entry ceiling(Object key) throws AccessorException;
1439                 abstract Entry higher(Object key) throws AccessorException;
1440                 abstract Entry lower(Object key) throws AccessorException;
1441                 abstract long size(Entry e) throws AccessorException;           
1442                 
1443                 Entry first() throws AccessorException {
1444                         try {
1445                                 b.position(0L);
1446                                 int count = b.readInt();
1447                                 if (count==0) return null;
1448                                 Object k = ks.deserialize(b);
1449                                 java.lang.ref.Reference<BinaryObject> ref = children.get(k);
1450                                 BinaryObject sa = ref == null ? null : ref.get();
1451                                 return new Entry(k, 4, sa);             
1452                         } catch (IOException e) {
1453                                 throw new AccessorException(e);
1454                         }
1455                 }
1456                 
1457                 abstract Entry last() throws AccessorException;
1458                                 
1459         }       
1460         
1461         static class Entry {
1462                 // Optional child accessor
1463                 BinaryObject accessor;
1464                 Object key;
1465                 long pos;
1466                 public Entry(Object key, long pos, BinaryObject accessor) {
1467                         this.key = key; this.pos = pos; this.accessor = accessor;
1468                 }
1469         }
1470
1471         /** Entries are indexed a table */
1472 //      class Table implements Index {          
1473 //      }
1474         
1475         /** Entry size is constant, binary Search */ 
1476         class Constant extends Index {
1477                 
1478                 Entry last() throws AccessorException {
1479                         try {
1480                                 if (b.length()<=4) return null;
1481                                 long pos = b.length() - constantSize;
1482                                 b.position( pos );
1483                                 Object key = ks.deserialize(b);
1484                                 return new Entry(key, pos, null);
1485                         } catch (IOException e) {
1486                                 throw new AccessorException(e);
1487                         }               
1488                 }
1489                 
1490
1491                 @Override
1492                 long getInsertPos(Object key) throws AccessorException {
1493                         try {
1494                                 int count = count();
1495                                 if (count==0) return -4L;                       
1496                                 
1497                                 // Check if it is the last entry
1498                                 long pos = b.length() - constantSize;
1499                                 b.position( pos );
1500                                 Object lastKey = ks.deserialize(b);
1501                                 int c = kb.compare(lastKey, key);
1502                                 if (c<0) return -b.length();
1503                                 if (c==0) return pos;
1504                                 
1505                                 // We can narrow down the search to region between two existing children 
1506                                 Entry fc = floorChildEntry(key);
1507                                 Entry cc = ceilingChildEntry(key);                      
1508                                 
1509                                 int fromIndex = fc == null ? 0 : indexOf(fc);
1510                                 int toIndex = cc == null ? count : indexOf(cc)+1; 
1511                                 
1512                                 // Do binary search                     
1513                                 int r = binarySearch(fromIndex, toIndex, key);
1514                                 if (r>=0) return getPos(r);
1515                                 r=-(r+1);
1516                                 if (r==count) return -b.length();
1517                                 return -getPos(r);
1518                         } catch (IOException e) {
1519                                 throw new AccessorException(e);
1520                         } catch (BindingException e) {
1521                                 throw new AccessorException(e);
1522                         }               
1523                 }       
1524                 
1525                 int indexOf(Entry e) {
1526                         return (int) ((e.pos - 4L) / constantSize);
1527                 }
1528                 int indexOf(long pos) {
1529                         return (int) ((pos - 4L) / constantSize);
1530                 }
1531                 
1532                 
1533                 /**
1534                  * 
1535                  * @param fromIndex
1536                  * @param toIndex exclusive
1537                  * @param key
1538                  * @return
1539                  * @throws AccessorException
1540                  */
1541                 int binarySearch(int fromIndex, int toIndex, Object key) throws AccessorException {
1542                         int low = fromIndex;
1543                         int high = toIndex - 1;
1544         
1545                         while (low <= high) {
1546                             int mid = (low + high) >>> 1;
1547                             Object midVal = getKey(mid);
1548                             int cmp = kb.compare(midVal, key);
1549         
1550                             if (cmp < 0)
1551                                 low = mid + 1;
1552                             else if (cmp > 0)
1553                                 high = mid - 1;
1554                             else
1555                                 return mid; // key found
1556                         }
1557                         return -(low + 1);  // key not found.                   
1558                 }
1559
1560                 @Override
1561                 public Entry getKey(Object key) throws AccessorException {
1562                         BinaryObject sa = getChild(key);
1563                         if (sa!=null) return new Entry(key, sa.b.getStartPositionInSourceBinary(), sa);
1564                         long pos = getInsertPos(key);
1565                         if (pos<0) return null;                 
1566                         return new Entry(key, pos, null);
1567                 }
1568
1569                 @Override
1570                 public long size(Entry e) {                     
1571                         return constantSize;
1572                 }
1573                 
1574                 Object getKey(int index) throws AccessorException {
1575                         try {
1576                                 long pos = 4L + ((long)index) * constantSize;
1577                                 b.position(pos);
1578                                 return ks.deserialize(b);
1579                         } catch (IOException e) {
1580                                 throw new AccessorException(e);
1581                         }               
1582                 }
1583
1584                 Entry getEntry(int index) throws AccessorException {
1585                         try {
1586                                 long pos = 4L + ((long)index) * constantSize;
1587                                 b.position(pos);
1588                                 Object key = ks.deserialize(b);
1589                                 return new Entry(key, pos, null);
1590                         } catch (IOException e) {
1591                                 throw new AccessorException(e);
1592                         }               
1593                 }
1594
1595                 long getPos(int index) {
1596                         return 4L + ((long)index) * constantSize;
1597                 }
1598                 
1599                 int count() throws IOException {
1600                         return (int) ((b.length()-4) / constantSize);
1601                 }
1602                 
1603                 @Override
1604                 Entry ceiling(Object key) throws AccessorException {
1605                         try {
1606                                 long pos = getInsertPos(key);
1607                                 // Exact match
1608                                 if (pos>0) return new Entry(key, pos, getChild(key));
1609                                 pos = -pos;
1610                                 int index = indexOf(pos);
1611                                 if (index>=count()) return null;
1612                                 key = getKeyAt(pos);
1613                                 return new Entry(key, pos, null);
1614                         } catch (IOException e) {
1615                                 throw new AccessorException(e);
1616                         } catch (BindingException e) {
1617                                 throw new AccessorException(e);
1618                         }               
1619                 }
1620
1621                 @Override
1622                 Entry higher(Object key) throws AccessorException {
1623                         try {
1624                                 long pos = getInsertPos(key);
1625         
1626                                 if (pos>0) {
1627                                         // Exact match
1628                                         int index = indexOf(pos)+1;
1629                                         if (index>=count()) return null;
1630                                         pos = getPos(index);
1631                                         key = getKeyAt(pos);
1632                                         return new Entry(key, pos, null);
1633                                 } else {
1634                                         // Insert here match
1635                                         int index = indexOf(-pos);
1636                                         if (index>=count()) return null;
1637                                         pos = getPos(index);
1638                                         key = getKeyAt(pos);
1639                                         return new Entry(key, pos, null);
1640                                 }                       
1641                         } catch (IOException e) {
1642                                 throw new AccessorException(e);
1643                         } catch (BindingException e) {
1644                                 throw new AccessorException(e);
1645                         }               
1646                         
1647                 }
1648
1649                 @Override
1650                 Entry lower(Object key) throws AccessorException {
1651                         try {
1652                                 long pos = getInsertPos(key);
1653                                 // Exact match
1654                                 if (pos>0) {
1655                                         int index = indexOf(pos)-1;
1656                                         if (index<0) return null;
1657                                         pos = getPos(index);
1658                                         key = getKeyAt(pos);
1659                                         return new Entry(key, pos, null);
1660                                 } else {
1661                                         int index = indexOf(-pos)-1;
1662                                         if (index<0) return null;
1663                                         pos = getPos(index);
1664                                         key = getKeyAt(pos);
1665                                         return new Entry(key, pos, null);
1666                                 }
1667                         } catch (IOException e) {
1668                                 throw new AccessorException(e);
1669                         } catch (BindingException e) {
1670                                 throw new AccessorException(e);
1671                         }               
1672                 }
1673
1674                 @Override
1675                 Entry floor(Object key) throws AccessorException {
1676                         try {
1677                                 long pos = getInsertPos(key);
1678                                 // Exact match
1679                                 if (pos>0) return new Entry(key, pos, getChild(key));
1680                                 int index = indexOf(-pos)-1;
1681                                 if (index<0) return null;
1682                                 pos = getPos(index);            
1683                                 key = getKeyAt(pos);
1684                                 return new Entry(key, pos, null);
1685                         } catch (IOException e) {
1686                                 throw new AccessorException(e);
1687                         } catch (BindingException e) {
1688                                 throw new AccessorException(e);
1689                         }               
1690                 }
1691
1692         }
1693         
1694         /** Variable size enetry, Sequential search */
1695         class Sequential extends Index {
1696
1697                 /**
1698                  * Get insert pos
1699                  * @param key
1700                  * @return if >0 position of existing entry of same key, <0 insertion position 
1701                  * @throws AccessorException 
1702                  */
1703                 @Override
1704                 long getInsertPos(Object key) throws AccessorException {
1705                         try {
1706                                 Entry start = floorChildEntry(key);
1707                                 // Exact match
1708                                 if (start !=null && kb.equals(key, start.key)) {
1709                                         return start.pos;
1710                                 }
1711                                 
1712                                 long len = b.length();
1713                                 long pos = start==null ? 4L : start.pos;
1714                                 b.position(pos);
1715                                 while (b.position()<len) {
1716                                         pos = b.position();
1717                                         Object k = ks.deserialize(b, null);
1718                                         int c = kb.compare(key, k);
1719                                         if (c==0) return pos;
1720                                         if (c<0) return -pos;
1721                                         vs.skip(b, null);
1722                                 }
1723                                 return -len;
1724                         } catch (IOException e) {
1725                                 throw new AccessorException(e);
1726                         } catch (BindingException e) {
1727                                 throw new AccessorException(e);
1728                         }               
1729                 }
1730                 
1731                 @Override
1732                 Entry getKey(Object key) throws AccessorException {
1733                         BinaryObject sa = getChild(key);
1734                         if (sa!=null) return new Entry(key, sa.b.getStartPositionInSourceBinary(), sa);
1735                         
1736                         long pos = getInsertPos(key);
1737                         if (pos<0) return null;
1738                         return new Entry(key, pos, null);
1739                 }
1740
1741                 @Override
1742                 Entry last() throws AccessorException {
1743                         try {
1744                                 Entry e = lastChildEntry();     
1745                                 long startPos = e!=null ? e.pos : 4L;
1746                                 b.position(startPos);
1747                                 Entry result = e!=null ? new Entry(e.key, e.pos, e.accessor) : new Entry(null, 0, null);
1748                                 while (b.position() < b.length()) {
1749                                         result.key = ks.deserialize(b, null);
1750                                         result.pos = b.position();                                      
1751                                         vs.skip(b, null);
1752                                         long valueLen = b.position() - result.pos;
1753                                         result.accessor = createSubAccessor(vb.type(), result.pos, valueLen, params);
1754                                         children.put(result.key, new SoftReference<BinaryObject>( result.accessor ));
1755                                 }
1756                                 return (result.key == null) ? null : result;
1757                         } catch (IOException e) {
1758                                 throw new AccessorException(e);
1759                         } catch (BindingException e) {
1760                                 throw new AccessorException(e);
1761                         } catch (AccessorConstructionException e) {
1762                                 throw new AccessorException(e);
1763                         }
1764                 }
1765
1766                 @Override
1767                 long size(Entry e) throws AccessorException {
1768                         try {
1769                                 long keyLen;
1770                                 if (ks.getConstantSize()!=null) {
1771                                         keyLen = ks.getConstantSize();
1772                                 } else {
1773                                         b.position(e.pos);
1774                                         ks.skip(b, null);
1775                                         keyLen = b.position() - e.pos;
1776                                 }
1777                                 
1778                                 long valueLen;                          
1779                                 if (e.accessor!=null) {
1780                                         valueLen = e.accessor.b.length();
1781                                 } else if (vs.getConstantSize()!=null) {
1782                                         valueLen = vs.getConstantSize();
1783                                 } else {
1784                                         long pos = e.pos + keyLen;
1785                                         b.position(pos);
1786                                         vs.skip(b, null);
1787                                         valueLen = b.position() - pos; 
1788                                 }
1789                                 return keyLen + valueLen;
1790                         } catch (IOException e1) {
1791                                 throw new AccessorException(e1);
1792                         }
1793                 }
1794
1795                 @Override
1796                 Entry ceiling(Object key) throws AccessorException {
1797                         try {
1798                                 long pos = getInsertPos(key);
1799                                 // Exact match
1800                                 if (pos>0) return new Entry(key, pos, getChild(key));
1801                                 pos = -pos;
1802                                 return getEntryAt(pos);
1803                         } catch (IOException e) {
1804                                 throw new AccessorException(e);
1805                         } catch (BindingException e) {
1806                                 throw new AccessorException(e);
1807                         }
1808                 }
1809
1810                 @Override
1811                 Entry higher(Object key) throws AccessorException {
1812                         try {
1813                                 long pos = getInsertPos(key);
1814                                 // Exact match
1815                                 if (pos>0) {
1816                                         if (pos>=b.length()) return null;
1817                                         b.position(pos);
1818                                         ks.skip(b, null);
1819                                         vs.skip(b, null);
1820                                         return getEntryAt(b.position());
1821                                 }
1822                                 pos = -pos;
1823                                 return getEntryAt(pos);
1824                         } catch (IOException e) {
1825                                 throw new AccessorException(e);
1826                         } catch (BindingException e) {
1827                                 throw new AccessorException(e);
1828                         }               
1829                 }
1830
1831                 @Override
1832                 Entry lower(Object key) throws AccessorException {
1833                         try {
1834                                 Entry start = lowerChildEntry(key);
1835                                 long len = b.length();
1836                                 long pos = start==null ? 4L : start.pos;
1837                                 long prevPos = 0;
1838                                 Object k = null;
1839                                 Object prevK = null;
1840                                 b.position(pos);
1841                                 while (b.position()<len) {
1842                                         prevPos = pos;
1843                                         pos = b.position();
1844                                         prevK = k;
1845                                         k = ks.deserialize(b, null);
1846                                         long valuePos = b.position();
1847                                         
1848                                         // Compare current key with search key
1849                                         int c = kb.compare(key, k);
1850                                         if (c<=0) {
1851                                                 if (prevK==null) return null;
1852                                                 return new Entry(prevK, prevPos, null);
1853                                         }
1854                                         vs.skip(b, null);
1855                                         long valueLen = b.position() - valuePos;
1856                                         assert(valueLen>=0);
1857                                         java.lang.ref.Reference<BinaryObject> ref = children.get(k);
1858                                         BinaryObject sa = ref!=null?ref.get():null;
1859                                         if (sa==null) {
1860                                                 sa = createSubAccessor(vb.type(), valuePos, valueLen, params);
1861                                                 children.put(k, new SoftReference<BinaryObject>(sa));
1862                                         }                                       
1863                                 }
1864                                 // There was no match, return the last entry
1865                                 return new Entry(k, pos, null); 
1866                         } catch (IOException e) {
1867                                 throw new AccessorException(e);
1868                         } catch (BindingException e) {
1869                                 throw new AccessorException(e);
1870                         } catch (AccessorConstructionException e) {
1871                                 throw new AccessorException(e);
1872                         }                       
1873                 }
1874
1875                 @Override
1876                 Entry floor(Object key) throws AccessorException {
1877                         try {                   
1878                                 Entry start = floorChildEntry(key);
1879                                 // Exact match
1880                                 if (start !=null && kb.equals(key, start.key)) {
1881                                         return start;
1882                                 }
1883                                                                 
1884                                 long len = b.length();
1885                                 long pos = start==null ? 4L : start.pos;
1886                                 long prevPos = 0;
1887                                 Object k = null;
1888                                 Object prevK = null;
1889                                 BinaryObject prevAccessor = null;
1890                                 b.position(pos);
1891                                 while (b.position()<len) {
1892                                         prevPos = pos;
1893                                         pos = b.position();
1894                                         prevK = k;
1895                                         k = ks.deserialize(b, null);
1896                                         long valuePos = b.position();
1897                                         
1898                                         int c = kb.compare(key, k);
1899                                         // Went over
1900                                         if (c<0) {
1901                                                 if (prevK==null) return null;
1902                                                 return new Entry(prevK, prevPos, prevAccessor);
1903                                         }
1904                                         vs.skip(b, null);
1905                                         long valueLen = valuePos - pos;
1906                                         java.lang.ref.Reference<BinaryObject> ref = children.get(k);
1907                                         BinaryObject sa = ref!=null?ref.get():null;
1908                                         if (sa==null) {
1909                                                 prevAccessor = createSubAccessor(vb.type(), valuePos, valueLen, params);
1910                                                 children.put(k, new SoftReference<BinaryObject>(prevAccessor));
1911                                         }
1912                                         // Exact match
1913                                         if (c==0) {
1914                                                 return new Entry(k, pos, prevAccessor);
1915                                         }                                       
1916                                 }
1917                                 return new Entry(k, pos, prevAccessor); 
1918                         } catch (IOException e) {
1919                                 throw new AccessorException(e);
1920                         } catch (BindingException e) {
1921                                 throw new AccessorException(e);
1922                         } catch (AccessorConstructionException e) {
1923                                 throw new AccessorException(e);
1924                         }
1925                 }
1926         }
1927         
1928 }
1929