]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaUnion.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / java / JavaUnion.java
1 /*******************************************************************************
2  *  Copyright (c) 2010 Association for Decentralized Information Management in
3  *  Industry THTH ry.
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
8  *
9  *  Contributors:
10  *      VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.accessor.java;
13
14 import java.lang.ref.SoftReference;
15 import java.util.concurrent.Executor;
16
17 import org.simantics.databoard.accessor.Accessor;
18 import org.simantics.databoard.accessor.UnionAccessor;
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.UnionValueAssigned;
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.UnionInterestSet;
29 import org.simantics.databoard.accessor.reference.ChildReference;
30 import org.simantics.databoard.accessor.reference.ComponentReference;
31 import org.simantics.databoard.accessor.reference.IndexReference;
32 import org.simantics.databoard.accessor.reference.LabelReference;
33 import org.simantics.databoard.accessor.reference.NameReference;
34 import org.simantics.databoard.adapter.AdaptException;
35 import org.simantics.databoard.adapter.AdapterConstructionException;
36 import org.simantics.databoard.binding.Binding;
37 import org.simantics.databoard.binding.UnionBinding;
38 import org.simantics.databoard.binding.error.BindingException;
39 import org.simantics.databoard.binding.mutable.MutableVariant;
40 import org.simantics.databoard.type.UnionType;
41
42 /**
43  * Accessor to Java Object of Union Type
44  *
45  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
46  */
47 public class JavaUnion extends JavaObject implements UnionAccessor {
48
49         /** Accessor to childr */
50         SoftReference<JavaObject> component;
51                 
52         public JavaUnion(Accessor parent, UnionBinding binding, Object object, AccessorParams params) {
53                 super(parent, binding, object, params);
54         }
55         
56         @Override
57         public UnionType type() {
58                 return (UnionType) binding.type();
59         }
60         
61         @Override
62         public UnionBinding getBinding() {
63                 return (UnionBinding) binding;
64         }
65
66         @SuppressWarnings("unchecked")
67         @Override
68         public <T extends Accessor> T getComponent(ChildReference reference)
69                         throws AccessorConstructionException {
70                 try {
71                         if (reference==null) return (T) this;
72                         
73                         if (reference instanceof LabelReference) {
74                                 LabelReference lr = (LabelReference) reference;
75                                 Integer tag = type().getComponentIndex( lr.label );
76                                 
77                                 if (tag==null && lr.label.equals("uv")) {
78                                         Accessor result = getComponentAccessor();
79                                         if (reference.getChildReference() != null)
80                                                 result = result.getComponent(reference.getChildReference());
81                                         return (T) result;
82                                 } else if (tag==null) {
83                                         throw new ReferenceException("Tag \""+lr.label+"\" not found");
84                                 }
85                                 
86                                 if (tag != getTag()) throw new ReferenceException("The union isn't currently assigned with the expected type ("+type().getComponent(tag).name+")");
87                                 Accessor result = getComponentAccessor();
88                                 if (reference.getChildReference() != null)
89                                         result = result.getComponent(reference.getChildReference());
90                                 return (T) result;                              
91                         }
92                         
93                         if (reference instanceof ComponentReference) {
94                                 Accessor result = getComponentAccessor();
95                                 if (reference.getChildReference() != null)
96                                         result = result.getComponent(reference.getChildReference());
97                                 return (T) result;
98                         }
99                         
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());
107                                 return (T) result;
108                         }
109                         
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());
118                                 return (T) result;
119                         }
120                         
121                         throw new ReferenceException(reference.getClass()+" is not a reference of UnionType");
122                 } catch (AccessorException ae) {
123                         throw new AccessorConstructionException(ae);
124                 }
125         }
126         
127         public int count() throws AccessorException {
128                 return type().getComponentCount();
129         };
130         
131         /**
132          * Get existing sub-accessor
133          * 
134          * @return sub-accessor or <code>null</code>
135          */
136         JavaObject getExistingAccessor() {
137                 SoftReference<JavaObject> c = component;
138                 if (c==null) return null;
139                 return c.get();         
140         }
141
142         @Override
143         public void setValue(Binding unionBinding, Object newUnionValue)
144                         throws AccessorException {
145                 writeLock();
146                 try {
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);
154                 } finally {
155                         writeUnlock();
156                 }
157         }
158
159         @SuppressWarnings("unchecked")
160         @Override
161         public <T extends Accessor> T getComponentAccessor() throws AccessorConstructionException {
162                 try {
163                         // Get existing or create new
164                         JavaObject sa = getExistingAccessor();
165
166                         if (sa==null) {
167                                 readLock();
168                                 try {
169                                         // Instantiate new accessor
170                                         int tag = getBinding().getTag(object);
171                                         Binding cb = getBinding().getComponentBinding(tag);
172                                         Object cv = getBinding().getValue(object);
173                                         
174                                         // Instantiate correct sub accessor. 
175                                         sa = createSubAccessor(this, cb, cv, params);
176                                         component = new SoftReference<JavaObject>(sa);
177                                         
178                                         // Add listener to component, if it is in our interest set
179                                         ListenerEntry le = listeners;
180                                         while (le!=null) {                              
181                                                 UnionInterestSet is = le.getInterestSet();
182                                                 InterestSet cis = is.getComponentInterest(tag);
183                                                 if (cis != null) {
184                                                         try {
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);
189                                                         }
190                                                 }
191                                                 le = le.next;
192                                         }
193                                 } finally {
194                                         readUnlock();
195                                 }
196
197                         }
198                         
199                         return (T) sa;
200                 } catch (BindingException be) {
201                         throw new AccessorConstructionException( be );
202                 }
203         }
204
205         @Override
206         public Object getComponentValue(Binding componentBinding) throws AccessorException {
207                 readLock();
208                 try {
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) {
218                         throw new AccessorException( e );
219                 } finally {
220                         readUnlock();
221                 }
222         }
223
224         @Override
225         public int getTag() throws AccessorException {
226                 readLock();
227                 try {
228                         return getBinding().getTag(object);
229                 } catch (BindingException e) {
230                         throw new AccessorException();
231                 } finally {
232                         readUnlock();
233                 }
234         }
235
236         @Override
237         public void setComponentValue(int tag, Binding componentBinding,
238                         Object componentValue) throws AccessorException {
239                 writeLock();
240                 try {
241                         int oldTag = getBinding().getTag(object);
242                         int newTag = tag;                       
243                         boolean hadSameTag = oldTag == newTag;
244                         
245                         // Write to component
246                         JavaObject sa = getExistingAccessor();
247                         
248                         // Tag type changes, invalidate old accessor
249                         if (sa!=null && !hadSameTag) {
250                                 component = null;
251                                 sa.invalidatedNotification();
252                         }
253                         
254                         // Tag type remains the same
255                         if (sa!=null && hadSameTag) {
256                                 sa.setValue(componentBinding, componentValue);
257                                 return;
258                         }
259                         
260                         // Write
261                         Binding cb = getBinding().getComponentBinding(newTag);
262                         Object cv = adapt(componentValue, componentBinding, cb);
263                         getBinding().setValue(object, newTag, cv);
264                         
265                         // Notify Listeners
266                         ListenerEntry le = listeners;
267                         while (le!=null) {                              
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);
273                                         emitEvent(le, e);
274                                 }
275                                 
276                                 // Attach component listener
277 //                              InterestSet cis = is.getComponentInterest(newTag);
278 //                              if (cis!=null && getExistingAccessor()==null) {
279 //                                      sa = getComponentAccessor();
280 //                              }
281                                 
282                                 le = le.next;
283                         }
284                         
285                 } catch (BindingException e) {
286                         throw new AccessorException(e);
287                 } catch (AdaptException e) {
288                         throw new AccessorException(e);
289                 } catch (AdapterConstructionException e) {
290                         throw new AccessorException(e);
291                 } finally {
292                         writeUnlock();
293                 }
294                 
295         }
296         
297         @Override
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) {
303                         int tag = getTag();
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);
310                 }
311         }       
312         
313         @Override
314         public void removeListener(Listener listener) throws AccessorException {
315                 ListenerEntry e = detachListener(listener);
316                 if (e==null) return;
317                 UnionInterestSet is = (UnionInterestSet) e.interestSet;
318                 
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);
326                         }
327                 }
328         }
329
330         @Override
331         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
332                 try {
333                         Event rollback = null;
334                         if (e instanceof ValueAssigned) {
335                                 ValueAssigned va = (ValueAssigned) e;
336                                 if (makeRollback) rollback = new ValueAssigned(getBinding(), getValue(getBinding())); 
337                                 setValue(va.newValue.getBinding(), va.newValue.getValue());
338                                 return rollback;
339                         } else          
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);
345                 
346                                 if (makeRollback) {
347                                         UnionBinding ub = getBinding();
348                                         int tag = getTag();
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);                      
353                                 }
354                                 setComponentValue(ua.tag, ua.newValue.getBinding(), ua.newValue.getValue());            
355                                 return rollback;
356                         } else {
357                                 throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Union Type");                           
358                         }
359                 } catch (BindingException be) {
360                         throw new AccessorException(be);
361                 }
362         }
363         
364         
365 }
366