/******************************************************************************* * 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; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.Queries; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.adapter.impl.EntityRemover; import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.layer0.Layer0; import org.simantics.project.features.IProjectFeature; import org.simantics.project.features.registry.GroupReference; import org.simantics.project.internal.ProjectPolicy; import org.simantics.project.internal.SafeName; import org.simantics.project.ontology.ProjectResource; /** * Utilities for project life-cycle management and configuration in a Simantics * graph database. * * @author Tuukka Lehtonen */ public class Projects { /** * @param processor * @param project * @return * @throws DatabaseException */ public static String getName(RequestProcessor processor, IProject project) throws DatabaseException { return processor.syncRequest(new SafeName(project.get())); } /** * @param graph * @param name * @return * @throws DatabaseException */ public static Resource createProject(WriteGraph graph, String name) throws DatabaseException { Resource root = graph.getResource("http://Projects"); Layer0 L0 = Layer0.getInstance(graph); ProjectResource PROJ = ProjectResource.getInstance(graph); Resource project = graph.newResource(); graph.claim(project, L0.InstanceOf, null, PROJ.Project); graph.claim(project, L0.PartOf, root); graph.claimLiteral(project, L0.HasName, name); return project; } /** * Creates a new project into the database with the specified name and * specified features. * * @param graph writable graph for creating the project * @param name name of the new project * @param features the features to attach to the new project * @return the resource of the new project * @throws DatabaseException */ public static Resource createProject(WriteGraph graph, String name, Collection features) throws DatabaseException { // Create the new project instance. Resource project = createProject(graph, name); setProjectInstalledGroups(graph, project, features); return project; } /** * @param graph * @param project * @return map of versionid to feature spec resource * @throws DatabaseException */ public static Map getInstalledFeatures(ReadGraph graph, Resource project) throws DatabaseException { ProjectResource PROJ = ProjectResource.getInstance(graph); if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("Looking for installed groups in project '" + NameUtils.getSafeName(graph, project)+ "'"); Map result = new HashMap(); // Remove previous project feature references for (Resource featureSpec : graph.getObjects(project, PROJ.HasFeature)) { Resource group = graph.getSingleObject(featureSpec, PROJ.HasGroupId); String groupId = graph.getPossibleValue(group, Bindings.STRING); // Re-use existing HasFeature definitions if possible. if (groupId == null) continue; if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("\t+ found existing feature group definition '" + NameUtils.getSafeName(graph, group) + "'"); result.put(groupId, featureSpec); } return result; } /** * @param graph write transaction handle * @param project the project to modify * @param features the features * @return * @throws DatabaseException */ public static Resource setProjectInstalledGroups(WriteGraph graph, Resource project, Collection groups) throws DatabaseException { if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("Setting installed groups for project '" + NameUtils.getSafeName(graph, project) + "' to " + groups); Set groupStringsToAdd = new HashSet(); for (GroupReference ref : groups) groupStringsToAdd.add(ref.toString()); Map existing = getInstalledFeatures(graph, project); Set specsToRemove = new HashSet(); for (Map.Entry entry : existing.entrySet()) { // Re-use existing HasFeature definitions if possible. if (groupStringsToAdd.remove(entry.getKey())) { if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("\t= reusing existing definition: " + entry.getKey()); continue; } if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("\t- marking for removal: " + entry.getKey()); specsToRemove.add(entry.getValue()); } for (Resource groupToRemove : specsToRemove) { uninstallGroup(graph, project, groupToRemove); } // Install the specified features to the project. for (String groupString : groupStringsToAdd) { installGroup(graph, project, groupString); } return project; } /** * @param graph write transaction handle * @param project the project to install the group id to * @param groupId the group id to install * @return the new group resource * @throws DatabaseException */ public static Resource installGroup(WriteGraph graph, Resource project, String groupId) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); ProjectResource PROJ = ProjectResource.getInstance(graph); if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("+ Installing group '" + groupId+ "' to project '" + NameUtils.getSafeName(graph, project) + "'"); Resource groupIdRes = graph.newResource(); graph.claim(groupIdRes, L0.InstanceOf, null, L0.String); graph.claimValue(groupIdRes, groupId); Resource isRequiredRes = graph.newResource(); graph.claim(isRequiredRes, L0.InstanceOf, null, L0.Boolean); graph.claimValue(isRequiredRes, true); Resource featureSpec = graph.newResource(); graph.claim(featureSpec, L0.InstanceOf, null, PROJ.FeatureSpec); graph.claim(project, PROJ.HasFeature, featureSpec); graph.claim(featureSpec, PROJ.HasGroupId, groupIdRes); graph.claim(featureSpec, PROJ.IsRequired, isRequiredRes); return groupIdRes; } /** * @param graph write transaction handle * @param project the project to uninstall the group id from * @param groupId the group id to uninstall * @return true if successfully uninstalled, false * if group id not found * @throws DatabaseException */ public static boolean uninstallGroup(WriteGraph graph, Resource project, String groupId) throws DatabaseException { ProjectResource PROJ = ProjectResource.getInstance(graph); if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("- Uninstalling group '" + groupId+ "' from project '" + NameUtils.getSafeName(graph, project) + "'"); for (Resource featureSpec : graph.getObjects(project, PROJ.HasFeature)) { Resource group = graph.getSingleObject(featureSpec, PROJ.HasGroupId); String existingGroup = graph.getPossibleValue(group, Bindings.STRING); // Re-use existing HasFeature definitions if possible. if (groupId.equals(existingGroup)) { if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("\t - found it, removing"); graph.deny(featureSpec, PROJ.HasGroupId, group); EntityRemover.remove(graph, group, false); return true; } graph.deny(project, PROJ.HasFeature, featureSpec); EntityRemover.remove(graph, featureSpec, false); } return false; } /** * @param graph write transaction handle * @param project the project to uninstall the group id from * @param featureSpec the feature specification to uninstall * @return true if successfully uninstalled, false * if group id not found * @throws DatabaseException */ public static boolean uninstallGroup(WriteGraph graph, Resource project, Resource featureSpec) throws DatabaseException { ProjectResource PROJ = ProjectResource.getInstance(graph); if (ProjectPolicy.TRACE_PROJECT_MANAGEMENT) System.out.println("- Uninstalling group '" + NameUtils.getSafeName(graph, featureSpec) + "' from project '" + NameUtils.getSafeName(graph, project) + "'"); Resource groupId = graph.getPossibleObject(featureSpec, PROJ.HasGroupId); if (groupId!=null) { graph.deny(featureSpec, PROJ.HasGroupId, groupId); EntityRemover.remove(graph, groupId, false); return true; } if (graph.hasStatement(project, PROJ.HasFeature, featureSpec)) { graph.deny(project, PROJ.HasFeature, featureSpec); EntityRemover.remove(graph, featureSpec, false); return true; } return false; } /** * Tries to load the specified project from a database. * *

* After this method completes, the project knows all its project features * (see {@link IProjectFeature}). The list of features should be available * through {@link IProject#getFeatures()}. *

* * @param graph readable graph for loading the project * @param project the project resource to load * @param activate true to invoke onActivated for * all {@link IProjectLifecycle}'s of this project. * @return the loaded project. */ public static IProject loadProject(RequestProcessor processor, Resource project) throws DatabaseException { IProject p = processor.syncRequest( Queries.adapt(project, IProject.class, false, true) ); return p; } /** * Destroys the specified project from the database. * * @param g writable graph for deleting the project * @param project the project to destroy * @throws DatabaseException */ public static void deleteProject(WriteGraph g, Resource project) throws DatabaseException { // NOTE: this will throw ServiceException if adapters are not initialized! RemoverUtil.remove(g, project); } }