]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaVariant.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaVariant.java
new file mode 100644 (file)
index 0000000..74b7efb
--- /dev/null
@@ -0,0 +1,334 @@
+/*******************************************************************************\r
+ *  Copyright (c) 2010 Association for Decentralized Information Management in\r
+ *  Industry THTH ry.\r
+ *  All rights reserved. This program and the accompanying materials\r
+ *  are made available under the terms of the Eclipse Public License v1.0\r
+ *  which accompanies this distribution, and is available at\r
+ *  http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ *  Contributors:\r
+ *      VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.accessor.java;
+
+import java.lang.ref.SoftReference;\r
+import java.util.concurrent.Executor;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.Accessor;\r
+import org.simantics.databoard.accessor.VariantAccessor;\r
+import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.accessor.error.ReferenceException;\r
+import org.simantics.databoard.accessor.event.Event;\r
+import org.simantics.databoard.accessor.event.ValueAssigned;\r
+import org.simantics.databoard.accessor.impl.AccessorParams;\r
+import org.simantics.databoard.accessor.impl.ListenerEntry;\r
+import org.simantics.databoard.accessor.interestset.InterestSet;\r
+import org.simantics.databoard.accessor.interestset.VariantInterestSet;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.accessor.reference.ComponentReference;\r
+import org.simantics.databoard.accessor.reference.LabelReference;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.VariantBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.MutableVariant;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.VariantType;\r
+
+public class JavaVariant extends JavaObject implements VariantAccessor {
+
+       SoftReference<JavaObject> child;        
+       
+       public JavaVariant(Accessor parent, VariantBinding binding, Object object, AccessorParams params) {
+               super(parent, binding, object, params);
+       }
+       
+       @Override
+       public VariantType type() {
+               return (VariantType) binding.type();
+       }
+       
+       @Override
+       public VariantBinding getBinding() {
+               return (VariantBinding) binding;
+       }
+
+       @SuppressWarnings("unchecked")
+       @Override
+       public <T extends Accessor> T getContentAccessor() throws AccessorConstructionException {
+               try {
+                       JavaObject sa = getExistingAccessor();
+                       if (sa==null) \r
+                       {\r
+                               readLock();\r
+                               try {
+                                       // Create new child
+                                       Binding cb = getBinding().getContentBinding(object);
+                                       Object cv = getBinding().getContent(object);
+                                       sa = JavaObject.createSubAccessor(this, cb, cv, params);
+                                       child = new SoftReference<JavaObject>(sa);
+                                       
+                                       // Attach listeners of interest set to the new accessor (of the value)
+                                       ListenerEntry le = listeners;
+                                       while (le!=null) {                              
+                                               VariantInterestSet is = le.getInterestSet();
+                                               InterestSet cis = is.getComponentInterest();
+                                               if (cis != null) {
+                                                       try {
+                                                               ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
+                                                               sa.addListener(le.listener, cis, childPath, le.executor);
+                                                       } catch (AccessorException e) {
+                                                               throw new AccessorConstructionException(e);
+                                                       }
+                                               }
+                                               if (is.inCompleteComponent()) {
+                                                       cis = InterestSet.newInterestSet(getContentType(), true, true, true);
+                                                       try {
+                                                               ChildReference childPath = ChildReference.concatenate(le.path, new ComponentReference() );
+                                                               sa.addListener(le.listener, cis, childPath, le.executor);
+                                                       } catch (AccessorException e) {
+                                                               throw new AccessorConstructionException(e);
+                                                       }
+                                               }
+                                               le = le.next;
+                                       }
+                               } finally {\r
+                                       readUnlock();\r
+                               }                               
+                       }
+                       return (T) sa;
+               } catch (BindingException e) {
+                       throw new AccessorConstructionException(e);
+               } catch (AccessorException e) {
+                       throw new AccessorConstructionException(e);
+               }
+       }
+
+       @SuppressWarnings("unchecked")
+       @Override
+       public <T extends Accessor> T getComponent(ChildReference reference)
+                       throws AccessorConstructionException {          
+               if (reference==null) return (T) this;\r
+               \r
+               if (reference instanceof LabelReference) {\r
+                       LabelReference lr = (LabelReference) reference;\r
+                       if (lr.label.equals("v")) {\r
+                               Accessor sa = getContentAccessor();\r
+                               if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
+                               return (T) sa;\r
+                       }                       \r
+               }               \r
+               
+               if (reference instanceof ComponentReference) {\r
+                       Accessor sa = getContentAccessor();\r
+                       if (reference.getChildReference()!=null) sa = sa.getComponent(reference.getChildReference());\r
+                       return (T) sa;\r
+               }\r
+               
+               throw new ReferenceException("Variant value reference expected, got "+reference.getClass().getName());
+       }
+
+       protected JavaObject getExistingAccessor() {
+               SoftReference<JavaObject> r = child;
+               if (r==null) return null;
+               JavaObject sa = r.get();
+               return sa;
+       }
+       
+       @Override
+       public void setValue(Binding variantBinding, Object newVariant)
+               throws AccessorException {\r
+               writeLock();
+               try {
+                       if (binding instanceof VariantBinding == false)
+                               throw new AccessorException("VariantBinding is expected.");\r
+                       \r
+                       Binding newValueBinding = ((VariantBinding)variantBinding).getContentBinding(newVariant);
+                       Object newValueObject = ((VariantBinding)variantBinding).getContent(newVariant);
+                       setContentValue(newValueBinding, newValueObject);
+               } catch (BindingException e) {
+                       throw new AccessorException( e ); 
+               } finally {\r
+                       writeUnlock();\r
+               }
+       }
+
+       @Override
+       public Object getContentValue(Binding contentBinding)
+       throws AccessorException {\r
+               readLock();
+               try {
+                       return getBinding().getContent(object);
+               } catch (BindingException e) {
+                       throw new AccessorException(e);
+               } finally {\r
+                       readUnlock();\r
+               }
+       }
+       
+       @Override
+       public Datatype getContentType() throws AccessorException {\r
+               readLock();
+               try {
+                       return getBinding().getContentType(object);
+               } catch (BindingException e) {
+                       throw new AccessorException(e);
+               } finally {\r
+                       readUnlock();\r
+               }
+       }
+       
+       @Override
+       public void setContentValue(Binding valueBinding, Object newValue)
+       throws AccessorException {\r
+               writeLock();
+               try {
+                       // reuse sub-accessor, if type matches, and sub-accessor exists
+                       JavaObject sa = getExistingAccessor();
+                       
+                       if (sa!=null && valueBinding.type().equals(sa.type())) {
+                               sa.setValue(valueBinding, newValue);
+                               return;
+                       }
+                       
+                       {
+                               // Replace the old value with a new value
+                               if (sa!=null) {
+                                       sa.invalidatedNotification();
+                                       child = null;
+                                       sa = null;
+                               }\r
+                               \r
+                               \r
+                               if (binding.isImmutable() && parent!=null && parent instanceof JavaArray) {\r
+                                       JavaObject jo = (JavaObject) parent;\r
+                                       ArrayBinding ab = (ArrayBinding) jo.binding;\r
+                                       Object nv = getBinding().create(valueBinding, newValue);\r
+                                       ab.set(jo.object, (Integer)keyInParent, nv);\r
+                                       this.object = nv;\r
+                               } else if (binding.isImmutable() && parent!=null && parent instanceof JavaRecord) {\r
+                                       JavaObject jo = (JavaObject) parent;\r
+                                       RecordBinding rb = (RecordBinding) jo.binding;\r
+                                       Object nv = getBinding().create(valueBinding, newValue);\r
+                                       rb.setComponent(jo.object, (Integer)keyInParent, nv);\r
+                                       this.object = nv;\r
+                               } else if (binding.isImmutable() && parent!=null && parent instanceof JavaVariant) {\r
+                                       JavaObject jo = (JavaObject) parent;\r
+                                       VariantBinding vb = (VariantBinding) jo.binding;\r
+                                       Object nv = getBinding().create(valueBinding, newValue);\r
+                                       vb.setContent(jo.object, getBinding(), nv);\r
+                                       this.object = nv;\r
+                               } else {                        \r
+                                       // Write new value\r
+                                       getBinding().setContent(object, valueBinding, newValue);\r
+                               }       \r
+                               
+                               
+                               // Notify Listeners
+                               ListenerEntry le = listeners;
+                               while (le!=null) {
+                                       // Notification
+                                       VariantInterestSet is = le.getInterestSet();
+                                       if (is.inNotifications()) {\r
+                                               if (is.inValues()) {\r
+                                                       MutableVariant value = new MutableVariant( valueBinding, valueBinding.isImmutable() ? newValue : valueBinding.clone(newValue) );\r
+                                                       ValueAssigned e = new ValueAssigned(Bindings.MUTABLE_VARIANT, value );\r
+                                                       emitEvent(le, e);\r
+                                               } else {\r
+                                                       emitEvent( le, new ValueAssigned() );                                                   \r
+                                               }
+                                       }
+                                       
+                                       // Attach component listener
+//                                     InterestSet cis = is.getComponentInterest();
+//                                     if (cis!=null) {
+//                                             sa = getValueAccessor();
+//                                     }
+                                       
+                                       le = le.next;
+                               }
+                               
+                       }
+               } catch (BindingException e) {
+                       throw new AccessorException(e);
+//             } catch (AccessorConstructionException e) {
+//                     throw new AccessorException(e);
+               } catch (AdaptException e) {
+                       throw new AccessorException(e);
+               } finally {\r
+                       writeUnlock();\r
+               }
+       }
+       
+       @Override
+       public void addListener(Listener listener, InterestSet interestSet,
+                       ChildReference path, Executor executor) throws AccessorException {
+               super.addListener(listener, interestSet, path, executor);
+               VariantInterestSet is = (VariantInterestSet) interestSet;
+               InterestSet cis = is.getComponentInterest();
+               if (cis==null && !is.inCompleteComponent()) return;
+               JavaObject sa = getExistingAccessor();
+               if (sa==null) return;
+               if (cis!=null) {
+                       ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
+                       sa.addListener(listener, cis, childPath, executor);
+               }
+               if (is.inCompleteComponent()) {
+                       ChildReference childPath = ChildReference.concatenate(path, new ComponentReference() );
+                       cis = InterestSet.newInterestSet(getContentType(), true, true, true);
+                       sa.addListener(listener, cis, childPath, executor);
+               }
+       }               
+       
+       @Override
+       public void removeListener(Listener listener) throws AccessorException {
+               ListenerEntry e = detachListener(listener);
+               if (e==null) return;
+               VariantInterestSet is = (VariantInterestSet) e.interestSet;
+               
+               InterestSet cis = is.getComponentInterest();
+               if (cis==null && !is.inCompleteComponent()) return;
+               JavaObject sa = getExistingAccessor();
+               if (sa==null) return;
+               if (cis!=null) {
+                       sa.removeListener(listener);
+               }
+               // Remove another?
+               if (is.inCompleteComponent()) {
+                       sa.removeListener(listener);
+               }               
+       }
+
+
+       @Override
+       Event applyLocal(Event e, boolean makeRollback) throws AccessorException {
+               try {
+                       Event rollback = null;                  
+                       if (e instanceof ValueAssigned) {
+                               ValueAssigned va = (ValueAssigned) e; 
+                               if (va.newValue==null) throw new AccessorException("Cannot apply variant assignment event, the value is missing");
+                               
+                               if (makeRollback) {
+                                       Binding cb = getBinding().getContentBinding(object);
+                                       Object cv = getBinding().getContent(object);
+                                       rollback = new ValueAssigned( Bindings.MUTABLE_VARIANT, new MutableVariant( cb, cv ) );
+                               }
+       \r
+                               setValue(va.newValue.getBinding(), va.newValue.getValue());
+//                             setContentValue(va.newValue.getBinding(), va.newValue.getValue());
+                               
+                               return rollback;\r
+                       } else {\r
+                               throw new AccessorException("Invalid event "+e.getClass().getName());\r
+                       }
+               } catch (BindingException be) {
+                       throw new AccessorException(be);
+               }
+       }
+       
+}
+