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