X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fbinding%2Fmutable%2FVariant.java;fp=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fbinding%2Fmutable%2FVariant.java;h=277a08ffb7edbc3605025c6c04899fc9eb088478;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/mutable/Variant.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/mutable/Variant.java new file mode 100644 index 000000000..277a08ffb --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/mutable/Variant.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * 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.mutable; + +import java.io.IOException; + +import org.simantics.databoard.Accessors; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.accessor.VariantAccessor; +import org.simantics.databoard.accessor.error.AccessorConstructionException; +import org.simantics.databoard.accessor.java.JavaObject; +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.error.BindingException; +import org.simantics.databoard.binding.error.RuntimeBindingException; +import org.simantics.databoard.binding.reflection.VoidBinding; +import org.simantics.databoard.parser.DataValuePrinter; +import org.simantics.databoard.parser.PrintFormat; +import org.simantics.databoard.parser.repository.DataValueRepository; +import org.simantics.databoard.parser.unparsing.DataTypePrinter; +import org.simantics.databoard.type.Datatype; + +/** + * Variant is a container to a data value of any type. + * This very class is immutable, the value and type cannot be changed, but the + * sub-class {@link MutableVariant} is not.

+ * + * Variant is hash-equals-comparable, even variants of bindings (and types). + * The hash function and comparison rules are defined in the manual.

+ * + * @see ImmutableVariantBinding is binding for Variant-class + * @author Toni Kalajainen + */ +public class Variant implements Comparable, Cloneable { + + public static Variant ofInstance(Object instance) { + Binding binding = Bindings.getBindingUnchecked( instance.getClass() ); + return new Variant(binding, instance); + } + + Binding binding; + Object value; + + /** + * Constract a variant with a default value of empty record {} + */ + public Variant() { + binding = VoidBinding.VOID_BINDING; + value = null; + } + + public Variant(Variant v) { + //assert(isValid(binding, value)); + this.binding = v.getBinding(); + this.value = v.getValue(); + } + + public Variant(Binding binding, Object value) { + //assert(isValid(binding, value)); + this.binding = binding; + this.value = value; + } + + public Object getValue() { + return value; + } + + /** + * Get and if necessary and possible, type-adapt the value. + * + * @param binding + * @return the value in given binding + * @throws AdaptException + */ + public Object getValue(Binding binding) throws AdaptException { + return Bindings.adapt(value, this.binding, binding); + } + + public VariantAccessor getAccessor() { + try { + return (VariantAccessor) Accessors.getAccessor( Bindings.VARIANT, this); + } catch (AccessorConstructionException e) { + // Unexpected + throw new RuntimeException(e); + } + } + + public Datatype type() { + return binding.type(); + } + + public Binding getBinding() { + return binding; + } + + @Override + public int hashCode() { + try { + return binding.hashValue(value); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + @Override + public boolean equals(Object obj) { + if(this == obj) + return true; + if(obj == null) + return false; + if(!(obj instanceof Variant)) + return false; + try { + Variant o = (Variant) obj; + if (o.binding==binding && o.value == value) return true; + return Bindings.equals(binding, value, o.binding, o.value); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + public boolean valueEquals(Binding binding, Object obj) + { + if (this.binding == binding) return binding.equals(obj, this.value); + Object adapted; + try { + adapted = Bindings.adapt(obj, binding, this.binding); + return this.binding.equals(adapted, this.value); + } catch (AdaptException e) { + return false; + } + } + + @Override + public int compareTo(Variant o) { + try { + if (o.binding==binding && o.value == value) return 0; + return Bindings.compare(binding, value, o.binding, o.value); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + @Override + public String toString() { + try { + StringBuilder sb = new StringBuilder(); + DataValueRepository repo = new DataValueRepository(); + DataValuePrinter printer = new DataValuePrinter(sb, repo); + printer.setFormat(PrintFormat.SINGLE_LINE); + printer.print(binding, value); + sb.append(" : "); + DataTypePrinter printer2 = new DataTypePrinter(sb); + printer2.print(binding.type()); + return sb.toString(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + public Variant clone() { + if (binding.isImmutable()) return new Variant(binding, value); + Object newValue = Bindings.cloneUnchecked(value, binding, binding); + return new Variant(binding, newValue); + } + + boolean isValid(Binding binding, Object obj) throws RuntimeBindingException { + try { + binding.assertInstaceIsValid(obj); + return true; + } catch (BindingException e) { + throw new RuntimeBindingException(e); + } + } + + + /** + * Open a variant to a component object. + * + * @param ref child reference, if null then this object is returned + * @return variant to this or new variant that refers to actual child object + * @throws AccessorConstructionException + */ + public Variant getComponent(ChildReference ref) throws AccessorConstructionException { + if ( ref == null ) return this; + JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref); + return new Variant( jo.getBinding(), jo.getObject() ); + } + +} + +