]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaRecord.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / java / JavaRecord.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.RecordAccessor;
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.ValueAssigned;
24 import org.simantics.databoard.accessor.impl.AccessorParams;
25 import org.simantics.databoard.accessor.impl.ListenerEntry;
26 import org.simantics.databoard.accessor.interestset.InterestSet;
27 import org.simantics.databoard.accessor.interestset.RecordInterestSet;
28 import org.simantics.databoard.accessor.reference.ChildReference;
29 import org.simantics.databoard.accessor.reference.IndexReference;
30 import org.simantics.databoard.accessor.reference.LabelReference;
31 import org.simantics.databoard.accessor.reference.NameReference;
32 import org.simantics.databoard.adapter.AdaptException;
33 import org.simantics.databoard.adapter.AdapterConstructionException;
34 import org.simantics.databoard.binding.Binding;
35 import org.simantics.databoard.binding.RecordBinding;
36 import org.simantics.databoard.binding.error.BindingException;
37 import org.simantics.databoard.binding.mutable.MutableVariant;
38 import org.simantics.databoard.type.RecordType;
39
40 /**
41  * Accessor to a Java Object of Record Type.
42  *
43  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
44  */
45 public class JavaRecord extends JavaObject implements RecordAccessor {
46
47         /** Accessors to children */
48         SoftReference<JavaObject>[] children;
49         
50         @SuppressWarnings("unchecked")
51         public JavaRecord(Accessor parent, RecordBinding binding, Object object, AccessorParams params) throws AccessorConstructionException {
52                 super(parent, binding, object, params);
53                 RecordType type = (RecordType) binding.type();
54                 if (type.isReferable()) throw new AccessorConstructionException("Refereable record are not supported");
55                 
56                 int count = binding.type().getComponentCount();
57                 children = new SoftReference[count];
58         }
59
60         @Override
61         public RecordBinding getBinding() {
62                 return (RecordBinding) binding;
63         }
64
65         @Override
66         public RecordType type() {
67                 return (RecordType) getBinding().type();
68         }       
69         
70         @Override
71         public int count() {
72                 return type().getComponentCount();
73         }
74
75         @SuppressWarnings("unchecked")
76         @Override
77         public <T extends Accessor> T getFieldAccessor(String fieldName) throws AccessorConstructionException
78         {
79                 int fieldIndex = type().getComponentIndex(fieldName);
80                 if (fieldIndex<0) throw new AccessorConstructionException("Field "+fieldName+" does not exist");
81                 return (T) getFieldAccessor(fieldIndex);
82         }       
83         
84         @SuppressWarnings("unchecked")
85         @Override
86         public <T extends Accessor> T getFieldAccessor(int index) throws AccessorConstructionException
87         {
88                 if (index<0 || index>=count()) throw new ReferenceException("Field index ("+index+") out of bounds ("+count()+")");
89                 
90                 readLock();
91                 try {
92                         // Get existing or create new
93                         SoftReference<JavaObject> ref = children[index];
94                         JavaObject sa = (ref!=null)?(JavaObject)ref.get():null;
95                         
96                         if (sa==null) {
97                                 // Instantiate new accessor
98                                 Binding cb = getBinding().getComponentBindings()[index];
99                                 Object cv = getBinding().getComponent(object, index);
100                                 sa = createSubAccessor(this, cb, cv, params);
101                                 sa.keyInParent = index;
102                                 children[index] = new SoftReference<JavaObject>(sa);
103
104                                 // Add component interest sets
105                                 ListenerEntry le = listeners;
106                                 while (le!=null) {                              
107                                         RecordInterestSet is = le.getInterestSet();
108                                         InterestSet cis = is.getComponentInterest(index); 
109                                         if (cis != null) {
110                                                 try {
111                                                         ChildReference childPath = ChildReference.concatenate( le.path, new IndexReference(index) );
112                                                         sa.addListener(le.listener, cis, childPath, le.executor);
113                                                 } catch (AccessorException e) {
114                                                         throw new AccessorConstructionException(e);
115                                                 }
116                                         }
117                                         le = le.next;
118                                 }                               
119                         }               
120                         
121                         return (T) sa;
122                 } catch (BindingException e) {
123                         throw new AccessorConstructionException(e);
124                 } finally {
125                         readUnlock();
126                 }
127         }
128
129         /**
130          * Get existing sub accessor
131          * @param index
132          * @return sub-accessor or <code>null</code>
133          */
134         JavaObject getExistingAccessor(int index)
135         {
136                 if (index<0 || index>=count()) throw new RuntimeException("Field index ("+index+") out of bounds ("+count()+")");
137                 
138                 // Get existing or create new
139                 SoftReference<JavaObject> ref = children[index];
140                 JavaObject accessor = (ref!=null)?(JavaObject)ref.get():null;
141                 return accessor;
142         }       
143         
144         @Override
145         public Object getFieldValue(String fieldName, Binding fieldBinding)
146                         throws AccessorException {
147                 int fieldIndex = type().getComponentIndex(fieldName);
148                 if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist");
149                 return getFieldValue(fieldIndex, fieldBinding);
150         }
151         
152         @Override
153         public Object getFieldValue(int index, Binding fieldBinding)
154                         throws AccessorException {
155                 readLock();
156                 try {
157                         Object cv = getBinding().getComponent(object, index);
158                         Binding cb = getBinding().getComponentBindings()[index];
159                         return adapt(cv, cb, fieldBinding);
160                 } catch (BindingException e) {
161                         throw new AccessorException(e);
162                 } catch (AdaptException e) {
163                         throw new AccessorException(e);
164                 } catch (AdapterConstructionException e) {
165                         throw new AccessorException(e);
166                 } finally {
167                         readUnlock();
168                 }
169         }
170
171         public void setFieldValue(String fieldName, Binding fieldBinding, Object value) throws AccessorException {
172                 int fieldIndex = type().getComponentIndex(fieldName);
173                 if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist");
174                 setFieldValue(fieldIndex, fieldBinding, value);
175         };
176         
177         @Override
178         public void setFieldValue(int index, Binding binding, Object value)
179         throws AccessorException {
180                 writeLock();
181                 try {                   
182                         JavaObject sa = getExistingAccessor(index);                             
183                         if (sa==null) {                         
184                                 // Init
185                                 Binding lb = getBinding().getComponentBindings()[index];
186                                 Binding rb = binding;
187                                 //Object oldlv = getBinding().getComponent(object, index);
188                                 Object rv = value;
189                                 
190                                 // Compare to existing value
191 //                              boolean equal = Bindings.equals(lb, oldlv, lb, rv);
192 //                              if (equal) return;
193
194                                 // Write
195                                 Object lv = adapt(rv, rb, lb);
196                                 getBinding().setComponent(object, index, lv);
197                                                                                                 
198                                 // Notify Listeners
199                                 ListenerEntry le = listeners;
200                                 while (le!=null) {                              
201                                         RecordInterestSet is = le.getInterestSet();
202                                         if (is.inNotificationsOf(index)) {
203                                                 MutableVariant newValue = is.inValuesOf(index) ? new MutableVariant(binding, value) : null;
204                                                 if (is.inValuesOf(index)) newValue = new MutableVariant(binding, binding.isImmutable() ? value : binding.clone(value));                                         
205                                                 Event e = new ValueAssigned(new IndexReference(index), newValue); 
206                                                 emitEvent(le, e);
207                                         }
208                                         le = le.next;
209                                 }                               
210                         } else {
211                                 // Recursive write using existing sub accessor
212                                 sa.setValue(binding, value);
213                         }                       
214                 } catch (BindingException e) {
215                         throw new AccessorException(e);
216                 } catch (AdaptException e) {
217                         throw new AccessorException(e);
218                 } catch (AdapterConstructionException e) {
219                         throw new AccessorException(e);
220                 } finally {
221                         writeUnlock();
222                 }
223         }
224         
225         @Override
226         public void addListener(Listener listener, InterestSet interestSet,
227                         ChildReference path, Executor executor) throws AccessorException {
228                 RecordInterestSet is = (RecordInterestSet) interestSet;
229                 super.addListener(listener, interestSet, path, executor);
230                 // Apply component interest set to existing sub-accessors
231                 if (is.componentInterests!=null) {
232                         for (int i=0; i<count(); i++) {
233                                 InterestSet cis = is.getComponentInterest(i);
234                                 if (cis==null) continue;
235                                 JavaObject childAccessor = getExistingAccessor(i);
236                                 if (childAccessor==null) continue;
237                                 ChildReference childPath = ChildReference.concatenate( path, new IndexReference(i));
238                                 childAccessor.addListener(listener, cis, childPath, executor);
239                         }
240                 }
241         }
242         
243         @Override
244         public void removeListener(Listener listener) throws AccessorException {
245                 ListenerEntry e = detachListener(listener);
246                 if (e==null) return;
247                 RecordInterestSet is = (RecordInterestSet) e.interestSet;
248                 
249                 // Apply component interest set to existing sub-accessors
250                 if (is.componentInterests!=null) {
251                         for (int i=0; i<count(); i++) {
252                                 InterestSet cis = is.getComponentInterest(i);
253                                 if (cis==null) continue;
254                                 JavaObject sa = getExistingAccessor(i);
255                                 if (sa==null) continue;
256                                 sa.removeListener(listener);
257                         }
258                 }
259         }
260
261
262         @SuppressWarnings("unchecked")
263         @Override
264         public <T extends Accessor> T getComponent(ChildReference reference) throws AccessorConstructionException {
265                 if (reference==null) return (T) this;
266                 
267                 if (reference instanceof LabelReference) {
268                         LabelReference lr = (LabelReference) reference;
269                         String fieldName = lr.label;
270                         Integer index = type().getComponentIndex(fieldName);
271                         if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");
272                         JavaObject sa = getFieldAccessor(index);
273                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());
274                         return (T) sa;                  
275                 }               
276                 
277                 if (reference instanceof IndexReference) {
278                         IndexReference ref = (IndexReference) reference;
279                         int index = ref.getIndex();
280                         JavaObject sa = getFieldAccessor(index);
281                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());
282                         return (T) sa;
283                 } 
284                 
285                 if (reference instanceof NameReference) {
286                         NameReference ref = (NameReference) reference;
287                         String fieldName = ref.getName();
288                         Integer index = type().getComponentIndex(fieldName);
289                         if (index==null) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");
290                         JavaObject sa = getFieldAccessor(index);
291                         if (reference.getChildReference() != null) sa = sa.getComponent(reference.getChildReference());
292                         return (T) sa;                  
293                 } 
294                 
295                 throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");
296                 
297         }
298
299         @Override
300         public void setValue(Binding binding, Object newValue) throws AccessorException {
301                 writeLock();
302                 try {
303                         RecordBinding rb = (RecordBinding) binding;
304                         for (int i=0; i<count(); i++) {
305                                 Binding componentBinding = rb.getComponentBinding(i);
306                                 Object componentValue = rb.getComponent(newValue, i);
307                                 setFieldValue(i, componentBinding, componentValue);
308                         }
309                 } catch (BindingException e) {
310                         throw new AccessorException(e);
311                 } finally {
312                         writeUnlock();
313                 }
314         }
315
316         
317         @Override
318         Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
319                 Event rollback = null;
320                 if (makeRollback) rollback = new ValueAssigned(getBinding(), getValue(getBinding())); 
321                 if (e instanceof ValueAssigned) {
322                         ValueAssigned va = (ValueAssigned) e;
323                         setValue(va.newValue.getBinding(), va.newValue.getValue());
324                         return rollback;
325                 } else {
326                         throw new AccessorException("Cannot apply "+e.getClass().getName()+" to Record Type");                          
327                 }
328         }       
329         
330 }
331