]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/ArraySerializer.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / serialization / impl / ArraySerializer.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.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
11
12 import org.simantics.databoard.binding.ArrayBinding;
13 import org.simantics.databoard.binding.Binding;
14 import org.simantics.databoard.binding.error.BindingException;
15 import org.simantics.databoard.binding.impl.ArrayListBinding;
16 import org.simantics.databoard.binding.util.IsReferableQuery;
17 import org.simantics.databoard.binding.util.Result;
18 import org.simantics.databoard.serialization.SerializationException;
19 import org.simantics.databoard.serialization.Serializer;
20 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;
21 import org.simantics.databoard.type.ArrayType;
22 import org.simantics.databoard.util.Range;
23
24 public class ArraySerializer extends CompositeSerializer {
25
26         Range length;
27         Integer fixedLength;
28         Integer fixedSize;
29         Integer fixedSizeOfComponent;
30         public Serializer componentSerializer;
31         boolean componentImmutable;
32         ArrayBinding binding;
33         DefaultValueIterator componentValueItr;
34         
35         /**
36          * 
37          * @param binding
38          * @param componentSerializer (optional) can be set after
39          */
40         public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {
41                 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
42                 ArrayType arrayType = (ArrayType) binding.type();
43                 this.componentSerializer = componentSerializer;
44                 this.binding = binding;
45                 this.length = arrayType.getLength();
46                 this.componentImmutable = binding.getComponentBinding().isImmutable();
47                 this.componentValueItr = new DefaultValueIterator();
48                 componentValueItr.binding = binding.componentBinding;
49         }
50         
51         @Override
52         public void finalizeConstruction() {
53                 fixedSizeOfComponent = componentSerializer.getConstantSize();
54                 if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)
55                 {
56                         fixedLength = length.getLower().getValue().intValue();
57                         fixedSize = fixedLength * fixedSizeOfComponent;
58                 }               
59         }
60
61         @Override
62         public Object deserialize(DataInput in, List<Object> identities) throws IOException {
63                 try {
64                         int length = fixedLength != null ? fixedLength : in.readInt();  
65                         if (length<0) throw new SerializationException("Cannot use negative array length");
66                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      
67
68                         ArrayList<Object> temp = new ArrayList<Object>(length);
69                         for(int i=0;i<length;++i)
70                                 temp.add(componentSerializer.deserialize(in, identities));
71                         return binding instanceof ArrayListBinding ? temp : binding.create(temp);
72                 } catch (BindingException e) {
73                         throw new IOException( e ); 
74                 }
75         }
76         
77         public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException
78         {
79                 try {
80                         int length = fixedLength != null ? fixedLength : in.readInt();
81                         if (length<0) throw new SerializationException("Cannot use negative array length");
82                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      
83                         
84                         int oldLen = binding.size(obj);
85                         
86                         if (oldLen!=length) {
87                                 if ( binding.isResizable() ) {
88                                         binding.setSize(obj, length);
89                                 } else {
90                                         obj = binding.create(length, componentValueItr);
91                                         oldLen = length;
92                                 }
93                         }
94                         
95                         if ( componentImmutable ) {
96                                 for(int i=0;i<length;i++) {
97                                         Object component = componentSerializer.deserialize(in, identities);
98                                         binding.set(obj, i, component);
99                                 }
100                         } else {
101                                 for(int i=0;i<length;i++) {
102                                         Object component = binding.get(obj, i);
103                                         component = componentSerializer.deserializeToTry(in, identities, component);
104                                         binding.set(obj, i, component); 
105                                 }
106                                 if (oldLen>length) binding.setSize(obj, length);                                
107                         }
108                         
109                         return obj;
110                 } catch (BindingException e) {
111                         throw new IOException( e ); 
112                 }
113                 
114         }       
115
116         @Override
117         public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
118                 try {
119                         int length = fixedLength != null ? fixedLength : in.readInt();
120                         if (length<0) throw new SerializationException("Cannot use negative array length");
121                         assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());                      
122                         
123                         int oldLen = binding.size(obj);
124                         
125                         if (oldLen!=length) {
126                                 if ( binding.isResizable() ) {
127                                         binding.setSize(obj, length);
128                                 } else {
129                                         throw new IOException("Cannot resize array");
130                                 }
131                         }
132                         
133                         if ( componentImmutable ) {
134                                 for(int i=0;i<length;i++) {
135                                         Object component = componentSerializer.deserialize(in, identities);
136                                         binding.set(obj, i, component);
137                                 }
138                         } else {
139                                 for(int i=0;i<length;i++) {
140                                         Object component = binding.get(obj, i);
141                                         component = componentSerializer.deserializeToTry(in, identities, component);
142                                         binding.set(obj, i, component); 
143                                 }
144                                 if (oldLen>length) binding.setSize(obj, length);                                
145                         }
146                 } catch (BindingException e) {
147                         throw new IOException( e ); 
148                 }               
149         }
150         
151         @Override
152         public void skip(DataInput in, List<Object> identities)
153         throws IOException {
154                 if (fixedSize!=null) {
155                         in.skipBytes(fixedSize);
156                         return;
157                 }
158                 int length = fixedLength != null ? fixedLength : in.readInt();
159                 
160                 if (fixedSizeOfComponent!=null) {
161                         // Skip all elements
162                         in.skipBytes(length * fixedSizeOfComponent);
163                 } else {
164                         // Skip each element individualy
165                         for(int i=0;i<length;++i)
166                                 componentSerializer.skip(in, identities);
167                 }
168         }
169
170         @Override
171         public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {
172                 try {
173                         int length = binding.size(obj);
174                         if (fixedLength==null) {
175                                 out.writeInt(length);
176                         } else { 
177                                 if (length!=fixedLength)
178                                         throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);
179                         }
180                         
181                         // Serialize elements
182                         for(int i=0;i<length;++i)
183                                 componentSerializer.serialize(out, identities, binding.get(obj, i));
184                 } catch (BindingException e) {
185                         throw new IOException( e ); 
186                 }
187         }
188
189         @Override
190         public Integer getConstantSize() {
191                 return fixedSize;
192         }
193
194         @Override
195         public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
196                 try {
197                         if (fixedSize!=null) return fixedSize;
198                         int length = binding.size(obj);
199                         if (fixedSizeOfComponent!=null)
200                                 return 4 + fixedSizeOfComponent * length;
201                         int result = 4;
202                         for(int i=0;i<length;++i)
203                                 result += componentSerializer.getSize(binding.get(obj, i), identities);
204                         return result;
205                 } catch (BindingException e) {
206                         throw new IOException( e ); 
207                 }
208         }
209
210         @Override
211         public int getMinSize() {
212                 return fixedSize != null ? fixedSize : 4;
213         }
214         
215 }
216
217 /**
218  * Default value iterator iterates default values.
219  * The iterator is infinite.
220  * 
221  * @author toni.kalajainen
222  */
223 class DefaultValueIterator implements Iterator<Object> {
224         
225         Binding binding;
226
227         @Override
228         public boolean hasNext() {
229                 return true;
230         }
231
232         @Override
233         public Object next() {
234                 try {
235                         return binding.createDefault();
236                 } catch (BindingException e) {
237                         return null;
238                 }
239         }
240
241         @Override
242         public void remove() {
243         }
244         
245 }