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.accessor.file;
15 import java.io.IOException;
16 import java.lang.ref.ReferenceQueue;
17 import java.lang.ref.WeakReference;
18 import java.util.HashMap;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.databoard.Datatypes;
23 import org.simantics.databoard.accessor.binary.BinaryObject;
24 import org.simantics.databoard.accessor.error.AccessorConstructionException;
25 import org.simantics.databoard.accessor.error.AccessorException;
26 import org.simantics.databoard.accessor.impl.AccessorParams;
27 import org.simantics.databoard.binding.Binding;
28 import org.simantics.databoard.binding.error.BindingConstructionException;
29 import org.simantics.databoard.binding.error.BindingException;
30 import org.simantics.databoard.util.binary.BinaryFile;
33 * File library handles sharing of file accessors and automatic closing of files.
35 * On call of getFile or createFile the file library opens a file and returns a
36 * file accessor. In concecutive runs the same accessor instance is returned,
37 * unless the file was garbage collected.
39 * The shared accessor instances are not concurrent-use-safe.
42 * The file handles are actually closed by two ways:
43 * a) File accessor are garbage collected and the the user calls {@link FileLibrary#expunge()}
44 * b) The user invokes {@link FileLibrary#close()} in the FileLibrary.
46 * Files are flushed before closed.
48 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
50 public class FileLibrary {
53 Map<File, Entry> files = new HashMap<File, Entry>();
56 ReferenceQueue<FileVariantAccessor> queue = new ReferenceQueue<FileVariantAccessor>();
59 AccessorParams params;
62 * Create new file library
64 public FileLibrary() {
65 params = AccessorParams.DEFAULT;
69 * Create new file library
71 public FileLibrary(AccessorParams params) {
76 * Get existing open file accessor.
79 * @return file or null
81 * @throws AccessorConstructionException
83 public FileVariantAccessor getExistingFile(File file) throws AccessorConstructionException {
84 file = file.getAbsoluteFile();
85 Entry ref = files.get(file);
86 FileVariantAccessor accessor = ref==null ? null : ref.get();
87 if (ref!=null && !ref.file.isOpen()) {
96 * Open file or get an existing file accessor.
97 * The caller must not close the file, it is closed upon garbage collection
98 * or when FileLibrary is closed.
101 * @return an accessor to the contents of a file
102 * @throws IOException
103 * @throws AccessorConstructionException
105 public FileVariantAccessor getFile(File file) throws AccessorConstructionException {
106 file = file.getAbsoluteFile();
107 Entry ref = files.get(file);
108 FileVariantAccessor accessor = ref==null ? null : ref.get();
110 if (ref!=null && !ref.file.isOpen()) {
117 if (accessor == null) {
118 BinaryFile bf = ref!=null ? ref.file : null;
121 bf = new BinaryFile(file);
122 } catch (IOException e1) {
123 throw new AccessorConstructionException(e1);
126 accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);
127 Entry e = new Entry(bf, accessor);
134 * Create a new file and put it in the library.
135 * If the file exists it is overwritten.
138 * @return accessor to contents of a file
139 * @throws AccessorConstructionException
141 public FileVariantAccessor createFile(File file) throws AccessorConstructionException {
142 file = file.getAbsoluteFile();
143 Entry ref = files.get(file);
144 FileVariantAccessor accessor = ref==null ? null : ref.get();
146 if (ref!=null && !ref.file.isOpen()) {
152 if (accessor == null) {
153 BinaryFile bf = ref!=null ? ref.file : null;
156 file.createNewFile();
157 bf = new BinaryFile(file);
158 } catch (IOException e1) {
159 throw new AccessorConstructionException(e1);
162 accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);
165 vb = Bindings.getBinding(void.class);
166 Object vv = vb.createDefault();
167 accessor.setContentValue(vb, vv);
168 } catch (BindingConstructionException e1) {
169 throw new AccessorConstructionException(e1);
170 } catch (AccessorException e) {
171 throw new AccessorConstructionException(e);
172 } catch (BindingException e) {
173 throw new AccessorConstructionException(e);
176 Entry e = new Entry(bf, accessor);
183 public boolean deleteFile(File file) throws AccessorException {
184 file = file.getAbsoluteFile();
186 Entry ref = files.remove(file);
188 FileVariantAccessor accessor = ref.get();
189 if (accessor!=null) {
195 } catch (IOException e) {
196 throw new AccessorException(e);
202 if (!file.exists()) {
205 boolean ok = file.delete();
211 * Close unused file accessors.
213 public void expunge() {
215 while ( (e = (Entry) queue.poll()) != null) {
216 // System.out.println("expunging "+e.file.file());
217 files.remove(e.file.file());
220 } catch (IOException e1) {
221 e1.printStackTrace();
227 * Close and free all files, this invalidates all existing FileAccessors.
228 * close() doesn't invalidate FileLibrary.
231 public void close() {
232 for (Entry e : files.values()) {
234 // System.out.println("closing "+e.file.file());
237 } catch (IOException e1) {
238 e1.printStackTrace();
244 class Entry extends WeakReference<FileVariantAccessor> {
246 public Entry(BinaryFile file, FileVariantAccessor accessor) {
247 super(accessor, FileLibrary.this.queue);