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 java.io.IOException;
15 import java.lang.ref.SoftReference;
16 import java.util.concurrent.Executor;
18 import org.simantics.databoard.Bindings;
19 import org.simantics.databoard.accessor.Accessor;
20 import org.simantics.databoard.accessor.OptionalAccessor;
21 import org.simantics.databoard.accessor.error.AccessorConstructionException;
22 import org.simantics.databoard.accessor.error.AccessorException;
23 import org.simantics.databoard.accessor.error.ReferenceException;
24 import org.simantics.databoard.accessor.event.Event;
25 import org.simantics.databoard.accessor.event.OptionalValueAssigned;
26 import org.simantics.databoard.accessor.event.OptionalValueRemoved;
27 import org.simantics.databoard.accessor.event.ValueAssigned;
28 import org.simantics.databoard.accessor.file.FileOptionalAccessor;
29 import org.simantics.databoard.accessor.impl.AccessorParams;
30 import org.simantics.databoard.accessor.impl.ListenerEntry;
31 import org.simantics.databoard.accessor.interestset.InterestSet;
32 import org.simantics.databoard.accessor.interestset.OptionalInterestSet;
33 import org.simantics.databoard.accessor.reference.ChildReference;
34 import org.simantics.databoard.accessor.reference.ComponentReference;
35 import org.simantics.databoard.accessor.reference.LabelReference;
36 import org.simantics.databoard.adapter.AdaptException;
37 import org.simantics.databoard.binding.Binding;
38 import org.simantics.databoard.binding.OptionalBinding;
39 import org.simantics.databoard.binding.error.BindingException;
40 import org.simantics.databoard.binding.mutable.MutableVariant;
41 import org.simantics.databoard.serialization.Serializer;
42 import org.simantics.databoard.serialization.SerializerConstructionException;
43 import org.simantics.databoard.type.Datatype;
44 import org.simantics.databoard.type.OptionalType;
45 import org.simantics.databoard.util.binary.Blob;
47 public class BinaryOptional extends BinaryObject implements OptionalAccessor, FileOptionalAccessor {
49 /** Accessor to component */
50 SoftReference<BinaryObject> component;
52 public BinaryOptional(BinaryObject parent, Blob blob, OptionalType type, AccessorParams params)
53 throws AccessorConstructionException {
54 super(parent, blob, type, params);
58 public OptionalType type() {
59 return (OptionalType) type;
63 public void setValueNoflush(Binding binding, Object newValue) throws AccessorException {
67 OptionalBinding ob = (OptionalBinding) binding;
69 boolean hasValue = ob.hasValue(newValue);
72 Binding cb = ob.getComponentBinding();
73 Object cv = ob.getValue(ov);
74 setComponentValueNoflush(cb, cv);
79 } catch (BindingException e) {
80 throw new AccessorException(e);
86 public void setComponentValueNoflush(Binding cb, Object cv)
87 throws AccessorException {
91 BinaryObject sa = getExistingAccessor();
98 Serializer cs = params.serializerScheme.getSerializer( cb );
99 int size = cs.getSize(cv, null)+1;
103 cs.serialize(b, null, cv);
106 ListenerEntry le = listeners;
108 OptionalInterestSet is = le.getInterestSet();
109 if (is.inNotifications()) {
110 MutableVariant newComponentValue = null;
111 if (is.inValues()) newComponentValue = new MutableVariant(cb, cb.isImmutable() ? cv : cb.clone(cv));
112 OptionalValueAssigned e = new OptionalValueAssigned(newComponentValue);
116 // Attach component interest
117 // if (is.getComponentInterest()!=null && getComponentAccessor()!=null) {
118 // sa = getComponentAccessor();
123 } catch (IOException e) {
124 throw new AccessorException(e);
125 } catch (AdaptException e) {
126 throw new AccessorException(e);
127 } catch (SerializerConstructionException e) {
128 throw new AccessorException(e);
135 public void setNoValueNoflush() throws AccessorException {
144 // Disconnect sub-accessor
145 BinaryObject sa = getExistingAccessor();
147 // Notify about disconnection of sub-accessor
148 if (sa!=null) sa.invalidatedNotification();
151 ListenerEntry le = listeners;
153 OptionalInterestSet is = le.getInterestSet();
154 if (is.inNotifications()) {
155 OptionalValueRemoved e = new OptionalValueRemoved();
161 } catch (IOException e) {
162 throw new AccessorException(e);
170 public void setNoValue() throws AccessorException {
176 } catch (IOException e) {
177 throw new AccessorException( e );
184 public void setComponentValue(Binding cb, Object cv)
185 throws AccessorException {
189 setComponentValueNoflush(cb, cv);
191 } catch (IOException e) {
192 throw new AccessorException( e );
198 @SuppressWarnings("unchecked")
200 public <T extends Accessor> T getComponentAccessor()
201 throws AccessorConstructionException {
205 // Get existing or create new
206 BinaryObject sa = getExistingAccessor();
207 if (sa!=null) return (T) sa;
209 // Instantiate new accessor
210 Datatype ct = type().getComponentType();
211 sa = createSubAccessor(ct, 1, b.length()-1, params);
212 component = new SoftReference<BinaryObject>(sa);
214 // Add listener to component, if it is in our interest set
215 ListenerEntry le = listeners;
217 OptionalInterestSet is = le.getInterestSet();
218 InterestSet cis = is.getComponentInterest();
221 ChildReference childPath = ChildReference.concatenate( le.path, new ComponentReference() );
222 sa.addListener(le.listener, cis, childPath, le.executor);
223 } catch (AccessorException e) {
224 throw new AccessorConstructionException(e);
228 // Attach component interest
229 if (is.getComponentInterest()!=null) {
230 sa = getComponentAccessor();
231 sa.addListener(le.listener, is.getComponentInterest(), null, le.executor);
239 } catch (IOException e) {
240 throw new AccessorConstructionException( e );
241 } catch (AccessorException e) {
242 throw new AccessorConstructionException( e );
249 * Get existing sub accessor
251 * @return sub-accessor or <code>null</code>
253 BinaryObject getExistingAccessor()
255 // Get existing or create new
256 SoftReference<BinaryObject> ref = component;
257 BinaryObject accessor = (ref!=null)?(BinaryObject)ref.get():null;
262 public Object getComponentValue(Binding cb)
263 throws AccessorException {
268 Serializer cs = params.serializerScheme.getSerializer( cb );
269 return cs.deserialize(b, null);
270 } catch (IOException e) {
271 throw new AccessorException( e );
272 } catch (SerializerConstructionException e) {
273 throw new AccessorException( e );
280 public boolean hasValue() throws AccessorException {
285 byte v = b.readByte();
286 if (v==0) return false;
287 if (v==1) return true;
288 throw new AccessorException("Unexpected value "+v+", expected 0/1");
289 } catch (IOException e) {
290 throw new AccessorException( e );
296 @SuppressWarnings("unchecked")
298 public <T extends Accessor> T getComponent(ChildReference reference)
299 throws AccessorConstructionException {
300 if (reference==null) return (T) this;
302 if (reference instanceof LabelReference) {
303 LabelReference lr = (LabelReference) reference;
304 if (lr.label.equals("o")) {
305 Accessor result = getComponentAccessor();
306 if (reference.getChildReference() != null)
307 result = result.getComponent(reference.getChildReference());
312 if (reference instanceof ComponentReference) {
313 Accessor result = getComponentAccessor();
314 if (reference.getChildReference() != null)
315 result = result.getComponent(reference.getChildReference());
319 throw new ReferenceException(reference.getClass()+" is not a reference of OptionalType");
324 public void addListener(Listener listener, InterestSet interestSet,
325 ChildReference path, Executor executor) throws AccessorException {
326 super.addListener(listener, interestSet, path, executor);
327 OptionalInterestSet is = (OptionalInterestSet) interestSet;
328 InterestSet cis = is.getComponentInterest();
329 if (cis==null) return;
330 BinaryObject sa = getExistingAccessor();
331 if (sa==null) return;
332 ChildReference childPath = ChildReference.concatenate( path, new ComponentReference() );
333 sa.addListener(listener, cis, childPath, executor);
337 public void removeListener(Listener listener) throws AccessorException {
338 ListenerEntry e = detachListener(listener);
340 OptionalInterestSet is = (OptionalInterestSet) e.interestSet;
342 InterestSet cis = is.getComponentInterest();
343 if (cis==null) return;
344 BinaryObject sa = getExistingAccessor();
345 if (sa==null) return;
346 sa.removeListener(listener);
350 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
351 Event rollback = null;
354 OptionalBinding cb = (OptionalBinding) Bindings
355 .getMutableBinding(type().getComponentType());
356 Object cv = getComponentValue(cb);
357 rollback = new OptionalValueAssigned(cb, cv);
359 rollback = new OptionalValueRemoved();
363 if (e instanceof ValueAssigned) {
364 ValueAssigned va = (ValueAssigned) e;
365 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
368 if (e instanceof OptionalValueAssigned) {
369 OptionalValueAssigned oa = (OptionalValueAssigned) e;
370 if (oa.newValue == null)
371 throw new AccessorException("Cannot apply field assignment event, the value is missing");
372 setComponentValueNoflush(oa.newValue.getBinding(), oa.newValue.getValue());
373 } else if (e instanceof OptionalValueRemoved) {
376 throw new AccessorException("Unexpected event type "+ e.getClass().getName() + " for an Optional Type");