]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaVariant.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / java / JavaVariant.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.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;
41
42 public class JavaVariant extends JavaObject implements VariantAccessor {
43
44         SoftReference<JavaObject> child;        
45         
46         public JavaVariant(Accessor parent, VariantBinding binding, Object object, AccessorParams params) {
47                 super(parent, binding, object, params);
48         }
49         
50         @Override
51         public VariantType type() {
52                 return (VariantType) binding.type();
53         }
54         
55         @Override
56         public VariantBinding getBinding() {
57                 return (VariantBinding) binding;
58         }
59
60         @SuppressWarnings("unchecked")
61         @Override
62         public <T extends Accessor> T getContentAccessor() throws AccessorConstructionException {
63                 try {
64                         JavaObject sa = getExistingAccessor();
65                         if (sa==null) 
66                         {
67                                 readLock();
68                                 try {
69                                         // Create new child
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);
74                                         
75                                         // Attach listeners of interest set to the new accessor (of the value)
76                                         ListenerEntry le = listeners;
77                                         while (le!=null) {                              
78                                                 VariantInterestSet is = le.getInterestSet();
79                                                 InterestSet cis = is.getComponentInterest();
80                                                 if (cis != null) {
81                                                         try {
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);
86                                                         }
87                                                 }
88                                                 if (is.inCompleteComponent()) {
89                                                         cis = InterestSet.newInterestSet(getContentType(), true, true, true);
90                                                         try {
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);
95                                                         }
96                                                 }
97                                                 le = le.next;
98                                         }
99                                 } finally {
100                                         readUnlock();
101                                 }                               
102                         }
103                         return (T) sa;
104                 } catch (BindingException e) {
105                         throw new AccessorConstructionException(e);
106                 } catch (AccessorException e) {
107                         throw new AccessorConstructionException(e);
108                 }
109         }
110
111         @SuppressWarnings("unchecked")
112         @Override
113         public <T extends Accessor> T getComponent(ChildReference reference)
114                         throws AccessorConstructionException {          
115                 if (reference==null) return (T) this;
116                 
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());
122                                 return (T) sa;
123                         }                       
124                 }               
125                 
126                 if (reference instanceof ComponentReference) {
127                         Accessor sa = getContentAccessor();
128                         if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());
129                         return (T) sa;
130                 }
131                 
132                 throw new ReferenceException("Variant value reference expected, got "+reference.getClass().getName());
133         }
134
135         protected JavaObject getExistingAccessor() {
136                 SoftReference<JavaObject> r = child;
137                 if (r==null) return null;
138                 JavaObject sa = r.get();
139                 return sa;
140         }
141         
142         @Override
143         public void setValue(Binding variantBinding, Object newVariant)
144                 throws AccessorException {
145                 writeLock();
146                 try {
147                         if (binding instanceof VariantBinding == false)
148                                 throw new AccessorException("VariantBinding is expected.");
149                         
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 ); 
155                 } finally {
156                         writeUnlock();
157                 }
158         }
159
160         @Override
161         public Object getContentValue(Binding contentBinding)
162         throws AccessorException {
163                 readLock();
164                 try {
165                         return getBinding().getContent(object);
166                 } catch (BindingException e) {
167                         throw new AccessorException(e);
168                 } finally {
169                         readUnlock();
170                 }
171         }
172         
173         @Override
174         public Datatype getContentType() throws AccessorException {
175                 readLock();
176                 try {
177                         return getBinding().getContentType(object);
178                 } catch (BindingException e) {
179                         throw new AccessorException(e);
180                 } finally {
181                         readUnlock();
182                 }
183         }
184         
185         @Override
186         public void setContentValue(Binding valueBinding, Object newValue)
187         throws AccessorException {
188                 writeLock();
189                 try {
190                         // reuse sub-accessor, if type matches, and sub-accessor exists
191                         JavaObject sa = getExistingAccessor();
192                         
193                         if (sa!=null && valueBinding.type().equals(sa.type())) {
194                                 sa.setValue(valueBinding, newValue);
195                                 return;
196                         }
197                         
198                         {
199                                 // Replace the old value with a new value
200                                 if (sa!=null) {
201                                         sa.invalidatedNotification();
202                                         child = null;
203                                         sa = null;
204                                 }
205                                 
206                                 
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);
212                                         this.object = 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);
218                                         this.object = 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);
224                                         this.object = nv;
225                                 } else {                        
226                                         // Write new value
227                                         getBinding().setContent(object, valueBinding, newValue);
228                                 }       
229                                 
230                                 
231                                 // Notify Listeners
232                                 ListenerEntry le = listeners;
233                                 while (le!=null) {
234                                         // Notification
235                                         VariantInterestSet is = le.getInterestSet();
236                                         if (is.inNotifications()) {
237                                                 if (is.inValues()) {
238                                                         MutableVariant value = new MutableVariant( valueBinding, valueBinding.isImmutable() ? newValue : valueBinding.clone(newValue) );
239                                                         ValueAssigned e = new ValueAssigned(Bindings.MUTABLE_VARIANT, value );
240                                                         emitEvent(le, e);
241                                                 } else {
242                                                         emitEvent( le, new ValueAssigned() );                                                   
243                                                 }
244                                         }
245                                         
246                                         // Attach component listener
247 //                                      InterestSet cis = is.getComponentInterest();
248 //                                      if (cis!=null) {
249 //                                              sa = getValueAccessor();
250 //                                      }
251                                         
252                                         le = le.next;
253                                 }
254                                 
255                         }
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);
262                 } finally {
263                         writeUnlock();
264                 }
265         }
266         
267         @Override
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;
276                 if (cis!=null) {
277                         ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
278                         sa.addListener(listener, cis, childPath, executor);
279                 }
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);
284                 }
285         }               
286         
287         @Override
288         public void removeListener(Listener listener) throws AccessorException {
289                 ListenerEntry e = detachListener(listener);
290                 if (e==null) return;
291                 VariantInterestSet is = (VariantInterestSet) e.interestSet;
292                 
293                 InterestSet cis = is.getComponentInterest();
294                 if (cis==null && !is.inCompleteComponent()) return;
295                 JavaObject sa = getExistingAccessor();
296                 if (sa==null) return;
297                 if (cis!=null) {
298                         sa.removeListener(listener);
299                 }
300                 // Remove another?
301                 if (is.inCompleteComponent()) {
302                         sa.removeListener(listener);
303                 }               
304         }
305
306
307         @Override
308         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
309                 try {
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");
314                                 
315                                 if (makeRollback) {
316                                         Binding cb = getBinding().getContentBinding(object);
317                                         Object cv = getBinding().getContent(object);
318                                         rollback = new ValueAssigned( Bindings.MUTABLE_VARIANT, new MutableVariant( cb, cv ) );
319                                 }
320         
321                                 setValue(va.newValue.getBinding(), va.newValue.getValue());
322 //                              setContentValue(va.newValue.getBinding(), va.newValue.getValue());
323                                 
324                                 return rollback;
325                         } else {
326                                 throw new AccessorException("Invalid event "+e.getClass().getName());
327                         }
328                 } catch (BindingException be) {
329                         throw new AccessorException(be);
330                 }
331         }
332         
333 }
334