--- /dev/null
+package fi.vtt.simantics.procore.internal;\r
+\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
+import java.io.FilenameFilter;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.ObjectInputStream;\r
+import java.io.ObjectOutputStream;\r
+import java.io.OutputStream;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.concurrent.CopyOnWriteArrayList;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.VirtualGraph.Persistency;\r
+import org.simantics.db.WriteOnlyGraph;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.impl.ClusterI;\r
+import org.simantics.db.impl.ResourceImpl;\r
+import org.simantics.db.impl.TransientGraph;\r
+import org.simantics.db.impl.graph.ReadGraphImpl;\r
+import org.simantics.db.impl.support.VirtualGraphServerSupport;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.db.service.ServerInformation;\r
+import org.simantics.db.service.TransferableGraphSupport;\r
+import org.simantics.db.service.VirtualGraphSupport;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.utils.FileUtils;\r
+\r
+public class VirtualGraphServerSupportImpl implements VirtualGraphSupport, VirtualGraphServerSupport {\r
+\r
+ final private static boolean DEBUG = false;\r
+ final private SessionImplSocket session;\r
+\r
+ final public File virtualGraphStoragePath;\r
+ public String dbString = null;\r
+\r
+ public TIntHashSet virtuals = new TIntHashSet();\r
+\r
+ final public CopyOnWriteArrayList<TransientGraph> providers = new CopyOnWriteArrayList<TransientGraph>();\r
+ final private CopyOnWriteArrayList<TransientGraph> workspaceProviders = new CopyOnWriteArrayList<TransientGraph>();\r
+ final private CopyOnWriteArrayList<TransientGraph> memoryProviders = new CopyOnWriteArrayList<TransientGraph>();\r
+\r
+ public AtomicInteger virtualId;\r
+ private boolean hasVirtuals = false;\r
+\r
+ public VirtualGraphServerSupportImpl(SessionImplSocket session, File path) {\r
+ this.session = session;\r
+ this.virtualGraphStoragePath = path;\r
+ }\r
+\r
+ void connect(String dbString) {\r
+\r
+ virtualId = new AtomicInteger(-2);\r
+\r
+ this.dbString = dbString;\r
+\r
+ File file = new File(virtualGraphStoragePath, "virtualGraphs." + dbString + ".dat");\r
+\r
+ // System.out.println("scanning " + file.getAbsolutePath());\r
+\r
+ if(file.exists()) {\r
+ try {\r
+ InputStream stream = new FileInputStream(file);\r
+ final ObjectInputStream os = new ObjectInputStream(stream);\r
+ virtualId = new AtomicInteger(os.readInt());\r
+ // System.out.println("virtualId=" + virtualId.get());\r
+ os.close();\r
+ stream.close();\r
+\r
+ hasVirtuals = true;\r
+\r
+ // Load existing workspace persistent graphs\r
+ for(File virtualGraph : virtualGraphStoragePath.listFiles(new FilenameFilter() {\r
+ @Override\r
+ public boolean accept(File dir, String name) {\r
+ return name.endsWith(".vg");\r
+ }\r
+ })) {\r
+ String name = virtualGraph.getName();\r
+ String[] parts = name.split("\\x2E", 2);\r
+ getWorkspacePersistent(parts[0]);\r
+ }\r
+\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ } else {\r
+ if (DEBUG)\r
+ System.out.println("No stored virtual graphs.");\r
+ }\r
+\r
+ }\r
+\r
+ public void saveVirtualGraphState(SessionImplSocket session) {\r
+\r
+ if(!hasVirtuals) return;\r
+\r
+ try {\r
+\r
+ String databaseId = session.getService(ServerInformation.class).getDatabaseId();\r
+ String serverId = session.getService(ServerInformation.class).getServerId();\r
+ File file = new File(virtualGraphStoragePath, "virtualGraphs." + databaseId + "." + serverId + ".dat");\r
+\r
+ OutputStream stream = new FileOutputStream(file);\r
+ final ObjectOutputStream os = new ObjectOutputStream(stream);\r
+ os.writeInt(virtualId.get());\r
+ os.flush();\r
+ stream.close();\r
+\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ }\r
+\r
+ public void disposeVirtualGraphs() {\r
+\r
+ if(!hasVirtuals) return;\r
+\r
+ saveVirtualGraphState(session);\r
+ for(TransientGraph graph : workspaceProviders) graph.dispose();\r
+\r
+ }\r
+\r
+ public void saveVirtualGraphs() {\r
+\r
+ if(!hasVirtuals) return;\r
+\r
+ saveVirtualGraphState(session);\r
+ for(TransientGraph graph : workspaceProviders) graph.save();\r
+\r
+ }\r
+\r
+ @Override\r
+ public void saveAll() {\r
+ saveVirtualGraphs();\r
+ }\r
+\r
+ @Override\r
+ public VirtualGraph getMemoryPersistent(String identifier) {\r
+\r
+ if(identifier == null) throw new IllegalArgumentException("Argument cannot be null!");\r
+\r
+ for(TransientGraph graph : memoryProviders) {\r
+ if(identifier.equals(graph.getIdentifier())) return graph;\r
+ }\r
+\r
+ String databaseId = session.getService(ServerInformation.class).getDatabaseId();\r
+ VirtualGraphServerSupport vgss = session.getService(VirtualGraphServerSupport.class);\r
+\r
+ TransientGraph result = TransientGraph.memoryPersistent(new SerialisationSupportImpl(session), vgss, session.resourceSupport, session, databaseId, identifier);\r
+ memoryProviders.add(result);\r
+ providers.add(result);\r
+ return result;\r
+ }\r
+\r
+ private TransientGraph createWorkspacePersistentInternal(String identifier) {\r
+\r
+ String databaseId = session.getService(ServerInformation.class).getDatabaseId();\r
+ VirtualGraphServerSupport vgss = session.getService(VirtualGraphServerSupport.class);\r
+\r
+ try {\r
+ return TransientGraph.workspacePersistent(new SerialisationSupportImpl(session), vgss, session.resourceSupport, session, databaseId, identifier);\r
+ } catch (Exception e) {\r
+ Activator.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Failed to restore contents of previous virtual graph with identifier '" + identifier + "'. Resetting its contents to empty. See exception for problem details.", e));\r
+ return TransientGraph.memoryPersistent(new SerialisationSupportImpl(session), vgss, session.resourceSupport, session, databaseId, identifier);\r
+ }\r
+\r
+ }\r
+ \r
+ @Override\r
+ public VirtualGraph getWorkspacePersistent(String identifier) {\r
+\r
+ if(identifier == null) throw new IllegalArgumentException("Argument cannot be null!");\r
+\r
+ for(TransientGraph graph : workspaceProviders) {\r
+ if(identifier.equals(graph.getIdentifier())) return graph;\r
+ }\r
+\r
+ TransientGraph result = createWorkspacePersistentInternal(identifier);\r
+ \r
+ workspaceProviders.add(result);\r
+ providers.add(result);\r
+ hasVirtuals = true;\r
+ return result;\r
+\r
+ }\r
+\r
+ @Override\r
+ public boolean discard(VirtualGraph provider) {\r
+ if (!(provider instanceof TransientGraph))\r
+ return false;\r
+ if (!providers.remove(provider))\r
+ return false;\r
+\r
+ TransientGraph tg = (TransientGraph) provider;\r
+\r
+ if (workspaceProviders.remove(provider)) {\r
+ // TODO: remove possibly existing data from disk\r
+ tg.dispose();\r
+ } else if (memoryProviders.remove(provider)) {\r
+ tg.dispose();\r
+ }\r
+ return true;\r
+ }\r
+\r
+ public Resource getPersistentResource(WriteOnlyGraph graph, Resource resource, Map<Resource, Resource> creation) throws DatabaseException {\r
+ if(resource.isPersistent()) return resource;\r
+ else {\r
+ Resource result = creation.get(resource);\r
+ if(result == null) {\r
+ result = graph.newResource();\r
+ creation.put(resource, result);\r
+ }\r
+ return result;\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public boolean integrate(WriteOnlyGraph graph, VirtualGraph provider) throws DatabaseException {\r
+\r
+ if (!(provider instanceof TransientGraph))\r
+ return false;\r
+ if (!providers.remove(provider))\r
+ return false;\r
+\r
+ workspaceProviders.remove(provider);\r
+ memoryProviders.remove(provider);\r
+ \r
+ TransferableGraphSupport tgSupport = graph.getService(TransferableGraphSupport.class);\r
+ TransientGraph tg = (TransientGraph) provider;\r
+ \r
+ Map<Resource, Resource> creation = new HashMap<Resource, Resource>();\r
+ for(Statement stm : tg.listStatements()) {\r
+ Resource subject = getPersistentResource(graph, stm.getSubject(), creation);\r
+ Resource predicate = getPersistentResource(graph, stm.getPredicate(), creation);\r
+ Resource object = getPersistentResource(graph, stm.getObject(), creation);\r
+ graph.claim(subject, predicate, null, object);\r
+ }\r
+ for(Resource r : tg.listValues()) {\r
+ byte[] value = tg.getValue(((ResourceImpl)r).id);\r
+ tgSupport.setValue(graph, getPersistentResource(graph, r, creation), null, value);\r
+ }\r
+ discard(provider);\r
+ return true;\r
+ \r
+ }\r
+\r
+ @Override\r
+ public Collection<TransientGraph> getVirtualGraphs(int subject) {\r
+ if(subject < 0 || virtuals.contains(subject)) return providers;\r
+ else return null; \r
+ }\r
+\r
+ @Override\r
+ public void removeVirtual(int id) {\r
+ virtuals.remove(id);\r
+ }\r
+\r
+ @Override\r
+ public void addVirtual(int id) {\r
+ assert(id > 0);\r
+ // System.err.println("addVirtual " + id);\r
+ virtuals.add(id);\r
+ ClusterI cluster = session.clusterTable.getClusterByResourceKey(id);\r
+ cluster.markVirtual();\r
+ }\r
+\r
+ @Override\r
+ public int createVirtual() {\r
+ return virtualId.decrementAndGet();\r
+ }\r
+\r
+ @Override\r
+ public File storagePath() {\r
+ return virtualGraphStoragePath;\r
+ }\r
+\r
+ @Override\r
+ public Collection<Statement> listStatements(VirtualGraph graph_) {\r
+ TransientGraph graph = (TransientGraph)graph_;\r
+ return graph.listStatements();\r
+ }\r
+\r
+ @Override\r
+ public Collection<Resource> listValues(VirtualGraph graph_) {\r
+ TransientGraph graph = (TransientGraph)graph_;\r
+ return graph.listValues();\r
+ }\r
+\r
+ @Override\r
+ public Collection<VirtualGraph> listGraphs() {\r
+ ArrayList<VirtualGraph> result = new ArrayList<VirtualGraph>();\r
+ result.addAll(memoryProviders);\r
+ result.addAll(workspaceProviders);\r
+ return result;\r
+ }\r
+\r
+ public String report(final File file) {\r
+\r
+ session.asyncRequest(new Read<String>() {\r
+\r
+ @Override\r
+ public String perform(ReadGraph graph) throws DatabaseException {\r
+\r
+ SerialisationSupport ss = session.getService(SerialisationSupport.class);\r
+ StringBuilder b = new StringBuilder();\r
+ try {\r
+ for(VirtualGraph vg : listGraphs()) {\r
+ TransientGraph tg = (TransientGraph)vg;\r
+ if(Persistency.MEMORY == tg.getPersistency()) b.append("Memory persistent virtual graph '" + tg.getIdentifier() + "'\n");\r
+ if(Persistency.WORKSPACE == tg.getPersistency()) b.append("Workspace persistent virtual graph '" + tg.getIdentifier() + "'\n");\r
+ for(Statement stm : listStatements(tg)) {\r
+ int s = ss.getTransientId(stm.getSubject());\r
+ int p = ss.getTransientId(stm.getPredicate());\r
+ int o = ss.getTransientId(stm.getObject());\r
+ String sName = NameUtils.getSafeName(graph, stm.getSubject());\r
+ String pName = NameUtils.getSafeName(graph, stm.getPredicate());\r
+ String oName = NameUtils.getSafeName(graph, stm.getObject());\r
+ b.append(" S '" + sName + "' '" + pName + "' '" + oName + "' " + s + " " + p + " " + o + "\n");\r
+ }\r
+ for(Resource r : listValues(tg)) {\r
+ String sName = NameUtils.getSafeName(graph, r);\r
+ Object value = graph.getPossibleValue(r);\r
+ b.append(" V '" + sName + "' '" + value + "'\n");\r
+ }\r
+ }\r
+ FileUtils.writeFile(file, b.toString().getBytes());\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ return "ERROR";\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ return "ERROR";\r
+ }\r
+ return "OK";\r
+\r
+ }\r
+\r
+ });\r
+ return "OK";\r
+\r
+ }\r
+\r
+ @Override\r
+ public VirtualGraph getGraph(ReadGraph graph, Resource subject, Resource predicate, Resource object) throws DatabaseException {\r
+ ReadGraphImpl impl = (ReadGraphImpl)graph;\r
+ return impl.processor.getProvider(subject, predicate, object);\r
+ }\r
+\r
+ @Override\r
+ public VirtualGraph getGraph(ReadGraph graph, Resource subject, Resource predicate) throws DatabaseException {\r
+ ReadGraphImpl impl = (ReadGraphImpl)graph;\r
+ return impl.processor.getProvider(subject, predicate);\r
+ }\r
+\r
+ @Override\r
+ public VirtualGraph getGraph(ReadGraph graph, Resource subject) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ if(graph.hasStatement(subject, L0.InstanceOf)) {\r
+ return getGraph(graph, subject, L0.InstanceOf);\r
+ } else if (graph.hasStatement(subject, L0.Inherits)) {\r
+ return getGraph(graph, subject, L0.Inherits);\r
+ } else if (graph.hasStatement(subject, L0.SubrelationOf)) {\r
+ return getGraph(graph, subject, L0.SubrelationOf);\r
+ } else {\r
+ throw new DatabaseException("Resource is invalid, should have a statement with either L0.InstanceOf, L0.Inherits or L0.SubrelationOf " + subject);\r
+ }\r
+ }\r
+ \r
+}\r