]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/binary/BinaryVariant.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / binary / BinaryVariant.java
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\r
4  *  All rights reserved. This program and the accompanying materials\r
5  *  are made available under the terms of the Eclipse Public License v1.0\r
6  *  which accompanies this distribution, and is available at\r
7  *  http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.accessor.binary;
13
14 import gnu.trove.map.hash.TObjectIntHashMap;\r
15 \r
16 import java.io.IOException;\r
17 import java.lang.ref.SoftReference;\r
18 import java.util.ArrayList;\r
19 import java.util.List;\r
20 import java.util.concurrent.Executor;\r
21 \r
22 import org.simantics.databoard.Bindings;\r
23 import org.simantics.databoard.Datatypes;\r
24 import org.simantics.databoard.accessor.Accessor;\r
25 import org.simantics.databoard.accessor.VariantAccessor;\r
26 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
27 import org.simantics.databoard.accessor.error.AccessorException;\r
28 import org.simantics.databoard.accessor.event.Event;\r
29 import org.simantics.databoard.accessor.event.ValueAssigned;\r
30 import org.simantics.databoard.accessor.file.FileVariantAccessor;\r
31 import org.simantics.databoard.accessor.impl.AccessorParams;\r
32 import org.simantics.databoard.accessor.impl.ListenerEntry;\r
33 import org.simantics.databoard.accessor.interestset.InterestSet;\r
34 import org.simantics.databoard.accessor.interestset.VariantInterestSet;\r
35 import org.simantics.databoard.accessor.reference.ChildReference;\r
36 import org.simantics.databoard.accessor.reference.ComponentReference;\r
37 import org.simantics.databoard.accessor.reference.LabelReference;\r
38 import org.simantics.databoard.adapter.AdaptException;\r
39 import org.simantics.databoard.binding.Binding;\r
40 import org.simantics.databoard.binding.VariantBinding;\r
41 import org.simantics.databoard.binding.error.BindingConstructionException;\r
42 import org.simantics.databoard.binding.error.BindingException;\r
43 import org.simantics.databoard.binding.mutable.MutableVariant;\r
44 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
45 import org.simantics.databoard.serialization.Serializer;\r
46 import org.simantics.databoard.serialization.SerializerConstructionException;\r
47 import org.simantics.databoard.type.Datatype;\r
48 import org.simantics.databoard.type.VariantType;\r
49 import org.simantics.databoard.util.binary.Blob;\r
50
51 public class BinaryVariant extends BinaryObject implements VariantAccessor, FileVariantAccessor {
52
53         static Datatype type_type = Datatypes.getDatatypeUnchecked( Datatype.class ); 
54         static Binding type_binding = Bindings.getBindingUnchecked( Datatype.class );
55         static Serializer type_serializer = Bindings.getSerializerUnchecked( type_binding );
56         
57         SoftReference<BinaryObject> child;      
58         
59         public BinaryVariant(BinaryObject parent, Blob blob, Datatype type, AccessorParams params) {
60                 super(parent, blob, type, params);
61         }
62         
63         public VariantType type() {
64                 return (VariantType) type;
65         }
66
67         @SuppressWarnings("unchecked")
68         @Override
69         public <T extends Accessor> T getContentAccessor()
70                         throws AccessorConstructionException {\r
71                 assert b.isOpen();\r
72                 readLock();
73                 try {
74                         BinaryObject sa = getExistingAccessor();
75                         if (sa==null) {
76                                 // Create new child                             
77                                 b.position(0L);
78                                 List<Object> ids = new ArrayList<Object>(0);
79                                 Datatype type = (Datatype) type_serializer.deserialize(b, ids);                         
80                                 sa = createSubAccessor(type, b.position(), b.length()-b.position(), params);                            
81                                 child = new SoftReference<BinaryObject>(sa);
82                                 
83                                 // Attach listeners of interest set to the new accessor (of the value)
84                                 ListenerEntry le = listeners;
85                                 while (le!=null) {                              
86                                         VariantInterestSet is = le.getInterestSet();
87                                         InterestSet cis = is.getComponentInterest();
88                                         if (cis != null) {
89                                                 try {
90                                                         ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
91                                                         sa.addListener(le.listener, cis, childPath, le.executor);
92                                                 } catch (AccessorException e) {
93                                                         throw new AccessorConstructionException(e);
94                                                 }
95                                         }
96                                         if (is.inCompleteComponent()) {
97                                                 cis = InterestSet.newInterestSet(getContentType(), true, true, true);
98                                                 try {
99                                                         ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
100                                                         sa.addListener(le.listener, cis, childPath, le.executor);
101                                                 } catch (AccessorException e) {
102                                                         throw new AccessorConstructionException(e);
103                                                 }
104                                         }
105                                         le = le.next;
106                                 }                                                               
107                         }
108                         return (T) sa;
109                 } catch (IOException e) {
110                         throw new AccessorConstructionException(e);
111                 } catch (AccessorException e) {
112                         throw new AccessorConstructionException(e);
113                 } finally {\r
114                         readUnlock();\r
115                 }
116         }
117                 
118         protected BinaryObject getExistingAccessor() {\r
119                 SoftReference<BinaryObject> r = child;
120                 if (r==null) return null;
121                 BinaryObject sa = r.get();
122                 return sa;
123         }               
124
125         @Override
126         public void setContentValueNoflush(Binding valueBinding, Object value)
127                         throws AccessorException {\r
128                 assert b.isOpen();\r
129                 writeLock();
130                 try {
131                         // reuse sub-accessor, if type matches, and sub-accessor exists
132                         BinaryObject sa = getExistingAccessor();
133                         if (sa!=null && valueBinding.type().equals(sa.type())) {
134                                 sa.setValue(valueBinding, value);
135                                 return;
136                         }
137                         
138                         {
139                                 // Replace the old value with a new value
140                                 if (sa!=null) {
141                                         sa.invalidatedNotification();
142                                         child = null;
143                                         sa = null;
144                                 }
145                                 
146                                 // Write                                
147                                 Binding cb = valueBinding;
148                                 Serializer cs = params.serializerScheme.getSerializer( cb );
149                                 Datatype ct = valueBinding.type();
150                                 Object cv = value;
151
152                                 TObjectIntHashMap<Object> ids = new TObjectIntHashMap<Object>(0);
153                                 int len = type_serializer.getSize(ct, ids);
154                                 len += cs.getSize(cv, null);
155                                 
156                                 b.setLength(len);
157                                 b.position(0L);
158                                 ids.clear();
159                                 type_serializer.serialize(b, ids, ct);
160                                 cs.serialize(b, null, cv);
161                                 
162                                 // Notify Listeners
163                                 ListenerEntry le = listeners;
164                                 while (le!=null) {                              
165                                         VariantInterestSet is = le.getInterestSet();
166                                         if (is.inNotifications()) {
167                                                 MutableVariant v = null;
168                                                 if (is.inValues()) v = new MutableVariant(valueBinding, valueBinding.isImmutable() ? value : valueBinding.clone(value));
169                                                 ValueAssigned e = new ValueAssigned( Bindings.MUTABLE_VARIANT, v );
170                                                 emitEvent(le, e);
171                                         }
172                                         
173                                         // Attach component listener
174 //                                      boolean hadSa = getExistingAccessor()!=null;
175 //                                      if (!hadSa) {
176 //                                              InterestSet cis = is.getComponentInterest();
177 //                                              if (cis!=null) {
178 //                                                      sa = getValueAccessor();
179 //                                              }
180 //                                      }
181                                         
182                                         le = le.next;
183                                 }
184                         }
185                         
186                 } catch (IOException e) {
187                         throw new AccessorException( e );
188                 } catch (AdaptException e) {
189                         throw new AccessorException( e );
190                 } catch (SerializerConstructionException e) {\r
191                         throw new AccessorException( e );\r
192                 } finally {\r
193                         writeUnlock();\r
194                 }
195         }
196         
197         @Override
198         public void setContentValue(Binding valueBinding, Object value)
199                         throws AccessorException {      \r
200                 assert b.isOpen();\r
201                 writeLock();\r
202                 try {
203                         setContentValueNoflush(valueBinding, value);
204                         flush();\r
205                 } finally {\r
206                         writeUnlock();\r
207                 }
208         }
209         
210         @Override
211         public Datatype getContentType() throws AccessorException {\r
212                 assert b.isOpen();\r
213                 readLock();
214                 try {
215                         b.position(0L);
216                         List<Object> ids = new ArrayList<Object>(0);                    
217                         Datatype type = (Datatype) type_serializer.deserialize(b, ids);
218                         return type;
219                 } catch (IOException e) {
220                         throw new AccessorException( e );
221                 } finally {\r
222                         readUnlock();\r
223                 }
224         }
225         
226         @Override
227         public Object getContentValue(Binding contentBinding)
228                         throws AccessorException {\r
229                 assert b.isOpen();\r
230                 readLock();
231                 try {
232                         b.position(0L);
233                         List<Object> ids = new ArrayList<Object>();
234                         Datatype type = (Datatype) type_serializer.deserialize(b, ids);
235                         ids.clear();
236                         
237                         if (!contentBinding.type().equals(type)) {
238                                 throw new AccessorException("Arg error, wrong type");
239                         }
240                         Serializer value_serializer = params.serializerScheme.getSerializer( contentBinding );
241                         return value_serializer.deserialize(b, ids);
242                         
243                         // The requested binding is a super type binding
244                         // Read the to the actual type and adapt
245                                                 
246 //                      Binding lcb = params.bindingFactory.getBinding(type);
247 //                      Binding rcb = contentBinding;
248 //                      Object lv = lcb.serializer().deserialize(b, ids);                       
249 //                      
250 //                      return adapt(lv, lcb, rcb);
251                 } catch (IOException e) {
252                         throw new AccessorException( e );
253                 } catch (SerializerConstructionException e) {\r
254                         throw new AccessorException( e );\r
255                 } finally {\r
256                         readUnlock();\r
257                 }
258         }
259
260         @SuppressWarnings("unchecked")
261         @Override
262         public <T extends Accessor> T getComponent(ChildReference reference)
263                         throws AccessorConstructionException {
264                 if (reference==null) return (T) this;\r
265                 
266                 if (reference instanceof LabelReference) {\r
267                         LabelReference lr = (LabelReference) reference;\r
268                         if (lr.label.equals("v")) {\r
269                                 Accessor sa = getContentAccessor();\r
270                                 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
271                                 return (T) sa;\r
272                         }                       \r
273                 }               \r
274                 \r
275                 if (reference instanceof ComponentReference) {\r
276                         Accessor sa = getContentAccessor();\r
277                         if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
278                         return (T) sa;\r
279                 }\r
280                 \r
281                 throw new AccessorConstructionException("Variant value reference expected, got "+reference.getClass().getName());\r
282         }
283
284         @Override
285         public void addListener(Listener listener, InterestSet interestSet,
286                         ChildReference path, Executor executor) throws AccessorException {
287                 super.addListener(listener, interestSet, path, executor);
288                 VariantInterestSet is = (VariantInterestSet) interestSet;
289                 InterestSet cis = is.getComponentInterest();
290                 if (cis==null && !is.inCompleteComponent()) return;
291                 BinaryObject sa = getExistingAccessor();
292                 if (sa==null) return;
293                 if (cis!=null) {
294                         ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
295                         sa.addListener(listener, cis, childPath, executor);
296                 }
297                 if (is.inCompleteComponent()) {
298                         ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
299                         cis = InterestSet.newInterestSet(getContentType(), true, true, true);
300                         sa.addListener(listener, cis, childPath, executor);
301                 }
302         }
303         
304         @Override
305         public void removeListener(Listener listener) throws AccessorException {
306                 ListenerEntry e = detachListener(listener);
307                 if (e==null) return;
308                 VariantInterestSet is = (VariantInterestSet) e.interestSet;
309                 
310                 InterestSet cis = is.getComponentInterest();
311                 if (cis==null && !is.inCompleteComponent()) return;
312                 BinaryObject sa = getExistingAccessor();
313                 if (sa==null) return;
314                 if (cis!=null) {
315                         sa.removeListener(listener);
316                 }
317                 // Remove another?
318                 if (is.inCompleteComponent()) {
319                         sa.removeListener(listener);
320                 }               
321         }
322         
323         @Override
324         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
325                 try {
326                         if (e instanceof ValueAssigned ) {
327                                 Event rollback = null;\r
328                                 ValueAssigned va = (ValueAssigned) e; 
329                                 if (va.newValue==null) throw new AccessorException("Cannot apply variant assignment event, the value is missing");
330                                 
331                                 if (makeRollback) {
332                                         b.position(0L);
333                                         List<Object> ids = new ArrayList<Object>();
334                                         Datatype type = (Datatype) type_serializer.deserialize(b, ids);
335                                         Binding cb = params.bindingScheme.getBinding(type);
336                                         Serializer value_serializer = params.serializerScheme.getSerializer( cb );
337                                         Object lv = value_serializer.deserialize(b, ids);                       
338                                         
339                                         rollback = new ValueAssigned( Bindings.MUTABLE_VARIANT, new MutableVariant( cb, lv ));
340                                 }
341         
342                                 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());\r
343 //                              setContentValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
344                                 
345                                 return rollback;\r
346                         } else {\r
347                                 throw new AccessorException("Invalid event "+e.getClass().getName());                           \r
348                         }
349                 } catch (IOException ioe) {
350                         throw new AccessorException(ioe);
351                 } catch (RuntimeSerializerConstructionException rsce) {
352                         throw new AccessorException(rsce);\r
353                 } catch (SerializerConstructionException e2) {                  \r
354                         throw new AccessorException(e2);\r
355                 } catch (BindingConstructionException e2) {\r
356                         throw new AccessorException(e2);\r
357                 }
358         }
359
360         @Override
361         public void setValueNoflush(Binding variantBinding, Object variantValue)
362                         throws AccessorException {\r
363                 assert b.isOpen();\r
364                 writeLock();
365                 try {
366                         VariantBinding vb = (VariantBinding) variantBinding;
367                         Object vv = variantValue;
368                         Binding cb = vb.getContentBinding(vv);
369                         Object cv = vb.getContent(vv, cb);                      
370                         setContentValueNoflush(cb, cv);
371                 } catch (BindingException e) {
372                         throw new AccessorException( e ); 
373                 } finally {\r
374                         writeUnlock();\r
375                 }
376         }
377         
378         
379 }
380