1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard;
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
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
49 * This is a facade class for accessor services.
51 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
53 public class Accessors {
56 * Open an accessor to byte data.
\r
61 * @return an accessor
\r
62 * @throws AccessorConstructionException
\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
70 * Open an accessor to byte data.
\r
74 * @return an accessor
\r
75 * @throws AccessorConstructionException
\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
83 * Open an accessor to byte data.
\r
87 * @return an accessor
\r
88 * @throws AccessorConstructionException
\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
97 * Open an accessor to a Java Object.
\r
99 * Accessor is disposed by leaving it to garbage collector.
\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
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
112 * @throws AccessorConstructionException
\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
121 * Open an accessor to a Java Object.
\r
123 * Accessor is disposed by leaving it to garbage collector.
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.
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.
137 * @throws AccessorConstructionException
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);
146 * Open an accessor to a Varint Object.
\r
148 * Accessor is disposed by leaving it to garbage collector.
\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
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
161 * @throws AccessorConstructionException
\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
170 * Open an accessor to a Varint Object.
\r
172 * Accessor is disposed by leaving it to garbage collector.
\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
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
184 * @param ref child reference
\r
186 * @throws AccessorConstructionException
\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
196 * Open Accessor to a Java Object. This version reads the type using reflection.
198 * Accessor is disposed by leaving it to garbage collector.
\r
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.
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
211 * @throws AccessorConstructionException
213 @SuppressWarnings("unchecked")
214 public static <T extends Accessor> T getAccessor(Object value)
215 throws AccessorConstructionException {
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);
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
229 * To share accessors of the same file use {@link FileLibrary} utility.
\r
233 * @return file accessor
\r
234 * @throws AccessorConstructionException
\r
236 public static FileVariantAccessor openAccessor(File file) throws AccessorConstructionException {
\r
238 BinaryFile bf = new BinaryFile(file);
\r
239 FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);
\r
241 } catch (IOException e) {
\r
242 throw new AccessorConstructionException(e);
\r
247 * Open a stream file (.stm). Stream file is an array of elements, with no
\r
248 * header. Element size is constant.
\r
250 * To create an empty stream file, just create an empty file.
\r
253 * @param type expected array type
\r
255 * @throws AccessorConstructionException
\r
257 public static FileArrayAccessor openStream(File file, ArrayType type) throws AccessorConstructionException {
\r
258 return openStream(file, type, "rw");
\r
262 * Open a stream file (.stm). Stream file is an array of elements, with no
\r
263 * header. Element size is constant.
\r
265 * To create an empty stream file, just create an empty file.
\r
268 * @param type expected array type
\r
269 * @param mode Mode "r" or "rw"
\r
271 * @throws AccessorConstructionException
\r
273 public static FileArrayAccessor openStream(File file, ArrayType type, String mode) throws AccessorConstructionException {
\r
274 return openStream(file, type, mode, null);
\r
278 * Open a stream file (.stm). Stream file is an array of elements, with no
\r
279 * header. Element size is constant.
\r
281 * To create an empty stream file, just create an empty 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
288 * @throws AccessorConstructionException
\r
290 public static FileArrayAccessor openStream(File file, ArrayType type, String mode, ArrayAccessor index) throws AccessorConstructionException {
\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
299 if ( index == null ) {
\r
300 return new BinaryArray(null, blob, type, AccessorParams.DEFAULT);
\r
302 return new BinaryVariableWidthStreamArray(null, blob, type, AccessorParams.DEFAULT, index);
\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
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
319 * The caller must close the file with {@link FileAccessor#close()}.
323 * @return an accessor to the root variant node
325 public static FileVariantAccessor createFile(File file)
326 throws AccessorConstructionException {
328 file.createNewFile();
329 BinaryFile bf = new BinaryFile(file);
330 FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);
332 // Write initial value
334 Binding vb = Bindings.getBinding(void.class);
335 Object vv = vb.createDefault();
336 result.setContentValue(vb, vv);
337 } catch (AccessorException e) {
339 try { result.close(); } catch (AccessorException e1) {}
341 throw new AccessorConstructionException(e);
342 } catch (BindingConstructionException e) {
344 try { result.close(); } catch (AccessorException e1) {}
346 throw new AccessorConstructionException(e);
347 } catch (BindingException e) {
349 try { result.close(); } catch (AccessorException e1) {}
351 throw new AccessorConstructionException(e);
355 } catch (IOException e) {
356 throw new AccessorConstructionException(e);
361 * Create a binary file (.dbb) and open an accessor. The file is always a variant.
\r
363 * File is closed with {@link FileAccessor#close()} at root or any
\r
366 * To share accessors of the same file use {@link FileLibrary} utility.
\r
371 * @return an accessor to the value node
372 * @throws AccessorConstructionException
374 @SuppressWarnings("unchecked")
375 public static <T extends FileAccessor> T createFile(File file, Datatype type) throws AccessorConstructionException
380 existed = file.createNewFile();
\r
381 bf = new BinaryFile(file);
\r
382 } catch (IOException e1) {
\r
383 throw new AccessorConstructionException(e1);
\r
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);
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
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
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
413 * The caller must close (FolderMap#close()) the accessor after usage.
\r
414 * This releases file handles and a directory polling thread.
\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
421 * @return MapAccessor
\r
423 public static DirectoryMap openDirectory(File directory) {
\r
424 return new DirectoryMap(directory);
\r
428 * Get an executor for current thread
\r
432 public static Executor getCurrentThread() {
\r
433 return Accessors.getCurrentThread();
\r
436 static Executor CURRENT_THREAD = new Executor() {
\r
438 public void execute(Runnable command) {
\r