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