-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in 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.project.management;\r
-\r
-import static org.simantics.db.common.utils.Transaction.writeGraph;\r
-\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-import java.util.regex.Matcher;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.WriteOnlyGraph;\r
-import org.simantics.db.common.utils.Transaction;\r
-import org.simantics.db.exception.AssumptionException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.util.Layer0Utils;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.graph.db.IImportAdvisor;\r
-import org.simantics.graph.db.ImportAdvisor;\r
-import org.simantics.graph.db.TransferableGraphException;\r
-import org.simantics.graph.db.TransferableGraphs;\r
-import org.simantics.graph.diff.Diff;\r
-import org.simantics.graph.diff.TransferableGraphDelta1;\r
-import org.simantics.graph.representation.TransferableGraph1;\r
-import org.simantics.layer0.DatabaseManagementResource;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.project.ontology.ProjectResource;\r
-\r
-/**\r
- * Database Management is a utility class for managing a database.\r
- * The following management operations are supported:\r
- * \r
- * o Install Builtins\r
- * o Install Layer0\r
- * o Install & Update GraphBundles\r
- * o Manage Projects (Install/Uninstall/Discover)\r
- * o Manage Features (Install/Uninstall/Discover)\r
- * o Manage GraphBundles\r
- * \r
- * This utility is based on Transaction class. The active graph must be\r
- * set for the current thread.\r
- *\r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
- */\r
-public class DatabaseManagement {\r
-\r
- public static final String PROJECTS_URI = "http://Projects"; \r
- Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );\r
-\r
- public DatabaseManagement() {\r
- }\r
-\r
- /////////////////////////////////////////////////////////////////////////// \r
- /////////////// Project Managemenet ////////////////////// \r
- /////////////////////////////////////////////////////////////////////////// \r
- /**\r
- * Create a new project. A new resource is created and linked to Projects \r
- * library. \r
- * \r
- * @param g\r
- * @param name\r
- * @param features a list of features\r
- * @return resource to the project\r
- * @throws DatabaseException\r
- */\r
- public Resource createProject(String name, Collection<String> features) throws DatabaseException {\r
- \r
- WriteGraph g = Transaction.writeGraph();\r
- g.setClusterSet4NewResource(g.getRootLibrary());\r
-\r
- Resource root = g.getResource(PROJECTS_URI);\r
- Layer0 L0 = Layer0.getInstance(g);\r
- ProjectResource PROJ = ProjectResource.getInstance(g);\r
-\r
- Resource project = g.newResource();\r
- g.claim(project, L0.InstanceOf, null, PROJ.Project);\r
- g.claim(project, L0.PartOf, root);\r
- g.claimLiteral(project, L0.HasName, name);\r
- \r
- // Create library for temporary resources\r
- if(Layer0Utils.getPossibleChild(g, root, "Temp") == null) {\r
- Resource tempLibrary = g.newResource();\r
- g.claim(tempLibrary, L0.InstanceOf, null, L0.Library);\r
- g.claimLiteral(tempLibrary, L0.HasName, "Temp");\r
- g.claim(root, L0.ConsistsOf, tempLibrary);\r
- }\r
-\r
- // Create library for trash\r
- if(Layer0Utils.getPossibleChild(g, root, "TrashBin") == null) {\r
- Resource trashLibrary = g.newResource();\r
- g.claim(trashLibrary, L0.InstanceOf, null, L0.Library);\r
- g.claimLiteral(trashLibrary, L0.HasName, "TrashBin");\r
- g.claim(root, L0.ConsistsOf, trashLibrary);\r
- }\r
-\r
- // Create library for document sessions\r
- if(Layer0Utils.getPossibleChild(g, root, "DocumentSessions") == null) {\r
- Resource documentSessions = g.newResource();\r
- g.claim(documentSessions, L0.InstanceOf, null, L0.Library);\r
- g.claimLiteral(documentSessions, L0.HasName, "DocumentSessions");\r
- g.claim(root, L0.ConsistsOf, documentSessions);\r
- }\r
-\r
- // Link features\r
- for (String feature_uri : features) {\r
- Resource r = g.getResource(feature_uri);\r
- g.claim(project, PROJ.HasFeature, r);\r
- }\r
- \r
- return project;\r
- }\r
- \r
- \r
- /**\r
- * Delete project. Project resource is unlinked it from the Projects library.\r
- * The rest is left for garbage collection.\r
- * \r
- * @param g\r
- * @param projectResource\r
- * @throws DatabaseException\r
- */\r
- public void deleteProject(Resource projectResource) throws DatabaseException {\r
- WriteGraph g = Transaction.writeGraph();\r
- Resource root = g.getResource(PROJECTS_URI);\r
- Layer0 l0 = Layer0.getInstance(g);\r
- g.denyStatement(projectResource, l0.PartOf, root);\r
- }\r
- \r
- \r
- /**\r
- * A query that reads all project URIs \r
- * \r
- * @param g graph\r
- * @return a query for graphs\r
- * @throws DatabaseException\r
- */\r
- public final Read<Set<String>> ProjectURIQuery =\r
- new Read<Set<String>>() {\r
- @Override\r
- public Set<String> perform(ReadGraph g) throws DatabaseException {\r
- Layer0 b = Layer0.getInstance(g);\r
- Resource root = g.getResource(PROJECTS_URI);\r
- Set<String> result = new HashSet<String>();\r
- for (Resource r : g.getObjects(root, b.ConsistsOf) )\r
- result.add( g.getURI(r) );\r
- return result;\r
- }\r
- }; \r
- \r
- /**\r
- * A query that reads all project resources \r
- * \r
- * @param g graph\r
- * @return a query for graphs\r
- * @throws DatabaseException\r
- */\r
- public final Read<Set<Resource>> ProjectsQuery =\r
- new Read<Set<Resource>>() {\r
- @Override\r
- public Set<Resource> perform(ReadGraph g) throws DatabaseException {\r
- Layer0 b = Layer0.getInstance(g);\r
- Resource root = g.getResource(PROJECTS_URI);\r
- return new HashSet<Resource>( g.getObjects(root, b.ConsistsOf) );\r
- }\r
- };\r
- \r
- \r
- /**\r
- * Get a list of all projects in the database. \r
- * \r
- * @param g\r
- * @return\r
- * @throws DatabaseException\r
- */\r
- public Collection<Resource> getProjects() throws DatabaseException {\r
- ReadGraph g = Transaction.readGraph();\r
- Layer0 b = Layer0.getInstance(g);\r
- Resource root = g.getResource(PROJECTS_URI);\r
- return g.getObjects(root, b.ConsistsOf);\r
- }\r
-\r
- /////////////////////////////////////////////////////////////////////////// \r
- /////////////// Feature Management ////////////////////// \r
- /////////////////////////////////////////////////////////////////////////// \r
- \r
-// /**\r
-// * Get all features in the database. \r
-// * \r
-// * @param features a collection to be filled with features\r
-// */\r
-// public void getFeatures(Collection<FeatureInfo> features) throws DatabaseException \r
-// {\r
-// ReadGraph g = Transaction.readGraph();\r
-// ProjectResource PROJ = ProjectResource.getInstance(g);\r
-// Layer0 L0 = Layer0.getInstance(g);\r
-//\r
-// for (Resource r : g.getObjects(PROJ.PublishedProjectFeatures, L0.ConsistsOf)) {\r
-// String URI = g.getURI(r);\r
-// String name = g.getRelatedValue(r, L0.HasLabel);\r
-// String vid_ = g.getRelatedValue(r, L0.HasName);\r
-// VersionedId vid = (VersionedId) VersionedId.parse(vid_);\r
-// FeatureInfo fi = new FeatureInfo(name, URI, vid); \r
-// features.add( fi ); \r
-// }\r
-// \r
-// }\r
-// \r
-// /**\r
-// * Get all features installed to a project\r
-// * \r
-// * @param g graph\r
-// * @param features a list of bundles\r
-// * @throws DatabaseException\r
-// */\r
-// public void getProjectFeatures(Resource project, Collection<FeatureInfo> features) throws DatabaseException {\r
-// ReadGraph g = Transaction.readGraph();\r
-// ProjectResource PROJ = ProjectResource.getInstance(g);\r
-// Layer0 L0 = Layer0.getInstance(g);\r
-// \r
-// for (Resource r : g.getObjects(project, PROJ.HasFeature)) {\r
-// String URI = g.getURI(r);\r
-// String name = g.getRelatedValue(r, L0.HasLabel);\r
-// String vid_ = g.getRelatedValue(r, L0.HasName);\r
-// VersionedId vid = (VersionedId) VersionedId.parse(vid_);\r
-// FeatureInfo fi = new FeatureInfo(name, URI, vid); \r
-// features.add( fi ); \r
-// }\r
-// }\r
-// \r
-// /**\r
-// * Configure project to use a feature.\r
-// * \r
-// * @param g\r
-// * @param project\r
-// * @param featureUri feature URI\r
-// * @throws DatabaseException\r
-// */\r
-// public void installFeature(Resource project, String featureUri)\r
-// throws DatabaseException\r
-// {\r
-// WriteGraph g = Transaction.writeGraph();\r
-// Resource feature = g.getResource(featureUri);\r
-// ProjectResource PROJ = ProjectResource.getInstance(g);\r
-// g.claim(project, PROJ.HasFeature, feature);\r
-// }\r
-// \r
-// /**\r
-// * Configure project not to use a feature.\r
-// * \r
-// * @param g\r
-// * @param project\r
-// * @param featureuri feature URI\r
-// * @throws DatabaseException\r
-// */\r
-// public void uninstallFeature(Resource project, String featureUri) \r
-// throws DatabaseException\r
-// {\r
-// WriteGraph g = Transaction.writeGraph();\r
-// Resource feature = g.getResource(featureUri);\r
-// ProjectResource PROJ = ProjectResource.getInstance(g);\r
-// g.denyStatement(project, PROJ.HasFeature, feature);\r
-// }\r
- \r
- \r
- /////////////////////////////////////////////////////////////////////////// \r
- /////////////// Transferable Graph Management ////////////////////// \r
- /////////////////////////////////////////////////////////////////////////// \r
- \r
- /**\r
- * Install transferable graph into database and manage install info.\r
- * If different but exact same version is already installed, the new \r
- * graph is merged.<p>\r
- * \r
- * Resource array field of tg argument is updated.\r
- * \r
- * @param tg transferable graph\r
- */\r
- public void installGraphBundle(GraphBundle tg)\r
- throws DatabaseException, TransferableGraphException \r
- {\r
- Resource oldResource = getGraphBundleResource(tg.getId(), tg.getMajor());\r
- // Install New\r
- if (oldResource == null) { \r
- IImportAdvisor advisor = new ImportAdvisor();\r
- long[] resourceArray = TransferableGraphs.importGraph(writeGraph(), tg.getGraph(), advisor);\r
- tg.setResourceArray(resourceArray);\r
- setGraphBundleEntry(tg);\r
- } else\r
- // Merge with old\r
- {\r
- // Merge &\r
- GraphBundle oldTG = getGraphBundle(oldResource);\r
- TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();\r
- long[] oldResourceArray = oldTG.getResourceArray();\r
- long[] newResourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResourceArray, delta);\r
- tg.setResourceArray(newResourceArray);\r
- // Manage\r
- setGraphBundleEntry(tg); \r
- }\r
- }\r
-\r
- /**\r
- * A query that reads all graphs in the database \r
- * \r
- * @param g graph\r
- * @return a query for graphs\r
- * @throws DatabaseException\r
- */\r
- public final Read<Set<GraphBundleRef>> GraphBundleRefQuery =\r
- new Read<Set<GraphBundleRef>>() {\r
- @Override\r
- public Set<GraphBundleRef> perform(ReadGraph g) throws DatabaseException {\r
- Object oldGraph = Transaction.setGraph(g);\r
- try {\r
- return getGraphBundleReferences();\r
- } finally {\r
- Transaction.setGraph(oldGraph);\r
- }\r
- }\r
- }; \r
-\r
- \r
- /**\r
- * A query that reads all graphs in the database \r
- * \r
- * @param g graph\r
- * @return a query for graphs\r
- * @throws DatabaseException\r
- */\r
- public final Read<Set<GraphBundle>> GraphBundleQuery =\r
- new Read<Set<GraphBundle>>() {\r
- @Override\r
- public Set<GraphBundle> perform(ReadGraph g) throws DatabaseException {\r
- Object oldGraph = Transaction.setGraph(g);\r
- try {\r
- return getGraphBundles();\r
- } finally {\r
- Transaction.setGraph(oldGraph);\r
- }\r
- }\r
- }; \r
-\r
- public Set<GraphBundle> getGraphBundles() \r
- throws DatabaseException {\r
- ReadGraph g = Transaction.readGraph();\r
- Set<GraphBundle> result = new HashSet<GraphBundle>();\r
-\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- Layer0 L0 = Layer0.getInstance(g); \r
- \r
- for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {\r
- if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue; \r
- String name = g.getPossibleRelatedValue(tg, L0.HasName);\r
- String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);\r
- Integer hash = g.getPossibleRelatedValue(tg, DatabaseManagement.HasHashCode);\r
- //System.out.println("Found in Database: " + vid);\r
- //TransferableGraph1 data = g.getRelatedValue(tg, DatabaseManagement.HasFile, tg_binding);\r
- GraphBundle entry = new GraphBundle(name, null, vid);\r
- entry.resource = tg;\r
- entry.hashcode = hash;\r
- long[] resourceArray = g.getPossibleRelatedValue(tg, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);\r
- if (resourceArray!=null) entry.setResourceArray(resourceArray);\r
- result.add(entry);\r
- } \r
- return result; \r
- }\r
-\r
- public Set<GraphBundleRef> getGraphBundleReferences() \r
- throws DatabaseException {\r
- ReadGraph g = Transaction.readGraph();\r
- Set<GraphBundleRef> result = new HashSet<GraphBundleRef>();\r
-\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- Layer0 L0 = Layer0.getInstance(g); \r
- \r
- for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {\r
- if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue;\r
- String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);\r
- result.add( GraphBundleRef.of( vid ) );\r
- } \r
- return result; \r
- }\r
- \r
- \r
- /**\r
- * Get TransferableGraph resource that is attached to InstalledTransferableGraphs. \r
- * \r
- * @param id id <symbolic_name>_<version>\r
- * @return TG resource or <tt>null</tt>\r
- * @throws DatabaseException\r
- */\r
- public GraphBundle getGraphBundle(Resource r) throws DatabaseException {\r
- ReadGraph g = Transaction.readGraph();\r
- Layer0 L0 = Layer0.getInstance(g);\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- \r
- String name = g.getPossibleRelatedValue(r, L0.HasName);\r
- String vid = g.getPossibleRelatedValue(r, DatabaseManagement.HasVersionedId);\r
- TransferableGraph1 data = g.getRelatedValue(r, DatabaseManagement.HasFile, tg_binding);\r
- GraphBundle entry = new GraphBundle(name, data, vid);\r
- long[] resourceArray = g.getPossibleRelatedValue(r, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);\r
- if (resourceArray!=null) entry.setResourceArray(resourceArray); \r
- return entry;\r
- } \r
- \r
- /**\r
- * Get TransferableGraph resource that is attached to InstalledTransferableGraphs. \r
- * \r
- * @param id id <symbolic_name>/<version>\r
- * @param major major version\r
- * @return resource or <tt>null</tt>\r
- * @throws DatabaseException\r
- */\r
- public Resource getGraphBundleResource(String id, int major) throws DatabaseException {\r
- ReadGraph g = Transaction.readGraph();\r
- Layer0 L0 = Layer0.getInstance(g);\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- \r
- for (Resource r : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {\r
- if ( !g.isInstanceOf(r, DatabaseManagement.GraphBundle) ) continue; \r
- String vid = g.getRelatedValue(r, DatabaseManagement.HasVersionedId);\r
- \r
- Matcher m = GraphBundle.VERSIONED_ID_PATTERN.matcher(vid);\r
- if (!m.matches()) continue;\r
- \r
- String rid = m.group(1);\r
- int rmajor = Integer.valueOf( m.group(2) );\r
- if (rid.equals(id) && rmajor==major) return r;\r
- }\r
- \r
- return null;\r
- }\r
-\r
- /**\r
- * Create a GraphBundle entry into the database and attach to \r
- * InstalledTransferableGraphs-library.\r
- * \r
- * @param entry\r
- * @param resourceArray\r
- * @return Resource\r
- * @throws DatabaseException\r
- */\r
- Resource createGraphBundle(GraphBundle entry) throws DatabaseException {\r
- WriteGraph g = Transaction.writeGraph();\r
- Layer0 L0 = Layer0.getInstance(g);\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
-\r
- Resource r = g.newResource();\r
- g.claim(r, L0.InstanceOf, DatabaseManagement.GraphBundle);\r
- g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);\r
- g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);\r
- g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);\r
- g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);\r
- g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);\r
- g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, r);\r
- return r;\r
- \r
- }\r
-\r
- public Resource createGraphBundle(WriteOnlyGraph g, GraphBundle entry) throws DatabaseException {\r
-\r
- Layer0 L0 = g.getService(Layer0.class);\r
- DatabaseManagementResource DatabaseManagement = g.getService(DatabaseManagementResource.class);\r
-\r
- Resource r = g.newResource();\r
- g.claim(r, L0.InstanceOf, null, DatabaseManagement.GraphBundle);\r
- g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);\r
- g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);\r
- g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);\r
- g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);\r
- g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);\r
- g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, L0.PartOf, r); \r
- return r;\r
- \r
- }\r
- \r
- /**\r
- * Set TransferableGraph info.\r
- * \r
- * @param entry \r
- * @param resourceArray\r
- * @return new or existing feature resource\r
- * @throws DatabaseException\r
- * @throws AssumptionException thrown if bundle exists but is not a GraphBundle \r
- */\r
- public Resource setGraphBundleEntry(GraphBundle entry) throws DatabaseException {\r
- Resource r = getGraphBundleResource(entry.getId(), entry.getMajor());\r
- \r
- // Create a new resource\r
- if (r==null) {\r
- r = createGraphBundle(entry);\r
- return r;\r
- }\r
- \r
- // Update values of an existing resource\r
- {\r
- WriteGraph g = Transaction.writeGraph(); \r
- Layer0 L0 = Layer0.getInstance(g);\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- g.claimLiteral(r, L0.HasName, entry.getName(), Bindings.STRING);\r
- g.claimLiteral(r, DatabaseManagement.HasVersionedId, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);\r
- g.claimLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);\r
- g.claimLiteral(r, DatabaseManagement.HasHashCode, entry.hashcode, Bindings.INTEGER);\r
- g.claimLiteral(r, DatabaseManagement.HasInstallInfo, entry.getResourceArray(), Bindings.LONG_ARRAY);\r
- return r;\r
- } \r
- } \r
- \r
-}\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.project.management;
+
+import static org.simantics.db.common.utils.Transaction.writeGraph;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.WriteOnlyGraph;
+import org.simantics.db.common.utils.Transaction;
+import org.simantics.db.exception.AssumptionException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.request.Read;
+import org.simantics.graph.db.IImportAdvisor;
+import org.simantics.graph.db.ImportAdvisor;
+import org.simantics.graph.db.TransferableGraphException;
+import org.simantics.graph.db.TransferableGraphs;
+import org.simantics.graph.diff.Diff;
+import org.simantics.graph.diff.TransferableGraphDelta1;
+import org.simantics.graph.representation.TransferableGraph1;
+import org.simantics.layer0.DatabaseManagementResource;
+import org.simantics.layer0.Layer0;
+import org.simantics.project.ontology.ProjectResource;
+
+/**
+ * Database Management is a utility class for managing a database.
+ * The following management operations are supported:
+ *
+ * o Install Builtins
+ * o Install Layer0
+ * o Install & Update GraphBundles
+ * o Manage Projects (Install/Uninstall/Discover)
+ * o Manage Features (Install/Uninstall/Discover)
+ * o Manage GraphBundles
+ *
+ * This utility is based on Transaction class. The active graph must be
+ * set for the current thread.
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class DatabaseManagement {
+
+ public static final String PROJECTS_URI = "http://Projects";
+ Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
+
+ public DatabaseManagement() {
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ /////////////// Project Managemenet //////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+ /**
+ * Create a new project. A new resource is created and linked to Projects
+ * library.
+ *
+ * @param g
+ * @param name
+ * @param features a list of features
+ * @return resource to the project
+ * @throws DatabaseException
+ */
+ public Resource createProject(String name, Collection<String> features) throws DatabaseException {
+
+ WriteGraph g = Transaction.writeGraph();
+ g.setClusterSet4NewResource(g.getRootLibrary());
+
+ Resource root = g.getResource(PROJECTS_URI);
+ Layer0 L0 = Layer0.getInstance(g);
+ ProjectResource PROJ = ProjectResource.getInstance(g);
+
+ Resource project = g.newResource();
+ g.claim(project, L0.InstanceOf, null, PROJ.Project);
+ g.claim(project, L0.PartOf, root);
+ g.claimLiteral(project, L0.HasName, name);
+
+ // Create library for temporary resources
+ if(Layer0Utils.getPossibleChild(g, root, "Temp") == null) {
+ Resource tempLibrary = g.newResource();
+ g.claim(tempLibrary, L0.InstanceOf, null, L0.Library);
+ g.claimLiteral(tempLibrary, L0.HasName, "Temp");
+ g.claim(root, L0.ConsistsOf, tempLibrary);
+ }
+
+ // Create library for trash
+ if(Layer0Utils.getPossibleChild(g, root, "TrashBin") == null) {
+ Resource trashLibrary = g.newResource();
+ g.claim(trashLibrary, L0.InstanceOf, null, L0.Library);
+ g.claimLiteral(trashLibrary, L0.HasName, "TrashBin");
+ g.claim(root, L0.ConsistsOf, trashLibrary);
+ }
+
+ // Create library for document sessions
+ if(Layer0Utils.getPossibleChild(g, root, "DocumentSessions") == null) {
+ Resource documentSessions = g.newResource();
+ g.claim(documentSessions, L0.InstanceOf, null, L0.Library);
+ g.claimLiteral(documentSessions, L0.HasName, "DocumentSessions");
+ g.claim(root, L0.ConsistsOf, documentSessions);
+ }
+
+ // Link features
+ for (String feature_uri : features) {
+ Resource r = g.getResource(feature_uri);
+ g.claim(project, PROJ.HasFeature, r);
+ }
+
+ return project;
+ }
+
+
+ /**
+ * Delete project. Project resource is unlinked it from the Projects library.
+ * The rest is left for garbage collection.
+ *
+ * @param g
+ * @param projectResource
+ * @throws DatabaseException
+ */
+ public void deleteProject(Resource projectResource) throws DatabaseException {
+ WriteGraph g = Transaction.writeGraph();
+ Resource root = g.getResource(PROJECTS_URI);
+ Layer0 l0 = Layer0.getInstance(g);
+ g.denyStatement(projectResource, l0.PartOf, root);
+ }
+
+
+ /**
+ * A query that reads all project URIs
+ *
+ * @param g graph
+ * @return a query for graphs
+ * @throws DatabaseException
+ */
+ public final Read<Set<String>> ProjectURIQuery =
+ new Read<Set<String>>() {
+ @Override
+ public Set<String> perform(ReadGraph g) throws DatabaseException {
+ Layer0 b = Layer0.getInstance(g);
+ Resource root = g.getResource(PROJECTS_URI);
+ Set<String> result = new HashSet<String>();
+ for (Resource r : g.getObjects(root, b.ConsistsOf) )
+ result.add( g.getURI(r) );
+ return result;
+ }
+ };
+
+ /**
+ * A query that reads all project resources
+ *
+ * @param g graph
+ * @return a query for graphs
+ * @throws DatabaseException
+ */
+ public final Read<Set<Resource>> ProjectsQuery =
+ new Read<Set<Resource>>() {
+ @Override
+ public Set<Resource> perform(ReadGraph g) throws DatabaseException {
+ Layer0 b = Layer0.getInstance(g);
+ Resource root = g.getResource(PROJECTS_URI);
+ return new HashSet<Resource>( g.getObjects(root, b.ConsistsOf) );
+ }
+ };
+
+
+ /**
+ * Get a list of all projects in the database.
+ *
+ * @param g
+ * @return
+ * @throws DatabaseException
+ */
+ public Collection<Resource> getProjects() throws DatabaseException {
+ ReadGraph g = Transaction.readGraph();
+ Layer0 b = Layer0.getInstance(g);
+ Resource root = g.getResource(PROJECTS_URI);
+ return g.getObjects(root, b.ConsistsOf);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ /////////////// Feature Management //////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+// /**
+// * Get all features in the database.
+// *
+// * @param features a collection to be filled with features
+// */
+// public void getFeatures(Collection<FeatureInfo> features) throws DatabaseException
+// {
+// ReadGraph g = Transaction.readGraph();
+// ProjectResource PROJ = ProjectResource.getInstance(g);
+// Layer0 L0 = Layer0.getInstance(g);
+//
+// for (Resource r : g.getObjects(PROJ.PublishedProjectFeatures, L0.ConsistsOf)) {
+// String URI = g.getURI(r);
+// String name = g.getRelatedValue(r, L0.HasLabel);
+// String vid_ = g.getRelatedValue(r, L0.HasName);
+// VersionedId vid = (VersionedId) VersionedId.parse(vid_);
+// FeatureInfo fi = new FeatureInfo(name, URI, vid);
+// features.add( fi );
+// }
+//
+// }
+//
+// /**
+// * Get all features installed to a project
+// *
+// * @param g graph
+// * @param features a list of bundles
+// * @throws DatabaseException
+// */
+// public void getProjectFeatures(Resource project, Collection<FeatureInfo> features) throws DatabaseException {
+// ReadGraph g = Transaction.readGraph();
+// ProjectResource PROJ = ProjectResource.getInstance(g);
+// Layer0 L0 = Layer0.getInstance(g);
+//
+// for (Resource r : g.getObjects(project, PROJ.HasFeature)) {
+// String URI = g.getURI(r);
+// String name = g.getRelatedValue(r, L0.HasLabel);
+// String vid_ = g.getRelatedValue(r, L0.HasName);
+// VersionedId vid = (VersionedId) VersionedId.parse(vid_);
+// FeatureInfo fi = new FeatureInfo(name, URI, vid);
+// features.add( fi );
+// }
+// }
+//
+// /**
+// * Configure project to use a feature.
+// *
+// * @param g
+// * @param project
+// * @param featureUri feature URI
+// * @throws DatabaseException
+// */
+// public void installFeature(Resource project, String featureUri)
+// throws DatabaseException
+// {
+// WriteGraph g = Transaction.writeGraph();
+// Resource feature = g.getResource(featureUri);
+// ProjectResource PROJ = ProjectResource.getInstance(g);
+// g.claim(project, PROJ.HasFeature, feature);
+// }
+//
+// /**
+// * Configure project not to use a feature.
+// *
+// * @param g
+// * @param project
+// * @param featureuri feature URI
+// * @throws DatabaseException
+// */
+// public void uninstallFeature(Resource project, String featureUri)
+// throws DatabaseException
+// {
+// WriteGraph g = Transaction.writeGraph();
+// Resource feature = g.getResource(featureUri);
+// ProjectResource PROJ = ProjectResource.getInstance(g);
+// g.denyStatement(project, PROJ.HasFeature, feature);
+// }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ /////////////// Transferable Graph Management //////////////////////
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Install transferable graph into database and manage install info.
+ * If different but exact same version is already installed, the new
+ * graph is merged.<p>
+ *
+ * Resource array field of tg argument is updated.
+ *
+ * @param tg transferable graph
+ */
+ public void installGraphBundle(GraphBundle tg)
+ throws DatabaseException, TransferableGraphException
+ {
+ Resource oldResource = getGraphBundleResource(tg.getId(), tg.getMajor());
+ // Install New
+ if (oldResource == null) {
+ IImportAdvisor advisor = new ImportAdvisor();
+ long[] resourceArray = TransferableGraphs.importGraph(writeGraph(), tg.getGraph(), advisor);
+ tg.setResourceArray(resourceArray);
+ setGraphBundleEntry(tg);
+ } else
+ // Merge with old
+ {
+ // Merge &
+ GraphBundle oldTG = getGraphBundle(oldResource);
+ TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();
+ long[] oldResourceArray = oldTG.getResourceArray();
+ long[] newResourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResourceArray, delta);
+ tg.setResourceArray(newResourceArray);
+ // Manage
+ setGraphBundleEntry(tg);
+ }
+ }
+
+ /**
+ * A query that reads all graphs in the database
+ *
+ * @param g graph
+ * @return a query for graphs
+ * @throws DatabaseException
+ */
+ public final Read<Set<GraphBundleRef>> GraphBundleRefQuery =
+ new Read<Set<GraphBundleRef>>() {
+ @Override
+ public Set<GraphBundleRef> perform(ReadGraph g) throws DatabaseException {
+ Object oldGraph = Transaction.setGraph(g);
+ try {
+ return getGraphBundleReferences();
+ } finally {
+ Transaction.setGraph(oldGraph);
+ }
+ }
+ };
+
+
+ /**
+ * A query that reads all graphs in the database
+ *
+ * @param g graph
+ * @return a query for graphs
+ * @throws DatabaseException
+ */
+ public final Read<Set<GraphBundle>> GraphBundleQuery =
+ new Read<Set<GraphBundle>>() {
+ @Override
+ public Set<GraphBundle> perform(ReadGraph g) throws DatabaseException {
+ Object oldGraph = Transaction.setGraph(g);
+ try {
+ return getGraphBundles();
+ } finally {
+ Transaction.setGraph(oldGraph);
+ }
+ }
+ };
+
+ public Set<GraphBundle> getGraphBundles()
+ throws DatabaseException {
+ ReadGraph g = Transaction.readGraph();
+ Set<GraphBundle> result = new HashSet<GraphBundle>();
+
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+ Layer0 L0 = Layer0.getInstance(g);
+
+ for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
+ if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue;
+ String name = g.getPossibleRelatedValue(tg, L0.HasName);
+ String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);
+ Integer hash = g.getPossibleRelatedValue(tg, DatabaseManagement.HasHashCode);
+ //System.out.println("Found in Database: " + vid);
+ //TransferableGraph1 data = g.getRelatedValue(tg, DatabaseManagement.HasFile, tg_binding);
+ GraphBundle entry = new GraphBundle(name, null, vid);
+ entry.resource = tg;
+ entry.hashcode = hash;
+ long[] resourceArray = g.getPossibleRelatedValue(tg, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);
+ if (resourceArray!=null) entry.setResourceArray(resourceArray);
+ result.add(entry);
+ }
+ return result;
+ }
+
+ public Set<GraphBundleRef> getGraphBundleReferences()
+ throws DatabaseException {
+ ReadGraph g = Transaction.readGraph();
+ Set<GraphBundleRef> result = new HashSet<GraphBundleRef>();
+
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+ Layer0 L0 = Layer0.getInstance(g);
+
+ for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
+ if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue;
+ String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);
+ result.add( GraphBundleRef.of( vid ) );
+ }
+ return result;
+ }
+
+
+ /**
+ * Get TransferableGraph resource that is attached to InstalledTransferableGraphs.
+ *
+ * @param id id <symbolic_name>_<version>
+ * @return TG resource or <tt>null</tt>
+ * @throws DatabaseException
+ */
+ public GraphBundle getGraphBundle(Resource r) throws DatabaseException {
+ ReadGraph g = Transaction.readGraph();
+ Layer0 L0 = Layer0.getInstance(g);
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+
+ String name = g.getPossibleRelatedValue(r, L0.HasName);
+ String vid = g.getPossibleRelatedValue(r, DatabaseManagement.HasVersionedId);
+ TransferableGraph1 data = g.getRelatedValue(r, DatabaseManagement.HasFile, tg_binding);
+ GraphBundle entry = new GraphBundle(name, data, vid);
+ long[] resourceArray = g.getPossibleRelatedValue(r, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);
+ if (resourceArray!=null) entry.setResourceArray(resourceArray);
+ return entry;
+ }
+
+ /**
+ * Get TransferableGraph resource that is attached to InstalledTransferableGraphs.
+ *
+ * @param id id <symbolic_name>/<version>
+ * @param major major version
+ * @return resource or <tt>null</tt>
+ * @throws DatabaseException
+ */
+ public Resource getGraphBundleResource(String id, int major) throws DatabaseException {
+ ReadGraph g = Transaction.readGraph();
+ Layer0 L0 = Layer0.getInstance(g);
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+
+ for (Resource r : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
+ if ( !g.isInstanceOf(r, DatabaseManagement.GraphBundle) ) continue;
+ String vid = g.getRelatedValue(r, DatabaseManagement.HasVersionedId);
+
+ Matcher m = GraphBundle.VERSIONED_ID_PATTERN.matcher(vid);
+ if (!m.matches()) continue;
+
+ String rid = m.group(1);
+ int rmajor = Integer.valueOf( m.group(2) );
+ if (rid.equals(id) && rmajor==major) return r;
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a GraphBundle entry into the database and attach to
+ * InstalledTransferableGraphs-library.
+ *
+ * @param entry
+ * @param resourceArray
+ * @return Resource
+ * @throws DatabaseException
+ */
+ Resource createGraphBundle(GraphBundle entry) throws DatabaseException {
+ WriteGraph g = Transaction.writeGraph();
+ Layer0 L0 = Layer0.getInstance(g);
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+
+ Resource r = g.newResource();
+ g.claim(r, L0.InstanceOf, DatabaseManagement.GraphBundle);
+ g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);
+ g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
+ g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
+ g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);
+ g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);
+ g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, r);
+ return r;
+
+ }
+
+ public Resource createGraphBundle(WriteOnlyGraph g, GraphBundle entry) throws DatabaseException {
+
+ Layer0 L0 = g.getService(Layer0.class);
+ DatabaseManagementResource DatabaseManagement = g.getService(DatabaseManagementResource.class);
+
+ Resource r = g.newResource();
+ g.claim(r, L0.InstanceOf, null, DatabaseManagement.GraphBundle);
+ g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);
+ g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
+ g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
+ g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);
+ g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);
+ g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, L0.PartOf, r);
+ return r;
+
+ }
+
+ /**
+ * Set TransferableGraph info.
+ *
+ * @param entry
+ * @param resourceArray
+ * @return new or existing feature resource
+ * @throws DatabaseException
+ * @throws AssumptionException thrown if bundle exists but is not a GraphBundle
+ */
+ public Resource setGraphBundleEntry(GraphBundle entry) throws DatabaseException {
+ Resource r = getGraphBundleResource(entry.getId(), entry.getMajor());
+
+ // Create a new resource
+ if (r==null) {
+ r = createGraphBundle(entry);
+ return r;
+ }
+
+ // Update values of an existing resource
+ {
+ WriteGraph g = Transaction.writeGraph();
+ Layer0 L0 = Layer0.getInstance(g);
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
+ g.claimLiteral(r, L0.HasName, entry.getName(), Bindings.STRING);
+ g.claimLiteral(r, DatabaseManagement.HasVersionedId, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
+ g.claimLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
+ g.claimLiteral(r, DatabaseManagement.HasHashCode, entry.hashcode, Bindings.INTEGER);
+ g.claimLiteral(r, DatabaseManagement.HasInstallInfo, entry.getResourceArray(), Bindings.LONG_ARRAY);
+ return r;
+ }
+ }
+
+}
+