1 /*******************************************************************************
2 * Copyright (c) 2010 Association for Decentralized Information Management in
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.databoard;
15 import java.io.IOException;
16 import java.nio.ByteBuffer;
17 import java.util.concurrent.Executor;
19 import org.simantics.databoard.accessor.Accessor;
20 import org.simantics.databoard.accessor.ArrayAccessor;
21 import org.simantics.databoard.accessor.binary.BinaryArray;
22 import org.simantics.databoard.accessor.binary.BinaryObject;
23 import org.simantics.databoard.accessor.binary.BinaryStreamArray;
24 import org.simantics.databoard.accessor.binary.BinaryVariableWidthStreamArray;
25 import org.simantics.databoard.accessor.error.AccessorConstructionException;
26 import org.simantics.databoard.accessor.error.AccessorException;
27 import org.simantics.databoard.accessor.file.FileAccessor;
28 import org.simantics.databoard.accessor.file.FileArrayAccessor;
29 import org.simantics.databoard.accessor.file.FileLibrary;
30 import org.simantics.databoard.accessor.file.FileVariantAccessor;
31 import org.simantics.databoard.accessor.impl.AccessorParams;
32 import org.simantics.databoard.accessor.impl.DirectoryMap;
33 import org.simantics.databoard.accessor.java.JavaObject;
34 import org.simantics.databoard.accessor.reference.ChildReference;
35 import org.simantics.databoard.binding.Binding;
36 import org.simantics.databoard.binding.error.BindingConstructionException;
37 import org.simantics.databoard.binding.error.BindingException;
38 import org.simantics.databoard.binding.mutable.Variant;
39 import org.simantics.databoard.serialization.Serializer;
40 import org.simantics.databoard.serialization.SerializerConstructionException;
41 import org.simantics.databoard.type.ArrayType;
42 import org.simantics.databoard.type.Datatype;
43 import org.simantics.databoard.util.binary.BinaryFile;
44 import org.simantics.databoard.util.binary.BinaryMemory;
45 import org.simantics.databoard.util.binary.Blob;
46 import org.simantics.databoard.util.binary.RandomAccessBinary;
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.
62 * @throws AccessorConstructionException
64 @SuppressWarnings("unchecked")
65 public static <T extends Accessor> T getAccessor(RandomAccessBinary binary, Datatype type, AccessorParams params) throws AccessorConstructionException {
66 return (T) BinaryObject.createAccessor(binary, type, params);
70 * Open an accessor to byte data.
75 * @throws AccessorConstructionException
77 @SuppressWarnings("unchecked")
78 public static <T extends Accessor> T getAccessor(RandomAccessBinary binary, Datatype type) throws AccessorConstructionException {
79 return (T) BinaryObject.createAccessor(binary, type, AccessorParams.DEFAULT);
83 * Open an accessor to byte data.
88 * @throws AccessorConstructionException
90 @SuppressWarnings("unchecked")
91 public static <T extends Accessor> T getAccessor(byte[] binary, Datatype type) throws AccessorConstructionException {
92 RandomAccessBinary rab = new BinaryMemory( ByteBuffer.wrap(binary) );
93 return (T) BinaryObject.createAccessor(rab, type, AccessorParams.DEFAULT);
97 * Open an accessor to a Java Object.
99 * Accessor is disposed by leaving it to garbage collector.
101 * Do not modify the object outside the accessor as long as you use the accessor.
102 * Exterioir modifications will mix up listening the mechanism.
103 * Also, do not create more than one accessor to one Object.
105 * You must provide mutual exclusion locking mechanism to the whole Object Model
106 * in AccessorParams, if you intend to use the accessors in multi-thread environment.
112 * @throws AccessorConstructionException
114 @SuppressWarnings("unchecked")
115 public static <T extends Accessor> T getAccessor(Binding binding, Object value, AccessorParams params)
116 throws AccessorConstructionException {
117 return (T) JavaObject.createAccessor(null, binding, value, params);
121 * Open an accessor to a Java Object.
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
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.
148 * Accessor is disposed by leaving it to garbage collector.
150 * Do not modify the object outside the accessor as long as you use the accessor.
151 * Exterioir modifications will mix up listening the mechanism.
152 * Also, do not create more than one accessor to one Object.
154 * The accessor is not multi-thread accessible. If you intend to use it in
155 * concurrent multi-thread environment, use the other method where you can
156 * pass lock objects in AccessorParams.
161 * @throws AccessorConstructionException
163 @SuppressWarnings("unchecked")
164 public static <T extends Accessor> T getAccessor(Variant variant)
165 throws AccessorConstructionException {
166 return (T) JavaObject.createAccessor(null, variant.getBinding(), variant.getValue(), AccessorParams.DEFAULT);
170 * Open an accessor to a Varint Object.
172 * Accessor is disposed by leaving it to garbage collector.
174 * Do not modify the object outside the accessor as long as you use the accessor.
175 * Exterioir modifications will mix up listening the mechanism.
176 * Also, do not create more than one accessor to one Object.
178 * The accessor is not multi-thread accessible. If you intend to use it in
179 * concurrent multi-thread environment, use the other method where you can
180 * pass lock objects in AccessorParams.
184 * @param ref child reference
186 * @throws AccessorConstructionException
188 @SuppressWarnings("unchecked")
189 public static <T extends Accessor> T getAccessor(Variant variant, ChildReference ref)
190 throws AccessorConstructionException {
191 Accessor a = getAccessor( variant );
192 return a.getComponent( ref );
196 * Open Accessor to a Java Object. This version reads the type using reflection.
198 * Accessor is disposed by leaving it to garbage collector.
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
205 * concurrent multi-thread environment, use the other method where you can
206 * pass lock objects in AccessorParams.
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.
226 * The accessor must be closed by invoking {@link FileAccessor#close()} at
227 * root or any sub-accessor.
229 * To share accessors of the same file use {@link FileLibrary} utility.
233 * @return file accessor
234 * @throws AccessorConstructionException
236 public static FileVariantAccessor openAccessor(File file) throws AccessorConstructionException {
238 BinaryFile bf = new BinaryFile(file);
239 FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);
241 } catch (IOException e) {
242 throw new AccessorConstructionException(e);
247 * Open a stream file (.stm). Stream file is an array of elements, with no
248 * header. Element size is constant.
250 * To create an empty stream file, just create an empty file.
253 * @param type expected array type
255 * @throws AccessorConstructionException
257 public static FileArrayAccessor openStream(File file, ArrayType type) throws AccessorConstructionException {
258 return openStream(file, type, "rw");
262 * Open a stream file (.stm). Stream file is an array of elements, with no
263 * header. Element size is constant.
265 * To create an empty stream file, just create an empty file.
268 * @param type expected array type
269 * @param mode Mode "r" or "rw"
271 * @throws AccessorConstructionException
273 public static FileArrayAccessor openStream(File file, ArrayType type, String mode) throws AccessorConstructionException {
274 return openStream(file, type, mode, null);
278 * Open a stream file (.stm). Stream file is an array of elements, with no
279 * header. Element size is constant.
281 * To create an empty stream file, just create an empty file.
284 * @param type expected array type
285 * @param mode Mode "r" or "rw"
286 * @param index accessor to long array that keeps the index of the variable width stream
288 * @throws AccessorConstructionException
290 public static FileArrayAccessor openStream(File file, ArrayType type, String mode, ArrayAccessor index) throws AccessorConstructionException {
292 BinaryFile bf = new BinaryFile(file, mode);
293 Blob blob = new Blob(bf);
294 Binding b = Bindings.getBinding(type.componentType);
295 Serializer s = Bindings.getSerializer(b);
296 if ( s.getConstantSize() != null ) {
297 return new BinaryStreamArray(null, blob, type, AccessorParams.DEFAULT);
299 if ( index == null ) {
300 return new BinaryArray(null, blob, type, AccessorParams.DEFAULT);
302 return new BinaryVariableWidthStreamArray(null, blob, type, AccessorParams.DEFAULT, index);
305 } catch (IOException e) {
306 throw new AccessorConstructionException(e);
307 } catch (AccessorException e) {
308 throw new AccessorConstructionException(e);
309 } catch (SerializerConstructionException e) {
310 throw new AccessorConstructionException(e);
315 * Create a new binary file with an empty value and open an accessor.
316 * If file already exists, it is overwritten.
317 * It is recommended that the file extension is .dbb (Databoard Binary)
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.
363 * File is closed with {@link FileAccessor#close()} at root or any
366 * To share accessors of the same file use {@link FileLibrary} utility.
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();
381 bf = new BinaryFile(file);
382 } catch (IOException e1) {
383 throw new AccessorConstructionException(e1);
387 FileVariantAccessor result = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, AccessorParams.DEFAULT);
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.
403 * Map entries are binary files (.dbb), and the file name is the key with the following encoding:
405 * Filenames have the following encoding:
406 * S<string>.dbb String types
407 * Control characters " : < > | ? * \ / % [0..31] [128..] are escaped as %<hex><hex>
409 * I<integer>.dbb Integer types
410 * L<long>.dbb Long types
411 * H<hex>.dbb All other cases the value as binary
413 * The caller must close (FolderMap#close()) the accessor after usage.
414 * This releases file handles and a directory polling thread.
416 * FolderMap is not concurrent-use-safe. Its files are not either.
417 * The user must ensure that the files are not used concurrently from
421 * @return MapAccessor
423 public static DirectoryMap openDirectory(File directory) {
424 return new DirectoryMap(directory);
428 * Get an executor for current thread
432 public static Executor getCurrentThread() {
433 return Accessors.getCurrentThread();
436 static Executor CURRENT_THREAD = new Executor() {
438 public void execute(Runnable command) {