]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaOptional.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / java / JavaOptional.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.OptionalAccessor;
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.OptionalValueAssigned;
24 import org.simantics.databoard.accessor.event.OptionalValueRemoved;
25 import org.simantics.databoard.accessor.event.ValueAssigned;
26 import org.simantics.databoard.accessor.impl.AccessorParams;
27 import org.simantics.databoard.accessor.impl.ListenerEntry;
28 import org.simantics.databoard.accessor.interestset.InterestSet;
29 import org.simantics.databoard.accessor.interestset.OptionalInterestSet;
30 import org.simantics.databoard.accessor.reference.ChildReference;
31 import org.simantics.databoard.accessor.reference.ComponentReference;
32 import org.simantics.databoard.accessor.reference.LabelReference;
33 import org.simantics.databoard.adapter.AdaptException;
34 import org.simantics.databoard.adapter.AdapterConstructionException;
35 import org.simantics.databoard.binding.Binding;
36 import org.simantics.databoard.binding.OptionalBinding;
37 import org.simantics.databoard.binding.error.BindingException;
38 import org.simantics.databoard.binding.mutable.MutableVariant;
39 import org.simantics.databoard.type.OptionalType;
40
41 public class JavaOptional extends JavaObject implements OptionalAccessor {
42
43         /** Accessor to component */
44         SoftReference<JavaObject> component;
45         
46         public JavaOptional(Accessor parent, OptionalBinding binding, Object object, AccessorParams params) {
47                 super(parent, binding, object, params);
48         }
49
50         @Override
51         public OptionalBinding getBinding() {
52                 return (OptionalBinding) binding;
53         }
54
55         @Override
56         public OptionalType type() {
57                 return (OptionalType) getBinding().type();
58         }       
59         
60         @SuppressWarnings("unchecked")
61         @Override
62         public <T extends Accessor> T getComponentAccessor() throws AccessorConstructionException
63         {
64                 try {
65                         if (!getBinding().hasValue(object)) return null;
66                         
67                         // Get existing or create new
68                         JavaObject sa = getExistingAccessor();
69                         
70                         if (sa==null) {
71                                 // Instantiate new accessor
72                                 Binding cb = getBinding().getComponentBinding();
73                                 Object cv = getBinding().getValue(object);
74                                 
75                                 // Instantiate correct sub accessor. 
76                                 sa = createSubAccessor(this, cb, cv, params);
77                                 component = new SoftReference<JavaObject>(sa);
78
79                                 // Add listener to component, if it is in our interest set
80                                 ListenerEntry le = listeners;
81                                 while (le!=null) {                              
82                                         OptionalInterestSet is = le.getInterestSet();
83                                         InterestSet cis = is.getComponentInterest(); 
84                                         if (cis != null) {
85                                                 try {
86                                                         ChildReference childPath = ChildReference.concatenate( le.path, new ComponentReference() );
87                                                         sa.addListener(le.listener, cis, childPath, le.executor);
88                                                 } catch (AccessorException e) {
89                                                         throw new AccessorConstructionException(e);
90                                                 }
91                                         }
92                                         le = le.next;
93                                 }                               
94                         }               
95                         
96                         return (T) sa;
97                 } catch (BindingException e) {
98                         throw new AccessorConstructionException(e);
99                 }
100         }
101
102         /**
103          * Get existing sub accessor
104          * 
105          * @return sub-accessor or <code>null</code>
106          */
107         JavaObject getExistingAccessor()
108         {
109                 // Get existing or create new
110                 SoftReference<JavaObject> ref = component;
111                 JavaObject accessor = (ref!=null)?(JavaObject)ref.get():null;
112                 return accessor;
113         }       
114         
115         @Override
116         public Object getComponentValue(Binding componentBinding)
117                         throws AccessorException {      
118                 readLock();
119                 try {
120                         if (!getBinding().hasValue(object))
121                                 throw new AccessorException("There is no component value");
122                         
123                         Binding cb = getBinding().getComponentBinding();
124                         Object cv = getBinding().getValue(object);
125                         return adapt(cv, cb, componentBinding);
126                 } catch (BindingException e) {
127                         throw new AccessorException(e);
128                 } catch (AdaptException e) {
129                         throw new AccessorException(e);
130                 } catch (AdapterConstructionException e) {
131                         throw new AccessorException(e);
132                 } finally {
133                         readUnlock();
134                 }
135         }
136         
137         @Override
138         public void addListener(Listener listener, InterestSet interestSet,
139                         ChildReference path, Executor executor) throws AccessorException {
140                 super.addListener(listener, interestSet, path, executor);
141                 OptionalInterestSet is = (OptionalInterestSet) interestSet;
142                 InterestSet cis = is.getComponentInterest();
143                 if (cis==null) return;
144                 JavaObject sa = getExistingAccessor();
145                 if (sa==null) return;
146                 ChildReference childPath = ChildReference.concatenate( path, new ComponentReference() );
147                 sa.addListener(listener, cis, childPath, executor);
148         }
149         
150         @Override
151         public void removeListener(Listener listener) throws AccessorException {
152                 ListenerEntry e = detachListener(listener);
153                 if (e==null) return;
154                 OptionalInterestSet is = (OptionalInterestSet) e.interestSet;
155                 
156                 InterestSet cis = is.getComponentInterest();
157                 if (cis==null) return;
158                 JavaObject sa = getExistingAccessor();
159                 if (sa==null) return;
160                 sa.removeListener(listener);            
161         }
162
163         @SuppressWarnings("unchecked")
164         @Override
165         public <T extends Accessor> T getComponent(ChildReference reference) throws AccessorConstructionException {
166                 if (reference==null) return (T) this;
167
168                 if (reference instanceof LabelReference) {
169                         LabelReference lr = (LabelReference) reference;
170                         if (lr.label.equals("o")) {
171                                 Accessor result = getComponentAccessor();
172                                 if (reference.getChildReference() != null)
173                                         result = result.getComponent(reference.getChildReference());
174                                 return (T) result;                      
175                         }                       
176                 }
177                 
178                 if (reference instanceof ComponentReference) {
179                         Accessor result = getComponentAccessor();
180                         if (reference.getChildReference() != null)
181                                 result = result.getComponent(reference.getChildReference());
182                         return (T) result;                      
183                 } 
184                 
185                 throw new ReferenceException(reference.getClass()+" is not a reference of OptionalType");               
186         }
187
188         @Override
189         public void setValue(Binding binding, Object newValue) throws AccessorException {
190                 writeLock();
191                 try {
192                         OptionalBinding rb = (OptionalBinding) binding;
193                         Object rv = newValue;
194                         boolean rvHasValue = rb.hasValue(newValue);
195                         
196                         if (rvHasValue) { 
197                                 Binding rcb = rb.getComponentBinding();
198                                 Object rcv = rb.getValue(rv);
199                                 setComponentValue(rcb, rcv);
200                         } else {
201                                 setNoValue();                           
202                         }
203                         
204                 } catch (BindingException e) {
205                         throw new AccessorException(e);
206                 } finally {
207                         writeUnlock();
208                 }
209         }
210
211         @Override
212         public boolean hasValue() throws AccessorException {
213                 readLock();
214                 try {
215                         return getBinding().hasValue(object);
216                 } catch (BindingException e) {
217                         throw new AccessorException(e);
218                 } finally {
219                         readUnlock();
220                 }
221         }
222
223
224         @Override
225         public void setNoValue() throws AccessorException {
226                 writeLock();
227                 try {
228                         boolean hadValue = getBinding().hasValue(object);
229                         if (!hadValue) return;
230                         
231                         // Write
232                         getBinding().setNoValue(object);                        
233
234                         // Disconnect sub-accessor
235                         JavaObject sa = getExistingAccessor();
236                         component = null;
237                         // Notify about disconnection of sub-accessor
238                         if (sa!=null) sa.invalidatedNotification();
239                                                 
240                         // Notify Listeners
241                         ListenerEntry le = listeners;
242                         while (le!=null) {                              
243                                 OptionalInterestSet is = le.getInterestSet();
244                                 if (is.inNotifications()) {
245                                         OptionalValueRemoved e = new OptionalValueRemoved();
246                                         emitEvent(le, e);
247                                 }
248                                 le = le.next;
249                         }
250                         
251                 } catch (BindingException e) {
252                         throw new AccessorException(e);
253                 } finally {
254                         writeUnlock();
255                 }
256         }
257
258         @Override
259         public void setComponentValue(Binding binding, Object value)
260                         throws AccessorException {
261                 writeLock();
262                 try {
263                         Binding rcb = binding;
264                         Object rcv = value;
265                         boolean hadValue = getBinding().hasValue(object);
266
267                         // Write to component
268                         JavaObject sa = getExistingAccessor();
269                         if (sa!=null) {
270                                 assert(hadValue);
271                                 sa.setValue(rcb, rcv);
272                                 return;
273                         }
274
275                         Binding lcb = getBinding().getComponentBinding();
276                         Object lcv = adapt(rcv, rcb, lcb);                      
277                         
278                         // Write
279                         getBinding().setValue(object, lcv);
280                         
281                         // Notify Listeners
282                         ListenerEntry le = listeners;
283                         while (le!=null) {                              
284                                 OptionalInterestSet is = le.getInterestSet();
285                                 if (is.inNotifications()) {                                     
286                                         MutableVariant newComponentValue = null;
287                                         if (is.inValues()) newComponentValue = new MutableVariant(lcb, lcb.isImmutable() ? lcv : lcb.clone(lcv));
288                                         OptionalValueAssigned e = new OptionalValueAssigned(newComponentValue);
289                                         emitEvent(le, e);
290                                 }
291                                 
292                                 // Attach component interest
293 //                              if (is.getComponentInterest()!=null && getComponentAccessor()!=null) {
294 //                                      sa = getComponentAccessor();
295 //                              }
296                                 
297                                 le = le.next;
298                         }
299                         
300                 } catch (BindingException e) {
301                         throw new AccessorException(e);
302                 } catch (AdaptException e) {
303                         throw new AccessorException(e);
304                 } catch (AdapterConstructionException e) {
305                         throw new AccessorException(e);
306                 } finally {
307                         writeUnlock();
308                 }
309                 
310         }
311
312         @Override
313         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
314                 try {
315                         Event rollback = null;
316                         if (makeRollback) {
317                                 OptionalBinding b = getBinding();
318                                 Binding cb = getBinding().getComponentBinding();                        
319                                 rollback = hasValue() ? new OptionalValueAssigned(cb, b.getValue(object)) : new OptionalValueRemoved(); 
320                         }                       
321                         if (e instanceof ValueAssigned) {
322                                 ValueAssigned va = (ValueAssigned) e;
323                                 setValue(va.newValue.getBinding(), va.newValue.getValue());
324                                 return rollback;
325                         } else          
326                         if (e instanceof OptionalValueAssigned) {
327                                 OptionalValueAssigned oa = (OptionalValueAssigned) e;
328                                 if (oa.newValue==null) throw new AccessorException("Cannot apply field assignment event, the value is missing");
329                                 setComponentValue(oa.newValue.getBinding(), oa.newValue.getValue());
330                         } else if (e instanceof OptionalValueRemoved) {
331                                 //OptionalValueRemoved or = (OptionalValueRemoved) e;
332                                 setNoValue();
333                         } else throw new AccessorException("Unexpected event type "+e.getClass().getName()+" for an Optional Type");
334                         
335                         return rollback;
336                 } catch (BindingException be) {
337                         throw new AccessorException( be );
338                 }
339         }
340
341         
342 }
343