]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/impl/StringVariantBinding.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / impl / StringVariantBinding.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.impl;\r
13 \r
14 import java.io.IOException;\r
15 import java.nio.ByteBuffer;\r
16 import java.util.Set;\r
17 \r
18 import org.simantics.databoard.Bindings;\r
19 import org.simantics.databoard.Datatypes;\r
20 import org.simantics.databoard.binding.Binding;\r
21 import org.simantics.databoard.binding.IntegerBinding;\r
22 import org.simantics.databoard.binding.LongBinding;\r
23 import org.simantics.databoard.binding.StringBinding;\r
24 import org.simantics.databoard.binding.VariantBinding;\r
25 import org.simantics.databoard.binding.error.BindingException;\r
26 import org.simantics.databoard.binding.mutable.MutableVariant;\r
27 import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;\r
28 import org.simantics.databoard.serialization.Serializer;\r
29 import org.simantics.databoard.serialization.SerializerConstructionException;\r
30 import org.simantics.databoard.serialization.SerializerFactory;\r
31 import org.simantics.databoard.type.Datatype;\r
32 import org.simantics.databoard.util.Base64;\r
33 import org.simantics.databoard.util.URIUtil;\r
34 import org.simantics.databoard.util.binary.BinaryMemory;\r
35 import org.simantics.databoard.util.binary.BinaryReadable;\r
36 \r
37 /**\r
38  * This class binding Variant to a filename/URL compatible String.\r
39  * The value is human-readable for strings, integers and longs. \r
40  * For datatypes the value is Base64 encoded binary.\r
41  * \r
42  *  Filenames have the following encoding:\r
43  *    S<string>       String types, if string doesn't have the following \r
44  *                    control characters " : < > | ? * # \ / % [0..31] [128..] are escaped with %<hex><hex>\r
45  *    I<integer>      Integer types\r
46  *    L<long>         Long types\r
47  *    B<base64>       All other cases. The value is binary encoded and presented as single line Base64 string.\r
48  *                    Base64 encoding has url and filename safe options enabled. \r
49  *\r
50  * See StringVariantBindingExample\r
51  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
52  */\r
53 public class StringVariantBinding extends VariantBinding {\r
54         \r
55         SerializerFactory serializationFactory;\r
56         VariantBinding variantBinding;\r
57         \r
58         public StringVariantBinding(SerializerFactory serializationFactory, VariantBinding variantBinding) {\r
59                 this.serializationFactory = serializationFactory;\r
60                 this.variantBinding = variantBinding;\r
61         }\r
62         \r
63         @Override\r
64         public Object create(Binding binding, Object value) throws BindingException {\r
65                 if (binding instanceof StringBinding && binding.type().equals(Datatypes.STRING)) {\r
66                         StringBinding sb = (StringBinding) binding;\r
67                         return "S"+URIUtil.encodeURI( sb.getValue(value) );\r
68                 }\r
69                 \r
70                 if (binding instanceof IntegerBinding && binding.type().equals(Datatypes.INTEGER)) {\r
71                         IntegerBinding ib = (IntegerBinding) binding;\r
72                         return "I"+ib.getValue_(value);\r
73                 }\r
74                 \r
75                 if (binding instanceof LongBinding && binding.type().equals(Datatypes.LONG)) {\r
76                         LongBinding lb = (LongBinding) binding;\r
77                         return "L"+lb.getValue_(value);\r
78                 }\r
79                 \r
80                 try {\r
81                         MutableVariant v = new MutableVariant(binding, value);\r
82                         byte[] data = serializationFactory.getSerializerUnchecked( variantBinding ).serialize(v);\r
83                         return "B"+Base64.encodeBytes(data, Base64.URL_SAFE);\r
84                 } catch (RuntimeSerializerConstructionException e) {\r
85                         throw new BindingException(e);\r
86                 } catch (IOException e) {\r
87                         throw new BindingException(e);\r
88                 }\r
89         }\r
90 \r
91         @Override\r
92         public Binding getContentBinding(Object variant) throws BindingException {\r
93                 String str = (String) variant;\r
94                 if (str.startsWith("S")) {\r
95                         return Bindings.STRING;\r
96                 }\r
97                 if (str.startsWith("I")) {\r
98                         return Bindings.INTEGER;\r
99                 }\r
100                 if (str.startsWith("L")) {\r
101                         return Bindings.LONG;\r
102                 }\r
103                 if (str.startsWith("B")) {\r
104                         try {\r
105                                 byte[]  data = Base64.decode(str.substring(1), Base64.URL_SAFE);\r
106                                 BinaryReadable readable = new BinaryMemory( ByteBuffer.wrap(data) ) ;\r
107                                 Datatype type = (Datatype) getDatatypeSerializer().deserialize(readable);\r
108                                 return Bindings.getMutableBinding(type);\r
109                         } catch (IOException e) {\r
110                                 throw new BindingException(e);\r
111                         }                       \r
112                 }\r
113                 \r
114                 throw new BindingException("Invalid string");\r
115         }\r
116 \r
117         @Override\r
118         public Datatype getContentType(Object variant) throws BindingException {\r
119                 String str = (String) variant;\r
120                 if (str.startsWith("S")) {\r
121                         return Bindings.STRING.type();\r
122                 }\r
123                 if (str.startsWith("I")) {\r
124                         return Bindings.INTEGER.type();\r
125                 }\r
126                 if (str.startsWith("L")) {\r
127                         return Bindings.LONG.type();\r
128                 }\r
129                 if (str.startsWith("B")) {\r
130                         try {\r
131                                 byte[]  data = Base64.decode(str.substring(1), Base64.URL_SAFE);\r
132                                 BinaryReadable readable = new BinaryMemory( ByteBuffer.wrap(data) ) ;\r
133                                 return (Datatype) getDatatypeSerializer().deserialize(readable);\r
134                         } catch (IOException e) {\r
135                                 throw new BindingException(e);\r
136                         }                       \r
137                 }\r
138                 \r
139                 throw new BindingException("Invalid string");\r
140         }\r
141 \r
142         @Override\r
143         public Object getContent(Object obj, Binding binding)\r
144                         throws BindingException {\r
145                 if (obj==null) throw new BindingException("null value is not Variant");\r
146                 if (obj instanceof String == false) throw new BindingException("wrong class, String expected");\r
147                 \r
148                 String str = (String) obj;\r
149                 \r
150                 if (str.startsWith("S")) {\r
151                         if (binding instanceof StringBinding == false) throw new BindingException("StringBinding expected, got "+binding.getClass().getSimpleName());\r
152                         String value = URIUtil.decodeURI( str.substring(1) );\r
153                         StringBinding sb = (StringBinding) binding;\r
154                         return sb.create(value);\r
155                 }\r
156                 \r
157                 if (str.startsWith("I")) {\r
158                         if (binding instanceof IntegerBinding == false) throw new BindingException("IntegerBinding expected, got "+binding.getClass().getSimpleName());\r
159                         try {\r
160                                 Integer value = Integer.valueOf( str.substring(1) );\r
161                                 IntegerBinding ib = (IntegerBinding) binding;\r
162                                 return ib.create(value);                                \r
163                         } catch (NumberFormatException nfe) {\r
164                                 throw new BindingException(nfe);\r
165                         }\r
166                 }\r
167 \r
168                 if (str.startsWith("L")) {\r
169                         if (binding instanceof LongBinding == false) throw new BindingException("LongBinding expected, got "+binding.getClass().getSimpleName());\r
170                         try {\r
171                                 Long value = Long.valueOf( str.substring(1) );\r
172                                 LongBinding lb = (LongBinding) binding;\r
173                                 return lb.create(value);                                \r
174                         } catch (NumberFormatException nfe) {\r
175                                 throw new BindingException(nfe);\r
176                         }\r
177                 }\r
178                 \r
179                 if (str.startsWith("B")) {\r
180                         try {\r
181                                 byte[] data = Base64.decode(str.substring(1), Base64.URL_SAFE);\r
182                                 BinaryReadable readable = new BinaryMemory( ByteBuffer.wrap(data) ) ;\r
183                                 Datatype type = (Datatype) getDatatypeSerializer().deserialize(readable);\r
184                                 if (!type.equals(binding.type()))\r
185                                         throw new BindingException("Binding for "+type.toSingleLineString()+" expected, but got "+binding.type());\r
186                                 return Bindings.getSerializer( binding ).deserialize(readable);\r
187                         } catch (IOException ioe) {\r
188                                 throw new BindingException(ioe);\r
189                         } catch (RuntimeSerializerConstructionException e) {\r
190                                 throw new BindingException(e);\r
191                         } catch (SerializerConstructionException e) {\r
192                                 throw new BindingException(e);\r
193                         }\r
194                 }\r
195                 \r
196                 throw new BindingException("Invalid value");            \r
197         }\r
198 \r
199         @Override\r
200         public Object getContent(Object obj) throws BindingException {\r
201                 if (obj==null) throw new BindingException("null value is not Variant");\r
202                 if (obj instanceof String == false) throw new BindingException("wrong class, String expected");\r
203                 \r
204                 String str = (String) obj;\r
205                 \r
206                 if (str.startsWith("S")) {\r
207                         /*String value =*/ URIUtil.decodeURI( str.substring(1) );                       \r
208                         return Bindings.STRING;\r
209                 }\r
210                 \r
211                 if (str.startsWith("I")) {\r
212                         try {\r
213                                 /*Integer value =*/ Integer.valueOf( str.substring(1) );\r
214                                 return Bindings.INTEGER;                                \r
215                         } catch (NumberFormatException nfe) {\r
216                                 throw new BindingException(nfe);\r
217                         }\r
218                 }\r
219 \r
220                 if (str.startsWith("L")) {\r
221                         try {\r
222                                 /*Long value =*/ Long.valueOf( str.substring(1) );\r
223                                 return Bindings.LONG;                           \r
224                         } catch (NumberFormatException nfe) {\r
225                                 throw new BindingException(nfe);\r
226                         }\r
227                 }\r
228                 \r
229                 if (str.startsWith("B")) {\r
230                         try {\r
231                                 byte[] data = Base64.decode(str.substring(1), Base64.URL_SAFE);\r
232                                 BinaryReadable readable = new BinaryMemory( ByteBuffer.wrap(data) );\r
233                                 MutableVariant variant = (MutableVariant) Bindings.getSerializerUnchecked( Bindings.MUTABLE_VARIANT).deserialize(readable);\r
234                                 return variant.getValue();\r
235                         } catch (IOException ioe) {\r
236                                 throw new BindingException(ioe);\r
237                         } catch (RuntimeSerializerConstructionException e) {\r
238                                 throw new BindingException(e);\r
239                         }\r
240                 }\r
241                 \r
242                 throw new BindingException("Invalid value");            \r
243         }\r
244 \r
245         @Override\r
246         public void setContent(Object variant, Binding binding, Object value)\r
247                         throws BindingException {\r
248                 throw new BindingException("Cannot set value to an immutable String");\r
249         }\r
250 \r
251         @Override\r
252         public void assertInstaceIsValid(Object obj, Set<Object> validInstances)\r
253                         throws BindingException {\r
254                 if (obj==null) throw new BindingException("null value is not Variant");\r
255                 if (obj instanceof String == false) throw new BindingException("wrong class, String expected");\r
256                 Object value = getContent(obj);\r
257                 Binding binding = getContentBinding(obj);\r
258                 binding.assertInstaceIsValid(value);\r
259         }\r
260 \r
261         @Override\r
262         public boolean isInstance(Object obj) {         \r
263                 return obj instanceof String;\r
264         }\r
265 \r
266         static Serializer DATATYPE_SERIALIZER; \r
267         static Serializer getDatatypeSerializer()\r
268         {\r
269                 if (DATATYPE_SERIALIZER == null) DATATYPE_SERIALIZER = Bindings.getSerializerUnchecked( Bindings.getBindingUnchecked(Datatype.class) );\r
270                 return DATATYPE_SERIALIZER;\r
271         }\r
272 \r
273         @Override\r
274         protected boolean baseEquals(Object obj) {\r
275                 StringVariantBinding o = (StringVariantBinding)obj;\r
276                 return super.baseEquals(obj) && o.serializationFactory == serializationFactory && o.variantBinding == variantBinding;\r
277         }\r
278 }\r