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