/******************************************************************************* * 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 */ 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 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> ProjectURIQuery = new Read>() { @Override public Set perform(ReadGraph g) throws DatabaseException { Layer0 b = Layer0.getInstance(g); Resource root = g.getResource(PROJECTS_URI); Set result = new HashSet(); 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> ProjectsQuery = new Read>() { @Override public Set perform(ReadGraph g) throws DatabaseException { Layer0 b = Layer0.getInstance(g); Resource root = g.getResource(PROJECTS_URI); return new HashSet( g.getObjects(root, b.ConsistsOf) ); } }; /** * Get a list of all projects in the database. * * @param g * @return * @throws DatabaseException */ public Collection 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 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 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.

* * 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> GraphBundleRefQuery = new Read>() { @Override public Set 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> GraphBundleQuery = new Read>() { @Override public Set perform(ReadGraph g) throws DatabaseException { Object oldGraph = Transaction.setGraph(g); try { return getGraphBundles(); } finally { Transaction.setGraph(oldGraph); } } }; public Set getGraphBundles() throws DatabaseException { ReadGraph g = Transaction.readGraph(); Set result = new HashSet(); 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 getGraphBundleReferences() throws DatabaseException { ReadGraph g = Transaction.readGraph(); Set result = new HashSet(); 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 _ * @return TG resource or null * @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 / * @param major major version * @return resource or null * @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; } } }