]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.project/src/org/simantics/project/Projects.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.project / src / org / simantics / project / Projects.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.project;
13
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.simantics.databoard.Bindings;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.RequestProcessor;
23 import org.simantics.db.Resource;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.request.Queries;
26 import org.simantics.db.common.utils.NameUtils;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.layer0.adapter.impl.EntityRemover;
29 import org.simantics.db.layer0.util.RemoverUtil;
30 import org.simantics.layer0.Layer0;
31 import org.simantics.project.features.IProjectFeature;
32 import org.simantics.project.features.registry.GroupReference;
33 import org.simantics.project.internal.ProjectPolicy;
34 import org.simantics.project.internal.SafeName;
35 import org.simantics.project.ontology.ProjectResource;
36
37 /**
38  * Utilities for project life-cycle management and configuration in a Simantics
39  * graph database.
40  * 
41  * @author Tuukka Lehtonen
42  */
43 public class Projects {
44
45     /**
46      * @param processor
47      * @param project
48      * @return
49      * @throws DatabaseException
50      */
51     public static String getName(RequestProcessor processor, IProject project) throws DatabaseException {
52         return processor.syncRequest(new SafeName(project.get()));
53     }
54
55     /**
56      * @param graph
57      * @param name
58      * @return
59      * @throws DatabaseException
60      */
61     public static Resource createProject(WriteGraph graph, String name) throws DatabaseException {
62         Resource root = graph.getResource("http://Projects");
63
64         Layer0 L0 = Layer0.getInstance(graph);
65         ProjectResource PROJ = ProjectResource.getInstance(graph);
66
67         Resource project = graph.newResource();
68         graph.claim(project, L0.InstanceOf, null, PROJ.Project);
69         graph.claim(project, L0.PartOf, root);
70         graph.claimLiteral(project, L0.HasName, name);
71
72         return project;
73     }
74
75     /**
76      * Creates a new project into the database with the specified name and
77      * specified features.
78      * 
79      * @param graph writable graph for creating the project
80      * @param name name of the new project
81      * @param features the features to attach to the new project
82      * @return the resource of the new project
83      * @throws DatabaseException
84      */
85     public static Resource createProject(WriteGraph graph, String name, Collection<GroupReference> features) throws DatabaseException {
86         // Create the new project instance.
87         Resource project = createProject(graph, name);
88         setProjectInstalledGroups(graph, project, features);
89         return project;
90     }
91
92     /**
93      * @param graph
94      * @param project
95      * @return map of versionid to feature spec resource
96      * @throws DatabaseException
97      */
98     public static Map<String, Resource> getInstalledFeatures(ReadGraph graph, Resource project) throws DatabaseException {
99         ProjectResource PROJ = ProjectResource.getInstance(graph);
100
101         if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
102             System.out.println("Looking for installed groups in project '" + NameUtils.getSafeName(graph, project)+ "'");
103
104         Map<String, Resource> result = new HashMap<String, Resource>();
105         // Remove previous project feature references
106         for (Resource featureSpec : graph.getObjects(project, PROJ.HasFeature)) {
107                 Resource group = graph.getSingleObject(featureSpec, PROJ.HasGroupId);
108             String groupId = graph.getPossibleValue(group, Bindings.STRING);
109             // Re-use existing HasFeature definitions if possible.
110             if (groupId == null) continue;
111             if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
112                 System.out.println("\t+ found existing feature group definition '" + NameUtils.getSafeName(graph, group) + "'");
113             result.put(groupId, featureSpec);            
114         }
115         return result;
116     }
117
118     /**
119      * @param graph write transaction handle
120      * @param project the project to modify
121      * @param features the features
122      * @return
123      * @throws DatabaseException
124      */
125     public static Resource setProjectInstalledGroups(WriteGraph graph, Resource project, Collection<GroupReference> groups) throws DatabaseException {
126         if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
127             System.out.println("Setting installed groups for project '" + NameUtils.getSafeName(graph, project) + "' to " + groups);
128
129         Set<String> groupStringsToAdd = new HashSet<String>();
130         for (GroupReference ref : groups)
131             groupStringsToAdd.add(ref.toString());
132
133         Map<String, Resource> existing = getInstalledFeatures(graph, project);
134         Set<Resource> specsToRemove = new HashSet<Resource>();
135
136         for (Map.Entry<String, Resource> entry : existing.entrySet()) {
137             // Re-use existing HasFeature definitions if possible.
138             if (groupStringsToAdd.remove(entry.getKey())) {
139                 if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
140                     System.out.println("\t= reusing existing definition: " + entry.getKey());
141                 continue;
142             }
143
144             if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
145                 System.out.println("\t- marking for removal: " + entry.getKey());
146             specsToRemove.add(entry.getValue());
147         }
148
149         for (Resource groupToRemove : specsToRemove) {
150             uninstallGroup(graph, project, groupToRemove);
151         }
152
153         // Install the specified features to the project.
154         for (String groupString : groupStringsToAdd) {
155             installGroup(graph, project, groupString);
156         }
157
158         return project;
159     }
160
161     /**
162      * @param graph write transaction handle
163      * @param project the project to install the group id to
164      * @param groupId the group id to install
165      * @return the new group resource
166      * @throws DatabaseException
167      */
168     public static Resource installGroup(WriteGraph graph, Resource project, String groupId) throws DatabaseException {
169         Layer0 L0 = Layer0.getInstance(graph);
170         ProjectResource PROJ = ProjectResource.getInstance(graph);
171
172         if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
173             System.out.println("+ Installing group '" + groupId+ "' to project '" + NameUtils.getSafeName(graph, project) + "'");
174
175         Resource groupIdRes = graph.newResource();
176         graph.claim(groupIdRes, L0.InstanceOf, null, L0.String);
177         graph.claimValue(groupIdRes, groupId);
178
179         Resource isRequiredRes = graph.newResource();
180         graph.claim(isRequiredRes, L0.InstanceOf, null, L0.Boolean);
181         graph.claimValue(isRequiredRes, true);
182
183         Resource featureSpec = graph.newResource();
184         graph.claim(featureSpec, L0.InstanceOf, null, PROJ.FeatureSpec);
185         graph.claim(project, PROJ.HasFeature, featureSpec);
186         graph.claim(featureSpec, PROJ.HasGroupId, groupIdRes);
187         graph.claim(featureSpec, PROJ.IsRequired, isRequiredRes);
188
189         return groupIdRes;
190     }
191
192     /**
193      * @param graph write transaction handle
194      * @param project the project to uninstall the group id from
195      * @param groupId the group id to uninstall
196      * @return <code>true</code> if successfully uninstalled, <code>false</code>
197      *         if group id not found
198      * @throws DatabaseException
199      */
200     public static boolean uninstallGroup(WriteGraph graph, Resource project, String groupId) throws DatabaseException {
201         ProjectResource PROJ = ProjectResource.getInstance(graph);
202
203         if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
204             System.out.println("- Uninstalling group '" + groupId+ "' from project '" + NameUtils.getSafeName(graph, project) + "'");
205
206         for (Resource featureSpec : graph.getObjects(project, PROJ.HasFeature)) {
207                 Resource group = graph.getSingleObject(featureSpec, PROJ.HasGroupId); 
208                 String existingGroup = graph.getPossibleValue(group, Bindings.STRING);
209             // Re-use existing HasFeature definitions if possible.
210             if (groupId.equals(existingGroup)) {
211                 if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
212                     System.out.println("\t - found it, removing");
213                 graph.deny(featureSpec, PROJ.HasGroupId, group);
214                 EntityRemover.remove(graph, group, false);
215                 return true;
216             }
217             graph.deny(project, PROJ.HasFeature, featureSpec);
218             EntityRemover.remove(graph, featureSpec, false);
219         }
220
221         return false;
222     }
223
224     /**
225      * @param graph write transaction handle
226      * @param project the project to uninstall the group id from
227      * @param featureSpec the feature specification to uninstall
228      * @return <code>true</code> if successfully uninstalled, <code>false</code>
229      *         if group id not found
230      * @throws DatabaseException
231      */
232     public static boolean uninstallGroup(WriteGraph graph, Resource project, Resource featureSpec) throws DatabaseException {
233         ProjectResource PROJ = ProjectResource.getInstance(graph);
234
235         if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT)
236             System.out.println("- Uninstalling group '" + NameUtils.getSafeName(graph, featureSpec) + "' from project '" + NameUtils.getSafeName(graph, project) + "'");
237
238         Resource groupId = graph.getPossibleObject(featureSpec, PROJ.HasGroupId);
239         if (groupId!=null) {
240             graph.deny(featureSpec, PROJ.HasGroupId, groupId);
241             EntityRemover.remove(graph, groupId, false);
242             return true;
243         }
244         
245         if (graph.hasStatement(project, PROJ.HasFeature, featureSpec)) {
246             graph.deny(project, PROJ.HasFeature, featureSpec);
247             EntityRemover.remove(graph, featureSpec, false);
248             return true;
249         }
250         
251         return false;
252     }
253
254     /**
255      * Tries to load the specified project from a database.
256      * 
257      * <p>
258      * After this method completes, the project knows all its project features
259      * (see {@link IProjectFeature}). The list of features should be available
260      * through {@link IProject#getFeatures()}.
261      * </p>
262      * 
263      * @param graph readable graph for loading the project
264      * @param project the project resource to load
265      * @param activate <code>true</code> to invoke <code>onActivated</code> for
266      *        all {@link IProjectLifecycle}'s of this project.
267      * @return the loaded project.
268      */
269     public static IProject loadProject(RequestProcessor processor, Resource project) throws DatabaseException {
270         IProject p = processor.syncRequest( Queries.adapt(project, IProject.class, false, true) );
271         return p;
272     }
273
274     /**
275      * Destroys the specified project from the database.
276      * 
277      * @param g writable graph for deleting the project
278      * @param project the project to destroy
279      * @throws DatabaseException
280      */
281     public static void deleteProject(WriteGraph g, Resource project) throws DatabaseException {
282         // NOTE: this will throw ServiceException if adapters are not initialized!
283         RemoverUtil.remove(g, project);
284     }
285
286 }