]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/Accessors.java
Re-implement URIStringUtils escape and unescape using Unicode
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / Accessors.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;
13
14 import java.io.File;\r
15 import java.io.IOException;\r
16 import java.nio.ByteBuffer;\r
17 import java.util.concurrent.Executor;\r
18 \r
19 import org.simantics.databoard.accessor.Accessor;\r
20 import org.simantics.databoard.accessor.ArrayAccessor;\r
21 import org.simantics.databoard.accessor.binary.BinaryArray;\r
22 import org.simantics.databoard.accessor.binary.BinaryObject;\r
23 import org.simantics.databoard.accessor.binary.BinaryStreamArray;\r
24 import org.simantics.databoard.accessor.binary.BinaryVariableWidthStreamArray;\r
25 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
26 import org.simantics.databoard.accessor.error.AccessorException;\r
27 import org.simantics.databoard.accessor.file.FileAccessor;\r
28 import org.simantics.databoard.accessor.file.FileArrayAccessor;\r
29 import org.simantics.databoard.accessor.file.FileLibrary;\r
30 import org.simantics.databoard.accessor.file.FileVariantAccessor;\r
31 import org.simantics.databoard.accessor.impl.AccessorParams;\r
32 import org.simantics.databoard.accessor.impl.DirectoryMap;\r
33 import org.simantics.databoard.accessor.java.JavaObject;\r
34 import org.simantics.databoard.accessor.reference.ChildReference;\r
35 import org.simantics.databoard.binding.Binding;\r
36 import org.simantics.databoard.binding.error.BindingConstructionException;\r
37 import org.simantics.databoard.binding.error.BindingException;\r
38 import org.simantics.databoard.binding.mutable.Variant;\r
39 import org.simantics.databoard.serialization.Serializer;\r
40 import org.simantics.databoard.serialization.SerializerConstructionException;\r
41 import org.simantics.databoard.type.ArrayType;\r
42 import org.simantics.databoard.type.Datatype;\r
43 import org.simantics.databoard.util.binary.BinaryFile;\r
44 import org.simantics.databoard.util.binary.BinaryMemory;\r
45 import org.simantics.databoard.util.binary.Blob;\r
46 import org.simantics.databoard.util.binary.RandomAccessBinary;\r
47
48 /**
49  * This is a facade class for accessor services.
50  *
51  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
52  */
53 public class Accessors {
54 \r
55         /**\r
56          * Open an accessor to byte data.\r
57          * \r
58          * @param binary\r
59          * @param type\r
60          * @param params\r
61          * @return an accessor\r
62          * @throws AccessorConstructionException \r
63          */\r
64         @SuppressWarnings("unchecked")\r
65         public static <T extends Accessor> T getAccessor(RandomAccessBinary binary, Datatype type, AccessorParams params) throws AccessorConstructionException {                \r
66                 return (T) BinaryObject.createAccessor(binary, type, params);\r
67         }\r
68         \r
69         /**\r
70          * Open an accessor to byte data.\r
71          * \r
72          * @param binary\r
73          * @param type\r
74          * @return an accessor\r
75          * @throws AccessorConstructionException \r
76          */\r
77         @SuppressWarnings("unchecked")\r
78         public static <T extends Accessor> T getAccessor(RandomAccessBinary binary, Datatype type) throws AccessorConstructionException {               \r
79                 return (T) BinaryObject.createAccessor(binary, type, AccessorParams.DEFAULT);\r
80         }       \r
81         \r
82         /**\r
83          * Open an accessor to byte data.\r
84          * \r
85          * @param binary\r
86          * @param type\r
87          * @return an accessor\r
88          * @throws AccessorConstructionException \r
89          */\r
90         @SuppressWarnings("unchecked")\r
91         public static <T extends Accessor> T getAccessor(byte[] binary, Datatype type) throws AccessorConstructionException {\r
92                 RandomAccessBinary rab = new BinaryMemory( ByteBuffer.wrap(binary) );\r
93                 return (T) BinaryObject.createAccessor(rab, type, AccessorParams.DEFAULT);\r
94         }\r
95 \r
96         /**\r
97          * Open an accessor to a Java Object.\r
98          * <p>\r
99          * Accessor is disposed by leaving it to garbage collector.\r
100          * <p>\r
101          * Do not modify the object outside the accessor as long as you use the accessor.\r
102          * Exterioir modifications will mix up listening the mechanism.\r
103          * Also, do not create more than one accessor to one Object. \r
104          * <p>\r
105          * You must provide mutual exclusion locking mechanism to the whole Object Model\r
106          * in AccessorParams, if you intend to use the accessors in multi-thread environment. \r
107          * \r
108          * @since 0.5\r
109          * @param binding\r
110          * @param value\r
111          * @return accessor\r
112          * @throws AccessorConstructionException\r
113          */\r
114         @SuppressWarnings("unchecked")\r
115         public static <T extends Accessor> T getAccessor(Binding binding, Object value, AccessorParams params) \r
116         throws AccessorConstructionException {\r
117                 return (T) JavaObject.createAccessor(null, binding, value, params);\r
118         }\r
119         
120         /**
121          * Open an accessor to a Java Object.\r
122          * <p>\r
123          * Accessor is disposed by leaving it to garbage collector.
124          * <p>
125          * Do not modify the object outside the accessor as long as you use the accessor.
126          * Exterioir modifications will mix up listening the mechanism.
127          * Also, do not create more than one accessor to one Object. 
128          * <p>
129          * The accessor is not multi-thread accessible. If you intend to use it in 
130          * concurrent multi-thread environment, use the other method where you can \r
131          * pass lock objects in AccessorParams. 
132          * 
133          * @since 0.5
134          * @param binding
135          * @param value
136          * @return accessor
137          * @throws AccessorConstructionException
138          */
139         @SuppressWarnings("unchecked")
140         public static <T extends Accessor> T getAccessor(Binding binding, Object value) 
141         throws AccessorConstructionException {
142                 return (T) JavaObject.createAccessor(null, binding, value, AccessorParams.DEFAULT);
143         }\r
144         \r
145         /**\r
146          * Open an accessor to a Varint Object.\r
147          * <p>\r
148          * Accessor is disposed by leaving it to garbage collector.\r
149          * <p>\r
150          * Do not modify the object outside the accessor as long as you use the accessor.\r
151          * Exterioir modifications will mix up listening the mechanism.\r
152          * Also, do not create more than one accessor to one Object. \r
153          * <p>\r
154          * The accessor is not multi-thread accessible. If you intend to use it in \r
155          * concurrent multi-thread environment, use the other method where you can \r
156          * pass lock objects in AccessorParams. \r
157          * \r
158          * @since 0.5\r
159          * @param variant\r
160          * @return accessor\r
161          * @throws AccessorConstructionException\r
162          */\r
163         @SuppressWarnings("unchecked")\r
164         public static <T extends Accessor> T getAccessor(Variant variant) \r
165         throws AccessorConstructionException {\r
166                 return (T) JavaObject.createAccessor(null, variant.getBinding(), variant.getValue(), AccessorParams.DEFAULT);\r
167         }       
168 \r
169         /**\r
170          * Open an accessor to a Varint Object.\r
171          * <p>\r
172          * Accessor is disposed by leaving it to garbage collector.\r
173          * <p>\r
174          * Do not modify the object outside the accessor as long as you use the accessor.\r
175          * Exterioir modifications will mix up listening the mechanism.\r
176          * Also, do not create more than one accessor to one Object. \r
177          * <p>\r
178          * The accessor is not multi-thread accessible. If you intend to use it in \r
179          * concurrent multi-thread environment, use the other method where you can \r
180          * pass lock objects in AccessorParams. \r
181          * \r
182          * @since 0.5\r
183          * @param binding\r
184          * @param ref child reference\r
185          * @return accessor\r
186          * @throws AccessorConstructionException\r
187          */\r
188         @SuppressWarnings("unchecked")\r
189         public static <T extends Accessor> T getAccessor(Variant variant, ChildReference ref) \r
190         throws AccessorConstructionException {\r
191                 Accessor a = getAccessor( variant );\r
192                 return a.getComponent( ref );\r
193         }       \r
194         
195         /**
196          * Open Accessor to a Java Object. This version reads the type using reflection.
197          * <p>\r
198          * Accessor is disposed by leaving it to garbage collector.\r
199          * <p>
200          * Do not modify the object outside the accessor as long as you use the accessor.
201          * Exterioir modifications will mix up listening the mechanism.
202          * Also, do not create more than one accessor to one Object. 
203          * <p>
204          * The accessor is not multi-thread accessible. If you intend to use it in \r
205          * concurrent multi-thread environment, use the other method where you can \r
206          * pass lock objects in AccessorParams. \r
207          * 
208          * @since 0.5
209          * @param value
210          * @return accessor
211          * @throws AccessorConstructionException
212          */
213         @SuppressWarnings("unchecked")
214         public static <T extends Accessor> T getAccessor(Object value) 
215         throws AccessorConstructionException {
216                 try {
217                         Binding binding = Bindings.getBinding(value.getClass());
218                         return (T) JavaObject.createAccessor(null, binding, value, AccessorParams.DEFAULT);
219                 } catch (BindingConstructionException e) {
220                         throw new AccessorConstructionException(e);
221                 }
222         }\r
223         \r
224         /**\r
225          * Open an accessor to a binary file (.dbb). The file is always a variant.\r
226          * The accessor must be closed by invoking {@link FileAccessor#close()} at \r
227          * root or any sub-accessor.\r
228          * <p>\r
229          * To share accessors of the same file use {@link FileLibrary} utility.\r
230          * \r
231          * @since 0.5\r
232          * @param file\r
233          * @return file accessor\r
234          * @throws AccessorConstructionException \r
235          */\r
236         public static FileVariantAccessor openAccessor(File file) throws AccessorConstructionException {                \r
237                 try {                   \r
238                         BinaryFile bf = new BinaryFile(file);\r
239                         FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);\r
240                         return result;\r
241                 } catch (IOException e) {\r
242                         throw new AccessorConstructionException(e);\r
243                 }\r
244         }\r
245 \r
246         /**\r
247          * Open a stream file (.stm). Stream file is an array of elements, with no \r
248          * header. Element size is constant. \r
249          * <p>\r
250          * To create an empty stream file, just create an empty file.\r
251          * \r
252          * @param file\r
253          * @param type expected array type\r
254          * @return accessor\r
255          * @throws AccessorConstructionException\r
256          */\r
257         public static FileArrayAccessor openStream(File file, ArrayType type) throws AccessorConstructionException {\r
258                 return openStream(file, type, "rw");\r
259         }\r
260 \r
261         /**\r
262          * Open a stream file (.stm). Stream file is an array of elements, with no \r
263          * header. Element size is constant. \r
264          * <p>\r
265          * To create an empty stream file, just create an empty file.\r
266          * \r
267          * @param file\r
268          * @param type expected array type\r
269          * @param mode Mode "r" or "rw"\r
270          * @return accessor\r
271          * @throws AccessorConstructionException\r
272          */\r
273         public static FileArrayAccessor openStream(File file, ArrayType type, String mode) throws AccessorConstructionException {\r
274                 return openStream(file, type, mode, null);\r
275         }\r
276         \r
277         /**\r
278          * Open a stream file (.stm). Stream file is an array of elements, with no \r
279          * header. Element size is constant. \r
280          * <p>\r
281          * To create an empty stream file, just create an empty file.\r
282          * \r
283          * @param file\r
284          * @param type expected array type\r
285          * @param mode Mode "r" or "rw"\r
286          * @param index accessor to long array that keeps the index of the variable width stream \r
287          * @return accessor\r
288          * @throws AccessorConstructionException\r
289          */\r
290         public static FileArrayAccessor openStream(File file, ArrayType type, String mode, ArrayAccessor index) throws AccessorConstructionException {\r
291                 try {                   \r
292                         BinaryFile bf = new BinaryFile(file, mode);\r
293                         Blob blob = new Blob(bf);\r
294                         Binding b = Bindings.getBinding(type.componentType);\r
295                         Serializer s = Bindings.getSerializer(b);\r
296                         if ( s.getConstantSize() != null ) {\r
297                                 return new BinaryStreamArray(null, blob, type, AccessorParams.DEFAULT);\r
298                         } else {\r
299                                 if ( index == null ) {\r
300                                         return new BinaryArray(null, blob, type, AccessorParams.DEFAULT);\r
301                                 } else {\r
302                                         return new BinaryVariableWidthStreamArray(null, blob, type, AccessorParams.DEFAULT, index);\r
303                                 }\r
304                         }\r
305                 } catch (IOException e) {\r
306                         throw new AccessorConstructionException(e);\r
307                 } catch (AccessorException e) {\r
308                         throw new AccessorConstructionException(e);\r
309                 } catch (SerializerConstructionException e) {\r
310                         throw new AccessorConstructionException(e);\r
311                 }               \r
312         }\r
313         
314         /**
315          * Create a new binary file with an empty value and open an accessor.
316          * If file already exists, it is overwritten.\r
317          * It is recommended that the file extension is .dbb (Databoard Binary)\r
318          * <p>
319          * The caller must close the file with {@link FileAccessor#close()}.  
320          * 
321          * @since 0.5
322          * @param file
323          * @return an accessor to the root variant node
324          */
325         public static FileVariantAccessor createFile(File file) 
326         throws AccessorConstructionException {
327                 try {\r
328                         file.createNewFile();
329                         BinaryFile bf = new BinaryFile(file);
330                         FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);
331                         
332                         // Write initial value
333                         try {
334                                 Binding vb = Bindings.getBinding(void.class);
335                                 Object vv = vb.createDefault();
336                                 result.setContentValue(vb, vv);
337                         } catch (AccessorException e) {
338                                 // Close file
339                                 try { result.close(); } catch (AccessorException e1) {}
340                                 // Rethrow exception
341                                 throw new AccessorConstructionException(e);
342                         } catch (BindingConstructionException e) {
343                                 // Close file
344                                 try { result.close(); } catch (AccessorException e1) {}
345                                 // Rethrow exception
346                                 throw new AccessorConstructionException(e);
347                         } catch (BindingException e) {
348                                 // Close file
349                                 try { result.close(); } catch (AccessorException e1) {}
350                                 // Rethrow exception
351                                 throw new AccessorConstructionException(e);
352                         } 
353                         
354                         return result;
355                 } catch (IOException e) {
356                         throw new AccessorConstructionException(e);
357                 }
358         }       
359
360         /**\r
361          * Create a binary file (.dbb) and open an accessor. The file is always a variant.\r
362          * <p>\r
363          * File is closed with {@link FileAccessor#close()} at root or any \r
364          * sub-accessor.\r
365          * <p>\r
366          * To share accessors of the same file use {@link FileLibrary} utility.\r
367          * 
368          * @param <T>
369          * @param file
370          * @param type
371          * @return an accessor to the value node
372          * @throws AccessorConstructionException 
373          */
374         @SuppressWarnings("unchecked")
375         public static <T extends FileAccessor> T createFile(File file, Datatype type) throws AccessorConstructionException
376         {
377                 boolean existed;\r
378                 BinaryFile bf;\r
379                 try {\r
380                         existed = file.createNewFile();\r
381                         bf = new BinaryFile(file);\r
382                 } catch (IOException e1) {\r
383                         throw new AccessorConstructionException(e1);\r
384                 }\r
385                 \r
386                 try {
387                         FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);\r
388                         Binding binding = Bindings.getMutableBinding(type);
389                         Object value = binding.createDefault();
390                         result.setContentValue(binding, value);
391                         return (T) result.getContentAccessor();
392                 } catch (BindingException e) {
393                         if (!existed) file.delete();
394                         throw new AccessorConstructionException(e);
395                 } catch (AccessorException e) {
396                         if (!existed) file.delete();
397                         throw new AccessorConstructionException(e);
398                 }
399         }
400         \r
401         /**\r
402          * Open a Map(Variant, Variant) accessor to a directory.\r
403          * Map entries are binary files (.dbb), and the file name is the key with the following encoding: \r
404          *   \r
405          *  Filenames have the following encoding:\r
406          *    S<string>.dbb   String types\r
407          *                        Control characters " : < > | ? * \ / % [0..31] [128..] are escaped as %<hex><hex>\r
408          *                        " "-space is _\r
409          *    I<integer>.dbb  Integer types\r
410          *    L<long>.dbb     Long types\r
411          *    H<hex>.dbb      All other cases the value as binary \r
412          * \r
413          * The caller must close (FolderMap#close()) the accessor after usage. \r
414          * This releases file handles and a directory polling thread.\r
415          * \r
416          * FolderMap is not concurrent-use-safe. Its files are not either.\r
417          * The user must ensure that the files are not used concurrently from \r
418          * different threads.\r
419          * \r
420          * @param directory\r
421          * @return MapAccessor\r
422          */\r
423         public static DirectoryMap openDirectory(File directory) {\r
424                 return new DirectoryMap(directory);\r
425         }       \r
426         \r
427         /**\r
428          * Get an executor for current thread\r
429          * \r
430          * @return executor\r
431          */\r
432         public static Executor getCurrentThread() {\r
433                 return Accessors.getCurrentThread();\r
434         }\r
435         \r
436         static Executor CURRENT_THREAD = new Executor() {\r
437                 @Override\r
438                 public void execute(Runnable command) {\r
439                         command.run();\r
440                 }               \r
441         };      \r
442         
443 }
444