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.java;
14 import java.lang.ref.SoftReference;
\r
15 import java.util.concurrent.Executor;
\r
17 import org.simantics.databoard.accessor.Accessor;
\r
18 import org.simantics.databoard.accessor.UnionAccessor;
\r
19 import org.simantics.databoard.accessor.error.AccessorConstructionException;
\r
20 import org.simantics.databoard.accessor.error.AccessorException;
\r
21 import org.simantics.databoard.accessor.error.ReferenceException;
\r
22 import org.simantics.databoard.accessor.event.Event;
\r
23 import org.simantics.databoard.accessor.event.UnionValueAssigned;
\r
24 import org.simantics.databoard.accessor.event.ValueAssigned;
\r
25 import org.simantics.databoard.accessor.impl.AccessorParams;
\r
26 import org.simantics.databoard.accessor.impl.ListenerEntry;
\r
27 import org.simantics.databoard.accessor.interestset.InterestSet;
\r
28 import org.simantics.databoard.accessor.interestset.UnionInterestSet;
\r
29 import org.simantics.databoard.accessor.reference.ChildReference;
\r
30 import org.simantics.databoard.accessor.reference.ComponentReference;
\r
31 import org.simantics.databoard.accessor.reference.IndexReference;
\r
32 import org.simantics.databoard.accessor.reference.LabelReference;
\r
33 import org.simantics.databoard.accessor.reference.NameReference;
\r
34 import org.simantics.databoard.adapter.AdaptException;
\r
35 import org.simantics.databoard.adapter.AdapterConstructionException;
\r
36 import org.simantics.databoard.binding.Binding;
\r
37 import org.simantics.databoard.binding.UnionBinding;
\r
38 import org.simantics.databoard.binding.error.BindingException;
\r
39 import org.simantics.databoard.binding.mutable.MutableVariant;
\r
40 import org.simantics.databoard.type.UnionType;
\r
43 * Accessor to Java Object of Union Type
45 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
47 public class JavaUnion extends JavaObject implements UnionAccessor {
49 /** Accessor to childr */
50 SoftReference<JavaObject> component;
52 public JavaUnion(Accessor parent, UnionBinding binding, Object object, AccessorParams params) {
53 super(parent, binding, object, params);
57 public UnionType type() {
58 return (UnionType) binding.type();
62 public UnionBinding getBinding() {
63 return (UnionBinding) binding;
66 @SuppressWarnings("unchecked")
68 public <T extends Accessor> T getComponent(ChildReference reference)
69 throws AccessorConstructionException {
71 if (reference==null) return (T) this;
\r
73 if (reference instanceof LabelReference) {
\r
74 LabelReference lr = (LabelReference) reference;
\r
75 Integer tag = type().getComponentIndex( lr.label );
\r
77 if (tag==null && lr.label.equals("uv")) {
\r
78 Accessor result = getComponentAccessor();
\r
79 if (reference.getChildReference() != null)
\r
80 result = result.getComponent(reference.getChildReference());
\r
82 } else if (tag==null) {
\r
83 throw new ReferenceException("Tag \""+lr.label+"\" not found");
\r
86 if (tag != getTag()) throw new ReferenceException("The union isn't currently assigned with the expected type ("+type().getComponent(tag).name+")");
\r
87 Accessor result = getComponentAccessor();
\r
88 if (reference.getChildReference() != null)
\r
89 result = result.getComponent(reference.getChildReference());
\r
93 if (reference instanceof ComponentReference) {
94 Accessor result = getComponentAccessor();
95 if (reference.getChildReference() != null)
96 result = result.getComponent(reference.getChildReference());
100 if (reference instanceof IndexReference) {
101 IndexReference ir = (IndexReference) reference;
102 if (ir.index<0 || ir.index>=type().getComponentCount()) throw new ReferenceException("Tag index out of bounds");
103 if (ir.index != getTag()) throw new ReferenceException("The union isn't currently assigned with the expected type ("+type().getComponent(ir.index).name+")");
104 Accessor result = getComponentAccessor();
105 if (reference.getChildReference() != null)
106 result = result.getComponent(reference.getChildReference());
110 if (reference instanceof NameReference) {
111 NameReference nr = (NameReference) reference;
112 Integer tag = type().getComponentIndex( nr.name );
113 if (tag==null) throw new ReferenceException("Tag by name \""+nr.name+"\" is not found");
114 if (tag != getTag()) throw new ReferenceException("The union isn't currently assigned with the expected type ("+type().getComponent(tag).name+")");
115 Accessor result = getComponentAccessor();
116 if (reference.getChildReference() != null)
117 result = result.getComponent(reference.getChildReference());
121 throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");
122 } catch (AccessorException ae) {
123 throw new AccessorConstructionException(ae);
127 public int count() throws AccessorException {
128 return type().getComponentCount();
132 * Get existing sub-accessor
134 * @return sub-accessor or <code>null</code>
136 JavaObject getExistingAccessor() {
137 SoftReference<JavaObject> c = component;
138 if (c==null) return null;
143 public void setValue(Binding unionBinding, Object newUnionValue)
144 throws AccessorException {
\r
147 UnionBinding newUb = (UnionBinding) unionBinding;
148 int tag = newUb.getTag(newUnionValue);
149 Binding cb = newUb.getComponentBinding(tag);
150 Object cv = newUb.getValue(newUnionValue);
151 setComponentValue(tag, cb, cv);
152 } catch (BindingException e) {
153 throw new AccessorException(e);
159 @SuppressWarnings("unchecked")
161 public <T extends Accessor> T getComponentAccessor() throws AccessorConstructionException {
163 // Get existing or create new
164 JavaObject sa = getExistingAccessor();
169 // Instantiate new accessor
170 int tag = getBinding().getTag(object);
171 Binding cb = getBinding().getComponentBinding(tag);
172 Object cv = getBinding().getValue(object);
174 // Instantiate correct sub accessor.
175 sa = createSubAccessor(this, cb, cv, params);
176 component = new SoftReference<JavaObject>(sa);
178 // Add listener to component, if it is in our interest set
179 ListenerEntry le = listeners;
181 UnionInterestSet is = le.getInterestSet();
182 InterestSet cis = is.getComponentInterest(tag);
185 ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
186 sa.addListener(le.listener, cis, childPath, le.executor);
187 } catch (AccessorException e) {
188 throw new AccessorConstructionException(e);
200 } catch (BindingException be) {
201 throw new AccessorConstructionException( be );
206 public Object getComponentValue(Binding componentBinding) throws AccessorException {
\r
209 int tag = getBinding().getTag(object);
210 Binding cb = getBinding().getComponentBinding(tag);
211 Object cv = getBinding().getValue(object);
212 return adapt(cv, cb, componentBinding);
213 } catch (AdaptException ae) {
214 throw new AccessorException( ae );
215 } catch (BindingException be) {
216 throw new AccessorException( be );
217 } catch (AdapterConstructionException e) {
\r
218 throw new AccessorException( e );
\r
225 public int getTag() throws AccessorException {
\r
228 return getBinding().getTag(object);
229 } catch (BindingException e) {
230 throw new AccessorException();
237 public void setComponentValue(int tag, Binding componentBinding,
238 Object componentValue) throws AccessorException {
241 int oldTag = getBinding().getTag(object);
243 boolean hadSameTag = oldTag == newTag;
245 // Write to component
246 JavaObject sa = getExistingAccessor();
248 // Tag type changes, invalidate old accessor
249 if (sa!=null && !hadSameTag) {
251 sa.invalidatedNotification();
254 // Tag type remains the same
255 if (sa!=null && hadSameTag) {
256 sa.setValue(componentBinding, componentValue);
261 Binding cb = getBinding().getComponentBinding(newTag);
262 Object cv = adapt(componentValue, componentBinding, cb);
263 getBinding().setValue(object, newTag, cv);
266 ListenerEntry le = listeners;
268 UnionInterestSet is = le.getInterestSet();
269 if (is.inNotificationsOf(tag)) {
270 MutableVariant newComponentValue = null;
271 if (is.inValuesOf(tag)) newComponentValue = new MutableVariant(cb, cb.isImmutable() ? cv : cb.clone(cv));
272 UnionValueAssigned e = new UnionValueAssigned(newTag, newComponentValue);
276 // Attach component listener
277 // InterestSet cis = is.getComponentInterest(newTag);
278 // if (cis!=null && getExistingAccessor()==null) {
279 // sa = getComponentAccessor();
285 } catch (BindingException e) {
286 throw new AccessorException(e);
287 } catch (AdaptException e) {
288 throw new AccessorException(e);
289 } catch (AdapterConstructionException e) {
\r
290 throw new AccessorException(e);
\r
298 public void addListener(Listener listener, InterestSet interestSet,
299 ChildReference path, Executor executor) throws AccessorException {
300 super.addListener(listener, interestSet, path, executor);
301 UnionInterestSet is = (UnionInterestSet) interestSet;
302 if (is.componentInterests!=null) {
304 InterestSet cis = is.componentInterests[tag];
305 if (cis==null) return;
306 JavaObject sa = getExistingAccessor();
307 if (sa==null) return;
308 ChildReference childPath = ChildReference.concatenate(path, new IndexReference(tag) );
309 sa.addListener(listener, cis, childPath, executor);
314 public void removeListener(Listener listener) throws AccessorException {
315 ListenerEntry e = detachListener(listener);
317 UnionInterestSet is = (UnionInterestSet) e.interestSet;
319 if (is.componentInterests!=null) {
320 for (int i=0; i<is.componentInterests.length; i++) {
321 InterestSet cis = is.componentInterests[i];
322 if (cis==null) continue;
323 JavaObject sa = getExistingAccessor();
324 if (sa==null) return;
325 sa.removeListener(listener);
331 Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
333 Event rollback = null;
\r
334 if (e instanceof ValueAssigned) {
\r
335 ValueAssigned va = (ValueAssigned) e;
\r
336 if (makeRollback) rollback = new ValueAssigned(getBinding(), getValue(getBinding()));
\r
337 setValue(va.newValue.getBinding(), va.newValue.getValue());
\r
340 if (e instanceof UnionValueAssigned) {
341 UnionValueAssigned ua = (UnionValueAssigned) e;
342 if (ua.tag<0 || ua.tag>=type().getComponentCount()) throw new AccessorException("Tag index ("+ua.tag+") out of bounds.");
343 if (!ua.newValue.type().equals( type().getComponent(ua.tag).type ) )
344 throw new AccessorException("Cannot assign "+ua.newValue.type()+" to "+type().getComponent(ua.tag).type);
347 UnionBinding ub = getBinding();
349 Binding cb = ub.getComponentBinding(tag);
350 Object cv = ub.getValue(object);
351 MutableVariant v = new MutableVariant(cb, cv);
352 rollback = new UnionValueAssigned(tag, v);
354 setComponentValue(ua.tag, ua.newValue.getBinding(), ua.newValue.getValue());
357 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Union Type");
\r
359 } catch (BindingException be) {
360 throw new AccessorException(be);