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.java;
14 import java.lang.ref.SoftReference;
15 import java.util.concurrent.Executor;
17 import org.simantics.databoard.accessor.Accessor;
18 import org.simantics.databoard.accessor.OptionalAccessor;
19 import org.simantics.databoard.accessor.error.AccessorConstructionException;
20 import org.simantics.databoard.accessor.error.AccessorException;
21 import org.simantics.databoard.accessor.error.ReferenceException;
22 import org.simantics.databoard.accessor.event.Event;
23 import org.simantics.databoard.accessor.event.OptionalValueAssigned;
24 import org.simantics.databoard.accessor.event.OptionalValueRemoved;
25 import org.simantics.databoard.accessor.event.ValueAssigned;
26 import org.simantics.databoard.accessor.impl.AccessorParams;
27 import org.simantics.databoard.accessor.impl.ListenerEntry;
28 import org.simantics.databoard.accessor.interestset.InterestSet;
29 import org.simantics.databoard.accessor.interestset.OptionalInterestSet;
30 import org.simantics.databoard.accessor.reference.ChildReference;
31 import org.simantics.databoard.accessor.reference.ComponentReference;
32 import org.simantics.databoard.accessor.reference.LabelReference;
33 import org.simantics.databoard.adapter.AdaptException;
34 import org.simantics.databoard.adapter.AdapterConstructionException;
35 import org.simantics.databoard.binding.Binding;
36 import org.simantics.databoard.binding.OptionalBinding;
37 import org.simantics.databoard.binding.error.BindingException;
38 import org.simantics.databoard.binding.mutable.MutableVariant;
39 import org.simantics.databoard.type.OptionalType;
41 public class JavaOptional extends JavaObject implements OptionalAccessor {
43 /** Accessor to component */
44 SoftReference<JavaObject> component;
46 public JavaOptional(Accessor parent, OptionalBinding binding, Object object, AccessorParams params) {
47 super(parent, binding, object, params);
51 public OptionalBinding getBinding() {
52 return (OptionalBinding) binding;
56 public OptionalType type() {
57 return (OptionalType) getBinding().type();
60 @SuppressWarnings("unchecked")
62 public <T extends Accessor> T getComponentAccessor() throws AccessorConstructionException
65 if (!getBinding().hasValue(object)) return null;
67 // Get existing or create new
68 JavaObject sa = getExistingAccessor();
71 // Instantiate new accessor
72 Binding cb = getBinding().getComponentBinding();
73 Object cv = getBinding().getValue(object);
75 // Instantiate correct sub accessor.
76 sa = createSubAccessor(this, cb, cv, params);
77 component = new SoftReference<JavaObject>(sa);
79 // Add listener to component, if it is in our interest set
80 ListenerEntry le = listeners;
82 OptionalInterestSet is = le.getInterestSet();
83 InterestSet cis = is.getComponentInterest();
86 ChildReference childPath = ChildReference.concatenate( le.path, new ComponentReference() );
87 sa.addListener(le.listener, cis, childPath, le.executor);
88 } catch (AccessorException e) {
89 throw new AccessorConstructionException(e);
97 } catch (BindingException e) {
98 throw new AccessorConstructionException(e);
103 * Get existing sub accessor
105 * @return sub-accessor or <code>null</code>
107 JavaObject getExistingAccessor()
109 // Get existing or create new
110 SoftReference<JavaObject> ref = component;
111 JavaObject accessor = (ref!=null)?(JavaObject)ref.get():null;
116 public Object getComponentValue(Binding componentBinding)
117 throws AccessorException {
120 if (!getBinding().hasValue(object))
121 throw new AccessorException("There is no component value");
123 Binding cb = getBinding().getComponentBinding();
124 Object cv = getBinding().getValue(object);
125 return adapt(cv, cb, componentBinding);
126 } catch (BindingException e) {
127 throw new AccessorException(e);
128 } catch (AdaptException e) {
129 throw new AccessorException(e);
130 } catch (AdapterConstructionException e) {
131 throw new AccessorException(e);
138 public void addListener(Listener listener, InterestSet interestSet,
139 ChildReference path, Executor executor) throws AccessorException {
140 super.addListener(listener, interestSet, path, executor);
141 OptionalInterestSet is = (OptionalInterestSet) interestSet;
142 InterestSet cis = is.getComponentInterest();
143 if (cis==null) return;
144 JavaObject sa = getExistingAccessor();
145 if (sa==null) return;
146 ChildReference childPath = ChildReference.concatenate( path, new ComponentReference() );
147 sa.addListener(listener, cis, childPath, executor);
151 public void removeListener(Listener listener) throws AccessorException {
152 ListenerEntry e = detachListener(listener);
154 OptionalInterestSet is = (OptionalInterestSet) e.interestSet;
156 InterestSet cis = is.getComponentInterest();
157 if (cis==null) return;
158 JavaObject sa = getExistingAccessor();
159 if (sa==null) return;
160 sa.removeListener(listener);
163 @SuppressWarnings("unchecked")
165 public <T extends Accessor> T getComponent(ChildReference reference) throws AccessorConstructionException {
166 if (reference==null) return (T) this;
168 if (reference instanceof LabelReference) {
169 LabelReference lr = (LabelReference) reference;
170 if (lr.label.equals("o")) {
171 Accessor result = getComponentAccessor();
172 if (reference.getChildReference() != null)
173 result = result.getComponent(reference.getChildReference());
178 if (reference instanceof ComponentReference) {
179 Accessor result = getComponentAccessor();
180 if (reference.getChildReference() != null)
181 result = result.getComponent(reference.getChildReference());
185 throw new ReferenceException(reference.getClass()+" is not a reference of OptionalType");
189 public void setValue(Binding binding, Object newValue) throws AccessorException {
192 OptionalBinding rb = (OptionalBinding) binding;
193 Object rv = newValue;
194 boolean rvHasValue = rb.hasValue(newValue);
197 Binding rcb = rb.getComponentBinding();
198 Object rcv = rb.getValue(rv);
199 setComponentValue(rcb, rcv);
204 } catch (BindingException e) {
205 throw new AccessorException(e);
212 public boolean hasValue() throws AccessorException {
215 return getBinding().hasValue(object);
216 } catch (BindingException e) {
217 throw new AccessorException(e);
225 public void setNoValue() throws AccessorException {
228 boolean hadValue = getBinding().hasValue(object);
229 if (!hadValue) return;
232 getBinding().setNoValue(object);
234 // Disconnect sub-accessor
235 JavaObject sa = getExistingAccessor();
237 // Notify about disconnection of sub-accessor
238 if (sa!=null) sa.invalidatedNotification();
241 ListenerEntry le = listeners;
243 OptionalInterestSet is = le.getInterestSet();
244 if (is.inNotifications()) {
245 OptionalValueRemoved e = new OptionalValueRemoved();
251 } catch (BindingException e) {
252 throw new AccessorException(e);
259 public void setComponentValue(Binding binding, Object value)
260 throws AccessorException {
263 Binding rcb = binding;
265 boolean hadValue = getBinding().hasValue(object);
267 // Write to component
268 JavaObject sa = getExistingAccessor();
271 sa.setValue(rcb, rcv);
275 Binding lcb = getBinding().getComponentBinding();
276 Object lcv = adapt(rcv, rcb, lcb);
279 getBinding().setValue(object, lcv);
282 ListenerEntry le = listeners;
284 OptionalInterestSet is = le.getInterestSet();
285 if (is.inNotifications()) {
286 MutableVariant newComponentValue = null;
287 if (is.inValues()) newComponentValue = new MutableVariant(lcb, lcb.isImmutable() ? lcv : lcb.clone(lcv));
288 OptionalValueAssigned e = new OptionalValueAssigned(newComponentValue);
292 // Attach component interest
293 // if (is.getComponentInterest()!=null && getComponentAccessor()!=null) {
294 // sa = getComponentAccessor();
300 } catch (BindingException e) {
301 throw new AccessorException(e);
302 } catch (AdaptException e) {
303 throw new AccessorException(e);
304 } catch (AdapterConstructionException e) {
305 throw new AccessorException(e);
313 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
315 Event rollback = null;
317 OptionalBinding b = getBinding();
318 Binding cb = getBinding().getComponentBinding();
319 rollback = hasValue() ? new OptionalValueAssigned(cb, b.getValue(object)) : new OptionalValueRemoved();
321 if (e instanceof ValueAssigned) {
322 ValueAssigned va = (ValueAssigned) e;
323 setValue(va.newValue.getBinding(), va.newValue.getValue());
326 if (e instanceof OptionalValueAssigned) {
327 OptionalValueAssigned oa = (OptionalValueAssigned) e;
328 if (oa.newValue==null) throw new AccessorException("Cannot apply field assignment event, the value is missing");
329 setComponentValue(oa.newValue.getBinding(), oa.newValue.getValue());
330 } else if (e instanceof OptionalValueRemoved) {
331 //OptionalValueRemoved or = (OptionalValueRemoved) e;
333 } else throw new AccessorException("Unexpected event type "+e.getClass().getName()+" for an Optional Type");
336 } catch (BindingException be) {
337 throw new AccessorException( be );