X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Faccessor%2Fjava%2FJavaOptional.java;fp=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Faccessor%2Fjava%2FJavaOptional.java;h=8ec107c6f7df166c82b289d59212dd4250dd0d38;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaOptional.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaOptional.java new file mode 100644 index 000000000..8ec107c6f --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/java/JavaOptional.java @@ -0,0 +1,343 @@ +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.accessor.java; + +import java.lang.ref.SoftReference; +import java.util.concurrent.Executor; + +import org.simantics.databoard.accessor.Accessor; +import org.simantics.databoard.accessor.OptionalAccessor; +import org.simantics.databoard.accessor.error.AccessorConstructionException; +import org.simantics.databoard.accessor.error.AccessorException; +import org.simantics.databoard.accessor.error.ReferenceException; +import org.simantics.databoard.accessor.event.Event; +import org.simantics.databoard.accessor.event.OptionalValueAssigned; +import org.simantics.databoard.accessor.event.OptionalValueRemoved; +import org.simantics.databoard.accessor.event.ValueAssigned; +import org.simantics.databoard.accessor.impl.AccessorParams; +import org.simantics.databoard.accessor.impl.ListenerEntry; +import org.simantics.databoard.accessor.interestset.InterestSet; +import org.simantics.databoard.accessor.interestset.OptionalInterestSet; +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.accessor.reference.ComponentReference; +import org.simantics.databoard.accessor.reference.LabelReference; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.adapter.AdapterConstructionException; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.OptionalBinding; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.binding.mutable.MutableVariant; +import org.simantics.databoard.type.OptionalType; + +public class JavaOptional extends JavaObject implements OptionalAccessor { + + /** Accessor to component */ + SoftReference component; + + public JavaOptional(Accessor parent, OptionalBinding binding, Object object, AccessorParams params) { + super(parent, binding, object, params); + } + + @Override + public OptionalBinding getBinding() { + return (OptionalBinding) binding; + } + + @Override + public OptionalType type() { + return (OptionalType) getBinding().type(); + } + + @SuppressWarnings("unchecked") + @Override + public T getComponentAccessor() throws AccessorConstructionException + { + try { + if (!getBinding().hasValue(object)) return null; + + // Get existing or create new + JavaObject sa = getExistingAccessor(); + + if (sa==null) { + // Instantiate new accessor + Binding cb = getBinding().getComponentBinding(); + Object cv = getBinding().getValue(object); + + // Instantiate correct sub accessor. + sa = createSubAccessor(this, cb, cv, params); + component = new SoftReference(sa); + + // Add listener to component, if it is in our interest set + ListenerEntry le = listeners; + while (le!=null) { + OptionalInterestSet 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); + } + } + le = le.next; + } + } + + return (T) sa; + } catch (BindingException e) { + throw new AccessorConstructionException(e); + } + } + + /** + * Get existing sub accessor + * + * @return sub-accessor or null + */ + JavaObject getExistingAccessor() + { + // Get existing or create new + SoftReference ref = component; + JavaObject accessor = (ref!=null)?(JavaObject)ref.get():null; + return accessor; + } + + @Override + public Object getComponentValue(Binding componentBinding) + throws AccessorException { + readLock(); + try { + if (!getBinding().hasValue(object)) + throw new AccessorException("There is no component value"); + + Binding cb = getBinding().getComponentBinding(); + Object cv = getBinding().getValue(object); + return adapt(cv, cb, componentBinding); + } catch (BindingException e) { + throw new AccessorException(e); + } catch (AdaptException e) { + throw new AccessorException(e); + } catch (AdapterConstructionException e) { + throw new AccessorException(e); + } finally { + readUnlock(); + } + } + + @Override + public void addListener(Listener listener, InterestSet interestSet, + ChildReference path, Executor executor) throws AccessorException { + super.addListener(listener, interestSet, path, executor); + OptionalInterestSet is = (OptionalInterestSet) interestSet; + InterestSet cis = is.getComponentInterest(); + if (cis==null) return; + JavaObject sa = getExistingAccessor(); + if (sa==null) return; + ChildReference childPath = ChildReference.concatenate( path, new ComponentReference() ); + sa.addListener(listener, cis, childPath, executor); + } + + @Override + public void removeListener(Listener listener) throws AccessorException { + ListenerEntry e = detachListener(listener); + if (e==null) return; + OptionalInterestSet is = (OptionalInterestSet) e.interestSet; + + InterestSet cis = is.getComponentInterest(); + if (cis==null) return; + JavaObject sa = getExistingAccessor(); + if (sa==null) return; + sa.removeListener(listener); + } + + @SuppressWarnings("unchecked") + @Override + public T getComponent(ChildReference reference) throws AccessorConstructionException { + if (reference==null) return (T) this; + + if (reference instanceof LabelReference) { + LabelReference lr = (LabelReference) reference; + if (lr.label.equals("o")) { + Accessor result = getComponentAccessor(); + if (reference.getChildReference() != null) + result = result.getComponent(reference.getChildReference()); + return (T) result; + } + } + + if (reference instanceof ComponentReference) { + Accessor result = getComponentAccessor(); + if (reference.getChildReference() != null) + result = result.getComponent(reference.getChildReference()); + return (T) result; + } + + throw new ReferenceException(reference.getClass()+" is not a reference of OptionalType"); + } + + @Override + public void setValue(Binding binding, Object newValue) throws AccessorException { + writeLock(); + try { + OptionalBinding rb = (OptionalBinding) binding; + Object rv = newValue; + boolean rvHasValue = rb.hasValue(newValue); + + if (rvHasValue) { + Binding rcb = rb.getComponentBinding(); + Object rcv = rb.getValue(rv); + setComponentValue(rcb, rcv); + } else { + setNoValue(); + } + + } catch (BindingException e) { + throw new AccessorException(e); + } finally { + writeUnlock(); + } + } + + @Override + public boolean hasValue() throws AccessorException { + readLock(); + try { + return getBinding().hasValue(object); + } catch (BindingException e) { + throw new AccessorException(e); + } finally { + readUnlock(); + } + } + + + @Override + public void setNoValue() throws AccessorException { + writeLock(); + try { + boolean hadValue = getBinding().hasValue(object); + if (!hadValue) return; + + // Write + getBinding().setNoValue(object); + + // Disconnect sub-accessor + JavaObject sa = getExistingAccessor(); + component = null; + // Notify about disconnection of sub-accessor + if (sa!=null) sa.invalidatedNotification(); + + // Notify Listeners + ListenerEntry le = listeners; + while (le!=null) { + OptionalInterestSet is = le.getInterestSet(); + if (is.inNotifications()) { + OptionalValueRemoved e = new OptionalValueRemoved(); + emitEvent(le, e); + } + le = le.next; + } + + } catch (BindingException e) { + throw new AccessorException(e); + } finally { + writeUnlock(); + } + } + + @Override + public void setComponentValue(Binding binding, Object value) + throws AccessorException { + writeLock(); + try { + Binding rcb = binding; + Object rcv = value; + boolean hadValue = getBinding().hasValue(object); + + // Write to component + JavaObject sa = getExistingAccessor(); + if (sa!=null) { + assert(hadValue); + sa.setValue(rcb, rcv); + return; + } + + Binding lcb = getBinding().getComponentBinding(); + Object lcv = adapt(rcv, rcb, lcb); + + // Write + getBinding().setValue(object, lcv); + + // Notify Listeners + ListenerEntry le = listeners; + while (le!=null) { + OptionalInterestSet is = le.getInterestSet(); + if (is.inNotifications()) { + MutableVariant newComponentValue = null; + if (is.inValues()) newComponentValue = new MutableVariant(lcb, lcb.isImmutable() ? lcv : lcb.clone(lcv)); + OptionalValueAssigned e = new OptionalValueAssigned(newComponentValue); + emitEvent(le, e); + } + + // Attach component interest +// if (is.getComponentInterest()!=null && getComponentAccessor()!=null) { +// sa = getComponentAccessor(); +// } + + le = le.next; + } + + } catch (BindingException e) { + throw new AccessorException(e); + } catch (AdaptException e) { + throw new AccessorException(e); + } catch (AdapterConstructionException e) { + throw new AccessorException(e); + } finally { + writeUnlock(); + } + + } + + @Override + Event applyLocal(Event e, boolean makeRollback) throws AccessorException { + try { + Event rollback = null; + if (makeRollback) { + OptionalBinding b = getBinding(); + Binding cb = getBinding().getComponentBinding(); + rollback = hasValue() ? new OptionalValueAssigned(cb, b.getValue(object)) : new OptionalValueRemoved(); + } + if (e instanceof ValueAssigned) { + ValueAssigned va = (ValueAssigned) e; + setValue(va.newValue.getBinding(), va.newValue.getValue()); + return rollback; + } else + if (e instanceof OptionalValueAssigned) { + OptionalValueAssigned oa = (OptionalValueAssigned) e; + if (oa.newValue==null) throw new AccessorException("Cannot apply field assignment event, the value is missing"); + setComponentValue(oa.newValue.getBinding(), oa.newValue.getValue()); + } else if (e instanceof OptionalValueRemoved) { + //OptionalValueRemoved or = (OptionalValueRemoved) e; + setNoValue(); + } else throw new AccessorException("Unexpected event type "+e.getClass().getName()+" for an Optional Type"); + + return rollback; + } catch (BindingException be) { + throw new AccessorException( be ); + } + } + + +} +