/******************************************************************************* * 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.binding; import java.util.IdentityHashMap; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.error.RuntimeBindingException; import org.simantics.databoard.binding.impl.BindingPrintContext; import org.simantics.databoard.binding.impl.ObjectVariantBinding; import org.simantics.databoard.binding.impl.StringVariantBinding; import org.simantics.databoard.binding.mutable.ImmutableVariantBinding; import org.simantics.databoard.binding.mutable.MutableVariant; import org.simantics.databoard.binding.mutable.MutableVariantBinding; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.VariantType; import org.simantics.databoard.util.DataValueUtil; import org.simantics.databoard.util.IdentityPair; /** * This is the abstract base class for bindings of VariantType Java Objects. * Variant is a container that has value of any Datatype. * * @see VariantType The Datatype * @see ImmutableVariantBinding Binds variant to {@link Variant} * @see MutableVariantBinding Binds variant to {@link MutableVariant} * @see ObjectVariantBinding Binds variant to java.lang.Object * @see StringVariantBinding Binds variant to java.lang.String (Filename and URL compatible) * @author Toni Kalajainen */ public abstract class VariantBinding extends Binding { public VariantBinding() { super(); this.type = Datatypes.VARIANT; } /** * Get the value in the variant. The returned value may represent internal * value of variant. * * @param variant the variant object to read the content from * @param contentBinding the format of return value * @return value variant's content * @throws BindingException */ public abstract Object getContent(Object variant, Binding contentBinding) throws BindingException; /** * Get the value of the variant. The value is bound with the suggested * binding, see {@link #getContentBinding(Object)}. * * @param variant the variant object * @return value variant's content * @throws BindingException */ public abstract Object getContent(Object variant) throws BindingException; /** * Get the data type of the content. * * @param variant the variant object * @return the data type * @throws BindingException */ public abstract Datatype getContentType(Object variant) throws BindingException; /** * Return a suggestion for the binding of the content of this variant. * * @param variant variant object * @return binding a binding */ public abstract Binding getContentBinding(Object variant) throws BindingException; /** * Create a new variant object. * The value argument may be included in the result. * * @param contentBinding the binding of the content * @param content content * @return new variant * @throws BindingException */ public abstract Object create(Binding contentBinding, Object content) throws BindingException; /** * Create a new variant object. * * @param contentBinding binding of the content * @param content content * @return new variant * @throws RuntimeBindingException */ public Object createUnchecked(Binding contentBinding, Object content) throws RuntimeBindingException { try { return create(contentBinding, content); } catch (BindingException e) { throw new RuntimeBindingException(e); } } @Override public void readFrom(Binding srcBinding, Object src, Object dst) throws BindingException { try { VariantBinding sb = (VariantBinding) srcBinding; Datatype newType = sb.getContentType(src); Datatype oldType = getContentType(dst); Binding scb = sb.getContentBinding(src); Object sc = sb.getContent(src, scb); if (newType.equals(oldType)) { Binding dcb = getContentBinding(dst); if (dcb.isImmutable()) { Object dc = Bindings.clone(sc, scb, scb); setContent(dst, scb, dc); } else { Object dc = getContent(dst, dcb); dc = dcb.readFromTry(scb, sc, dc); setContent(dst, dcb, dc); } } else { Object dc = Bindings.clone(sc, scb, scb); setContent(dst, scb, dc); } } catch (AdaptException e) { throw new BindingException(e); } } /** * Set the content of an variant. * * @param variant variant object * @param contentBinding content's binding * @param content new content * @throws BindingException */ public abstract void setContent(Object variant, Binding contentBinding, Object content) throws BindingException; @Override public void accept(Visitor1 v, Object obj) { v.visit(this, obj); } @Override public T accept(Visitor v) { return v.visit(this); } @Override public int deepHashValue(Object value, IdentityHashMap hashedObjects) throws BindingException { Datatype type = getContentType(value); Binding binding = getContentBinding(value); Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class); Object element = getContent(value, binding); return dataTypeBinding.deepHashValue(type, hashedObjects) + binding.deepHashValue(element, hashedObjects); } @Override public int deepCompare(Object o1, Object o2, Set> compareHistory) throws BindingException { // Compare Type Datatype t1 = getContentType(o1); Datatype t2 = getContentType(o2); Binding dataTypeBinding = Bindings.getBindingUnchecked(Datatype.class); int dif = dataTypeBinding.compare(t1, t2); if (dif!=0) return dif; // Compare Value Binding bi1 = getContentBinding(o1); Binding bi2 = getContentBinding(o2); Object va1 = getContent(o1, bi1); Object va2 = getContent(o2, bi2); return DataValueUtil.compare(bi1, va1, bi2, va2); } @Override protected void toString(Object value, BindingPrintContext ctx) throws BindingException { Binding b = getContentBinding(value); b.toString(getContent(value), ctx); ctx.b.append(" : "); ctx.b.append( ctx.singleLine ? b.type.toSingleLineString() : b.type.toString() ); } @Override public Binding getComponentBinding(ChildReference path) { if (path==null) return this; throw new IllegalArgumentException(); } @Override public int getComponentCount() { return 0; } @Override public Binding getComponentBinding(int index) { throw new IllegalArgumentException(); } }