]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/file/FileLibrary.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / file / FileLibrary.java
1 /*******************************************************************************
2  * Copyright (c) 2010- Association for Decentralized Information Management in
3  * Industry THTH ry.
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
8  * 
9  * Contributors:
10  *    VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.databoard.accessor.file;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.lang.ref.ReferenceQueue;
17 import java.lang.ref.WeakReference;
18 import java.util.HashMap;
19 import java.util.Map;
20
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;
31
32 /**
33  * File library handles sharing of file accessors and automatic closing of files.
34  * <p>
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.
38  *
39  * The shared accessor instances are not concurrent-use-safe.
40  * 
41  * <p>
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.
45  *  
46  * Files are flushed before closed.
47  *
48  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
49  */
50 public class FileLibrary {
51
52         /** Files */
53         Map<File, Entry> files = new HashMap<File, Entry>();    
54         
55         /** Queue */ 
56         ReferenceQueue<FileVariantAccessor> queue = new ReferenceQueue<FileVariantAccessor>();
57         
58         /** Acessor params */
59         AccessorParams params;
60         
61         /**
62          * Create new file library
63          */
64         public FileLibrary() {
65                 params = AccessorParams.DEFAULT;
66         }
67
68         /**
69          * Create new file library
70          */
71         public FileLibrary(AccessorParams params) {
72                 this.params = params;
73         }
74
75         /**
76          * Get existing open file accessor.
77          * 
78          * @param file
79          * @return file or null
80          * @throws IOException 
81          * @throws AccessorConstructionException 
82          */
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()) {
88                         files.remove(file);
89                         return null;
90                 }
91                 expunge();
92                 return accessor;
93         }
94         
95         /**
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. 
99          * 
100          * @param file
101          * @return an accessor to the contents of a file
102          * @throws IOException 
103          * @throws AccessorConstructionException 
104          */
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();
109                 expunge();
110                 if (ref!=null && !ref.file.isOpen()) {
111                         files.remove(file);
112                         ref = null;
113                 }
114                 
115                 
116                 // Open file
117                 if (accessor == null) {
118                         BinaryFile bf = ref!=null ? ref.file : null;
119                         if (bf==null) {
120                                 try {
121                                         bf = new BinaryFile(file);
122                                 } catch (IOException e1) {
123                                         throw new AccessorConstructionException(e1);
124                                 }
125                         }
126                         accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);
127                         Entry e = new Entry(bf, accessor);                      
128                         files.put(file, e);
129                 }
130                 return accessor;
131         }
132         
133         /**
134          * Create a new file and put it in the library.
135          * If the file exists it is overwritten. 
136          *
137          * @param file
138          * @return accessor to contents of a file
139          * @throws AccessorConstructionException 
140          */
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();
145                 expunge();
146                 if (ref!=null && !ref.file.isOpen()) {
147                         files.remove(file);
148                         ref = null;
149                 }
150                 
151                 // Create a new file
152                 if (accessor == null) {
153                         BinaryFile bf = ref!=null ? ref.file : null;
154                         if (bf==null) {
155                                 try {
156                                         file.createNewFile();
157                                         bf = new BinaryFile(file);
158                                 } catch (IOException e1) {
159                                         throw new AccessorConstructionException(e1);
160                                 }
161                         }
162                         accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);
163                         Binding vb;
164                         try {
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);
174                         }
175                         
176                         Entry e = new Entry(bf, accessor);                      
177                         files.put(file, e);                     
178                 }
179
180                 return accessor;
181         }
182         
183         public boolean deleteFile(File file) throws AccessorException {         
184                 file = file.getAbsoluteFile();
185                 expunge();
186                 Entry ref = files.remove(file);
187                 if (ref!=null) {
188                         FileVariantAccessor accessor = ref.get();
189                         if (accessor!=null) {
190                                 accessor.close();
191                                 accessor = null;
192                         } else {
193                                 try {
194                                         ref.file.close();
195                                 } catch (IOException e) {
196                                         throw new AccessorException(e);
197                                 }
198                         }
199                 }
200                 expunge();
201                 
202                 if (!file.exists()) {
203                         return true;
204                 }
205                 boolean ok = file.delete();
206                 return ok;
207         }
208         
209
210         /**
211          * Close unused file accessors. 
212          */
213         public void expunge() {
214                 Entry e;
215         while ( (e = (Entry) queue.poll()) != null) {
216 //                      System.out.println("expunging "+e.file.file());
217                 files.remove(e.file.file());
218                 try {
219                                 e.file.close();
220                         } catch (IOException e1) {
221                                 e1.printStackTrace();
222                         }
223         }               
224         }
225         
226         /**
227          * Close and free all files, this invalidates all existing FileAccessors.
228          * close() doesn't invalidate FileLibrary.
229          * 
230          */
231     public void close() {
232         for (Entry e : files.values()) {
233                 try {
234 //                      System.out.println("closing "+e.file.file());
235                         e.file.flush();
236                                 e.file.close();
237                         } catch (IOException e1) {
238                                 e1.printStackTrace();
239                         }
240         }
241         files.clear();
242     }
243
244     class Entry extends WeakReference<FileVariantAccessor> {
245         BinaryFile file;                
246         public Entry(BinaryFile file, FileVariantAccessor accessor) {
247                         super(accessor, FileLibrary.this.queue);
248                         this.file = file;
249                 }
250     }
251     
252 }
253
254