]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaVariant.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / java / JavaVariant.java
1 /*******************************************************************************\r
2  *  Copyright (c) 2010 Association for Decentralized Information Management in\r
3  *  Industry THTH ry.\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
8  *\r
9  *  Contributors:\r
10  *      VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.accessor.java;
13
14 import java.lang.ref.SoftReference;\r
15 import java.util.concurrent.Executor;\r
16 \r
17 import org.simantics.databoard.Bindings;\r
18 import org.simantics.databoard.accessor.Accessor;\r
19 import org.simantics.databoard.accessor.VariantAccessor;\r
20 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
21 import org.simantics.databoard.accessor.error.AccessorException;\r
22 import org.simantics.databoard.accessor.error.ReferenceException;\r
23 import org.simantics.databoard.accessor.event.Event;\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.VariantInterestSet;\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.LabelReference;\r
32 import org.simantics.databoard.adapter.AdaptException;\r
33 import org.simantics.databoard.binding.ArrayBinding;\r
34 import org.simantics.databoard.binding.Binding;\r
35 import org.simantics.databoard.binding.RecordBinding;\r
36 import org.simantics.databoard.binding.VariantBinding;\r
37 import org.simantics.databoard.binding.error.BindingException;\r
38 import org.simantics.databoard.binding.mutable.MutableVariant;\r
39 import org.simantics.databoard.type.Datatype;\r
40 import org.simantics.databoard.type.VariantType;\r
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) \r
66                         {\r
67                                 readLock();\r
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 {\r
100                                         readUnlock();\r
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;\r
116                 \r
117                 if (reference instanceof LabelReference) {\r
118                         LabelReference lr = (LabelReference) reference;\r
119                         if (lr.label.equals("v")) {\r
120                                 Accessor sa = getContentAccessor();\r
121                                 if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
122                                 return (T) sa;\r
123                         }                       \r
124                 }               \r
125                 
126                 if (reference instanceof ComponentReference) {\r
127                         Accessor sa = getContentAccessor();\r
128                         if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
129                         return (T) sa;\r
130                 }\r
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 {\r
145                 writeLock();
146                 try {
147                         if (binding instanceof VariantBinding == false)
148                                 throw new AccessorException("VariantBinding is expected.");\r
149                         \r
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 {\r
156                         writeUnlock();\r
157                 }
158         }
159
160         @Override
161         public Object getContentValue(Binding contentBinding)
162         throws AccessorException {\r
163                 readLock();
164                 try {
165                         return getBinding().getContent(object);
166                 } catch (BindingException e) {
167                         throw new AccessorException(e);
168                 } finally {\r
169                         readUnlock();\r
170                 }
171         }
172         
173         @Override
174         public Datatype getContentType() throws AccessorException {\r
175                 readLock();
176                 try {
177                         return getBinding().getContentType(object);
178                 } catch (BindingException e) {
179                         throw new AccessorException(e);
180                 } finally {\r
181                         readUnlock();\r
182                 }
183         }
184         
185         @Override
186         public void setContentValue(Binding valueBinding, Object newValue)
187         throws AccessorException {\r
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                                 }\r
205                                 \r
206                                 \r
207                                 if (binding.isImmutable() && parent!=null && parent instanceof JavaArray) {\r
208                                         JavaObject jo = (JavaObject) parent;\r
209                                         ArrayBinding ab = (ArrayBinding) jo.binding;\r
210                                         Object nv = getBinding().create(valueBinding, newValue);\r
211                                         ab.set(jo.object, (Integer)keyInParent, nv);\r
212                                         this.object = nv;\r
213                                 } else if (binding.isImmutable() && parent!=null && parent instanceof JavaRecord) {\r
214                                         JavaObject jo = (JavaObject) parent;\r
215                                         RecordBinding rb = (RecordBinding) jo.binding;\r
216                                         Object nv = getBinding().create(valueBinding, newValue);\r
217                                         rb.setComponent(jo.object, (Integer)keyInParent, nv);\r
218                                         this.object = nv;\r
219                                 } else if (binding.isImmutable() && parent!=null && parent instanceof JavaVariant) {\r
220                                         JavaObject jo = (JavaObject) parent;\r
221                                         VariantBinding vb = (VariantBinding) jo.binding;\r
222                                         Object nv = getBinding().create(valueBinding, newValue);\r
223                                         vb.setContent(jo.object, getBinding(), nv);\r
224                                         this.object = nv;\r
225                                 } else {                        \r
226                                         // Write new value\r
227                                         getBinding().setContent(object, valueBinding, newValue);\r
228                                 }       \r
229                                 
230                                 
231                                 // Notify Listeners
232                                 ListenerEntry le = listeners;
233                                 while (le!=null) {
234                                         // Notification
235                                         VariantInterestSet is = le.getInterestSet();
236                                         if (is.inNotifications()) {\r
237                                                 if (is.inValues()) {\r
238                                                         MutableVariant value = new MutableVariant( valueBinding, valueBinding.isImmutable() ? newValue : valueBinding.clone(newValue) );\r
239                                                         ValueAssigned e = new ValueAssigned(Bindings.MUTABLE_VARIANT, value );\r
240                                                         emitEvent(le, e);\r
241                                                 } else {\r
242                                                         emitEvent( le, new ValueAssigned() );                                                   \r
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 {\r
263                         writeUnlock();\r
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         \r
321                                 setValue(va.newValue.getBinding(), va.newValue.getValue());
322 //                              setContentValue(va.newValue.getBinding(), va.newValue.getValue());
323                                 
324                                 return rollback;\r
325                         } else {\r
326                                 throw new AccessorException("Invalid event "+e.getClass().getName());\r
327                         }
328                 } catch (BindingException be) {
329                         throw new AccessorException(be);
330                 }
331         }
332         
333 }
334