]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/mutable/Variant.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / mutable / Variant.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.binding.mutable;
13
14 import java.io.IOException;
15
16 import org.simantics.databoard.Accessors;
17 import org.simantics.databoard.Bindings;
18 import org.simantics.databoard.accessor.VariantAccessor;
19 import org.simantics.databoard.accessor.error.AccessorConstructionException;
20 import org.simantics.databoard.accessor.java.JavaObject;
21 import org.simantics.databoard.accessor.reference.ChildReference;
22 import org.simantics.databoard.adapter.AdaptException;
23 import org.simantics.databoard.binding.Binding;
24 import org.simantics.databoard.binding.error.BindingException;
25 import org.simantics.databoard.binding.error.RuntimeBindingException;
26 import org.simantics.databoard.binding.reflection.VoidBinding;
27 import org.simantics.databoard.parser.DataValuePrinter;
28 import org.simantics.databoard.parser.PrintFormat;
29 import org.simantics.databoard.parser.repository.DataValueRepository;
30 import org.simantics.databoard.parser.unparsing.DataTypePrinter;
31 import org.simantics.databoard.type.Datatype;
32
33 /**
34  * Variant is a container to a data value of any type. 
35  * This very class is immutable, the value and type cannot be changed, but the 
36  * sub-class {@link MutableVariant} is not. <p>
37  *
38  * Variant is hash-equals-comparable, even variants of bindings (and types). 
39  * The hash function and comparison rules are defined in the manual.  <p>
40  *
41  * @see ImmutableVariantBinding is binding for Variant-class
42  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
43  */
44 public class Variant implements Comparable<Variant>, Cloneable {
45         
46         public static Variant ofInstance(Object instance) {
47                 Binding binding = Bindings.getBindingUnchecked( instance.getClass() );
48                 return new Variant(binding, instance);
49         }
50         
51         Binding binding;
52         Object value;
53         
54         /**
55          * Constract a variant with a default value of empty record {}
56          */
57         public Variant() {
58                 binding = VoidBinding.VOID_BINDING;
59                 value = null;
60         }
61
62         public Variant(Variant v) {
63                 //assert(isValid(binding, value));
64                 this.binding = v.getBinding();
65                 this.value = v.getValue();
66         }       
67         
68         public Variant(Binding binding, Object value) {
69                 //assert(isValid(binding, value));
70                 this.binding = binding;
71                 this.value = value;
72         }
73         
74         public Object getValue() {
75                 return value;
76         }
77
78         /**
79          * Get and if necessary and possible, type-adapt the value.
80          * 
81          * @param binding
82          * @return the value in given binding
83          * @throws AdaptException
84          */
85         public Object getValue(Binding binding) throws AdaptException {
86                 return Bindings.adapt(value, this.binding, binding);
87         }
88
89         public VariantAccessor getAccessor() {
90                 try {
91                         return (VariantAccessor) Accessors.getAccessor( Bindings.VARIANT, this);
92                 } catch (AccessorConstructionException e) {
93                         // Unexpected
94                         throw new RuntimeException(e);
95                 }
96         }
97         
98         public Datatype type() {
99                 return binding.type();
100         }
101         
102         public Binding getBinding() {
103                 return binding;
104         }
105         
106         @Override
107         public int hashCode() {
108                 try {
109                         return binding.hashValue(value);
110                 } catch (BindingException e) {
111                         throw new RuntimeBindingException(e);
112                 }
113         }
114         
115         @Override
116         public boolean equals(Object obj) {
117                 if(this == obj)
118                         return true;
119                 if(obj == null)
120                         return false;
121                 if(!(obj instanceof Variant))
122                         return false;
123                 try {
124                         Variant o = (Variant) obj;
125                         if (o.binding==binding && o.value == value) return true;
126                         return Bindings.equals(binding, value, o.binding, o.value);
127                 } catch (BindingException e) {
128                         throw new RuntimeBindingException(e);
129                 }
130         }
131         
132         public boolean valueEquals(Binding binding, Object obj)
133         {
134                 if (this.binding == binding) return binding.equals(obj, this.value);
135                 Object adapted;
136                 try {
137                         adapted = Bindings.adapt(obj, binding, this.binding);
138                         return this.binding.equals(adapted, this.value);
139                 } catch (AdaptException e) {
140                         return false;
141                 }
142         }
143         
144         @Override
145         public int compareTo(Variant o) {
146                 try {
147                         if (o.binding==binding && o.value == value) return 0;
148                         return Bindings.compare(binding, value, o.binding, o.value);
149                 } catch (BindingException e) {
150                         throw new RuntimeBindingException(e);
151                 }
152         }
153         
154         @Override
155         public String toString() {
156                 try {
157                         StringBuilder sb = new StringBuilder();                 
158                         DataValueRepository repo = new DataValueRepository();
159                         DataValuePrinter printer = new DataValuePrinter(sb, repo);
160                         printer.setFormat(PrintFormat.SINGLE_LINE);
161                         printer.print(binding, value);
162                         sb.append(" : ");
163                         DataTypePrinter printer2 = new DataTypePrinter(sb);
164                         printer2.print(binding.type());
165                         return sb.toString();
166                 } catch (IOException e) {
167                         throw new RuntimeException(e);
168                 } catch (BindingException e) {
169                         throw new RuntimeBindingException(e);
170                 }
171         }
172         
173         public Variant clone() {
174                 if (binding.isImmutable()) return new Variant(binding, value);
175                 Object newValue = Bindings.cloneUnchecked(value, binding, binding);
176                 return new Variant(binding, newValue);
177         }
178
179         boolean isValid(Binding binding, Object obj) throws RuntimeBindingException {
180                 try {
181                         binding.assertInstaceIsValid(obj);
182                         return true;
183                 } catch (BindingException e) {
184                         throw new RuntimeBindingException(e);
185                 }
186         }
187
188         
189         /**
190          * Open a variant to a component object.
191          *  
192          * @param ref child reference, if null then this object is returned
193          * @return variant to this or new variant that refers to actual child object
194          * @throws AccessorConstructionException 
195          */
196         public Variant getComponent(ChildReference ref) throws AccessorConstructionException {
197                 if ( ref == null ) return this;
198                 JavaObject jo = (JavaObject) Accessors.getAccessor(this, ref);
199                 return new Variant( jo.getBinding(), jo.getObject() );
200         }
201                 
202 }
203
204