--- /dev/null
+package org.simantics.db.service;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.Files;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.parser.repository.DataValueRepository;\r
+import org.simantics.db.exception.RuntimeDatabaseException;\r
+\r
+public class ClusterSets {\r
+\r
+ // final private static boolean DEBUG = false;\r
+\r
+ private File writeDirectory;\r
+ final private String databaseId;\r
+ final private HashMap<Long, Long> clusterSets; // Maps cluster set resource id to last user cluster id in the cluster set.\r
+ final private HashMap<Long, Long> reverseMap;\r
+ private int refCount; // Reference counter for user of this class.\r
+ private boolean modified; // True if modified since last save.\r
+\r
+ public void setWriteDirectory(File writeDirectory) {\r
+ this.writeDirectory = writeDirectory;\r
+ }\r
+ \r
+ private File getFile1(File directory) {\r
+ return new File(directory, "clusterSets." + this.databaseId + ".dat");\r
+ }\r
+\r
+ private File getFile2(File directory) {\r
+ return new File(directory, "clusterSets." + this.databaseId + ".dat.reverse");\r
+ }\r
+\r
+ public ClusterSets(File readDirectory, File writeDirectory, String databaseId) {\r
+\r
+ try {\r
+\r
+ this.databaseId = databaseId;\r
+ this.writeDirectory = writeDirectory;\r
+\r
+ readDirectory.mkdirs();\r
+\r
+ File file1 = getFile1(readDirectory);\r
+ File file2 = getFile2(readDirectory);\r
+\r
+ this.refCount = 1;\r
+ PersistentData pd, pd2;\r
+ try {\r
+ pd = (PersistentData)Files.readFile(file1, PersistentData.BINDING);\r
+ } catch (IOException e) {\r
+ // New file\r
+ pd = new PersistentData();\r
+ pd.values = new HashMap<Long, Long>();\r
+ Files.writeFile(file1, PersistentData.BINDING, pd);\r
+ }\r
+ try {\r
+ pd2 = (PersistentData)Files.readFile(file2, PersistentData.BINDING);\r
+ } catch (IOException e) {\r
+ // New file\r
+ pd2 = new PersistentData();\r
+ pd2.values = new HashMap<Long, Long>();\r
+ Files.writeFile(file2, PersistentData.BINDING, pd2);\r
+ }\r
+ this.clusterSets = pd.values;\r
+ this.reverseMap = pd2.values;\r
+ this.modified = false;\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ throw new RuntimeDatabaseException("Failed to create ClusterSets.");\r
+ }\r
+ }\r
+ public synchronized int inc() {\r
+ return ++refCount;\r
+ }\r
+ public synchronized int dec() {\r
+ return --refCount;\r
+ }\r
+ // Save is thread safe.\r
+ public void dispose() {\r
+ try {\r
+ // We still save changes even if transaction is not finished.\r
+ // This is because we have no cancel mechanism for cluster (sets).\r
+ save();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ throw new RuntimeDatabaseException("Failed to save ClusterSets.");\r
+ } \r
+ }\r
+ // clusterSets is not thread safe.\r
+ public synchronized boolean containsKey(long resourceId) {\r
+ return clusterSets.containsKey(resourceId);\r
+ }\r
+ public synchronized Long get(Long resourceId) {\r
+ return clusterSets.get(resourceId);\r
+ }\r
+ public synchronized void put(long resourceId, long clusterId) {\r
+ clusterSets.put(resourceId, clusterId);\r
+ reverseMap.put(clusterId, resourceId);\r
+ modified = true;\r
+ }\r
+ public synchronized Long getClusterSet(Long clusterId) {\r
+ return reverseMap.get(clusterId);\r
+ }\r
+ public void clear() {\r
+ \r
+ for(Long key : clusterSets.keySet())\r
+ clusterSets.put(key, -1L);\r
+ \r
+ touch();\r
+ \r
+ }\r
+ public synchronized void touch() {\r
+ modified = true;\r
+ }\r
+ public synchronized void save() throws IOException {\r
+\r
+ if (!modified)\r
+ return;\r
+ \r
+ writeDirectory.mkdirs();\r
+ File file1 = getFile1(writeDirectory);\r
+ File file2 = getFile2(writeDirectory);\r
+ PersistentData pd = new PersistentData();\r
+ pd.values = clusterSets;\r
+ Files.writeFile(file1, PersistentData.BINDING, pd);\r
+ pd = new PersistentData();\r
+ pd.values = reverseMap;\r
+ Files.writeFile(file2, PersistentData.BINDING, pd);\r
+ modified = false;\r
+\r
+ }\r
+ static public class PersistentData {\r
+ final public static Binding BINDING = Bindings.getBindingUnchecked(PersistentData.class);\r
+ // public TreeMap<Long, Long> values;\r
+ public HashMap<Long, Long> values;\r
+ public static void main(String[] args) throws Exception {\r
+ System.err.println("" + BINDING.type().toSingleLineString());\r
+ PersistentData pd = new PersistentData();\r
+ // pd.values = new TreeMap<Long, Long>();\r
+ pd.values = new HashMap<Long, Long>();\r
+ for (long i=0; i<10; ++i)\r
+ pd.values.put(i, i);\r
+ BINDING.printValue(pd, System.err, new DataValueRepository(), true);\r
+ }\r
+ }\r
+ \r
+}\r