+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.project.features;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.core.runtime.IConfigurationElement;\r
+import org.eclipse.core.runtime.IExecutableExtension;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.CommentMetadata;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.AssumptionException;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.service.VirtualGraphSupport;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.project.exception.ProjectException;\r
+import org.simantics.project.ontology.ProjectResource;\r
+import org.simantics.scl.reflection.OntologyVersions;\r
+\r
+/**\r
+ * A project feature for validating that a set of namespaces (URIs) are\r
+ * reachable in the database for which this feature is configured.\r
+ * \r
+ * The URIs are described as class arguments in the extension class spec (after\r
+ * ':' character).\r
+ * \r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class DependencyValidationFeature extends AbstractProjectFeature implements IExecutableExtension {\r
+\r
+ private String virtualGraphId;\r
+ private String[] uris = {};\r
+\r
+ public DependencyValidationFeature() {\r
+ }\r
+\r
+ public DependencyValidationFeature(String virtualGraphId, String[] uris) {\r
+ this.virtualGraphId = virtualGraphId;\r
+ this.uris = uris;\r
+ }\r
+\r
+ @Override\r
+ public void setInitializationData(IConfigurationElement config, String propertyName, Object data)\r
+ throws CoreException {\r
+ if (data instanceof String) {\r
+ // Expecting comma-separated list of URIs in the argument.\r
+ String[] uris = ((String) data).split(",");\r
+ if (uris.length > 0) {\r
+ for(int i=0;i<uris.length;i++) uris[i] = OntologyVersions.getInstance().currentVersion(uris[i]);\r
+ // Validate the input data to contain valid URIs\r
+ for (String uri : uris) {\r
+ try {\r
+ new URI(uri);\r
+ } catch (URISyntaxException e) {\r
+ throw new CoreException(new Status(IStatus.ERROR, config.getContributor().getName(), "extension configuration element executable extension attribute '" + propertyName + "' argument contains invalid URIs. See cause for details.", e));\r
+ }\r
+ }\r
+\r
+ this.uris = uris;\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void configure() throws ProjectException {\r
+ try {\r
+ Session s = getSession();\r
+ VirtualGraph vg = null;\r
+ if (virtualGraphId != null) {\r
+ VirtualGraphSupport support = s.getService(VirtualGraphSupport.class);\r
+ vg = support.getWorkspacePersistent(virtualGraphId);\r
+ }\r
+ getSession().syncRequest(new WriteRequest(vg) {\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ configure(graph);\r
+ graph.addMetadata(graph.getMetadata(CommentMetadata.class).add("Configured by Dependency Validation Feature."));\r
+ }\r
+ });\r
+ } catch (DatabaseException e) {\r
+ throw new ProjectException(e.getMessage(), e);\r
+ }\r
+ }\r
+\r
+ protected void configure(WriteGraph graph) throws DatabaseException {\r
+ Collection<String> nss = new ArrayList<String>();\r
+ Collection<String> notFound = new ArrayList<String>();\r
+\r
+ Resource project = getProject().get();\r
+ String projectName = NameUtils.getSafeName(graph, project);\r
+\r
+ ProjectResource PROJ = ProjectResource.getInstance(graph);\r
+\r
+ ArrayList<Resource> resourcesToLinkToProject = new ArrayList<Resource>();\r
+\r
+ for (String uri : uris) {\r
+ // This will fail if the extension-specified URI does not exist\r
+ Resource namespaceRequirement = null;\r
+ try {\r
+ namespaceRequirement = graph.getResource(uri);\r
+ resourcesToLinkToProject.add(namespaceRequirement);\r
+ } catch (ResourceNotFoundException e) {\r
+ notFound.add(uri);\r
+ continue;\r
+ }\r
+\r
+ for (Resource nsp : graph.getObjects(namespaceRequirement, PROJ.RequiresNamespace)) {\r
+ String ns = graph.getValue(nsp);\r
+ nss.add(ns);\r
+ }\r
+\r
+ for (String ns : nss) {\r
+ try {\r
+ // This will fail if the namespace is not found.\r
+ graph.getResource(ns);\r
+ } catch (ResourceNotFoundException e) {\r
+ notFound.add(ns);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!notFound.isEmpty()) {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("Failed to locate the following namespaces required by project '");\r
+ sb.append(projectName);\r
+ sb.append("':\n");\r
+ for (String nf : notFound) {\r
+ sb.append("\t");\r
+ sb.append(nf);\r
+ sb.append("\n");\r
+ }\r
+ throw new AssumptionException(sb.toString());\r
+ }\r
+\r
+ // Ensure that the namespace requirements are linked to the project to\r
+ // make them discoverable by database queries.\r
+ linkTo(graph, project, resourcesToLinkToProject);\r
+ }\r
+\r
+ protected void linkTo(WriteGraph graph, Resource target, ArrayList<Resource> resourcesToLink) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ for (Resource resource : resourcesToLink) {\r
+ if (!graph.hasStatement(target, L0.IsLinkedTo, resource))\r
+ graph.claim(target, L0.IsLinkedTo, resource);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void deconfigure() throws ProjectException {\r
+ }\r
+\r
+}\r