1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.project.management;
14 import static org.simantics.db.common.utils.Transaction.writeGraph;
16 import java.util.Collection;
17 import java.util.HashSet;
19 import java.util.regex.Matcher;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.databoard.binding.Binding;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.WriteGraph;
26 import org.simantics.db.WriteOnlyGraph;
27 import org.simantics.db.common.utils.Transaction;
28 import org.simantics.db.exception.AssumptionException;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.util.Layer0Utils;
31 import org.simantics.db.request.Read;
32 import org.simantics.graph.db.IImportAdvisor;
33 import org.simantics.graph.db.ImportAdvisor;
34 import org.simantics.graph.db.TransferableGraphException;
35 import org.simantics.graph.db.TransferableGraphs;
36 import org.simantics.graph.diff.Diff;
37 import org.simantics.graph.diff.TransferableGraphDelta1;
38 import org.simantics.graph.representation.TransferableGraph1;
39 import org.simantics.layer0.DatabaseManagementResource;
40 import org.simantics.layer0.Layer0;
41 import org.simantics.project.ontology.ProjectResource;
44 * Database Management is a utility class for managing a database.
45 * The following management operations are supported:
49 * o Install & Update GraphBundles
50 * o Manage Projects (Install/Uninstall/Discover)
51 * o Manage Features (Install/Uninstall/Discover)
52 * o Manage GraphBundles
54 * This utility is based on Transaction class. The active graph must be
55 * set for the current thread.
57 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
59 public class DatabaseManagement {
61 public static final String PROJECTS_URI = "http://Projects";
62 Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
64 public DatabaseManagement() {
67 ///////////////////////////////////////////////////////////////////////////
68 /////////////// Project Managemenet //////////////////////
69 ///////////////////////////////////////////////////////////////////////////
71 * Create a new project. A new resource is created and linked to Projects
76 * @param features a list of features
77 * @return resource to the project
78 * @throws DatabaseException
80 public Resource createProject(String name, Collection<String> features) throws DatabaseException {
82 WriteGraph g = Transaction.writeGraph();
83 g.setClusterSet4NewResource(g.getRootLibrary());
85 Resource root = g.getResource(PROJECTS_URI);
86 Layer0 L0 = Layer0.getInstance(g);
87 ProjectResource PROJ = ProjectResource.getInstance(g);
89 Resource project = g.newResource();
90 g.claim(project, L0.InstanceOf, null, PROJ.Project);
91 g.claim(project, L0.PartOf, root);
92 g.claimLiteral(project, L0.HasName, name);
94 // Create library for temporary resources
95 if(Layer0Utils.getPossibleChild(g, root, "Temp") == null) {
96 Resource tempLibrary = g.newResource();
97 g.claim(tempLibrary, L0.InstanceOf, null, L0.Library);
98 g.claimLiteral(tempLibrary, L0.HasName, "Temp");
99 g.claim(root, L0.ConsistsOf, tempLibrary);
102 // Create library for trash
103 if(Layer0Utils.getPossibleChild(g, root, "TrashBin") == null) {
104 Resource trashLibrary = g.newResource();
105 g.claim(trashLibrary, L0.InstanceOf, null, L0.Library);
106 g.claimLiteral(trashLibrary, L0.HasName, "TrashBin");
107 g.claim(root, L0.ConsistsOf, trashLibrary);
110 // Create library for document sessions
111 if(Layer0Utils.getPossibleChild(g, root, "DocumentSessions") == null) {
112 Resource documentSessions = g.newResource();
113 g.claim(documentSessions, L0.InstanceOf, null, L0.Library);
114 g.claimLiteral(documentSessions, L0.HasName, "DocumentSessions");
115 g.claim(root, L0.ConsistsOf, documentSessions);
119 for (String feature_uri : features) {
120 Resource r = g.getResource(feature_uri);
121 g.claim(project, PROJ.HasFeature, r);
129 * Delete project. Project resource is unlinked it from the Projects library.
130 * The rest is left for garbage collection.
133 * @param projectResource
134 * @throws DatabaseException
136 public void deleteProject(Resource projectResource) throws DatabaseException {
137 WriteGraph g = Transaction.writeGraph();
138 Resource root = g.getResource(PROJECTS_URI);
139 Layer0 l0 = Layer0.getInstance(g);
140 g.denyStatement(projectResource, l0.PartOf, root);
145 * A query that reads all project URIs
148 * @return a query for graphs
149 * @throws DatabaseException
151 public final Read<Set<String>> ProjectURIQuery =
152 new Read<Set<String>>() {
154 public Set<String> perform(ReadGraph g) throws DatabaseException {
155 Layer0 b = Layer0.getInstance(g);
156 Resource root = g.getResource(PROJECTS_URI);
157 Set<String> result = new HashSet<String>();
158 for (Resource r : g.getObjects(root, b.ConsistsOf) )
159 result.add( g.getURI(r) );
165 * A query that reads all project resources
168 * @return a query for graphs
169 * @throws DatabaseException
171 public final Read<Set<Resource>> ProjectsQuery =
172 new Read<Set<Resource>>() {
174 public Set<Resource> perform(ReadGraph g) throws DatabaseException {
175 Layer0 b = Layer0.getInstance(g);
176 Resource root = g.getResource(PROJECTS_URI);
177 return new HashSet<Resource>( g.getObjects(root, b.ConsistsOf) );
183 * Get a list of all projects in the database.
187 * @throws DatabaseException
189 public Collection<Resource> getProjects() throws DatabaseException {
190 ReadGraph g = Transaction.readGraph();
191 Layer0 b = Layer0.getInstance(g);
192 Resource root = g.getResource(PROJECTS_URI);
193 return g.getObjects(root, b.ConsistsOf);
196 ///////////////////////////////////////////////////////////////////////////
197 /////////////// Feature Management //////////////////////
198 ///////////////////////////////////////////////////////////////////////////
201 // * Get all features in the database.
203 // * @param features a collection to be filled with features
205 // public void getFeatures(Collection<FeatureInfo> features) throws DatabaseException
207 // ReadGraph g = Transaction.readGraph();
208 // ProjectResource PROJ = ProjectResource.getInstance(g);
209 // Layer0 L0 = Layer0.getInstance(g);
211 // for (Resource r : g.getObjects(PROJ.PublishedProjectFeatures, L0.ConsistsOf)) {
212 // String URI = g.getURI(r);
213 // String name = g.getRelatedValue(r, L0.HasLabel);
214 // String vid_ = g.getRelatedValue(r, L0.HasName);
215 // VersionedId vid = (VersionedId) VersionedId.parse(vid_);
216 // FeatureInfo fi = new FeatureInfo(name, URI, vid);
217 // features.add( fi );
223 // * Get all features installed to a project
226 // * @param features a list of bundles
227 // * @throws DatabaseException
229 // public void getProjectFeatures(Resource project, Collection<FeatureInfo> features) throws DatabaseException {
230 // ReadGraph g = Transaction.readGraph();
231 // ProjectResource PROJ = ProjectResource.getInstance(g);
232 // Layer0 L0 = Layer0.getInstance(g);
234 // for (Resource r : g.getObjects(project, PROJ.HasFeature)) {
235 // String URI = g.getURI(r);
236 // String name = g.getRelatedValue(r, L0.HasLabel);
237 // String vid_ = g.getRelatedValue(r, L0.HasName);
238 // VersionedId vid = (VersionedId) VersionedId.parse(vid_);
239 // FeatureInfo fi = new FeatureInfo(name, URI, vid);
240 // features.add( fi );
245 // * Configure project to use a feature.
249 // * @param featureUri feature URI
250 // * @throws DatabaseException
252 // public void installFeature(Resource project, String featureUri)
253 // throws DatabaseException
255 // WriteGraph g = Transaction.writeGraph();
256 // Resource feature = g.getResource(featureUri);
257 // ProjectResource PROJ = ProjectResource.getInstance(g);
258 // g.claim(project, PROJ.HasFeature, feature);
262 // * Configure project not to use a feature.
266 // * @param featureuri feature URI
267 // * @throws DatabaseException
269 // public void uninstallFeature(Resource project, String featureUri)
270 // throws DatabaseException
272 // WriteGraph g = Transaction.writeGraph();
273 // Resource feature = g.getResource(featureUri);
274 // ProjectResource PROJ = ProjectResource.getInstance(g);
275 // g.denyStatement(project, PROJ.HasFeature, feature);
279 ///////////////////////////////////////////////////////////////////////////
280 /////////////// Transferable Graph Management //////////////////////
281 ///////////////////////////////////////////////////////////////////////////
284 * Install transferable graph into database and manage install info.
285 * If different but exact same version is already installed, the new
286 * graph is merged.<p>
288 * Resource array field of tg argument is updated.
290 * @param tg transferable graph
292 public void installGraphBundle(GraphBundle tg)
293 throws DatabaseException, TransferableGraphException
295 Resource oldResource = getGraphBundleResource(tg.getId(), tg.getMajor());
297 if (oldResource == null) {
298 IImportAdvisor advisor = new ImportAdvisor();
299 long[] resourceArray = TransferableGraphs.importGraph(writeGraph(), tg.getGraph(), advisor);
300 tg.setResourceArray(resourceArray);
301 setGraphBundleEntry(tg);
306 GraphBundle oldTG = getGraphBundle(oldResource);
307 TransferableGraphDelta1 delta = new Diff(oldTG.getGraph(), tg.getGraph()).diff();
308 long[] oldResourceArray = oldTG.getResourceArray();
309 long[] newResourceArray = TransferableGraphs.applyDelta(writeGraph(), oldResourceArray, delta);
310 tg.setResourceArray(newResourceArray);
312 setGraphBundleEntry(tg);
317 * A query that reads all graphs in the database
320 * @return a query for graphs
321 * @throws DatabaseException
323 public final Read<Set<GraphBundleRef>> GraphBundleRefQuery =
324 new Read<Set<GraphBundleRef>>() {
326 public Set<GraphBundleRef> perform(ReadGraph g) throws DatabaseException {
327 Object oldGraph = Transaction.setGraph(g);
329 return getGraphBundleReferences();
331 Transaction.setGraph(oldGraph);
338 * A query that reads all graphs in the database
341 * @return a query for graphs
342 * @throws DatabaseException
344 public final Read<Set<GraphBundle>> GraphBundleQuery =
345 new Read<Set<GraphBundle>>() {
347 public Set<GraphBundle> perform(ReadGraph g) throws DatabaseException {
348 Object oldGraph = Transaction.setGraph(g);
350 return getGraphBundles();
352 Transaction.setGraph(oldGraph);
357 public Set<GraphBundle> getGraphBundles()
358 throws DatabaseException {
359 ReadGraph g = Transaction.readGraph();
360 Set<GraphBundle> result = new HashSet<GraphBundle>();
362 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
363 Layer0 L0 = Layer0.getInstance(g);
365 for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
366 if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue;
367 String name = g.getPossibleRelatedValue(tg, L0.HasName);
368 String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);
369 Integer hash = g.getPossibleRelatedValue(tg, DatabaseManagement.HasHashCode);
370 //System.out.println("Found in Database: " + vid);
371 //TransferableGraph1 data = g.getRelatedValue(tg, DatabaseManagement.HasFile, tg_binding);
372 GraphBundle entry = new GraphBundle(name, null, vid);
374 entry.hashcode = hash;
375 long[] resourceArray = g.getPossibleRelatedValue(tg, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);
376 if (resourceArray!=null) entry.setResourceArray(resourceArray);
382 public Set<GraphBundleRef> getGraphBundleReferences()
383 throws DatabaseException {
384 ReadGraph g = Transaction.readGraph();
385 Set<GraphBundleRef> result = new HashSet<GraphBundleRef>();
387 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
388 Layer0 L0 = Layer0.getInstance(g);
390 for (Resource tg : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
391 if ( !g.isInstanceOf(tg, DatabaseManagement.GraphBundle) ) continue;
392 String vid = g.getPossibleRelatedValue(tg, DatabaseManagement.HasVersionedId);
393 result.add( GraphBundleRef.of( vid ) );
400 * Get TransferableGraph resource that is attached to InstalledTransferableGraphs.
402 * @param id id <symbolic_name>_<version>
403 * @return TG resource or <tt>null</tt>
404 * @throws DatabaseException
406 public GraphBundle getGraphBundle(Resource r) throws DatabaseException {
407 ReadGraph g = Transaction.readGraph();
408 Layer0 L0 = Layer0.getInstance(g);
409 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
411 String name = g.getPossibleRelatedValue(r, L0.HasName);
412 String vid = g.getPossibleRelatedValue(r, DatabaseManagement.HasVersionedId);
413 TransferableGraph1 data = g.getRelatedValue(r, DatabaseManagement.HasFile, tg_binding);
414 GraphBundle entry = new GraphBundle(name, data, vid);
415 long[] resourceArray = g.getPossibleRelatedValue(r, DatabaseManagement.HasInstallInfo, Bindings.LONG_ARRAY);
416 if (resourceArray!=null) entry.setResourceArray(resourceArray);
421 * Get TransferableGraph resource that is attached to InstalledTransferableGraphs.
423 * @param id id <symbolic_name>/<version>
424 * @param major major version
425 * @return resource or <tt>null</tt>
426 * @throws DatabaseException
428 public Resource getGraphBundleResource(String id, int major) throws DatabaseException {
429 ReadGraph g = Transaction.readGraph();
430 Layer0 L0 = Layer0.getInstance(g);
431 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
433 for (Resource r : g.getObjects(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf)) {
434 if ( !g.isInstanceOf(r, DatabaseManagement.GraphBundle) ) continue;
435 String vid = g.getRelatedValue(r, DatabaseManagement.HasVersionedId);
437 Matcher m = GraphBundle.VERSIONED_ID_PATTERN.matcher(vid);
438 if (!m.matches()) continue;
440 String rid = m.group(1);
441 int rmajor = Integer.valueOf( m.group(2) );
442 if (rid.equals(id) && rmajor==major) return r;
449 * Create a GraphBundle entry into the database and attach to
450 * InstalledTransferableGraphs-library.
453 * @param resourceArray
455 * @throws DatabaseException
457 Resource createGraphBundle(GraphBundle entry) throws DatabaseException {
458 WriteGraph g = Transaction.writeGraph();
459 Layer0 L0 = Layer0.getInstance(g);
460 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
462 Resource r = g.newResource();
463 g.claim(r, L0.InstanceOf, DatabaseManagement.GraphBundle);
464 g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);
465 g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
466 g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
467 g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);
468 g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);
469 g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, r);
474 public Resource createGraphBundle(WriteOnlyGraph g, GraphBundle entry) throws DatabaseException {
476 Layer0 L0 = g.getService(Layer0.class);
477 DatabaseManagementResource DatabaseManagement = g.getService(DatabaseManagementResource.class);
479 Resource r = g.newResource();
480 g.claim(r, L0.InstanceOf, null, DatabaseManagement.GraphBundle);
481 g.addLiteral(r, L0.HasName, L0.NameOf, L0.String, entry.getName(), Bindings.STRING);
482 g.addLiteral(r, DatabaseManagement.HasVersionedId, DatabaseManagement.HasVersionedId_Inverse, L0.String, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
483 g.addLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
484 g.addLiteral(r, DatabaseManagement.HasHashCode, DatabaseManagement.HasHashCode_Inverse, L0.Integer, entry.hashcode, Bindings.INTEGER);
485 g.addLiteral(r, DatabaseManagement.HasInstallInfo, DatabaseManagement.HasInstallInfo_Inverse, L0.LongArray, entry.getResourceArray(), Bindings.LONG_ARRAY);
486 g.claim(DatabaseManagement.InstalledGraphBundles, L0.ConsistsOf, L0.PartOf, r);
492 * Set TransferableGraph info.
495 * @param resourceArray
496 * @return new or existing feature resource
497 * @throws DatabaseException
498 * @throws AssumptionException thrown if bundle exists but is not a GraphBundle
500 public Resource setGraphBundleEntry(GraphBundle entry) throws DatabaseException {
501 Resource r = getGraphBundleResource(entry.getId(), entry.getMajor());
503 // Create a new resource
505 r = createGraphBundle(entry);
509 // Update values of an existing resource
511 WriteGraph g = Transaction.writeGraph();
512 Layer0 L0 = Layer0.getInstance(g);
513 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
514 g.claimLiteral(r, L0.HasName, entry.getName(), Bindings.STRING);
515 g.claimLiteral(r, DatabaseManagement.HasVersionedId, entry.getId()+"/"+entry.getMajor()+"."+entry.getMinor()+"."+entry.getService()+"."+entry.getQualifier(), Bindings.STRING);
516 g.claimLiteral(r, DatabaseManagement.HasFile, DatabaseManagement.HasFile_Inverse, L0.Graph, entry.graph, tg_binding);
517 g.claimLiteral(r, DatabaseManagement.HasHashCode, entry.hashcode, Bindings.INTEGER);
518 g.claimLiteral(r, DatabaseManagement.HasInstallInfo, entry.getResourceArray(), Bindings.LONG_ARRAY);