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