1 /*******************************************************************************
2 * Copyright (c) 2010 Association for Decentralized Information Management in
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard.accessor.binary;
14 import gnu.trove.map.hash.TObjectIntHashMap;
16 import java.io.IOException;
17 import java.lang.ref.SoftReference;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.Executor;
22 import org.simantics.databoard.Bindings;
23 import org.simantics.databoard.Datatypes;
24 import org.simantics.databoard.accessor.Accessor;
25 import org.simantics.databoard.accessor.VariantAccessor;
26 import org.simantics.databoard.accessor.error.AccessorConstructionException;
27 import org.simantics.databoard.accessor.error.AccessorException;
28 import org.simantics.databoard.accessor.event.Event;
29 import org.simantics.databoard.accessor.event.ValueAssigned;
30 import org.simantics.databoard.accessor.file.FileVariantAccessor;
31 import org.simantics.databoard.accessor.impl.AccessorParams;
32 import org.simantics.databoard.accessor.impl.ListenerEntry;
33 import org.simantics.databoard.accessor.interestset.InterestSet;
34 import org.simantics.databoard.accessor.interestset.VariantInterestSet;
35 import org.simantics.databoard.accessor.reference.ChildReference;
36 import org.simantics.databoard.accessor.reference.ComponentReference;
37 import org.simantics.databoard.accessor.reference.LabelReference;
38 import org.simantics.databoard.adapter.AdaptException;
39 import org.simantics.databoard.binding.Binding;
40 import org.simantics.databoard.binding.VariantBinding;
41 import org.simantics.databoard.binding.error.BindingConstructionException;
42 import org.simantics.databoard.binding.error.BindingException;
43 import org.simantics.databoard.binding.mutable.MutableVariant;
44 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
45 import org.simantics.databoard.serialization.Serializer;
46 import org.simantics.databoard.serialization.SerializerConstructionException;
47 import org.simantics.databoard.type.Datatype;
48 import org.simantics.databoard.type.VariantType;
49 import org.simantics.databoard.util.binary.Blob;
51 public class BinaryVariant extends BinaryObject implements VariantAccessor, FileVariantAccessor {
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 );
57 SoftReference<BinaryObject> child;
59 public BinaryVariant(BinaryObject parent, Blob blob, Datatype type, AccessorParams params) {
60 super(parent, blob, type, params);
63 public VariantType type() {
64 return (VariantType) type;
67 @SuppressWarnings("unchecked")
69 public <T extends Accessor> T getContentAccessor()
70 throws AccessorConstructionException {
74 BinaryObject sa = getExistingAccessor();
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);
83 // Attach listeners of interest set to the new accessor (of the value)
84 ListenerEntry le = listeners;
86 VariantInterestSet is = le.getInterestSet();
87 InterestSet cis = is.getComponentInterest();
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);
96 if (is.inCompleteComponent()) {
97 cis = InterestSet.newInterestSet(getContentType(), true, true, true);
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);
109 } catch (IOException e) {
110 throw new AccessorConstructionException(e);
111 } catch (AccessorException e) {
112 throw new AccessorConstructionException(e);
118 protected BinaryObject getExistingAccessor() {
119 SoftReference<BinaryObject> r = child;
120 if (r==null) return null;
121 BinaryObject sa = r.get();
126 public void setContentValueNoflush(Binding valueBinding, Object value)
127 throws AccessorException {
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);
139 // Replace the old value with a new value
141 sa.invalidatedNotification();
147 Binding cb = valueBinding;
148 Serializer cs = params.serializerScheme.getSerializer( cb );
149 Datatype ct = valueBinding.type();
152 TObjectIntHashMap<Object> ids = new TObjectIntHashMap<Object>(0);
153 int len = type_serializer.getSize(ct, ids);
154 len += cs.getSize(cv, null);
159 type_serializer.serialize(b, ids, ct);
160 cs.serialize(b, null, cv);
163 ListenerEntry le = listeners;
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 );
173 // Attach component listener
174 // boolean hadSa = getExistingAccessor()!=null;
176 // InterestSet cis = is.getComponentInterest();
178 // sa = getValueAccessor();
186 } catch (IOException e) {
187 throw new AccessorException( e );
188 } catch (AdaptException e) {
189 throw new AccessorException( e );
190 } catch (SerializerConstructionException e) {
191 throw new AccessorException( e );
198 public void setContentValue(Binding valueBinding, Object value)
199 throws AccessorException {
203 setContentValueNoflush(valueBinding, value);
211 public Datatype getContentType() throws AccessorException {
216 List<Object> ids = new ArrayList<Object>(0);
217 Datatype type = (Datatype) type_serializer.deserialize(b, ids);
219 } catch (IOException e) {
220 throw new AccessorException( e );
227 public Object getContentValue(Binding contentBinding)
228 throws AccessorException {
233 List<Object> ids = new ArrayList<Object>();
234 Datatype type = (Datatype) type_serializer.deserialize(b, ids);
237 if (!contentBinding.type().equals(type)) {
238 throw new AccessorException("Arg error, wrong type");
240 Serializer value_serializer = params.serializerScheme.getSerializer( contentBinding );
241 return value_serializer.deserialize(b, ids);
243 // The requested binding is a super type binding
244 // Read the to the actual type and adapt
246 // Binding lcb = params.bindingFactory.getBinding(type);
247 // Binding rcb = contentBinding;
248 // Object lv = lcb.serializer().deserialize(b, ids);
250 // return adapt(lv, lcb, rcb);
251 } catch (IOException e) {
252 throw new AccessorException( e );
253 } catch (SerializerConstructionException e) {
254 throw new AccessorException( e );
260 @SuppressWarnings("unchecked")
262 public <T extends Accessor> T getComponent(ChildReference reference)
263 throws AccessorConstructionException {
264 if (reference==null) return (T) this;
266 if (reference instanceof LabelReference) {
267 LabelReference lr = (LabelReference) reference;
268 if (lr.label.equals("v")) {
269 Accessor sa = getContentAccessor();
270 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());
275 if (reference instanceof ComponentReference) {
276 Accessor sa = getContentAccessor();
277 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());
281 throw new AccessorConstructionException("Variant value reference expected, got "+reference.getClass().getName());
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;
294 ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
295 sa.addListener(listener, cis, childPath, executor);
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);
305 public void removeListener(Listener listener) throws AccessorException {
306 ListenerEntry e = detachListener(listener);
308 VariantInterestSet is = (VariantInterestSet) e.interestSet;
310 InterestSet cis = is.getComponentInterest();
311 if (cis==null && !is.inCompleteComponent()) return;
312 BinaryObject sa = getExistingAccessor();
313 if (sa==null) return;
315 sa.removeListener(listener);
318 if (is.inCompleteComponent()) {
319 sa.removeListener(listener);
324 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
326 if (e instanceof ValueAssigned ) {
327 Event rollback = null;
328 ValueAssigned va = (ValueAssigned) e;
329 if (va.newValue==null) throw new AccessorException("Cannot apply variant assignment event, the value is missing");
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);
339 rollback = new ValueAssigned( Bindings.MUTABLE_VARIANT, new MutableVariant( cb, lv ));
342 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
343 // setContentValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
347 throw new AccessorException("Invalid event "+e.getClass().getName());
349 } catch (IOException ioe) {
350 throw new AccessorException(ioe);
351 } catch (RuntimeSerializerConstructionException rsce) {
352 throw new AccessorException(rsce);
353 } catch (SerializerConstructionException e2) {
354 throw new AccessorException(e2);
355 } catch (BindingConstructionException e2) {
356 throw new AccessorException(e2);
361 public void setValueNoflush(Binding variantBinding, Object variantValue)
362 throws AccessorException {
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 );