]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/file/FileLibrary.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/file/FileLibrary.java
new file mode 100644 (file)
index 0000000..436168e
--- /dev/null
@@ -0,0 +1,254 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010- Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *    VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.accessor.file;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.lang.ref.ReferenceQueue;\r
+import java.lang.ref.WeakReference;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.accessor.binary.BinaryObject;\r
+import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.accessor.impl.AccessorParams;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.util.binary.BinaryFile;\r
+\r
+/**\r
+ * File library handles sharing of file accessors and automatic closing of files.\r
+ * <p>\r
+ * On call of getFile or createFile the file library opens a file and returns a \r
+ * file accessor. In concecutive runs the same accessor instance is returned, \r
+ * unless the file was garbage collected.\r
+ *\r
+ * The shared accessor instances are not concurrent-use-safe.\r
+ * \r
+ * <p>\r
+ * The file handles are actually closed by two ways:\r
+ *  a) File accessor are garbage collected and the the user calls {@link FileLibrary#expunge()}\r
+ *  b) The user invokes {@link FileLibrary#close()} in the FileLibrary.\r
+ *  \r
+ * Files are flushed before closed.\r
+ *\r
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
+ */\r
+public class FileLibrary {\r
+\r
+       /** Files */\r
+       Map<File, Entry> files = new HashMap<File, Entry>();    \r
+       \r
+       /** Queue */ \r
+       ReferenceQueue<FileVariantAccessor> queue = new ReferenceQueue<FileVariantAccessor>();\r
+       \r
+       /** Acessor params */\r
+       AccessorParams params;\r
+       \r
+       /**\r
+        * Create new file library\r
+        */\r
+       public FileLibrary() {\r
+               params = AccessorParams.DEFAULT;\r
+       }\r
+\r
+       /**\r
+        * Create new file library\r
+        */\r
+       public FileLibrary(AccessorParams params) {\r
+               this.params = params;\r
+       }\r
+\r
+       /**\r
+        * Get existing open file accessor.\r
+        * \r
+        * @param file\r
+        * @return file or null\r
+        * @throws IOException \r
+        * @throws AccessorConstructionException \r
+        */\r
+       public FileVariantAccessor getExistingFile(File file) throws AccessorConstructionException {\r
+               file = file.getAbsoluteFile();\r
+               Entry ref = files.get(file);\r
+               FileVariantAccessor accessor = ref==null ? null : ref.get();\r
+               if (ref!=null && !ref.file.isOpen()) {\r
+                       files.remove(file);\r
+                       return null;\r
+               }\r
+               expunge();\r
+               return accessor;\r
+       }\r
+       \r
+       /**\r
+        * Open file or get an existing file accessor.\r
+        * The caller must not close the file, it is closed upon garbage collection\r
+        * or when FileLibrary is closed. \r
+        * \r
+        * @param file\r
+        * @return an accessor to the contents of a file\r
+        * @throws IOException \r
+        * @throws AccessorConstructionException \r
+        */\r
+       public FileVariantAccessor getFile(File file) throws AccessorConstructionException {\r
+               file = file.getAbsoluteFile();\r
+               Entry ref = files.get(file);\r
+               FileVariantAccessor accessor = ref==null ? null : ref.get();\r
+               expunge();\r
+               if (ref!=null && !ref.file.isOpen()) {\r
+                       files.remove(file);\r
+                       ref = null;\r
+               }\r
+               \r
+               \r
+               // Open file\r
+               if (accessor == null) {\r
+                       BinaryFile bf = ref!=null ? ref.file : null;\r
+                       if (bf==null) {\r
+                               try {\r
+                                       bf = new BinaryFile(file);\r
+                               } catch (IOException e1) {\r
+                                       throw new AccessorConstructionException(e1);\r
+                               }\r
+                       }\r
+                       accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);\r
+                       Entry e = new Entry(bf, accessor);                      \r
+                       files.put(file, e);\r
+               }\r
+               return accessor;\r
+       }\r
+       \r
+       /**\r
+        * Create a new file and put it in the library.\r
+        * If the file exists it is overwritten. \r
+        *\r
+        * @param file\r
+        * @return accessor to contents of a file\r
+        * @throws AccessorConstructionException \r
+        */\r
+       public FileVariantAccessor createFile(File file) throws AccessorConstructionException {\r
+               file = file.getAbsoluteFile();\r
+               Entry ref = files.get(file);\r
+               FileVariantAccessor accessor = ref==null ? null : ref.get();\r
+               expunge();\r
+               if (ref!=null && !ref.file.isOpen()) {\r
+                       files.remove(file);\r
+                       ref = null;\r
+               }\r
+               \r
+               // Create a new file\r
+               if (accessor == null) {\r
+                       BinaryFile bf = ref!=null ? ref.file : null;\r
+                       if (bf==null) {\r
+                               try {\r
+                                       file.createNewFile();\r
+                                       bf = new BinaryFile(file);\r
+                               } catch (IOException e1) {\r
+                                       throw new AccessorConstructionException(e1);\r
+                               }\r
+                       }\r
+                       accessor = (FileVariantAccessor) BinaryObject.createAccessor(bf, Datatypes.VARIANT, params);\r
+                       Binding vb;\r
+                       try {\r
+                               vb = Bindings.getBinding(void.class);\r
+                               Object vv = vb.createDefault();\r
+                               accessor.setContentValue(vb, vv);\r
+                       } catch (BindingConstructionException e1) {\r
+                               throw new AccessorConstructionException(e1);\r
+                       } catch (AccessorException e) {\r
+                               throw new AccessorConstructionException(e);\r
+                       } catch (BindingException e) {\r
+                               throw new AccessorConstructionException(e);\r
+                       }\r
+                       \r
+                       Entry e = new Entry(bf, accessor);                      \r
+                       files.put(file, e);                     \r
+               }\r
+\r
+               return accessor;\r
+       }\r
+       \r
+       public boolean deleteFile(File file) throws AccessorException {         \r
+               file = file.getAbsoluteFile();\r
+               expunge();\r
+               Entry ref = files.remove(file);\r
+               if (ref!=null) {\r
+                       FileVariantAccessor accessor = ref.get();\r
+                       if (accessor!=null) {\r
+                               accessor.close();\r
+                               accessor = null;\r
+                       } else {\r
+                               try {\r
+                                       ref.file.close();\r
+                               } catch (IOException e) {\r
+                                       throw new AccessorException(e);\r
+                               }\r
+                       }\r
+               }\r
+               expunge();\r
+               \r
+               if (!file.exists()) {\r
+                       return true;\r
+               }\r
+               boolean ok = file.delete();\r
+               return ok;\r
+       }\r
+       \r
+\r
+       /**\r
+        * Close unused file accessors. \r
+        */\r
+       public void expunge() {\r
+               Entry e;\r
+        while ( (e = (Entry) queue.poll()) != null) {\r
+//                     System.out.println("expunging "+e.file.file());\r
+               files.remove(e.file.file());\r
+               try {\r
+                               e.file.close();\r
+                       } catch (IOException e1) {\r
+                               e1.printStackTrace();\r
+                       }\r
+        }              \r
+       }\r
+       \r
+       /**\r
+        * Close and free all files, this invalidates all existing FileAccessors.\r
+        * close() doesn't invalidate FileLibrary.\r
+        * \r
+        */\r
+    public void close() {\r
+       for (Entry e : files.values()) {\r
+               try {\r
+//                     System.out.println("closing "+e.file.file());\r
+                       e.file.flush();\r
+                               e.file.close();\r
+                       } catch (IOException e1) {\r
+                               e1.printStackTrace();\r
+                       }\r
+       }\r
+       files.clear();\r
+    }\r
+\r
+    class Entry extends WeakReference<FileVariantAccessor> {\r
+       BinaryFile file;                \r
+       public Entry(BinaryFile file, FileVariantAccessor accessor) {\r
+                       super(accessor, FileLibrary.this.queue);\r
+                       this.file = file;\r
+               }\r
+    }\r
+    \r
+}\r
+\r
+\r