]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/MapSerializer.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / serialization / impl / MapSerializer.java
1 package org.simantics.databoard.serialization.impl;
2
3 import gnu.trove.map.hash.TObjectIntHashMap;
4
5 import java.io.DataInput;
6 import java.io.DataOutput;
7 import java.io.IOException;
8 import java.util.List;
9 import java.util.TreeSet;
10
11 import org.simantics.databoard.binding.MapBinding;
12 import org.simantics.databoard.binding.error.BindingException;
13 import org.simantics.databoard.binding.util.IsReferableQuery;
14 import org.simantics.databoard.binding.util.Result;
15 import org.simantics.databoard.serialization.SerializationException;
16 import org.simantics.databoard.serialization.Serializer;
17 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;
18
19 public class MapSerializer extends CompositeSerializer {
20
21         Integer fixedSizeOfKey, fixedSizeOfValue, fixedSizeOfEntry;
22         public Serializer keySerializer, valueSerializer;
23         MapBinding binding;
24         
25         /**
26          * 
27          * @param binding
28          * @param keySerializer (optional) can be set later
29          * @param valueSerializer (optional) can be set later
30          */
31         public MapSerializer(MapBinding binding, Serializer keySerializer, Serializer valueSerializer) {
32                 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
33                 this.keySerializer = keySerializer;
34                 this.valueSerializer = valueSerializer;
35                 this.binding = binding;
36                 
37         }
38         
39         @Override
40         public void finalizeConstruction() {
41                 fixedSizeOfKey = keySerializer.getConstantSize();
42                 fixedSizeOfValue = valueSerializer.getConstantSize();
43                 fixedSizeOfEntry = (fixedSizeOfKey!=null && fixedSizeOfValue!=null) ? (fixedSizeOfKey+fixedSizeOfValue) : null; 
44         }
45
46         @Override
47         public Object deserialize(DataInput in, List<Object> identities) throws IOException{
48                 try {
49                         int length = in.readInt();
50                         if (length<0) throw new SerializationException("Cannot use negative array length");
51                         assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
52                         
53                         Object keys[] = new Object[length];
54                         Object values[] = new Object[length];
55                                                 
56                         for(int i=0;i<length;++i) {
57                                 keys[i] = keySerializer.deserialize(in, identities);
58                                 values[i] = valueSerializer.deserialize(in, identities);                                
59                         }
60                         return binding.create(keys, values);
61                 } catch (BindingException e) {
62                         throw new IOException( e ); 
63                 }                       
64         }
65         
66         @Override
67         public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
68                 try {
69                         TreeSet<Object> oldKeys = new TreeSet<Object>( binding.getKeyBinding() );
70                         binding.getKeys(obj, oldKeys);
71                         
72                         int length = in.readInt();
73                         if (length<0) throw new SerializationException("Cannot use negative array length");
74                         assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
75                         
76                         for(int i=0;i<length;++i) {
77                                 Object key = keySerializer.deserialize(in, identities);
78                                 Object value = valueSerializer.deserialize(in, identities);
79                                 binding.put(obj, key, value);
80                                 oldKeys.remove(key);
81                         }
82                         
83                         // remove unused keys
84                         for (Object key : oldKeys)
85                                 binding.remove(obj, key);
86                 } catch (BindingException e) {
87                         throw new IOException( e ); 
88                 }
89                         
90         }
91         
92         @Override
93         public void skip(DataInput in, List<Object> identities)
94         throws IOException, SerializationException {
95                 int length = in.readInt();
96                 if (fixedSizeOfEntry!=null) {
97                         in.skipBytes( length * fixedSizeOfEntry );
98                         return;
99                 }
100                 for(int i=0;i<length;++i) {
101                         if (fixedSizeOfKey!=null) {
102                                 in.skipBytes(fixedSizeOfKey);
103                         } else {
104                                 keySerializer.skip(in, identities);
105                         }
106                         
107                         if (fixedSizeOfValue!=null) {
108                                 in.skipBytes(fixedSizeOfValue);
109                         } else {
110                                 valueSerializer.skip(in, identities);
111                         }
112                 }
113         }
114
115         @Override
116         public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object map) throws IOException {
117                 try {
118                         int length = binding.size(map);
119                         //if (binding.isOrderedMap(map)) 
120                         {
121                                 Object[] keys = new Object[length];
122                                 Object[] values = new Object[length];
123                                 binding.getAll(map, keys, values);
124                                 out.writeInt(length);
125                                 for(int i=0;i<length;++i) {
126                                         Object key = keys[i];
127                                         Object value = values[i];
128                                         keySerializer.serialize(out, identities, key);
129                                         valueSerializer.serialize(out, identities, value);                              
130                                 }
131                         }
132                         /*
133                         else {
134                                 // Sort keys by putting into a treemap
135                                 TreeMap<Object, Object> copyMap = new TreeMap<Object, Object>(binding.getKeyBinding());
136                                 binding.getAll(map, copyMap);
137                                 Iterator<Entry<Object, Object>> iter = copyMap.entrySet().iterator();
138                                 putLength(out, length);
139                                 while (iter.hasNext()) {
140                                         Entry<Object, Object> e = iter.next();
141                                         Object key = e.getKey();
142                                         Object value = e.getValue();
143                                         keySerializer.serialize(out, identities, key);
144                                         valueSerializer.serialize(out, identities, value);                              
145                                 }
146                         }*/
147                 } catch (BindingException e) {
148                         throw new IOException( e ); 
149                 }
150         }
151
152         @Override
153         public Integer getConstantSize() {
154                 return null;
155         }
156
157         @Override
158         public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
159                 try {
160                         int length = binding.size(obj);
161                         if (fixedSizeOfEntry!=null)
162                                 return 4 + fixedSizeOfEntry * length;
163                         int result = 4;
164                         Object keys[] = binding.getKeys(obj);
165                         for(int i=0;i<length;++i) {
166                                 Object key = keys[i];
167                                 Object value = binding.get(obj, key);
168                                 result += keySerializer.getSize(key, identities);
169                                 result += valueSerializer.getSize(value, identities);
170                         }
171                         return result;
172                 } catch (BindingException e) {
173                         throw new IOException( e ); 
174                 }
175         }
176
177         @Override
178         public int getMinSize() {
179                 return 4;
180         }
181         
182 }