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