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.Bindings;
18 import org.simantics.databoard.accessor.Accessor;
19 import org.simantics.databoard.accessor.VariantAccessor;
20 import org.simantics.databoard.accessor.error.AccessorConstructionException;
21 import org.simantics.databoard.accessor.error.AccessorException;
22 import org.simantics.databoard.accessor.error.ReferenceException;
23 import org.simantics.databoard.accessor.event.Event;
24 import org.simantics.databoard.accessor.event.ValueAssigned;
25 import org.simantics.databoard.accessor.impl.AccessorParams;
26 import org.simantics.databoard.accessor.impl.ListenerEntry;
27 import org.simantics.databoard.accessor.interestset.InterestSet;
28 import org.simantics.databoard.accessor.interestset.VariantInterestSet;
29 import org.simantics.databoard.accessor.reference.ChildReference;
30 import org.simantics.databoard.accessor.reference.ComponentReference;
31 import org.simantics.databoard.accessor.reference.LabelReference;
32 import org.simantics.databoard.adapter.AdaptException;
33 import org.simantics.databoard.binding.ArrayBinding;
34 import org.simantics.databoard.binding.Binding;
35 import org.simantics.databoard.binding.RecordBinding;
36 import org.simantics.databoard.binding.VariantBinding;
37 import org.simantics.databoard.binding.error.BindingException;
38 import org.simantics.databoard.binding.mutable.MutableVariant;
39 import org.simantics.databoard.type.Datatype;
40 import org.simantics.databoard.type.VariantType;
42 public class JavaVariant extends JavaObject implements VariantAccessor {
44 SoftReference<JavaObject> child;
46 public JavaVariant(Accessor parent, VariantBinding binding, Object object, AccessorParams params) {
47 super(parent, binding, object, params);
51 public VariantType type() {
52 return (VariantType) binding.type();
56 public VariantBinding getBinding() {
57 return (VariantBinding) binding;
60 @SuppressWarnings("unchecked")
62 public <T extends Accessor> T getContentAccessor() throws AccessorConstructionException {
64 JavaObject sa = getExistingAccessor();
70 Binding cb = getBinding().getContentBinding(object);
71 Object cv = getBinding().getContent(object);
72 sa = JavaObject.createSubAccessor(this, cb, cv, params);
73 child = new SoftReference<JavaObject>(sa);
75 // Attach listeners of interest set to the new accessor (of the value)
76 ListenerEntry le = listeners;
78 VariantInterestSet is = le.getInterestSet();
79 InterestSet cis = is.getComponentInterest();
82 ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
83 sa.addListener(le.listener, cis, childPath, le.executor);
84 } catch (AccessorException e) {
85 throw new AccessorConstructionException(e);
88 if (is.inCompleteComponent()) {
89 cis = InterestSet.newInterestSet(getContentType(), true, true, true);
91 ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
92 sa.addListener(le.listener, cis, childPath, le.executor);
93 } catch (AccessorException e) {
94 throw new AccessorConstructionException(e);
104 } catch (BindingException e) {
105 throw new AccessorConstructionException(e);
106 } catch (AccessorException e) {
107 throw new AccessorConstructionException(e);
111 @SuppressWarnings("unchecked")
113 public <T extends Accessor> T getComponent(ChildReference reference)
114 throws AccessorConstructionException {
115 if (reference==null) return (T) this;
117 if (reference instanceof LabelReference) {
118 LabelReference lr = (LabelReference) reference;
119 if (lr.label.equals("v")) {
120 Accessor sa = getContentAccessor();
121 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());
126 if (reference instanceof ComponentReference) {
127 Accessor sa = getContentAccessor();
128 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());
132 throw new ReferenceException("Variant value reference expected, got "+reference.getClass().getName());
135 protected JavaObject getExistingAccessor() {
136 SoftReference<JavaObject> r = child;
137 if (r==null) return null;
138 JavaObject sa = r.get();
143 public void setValue(Binding variantBinding, Object newVariant)
144 throws AccessorException {
147 if (binding instanceof VariantBinding == false)
148 throw new AccessorException("VariantBinding is expected.");
150 Binding newValueBinding = ((VariantBinding)variantBinding).getContentBinding(newVariant);
151 Object newValueObject = ((VariantBinding)variantBinding).getContent(newVariant);
152 setContentValue(newValueBinding, newValueObject);
153 } catch (BindingException e) {
154 throw new AccessorException( e );
161 public Object getContentValue(Binding contentBinding)
162 throws AccessorException {
165 return getBinding().getContent(object);
166 } catch (BindingException e) {
167 throw new AccessorException(e);
174 public Datatype getContentType() throws AccessorException {
177 return getBinding().getContentType(object);
178 } catch (BindingException e) {
179 throw new AccessorException(e);
186 public void setContentValue(Binding valueBinding, Object newValue)
187 throws AccessorException {
190 // reuse sub-accessor, if type matches, and sub-accessor exists
191 JavaObject sa = getExistingAccessor();
193 if (sa!=null && valueBinding.type().equals(sa.type())) {
194 sa.setValue(valueBinding, newValue);
199 // Replace the old value with a new value
201 sa.invalidatedNotification();
207 if (binding.isImmutable() && parent!=null && parent instanceof JavaArray) {
208 JavaObject jo = (JavaObject) parent;
209 ArrayBinding ab = (ArrayBinding) jo.binding;
210 Object nv = getBinding().create(valueBinding, newValue);
211 ab.set(jo.object, (Integer)keyInParent, nv);
213 } else if (binding.isImmutable() && parent!=null && parent instanceof JavaRecord) {
214 JavaObject jo = (JavaObject) parent;
215 RecordBinding rb = (RecordBinding) jo.binding;
216 Object nv = getBinding().create(valueBinding, newValue);
217 rb.setComponent(jo.object, (Integer)keyInParent, nv);
219 } else if (binding.isImmutable() && parent!=null && parent instanceof JavaVariant) {
220 JavaObject jo = (JavaObject) parent;
221 VariantBinding vb = (VariantBinding) jo.binding;
222 Object nv = getBinding().create(valueBinding, newValue);
223 vb.setContent(jo.object, getBinding(), nv);
227 getBinding().setContent(object, valueBinding, newValue);
232 ListenerEntry le = listeners;
235 VariantInterestSet is = le.getInterestSet();
236 if (is.inNotifications()) {
238 MutableVariant value = new MutableVariant( valueBinding, valueBinding.isImmutable() ? newValue : valueBinding.clone(newValue) );
239 ValueAssigned e = new ValueAssigned(Bindings.MUTABLE_VARIANT, value );
242 emitEvent( le, new ValueAssigned() );
246 // Attach component listener
247 // InterestSet cis = is.getComponentInterest();
249 // sa = getValueAccessor();
256 } catch (BindingException e) {
257 throw new AccessorException(e);
258 // } catch (AccessorConstructionException e) {
259 // throw new AccessorException(e);
260 } catch (AdaptException e) {
261 throw new AccessorException(e);
268 public void addListener(Listener listener, InterestSet interestSet,
269 ChildReference path, Executor executor) throws AccessorException {
270 super.addListener(listener, interestSet, path, executor);
271 VariantInterestSet is = (VariantInterestSet) interestSet;
272 InterestSet cis = is.getComponentInterest();
273 if (cis==null && !is.inCompleteComponent()) return;
274 JavaObject sa = getExistingAccessor();
275 if (sa==null) return;
277 ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
278 sa.addListener(listener, cis, childPath, executor);
280 if (is.inCompleteComponent()) {
281 ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
282 cis = InterestSet.newInterestSet(getContentType(), true, true, true);
283 sa.addListener(listener, cis, childPath, executor);
288 public void removeListener(Listener listener) throws AccessorException {
289 ListenerEntry e = detachListener(listener);
291 VariantInterestSet is = (VariantInterestSet) e.interestSet;
293 InterestSet cis = is.getComponentInterest();
294 if (cis==null && !is.inCompleteComponent()) return;
295 JavaObject sa = getExistingAccessor();
296 if (sa==null) return;
298 sa.removeListener(listener);
301 if (is.inCompleteComponent()) {
302 sa.removeListener(listener);
308 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
310 Event rollback = null;
311 if (e instanceof ValueAssigned) {
312 ValueAssigned va = (ValueAssigned) e;
313 if (va.newValue==null) throw new AccessorException("Cannot apply variant assignment event, the value is missing");
316 Binding cb = getBinding().getContentBinding(object);
317 Object cv = getBinding().getContent(object);
318 rollback = new ValueAssigned( Bindings.MUTABLE_VARIANT, new MutableVariant( cb, cv ) );
321 setValue(va.newValue.getBinding(), va.newValue.getValue());
322 // setContentValue(va.newValue.getBinding(), va.newValue.getValue());
326 throw new AccessorException("Invalid event "+e.getClass().getName());
328 } catch (BindingException be) {
329 throw new AccessorException(be);