1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.accessor.binary;
14 import java.io.IOException;
\r
15 import java.lang.ref.SoftReference;
\r
16 import java.util.concurrent.Executor;
\r
18 import org.simantics.databoard.Bindings;
\r
19 import org.simantics.databoard.accessor.Accessor;
\r
20 import org.simantics.databoard.accessor.OptionalAccessor;
\r
21 import org.simantics.databoard.accessor.error.AccessorConstructionException;
\r
22 import org.simantics.databoard.accessor.error.AccessorException;
\r
23 import org.simantics.databoard.accessor.error.ReferenceException;
\r
24 import org.simantics.databoard.accessor.event.Event;
\r
25 import org.simantics.databoard.accessor.event.OptionalValueAssigned;
\r
26 import org.simantics.databoard.accessor.event.OptionalValueRemoved;
\r
27 import org.simantics.databoard.accessor.event.ValueAssigned;
\r
28 import org.simantics.databoard.accessor.file.FileOptionalAccessor;
\r
29 import org.simantics.databoard.accessor.impl.AccessorParams;
\r
30 import org.simantics.databoard.accessor.impl.ListenerEntry;
\r
31 import org.simantics.databoard.accessor.interestset.InterestSet;
\r
32 import org.simantics.databoard.accessor.interestset.OptionalInterestSet;
\r
33 import org.simantics.databoard.accessor.reference.ChildReference;
\r
34 import org.simantics.databoard.accessor.reference.ComponentReference;
\r
35 import org.simantics.databoard.accessor.reference.LabelReference;
\r
36 import org.simantics.databoard.adapter.AdaptException;
\r
37 import org.simantics.databoard.binding.Binding;
\r
38 import org.simantics.databoard.binding.OptionalBinding;
\r
39 import org.simantics.databoard.binding.error.BindingException;
\r
40 import org.simantics.databoard.binding.mutable.MutableVariant;
\r
41 import org.simantics.databoard.serialization.Serializer;
\r
42 import org.simantics.databoard.serialization.SerializerConstructionException;
\r
43 import org.simantics.databoard.type.Datatype;
\r
44 import org.simantics.databoard.type.OptionalType;
\r
45 import org.simantics.databoard.util.binary.Blob;
\r
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 {
\r
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 {
\r
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) {
\r
128 throw new AccessorException(e);
\r
135 public void setNoValueNoflush() throws AccessorException {
\r
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 {
\r
176 } catch (IOException e) {
177 throw new AccessorException( e );
184 public void setComponentValue(Binding cb, Object cv)
185 throws AccessorException {
\r
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 {
\r
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 {
\r
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) {
\r
273 throw new AccessorException( e );
\r
280 public boolean hasValue() throws AccessorException {
\r
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;
\r
302 if (reference instanceof LabelReference) {
\r
303 LabelReference lr = (LabelReference) reference;
\r
304 if (lr.label.equals("o")) {
\r
305 Accessor result = getComponentAccessor();
\r
306 if (reference.getChildReference() != null)
\r
307 result = result.getComponent(reference.getChildReference());
\r
308 return (T) result;
\r
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) {
\r
364 ValueAssigned va = (ValueAssigned) e;
\r
365 setValueNoflush(va.newValue.getBinding(), va.newValue.getValue());
\r
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");