--- /dev/null
+package org.simantics.document.linking.utils;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.UUID;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ObjectsWithType;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Instances;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.document.DocumentResource;\r
+import org.simantics.document.linking.ontology.DocumentLink;\r
+import org.simantics.document.linking.report.evaluator.PredefinedVariables;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.simulation.ontology.SimulationResource;\r
+\r
+/**\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class SourceLinkUtil {\r
+ \r
+ /**\r
+ * Creates a document link\r
+ * @param graph\r
+ * @param instance Object, where the link is attached\r
+ * @param relation Property relation (functional) or null.\r
+ * @param document\r
+ * @return\r
+ * @throws DatabaseException\r
+ */\r
+ public static Resource createDocumentLink(WriteGraph graph, Resource instance, Resource relation, Resource document) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ \r
+ Resource link = null;\r
+ DependencyCheckResult result = checkDependecies(graph, document, instance);\r
+ if (result == DependencyCheckResult.NoLocationModel)\r
+ throw new DatabaseException("Location of document link is not part of a model.");\r
+ if (result == DependencyCheckResult.DifferentModel) {\r
+ throw new DatabaseException("Location of document link and document are in different models, document link cannot be created.");\r
+ }\r
+ if (result == DependencyCheckResult.NoReferenceModel) {\r
+ //referred document and location are not in the same model, create an URI reference.\r
+ String uri = graph.getPossibleURI(document);\r
+ if (uri != null) {\r
+ if (relation != null && graph.isInstanceOf(relation, l0.FunctionalRelation)) {\r
+ link = SourceLinkUtil.createFunctionalSource(graph, uri, instance, relation);\r
+ } else {\r
+ link = SourceLinkUtil.createInstanceSource(graph, uri, instance);\r
+ }\r
+ }\r
+ }\r
+ if (link == null) {\r
+ if (relation != null && graph.isInstanceOf(relation, l0.FunctionalRelation)) {\r
+ link = SourceLinkUtil.createFunctionalSource(graph, document, instance, relation);\r
+ } else {\r
+ link = SourceLinkUtil.createInstanceSource(graph, document, instance);\r
+ }\r
+ }\r
+ \r
+ return link;\r
+ }\r
+ \r
+ public static Resource createDocumentLink(WriteGraph graph, Resource instance, Resource document) throws DatabaseException {\r
+ return createDocumentLink(graph, instance, null, document);\r
+ }\r
+ \r
+ public static Resource createInstanceSource(WriteGraph graph, Resource reference, Resource location) throws DatabaseException {\r
+ return createInstanceSource(graph, reference, location, "");\r
+ }\r
+\r
+ public static Resource createInstanceSource(WriteGraph graph, Resource reference, Resource location, String comment) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ \r
+ \r
+ \r
+ // prevent duplicate references \r
+ Collection<Resource> sources = graph.syncRequest(new ObjectsWithType(location, sl.hasFunctionalSource, sl.InstanceSource));\r
+ for (Resource source : sources) {\r
+ if (reference.equals(graph.getPossibleObject(source, sl.hasSourceReference)))\r
+ return source;\r
+ }\r
+ \r
+ if (!ensureDependencies(graph, reference, location))\r
+ return null;\r
+ \r
+ Resource source = graph.newResource();\r
+ graph.claim(source, l0.InstanceOf, sl.InstanceSource);\r
+ graph.claim(source, sl.hasSourceReference, reference);\r
+ graph.claimLiteral(source, sl.hasSourceComment, comment, Bindings.STRING);\r
+ graph.claim(location, sl.hasInstanceSource, source);\r
+ // search / indexing requires this\r
+ graph.claim(location, l0.ConsistsOf, source);\r
+ graph.claimLiteral(source, l0.HasName,UUID.randomUUID().toString(), Bindings.STRING);\r
+ return source;\r
+ }\r
+ \r
+ public static Resource createInstanceSource(WriteGraph graph, String reference, Resource location) throws DatabaseException {\r
+ return createInstanceSource(graph, reference, location, "");\r
+ }\r
+\r
+ public static Resource createInstanceSource(WriteGraph graph, String reference, Resource location, String comment) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ \r
+ \r
+ \r
+ // prevent duplicate references \r
+ Collection<Resource> sources = graph.syncRequest(new ObjectsWithType(location, sl.hasFunctionalSource, sl.InstanceSource));\r
+ for (Resource source : sources) {\r
+ if (reference.equals(graph.getPossibleRelatedValue(source, sl.hasSourceReferenceURI, Bindings.STRING)))\r
+ return source;\r
+ }\r
+ \r
+ if (!ensureDependencies(graph, null, location))\r
+ return null;\r
+ \r
+ Resource source = graph.newResource();\r
+ graph.claim(source, l0.InstanceOf, sl.InstanceSource);\r
+ graph.claimLiteral(source, sl.hasSourceReferenceURI, reference, Bindings.STRING);\r
+ graph.claimLiteral(source, sl.hasSourceComment, comment, Bindings.STRING);\r
+ graph.claim(location, sl.hasInstanceSource, source);\r
+ // search / indexing requires this\r
+ graph.claim(location, l0.ConsistsOf, source);\r
+ graph.claimLiteral(source, l0.HasName,UUID.randomUUID().toString(), Bindings.STRING);\r
+ return source;\r
+ }\r
+ \r
+ public static Resource createFunctionalSource(WriteGraph graph, Resource reference, Resource location, Resource relation) throws DatabaseException {\r
+ return createFunctionalSource(graph, reference, location, relation, "");\r
+ }\r
+\r
+ \r
+ public static Resource createFunctionalSource(WriteGraph graph, Resource reference, Resource location, Resource relation, String comment) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ \r
+ \r
+ \r
+ // prevent duplicate references\r
+ Collection<Resource> sources = graph.syncRequest(new ObjectsWithType(location, sl.hasFunctionalSource, sl.FunctionalSource));\r
+ for (Resource source : sources) {\r
+ if (relation.equals(graph.getPossibleObject(source, sl.consernsRelation)) && \r
+ reference.equals(graph.getPossibleObject(source, sl.hasSourceReference)))\r
+ return null;\r
+ }\r
+ \r
+ if (!ensureDependencies(graph, reference, location))\r
+ return null;\r
+ \r
+ Resource source = graph.newResource();\r
+ graph.claim(source, l0.InstanceOf, sl.FunctionalSource);\r
+ graph.claim(source, sl.hasSourceReference, reference);\r
+ graph.claimLiteral(source, sl.hasSourceComment, comment, Bindings.STRING);\r
+ graph.claim(source, sl.consernsRelation, relation);\r
+ \r
+ graph.claim(location, sl.hasFunctionalSource, source);\r
+ // search / indexing requires this\r
+ graph.claim(location, l0.ConsistsOf, source);\r
+ graph.claimLiteral(source, l0.HasName,UUID.randomUUID().toString(), Bindings.STRING);\r
+ return source;\r
+ }\r
+ \r
+ public static Resource createFunctionalSource(WriteGraph graph, String reference, Resource location, Resource relation) throws DatabaseException {\r
+ return createFunctionalSource(graph, reference, location, relation, "");\r
+ }\r
+\r
+ \r
+ public static Resource createFunctionalSource(WriteGraph graph, String reference, Resource location, Resource relation, String comment) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ \r
+ \r
+ \r
+ // prevent duplicate references\r
+ Collection<Resource> sources = graph.syncRequest(new ObjectsWithType(location, sl.hasFunctionalSource, sl.FunctionalSource));\r
+ for (Resource source : sources) {\r
+ if (relation.equals(graph.getPossibleObject(source, sl.consernsRelation)) && \r
+ reference.equals(graph.getPossibleRelatedValue(source, sl.hasSourceReferenceURI, Bindings.STRING)))\r
+ return null;\r
+ }\r
+ \r
+ if (!ensureDependencies(graph, null, location))\r
+ return null;\r
+ \r
+ Resource source = graph.newResource();\r
+ graph.claim(source, l0.InstanceOf, sl.FunctionalSource);\r
+ graph.claimLiteral(source, sl.hasSourceReferenceURI, reference, Bindings.STRING);\r
+ graph.claimLiteral(source, sl.hasSourceComment, comment, Bindings.STRING);\r
+ graph.claim(source, sl.consernsRelation, relation);\r
+ \r
+ graph.claim(location, sl.hasFunctionalSource, source);\r
+ // search / indexing requires this\r
+ graph.claim(location, l0.ConsistsOf, source);\r
+ graph.claimLiteral(source, l0.HasName,UUID.randomUUID().toString(), Bindings.STRING);\r
+ return source;\r
+ }\r
+ \r
+ public static Resource getModel(ReadGraph graph, Resource location) throws DatabaseException {\r
+ SimulationResource sim = SimulationResource.getInstance(graph);\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ List<Resource> list = new ArrayList<Resource>();\r
+ list.add(l0.PartOf);\r
+ list.add(l0.IsDependencyOf);\r
+ list.add(l0.PropertyOf);\r
+ list.add(l0.IsOwnedBy);\r
+ \r
+ Resource r = location;\r
+ Resource model = null;\r
+ while (r != null) {\r
+ if (graph.isInstanceOf(r, sim.Model)) {\r
+ model = r;\r
+ break;\r
+ }\r
+ Resource r2 = null;\r
+ for (Resource rel : list) {\r
+ r2 = graph.getPossibleObject(r, rel);\r
+ if (r2 != null)\r
+ break;\r
+ }\r
+ r = r2;\r
+ }\r
+ \r
+ return model;\r
+ }\r
+ \r
+ /**\r
+ * Ensures that the model's ontology dependencies are correct, and the reference will not create dependency between two models.\r
+ * \r
+ * @param graph\r
+ * @param reference\r
+ * @param location\r
+ * @return true, if everything is correct. \r
+ * @throws DatabaseException\r
+ */\r
+ private static boolean ensureDependencies(WriteGraph graph, Resource reference, Resource location) throws DatabaseException {\r
+\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ Resource model = getModel(graph, location);\r
+\r
+ if (model == null)\r
+ return true;\r
+\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ Set<Resource> depencecies = new HashSet<Resource>();\r
+ depencecies.add(getOntology(graph, sl.Source));\r
+ if (reference != null) {\r
+ Resource refModel = getModel(graph, reference);\r
+ if (refModel != null && !refModel.equals(model))\r
+ return false;\r
+ for (Resource t : graph.getTypes(reference)) {\r
+ Resource o = getOntology(graph, t);\r
+ if (o != null)\r
+ depencecies.add(o);\r
+ }\r
+ }\r
+ \r
+ Collection<Resource> linkedTo = graph.getObjects(model, l0.IsLinkedTo);\r
+ for (Resource dep : depencecies) {\r
+ if (!linkedTo.contains(dep)) {\r
+ graph.claim(model, l0.IsLinkedTo, dep);\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ \r
+ private static enum DependencyCheckResult{NoLocationModel, NoReferenceModel, SameModel,DifferentModel};\r
+ \r
+ private static DependencyCheckResult checkDependecies(ReadGraph graph, Resource reference, Resource location) throws DatabaseException{\r
+ Resource model = getModel(graph, location);\r
+\r
+ if (model == null)\r
+ return DependencyCheckResult.NoLocationModel;\r
+ Resource refModel = getModel(graph, reference);\r
+ if (refModel != null) {\r
+ if (refModel.equals(model))\r
+ return DependencyCheckResult.SameModel;\r
+ return DependencyCheckResult.DifferentModel;\r
+ }\r
+ return DependencyCheckResult.NoReferenceModel;\r
+ }\r
+ \r
+ \r
+ private static Resource getOntology(ReadGraph graph, Resource type) throws DatabaseException{\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ Resource r = type;\r
+ while (r != null) {\r
+ if (graph.isInstanceOf(r, l0.Ontology))\r
+ return r;\r
+ r = graph.getPossibleObject(r, l0.PartOf);\r
+ }\r
+ \r
+ r = type;\r
+ while (r != null) {\r
+ if (graph.isInstanceOf(r, l0.Library))\r
+ return r;\r
+ r = graph.getPossibleObject(r, l0.PartOf);\r
+ } \r
+ return null;\r
+ }\r
+ \r
+ public static boolean isSource(ReadGraph graph, Resource source) throws DatabaseException{\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ return (graph.isInstanceOf(source, sl.Source));\r
+ }\r
+ \r
+ public static boolean isValidSource(ReadGraph graph, Resource source) throws DatabaseException{\r
+ Resource reference = getReferredDocument(graph, source);\r
+ return isValidReference(graph, reference);\r
+ }\r
+ \r
+ public static boolean isUpToDateSource(ReadGraph graph, Resource source) throws DatabaseException{\r
+ Resource reference = getReferredDocument(graph, source);\r
+ return isUpToDateReference(graph, reference);\r
+ }\r
+ \r
+ public static Resource getReferredDocument(ReadGraph graph, Resource source) throws DatabaseException {\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ Resource document = graph.getPossibleObject(source, sl.hasSourceReference);\r
+ if (document != null) {\r
+ return document;\r
+ }\r
+ String URI = graph.getPossibleRelatedValue(source, sl.hasSourceReferenceURI, Bindings.STRING);\r
+ if (URI != null)\r
+ return graph.getPossibleResource(URI);\r
+ return null;\r
+ }\r
+ \r
+ public static boolean isValidReference(ReadGraph graph, Resource reference) throws DatabaseException{\r
+ if (reference == null)\r
+ return false;\r
+ return graph.hasStatement(reference);\r
+ \r
+ }\r
+ \r
+ public static boolean isUpToDateReference(ReadGraph graph, Resource reference) throws DatabaseException{\r
+ if (reference == null)\r
+ return false;\r
+ DocumentResource doc = DocumentResource.getInstance(graph);\r
+ return !graph.hasStatement(reference,doc.HasNewerVersion);\r
+ \r
+ }\r
+ \r
+ public static void updateToLatest(WriteGraph graph, Resource source) throws DatabaseException {\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ DocumentResource doc = DocumentResource.getInstance(graph);\r
+ \r
+ if (!graph.isInstanceOf(source, sl.Source))\r
+ return;\r
+ Resource reference = getReferredDocument(graph, source);\r
+ Resource newRef = reference;\r
+ while (true) {\r
+ Resource r = graph.getPossibleObject(newRef, doc.HasNewerVersion);\r
+ if (r != null)\r
+ newRef = r;\r
+ else\r
+ break;\r
+ }\r
+ if (newRef.equals(reference))\r
+ return;\r
+ if (graph.hasStatement(source, sl.hasSourceReference)) {\r
+ graph.deny(source, sl.hasSourceReference,reference);\r
+ graph.claim(source, sl.hasSourceReference, newRef);\r
+ } else if (graph.hasStatement(source,sl.hasSourceReferenceURI)) {\r
+ graph.deny(source, sl.hasSourceReferenceURI);\r
+ graph.claimLiteral(source, sl.hasSourceReferenceURI, graph.getURI(newRef),Bindings.STRING);\r
+ }\r
+ }\r
+ \r
+ public static Collection<Resource> findAllSources(ReadGraph graph, Resource model, Resource resource) throws DatabaseException {\r
+ DocumentLink sl = DocumentLink.getInstance(graph);\r
+ Instances instancesQuery = graph.adapt(sl.Source, Instances.class);\r
+ Collection<Resource> found = instancesQuery.find(graph, model);\r
+ Collection<Resource> result = new ArrayList<Resource>();\r
+ for (Resource source : found) {\r
+ if (graph.hasStatement(source,sl.hasSourceReference,resource) || graph.hasStatement(source, sl.hasSourceReferenceURI))\r
+ result.add(source);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ public static String getValueString(Object value) {\r
+ if (value.getClass().isArray()) {\r
+ if (value instanceof double[]) {\r
+ return Arrays.toString((double[])value);\r
+ } else if (value instanceof float[]) {\r
+ return Arrays.toString((float[])value);\r
+ } else if (value instanceof int[]) {\r
+ return Arrays.toString((int[])value);\r
+ } else if (value instanceof boolean[]) {\r
+ return Arrays.toString((boolean[])value);\r
+ } else if (value instanceof byte[]) {\r
+ return Arrays.toString((byte[])value);\r
+ } else if (value instanceof String[]) {\r
+ return Arrays.toString((String[])value);\r
+ } else if (value instanceof Object[]) {\r
+ return Arrays.toString((Object[])value);\r
+ } else {\r
+ return "TODO: Array " + value.getClass().getSimpleName();\r
+ }\r
+ } else {\r
+ return value.toString();\r
+ }\r
+ }\r
+ \r
+ public static List<Resource> getPath(ReadGraph graph, Resource model, Resource obj) throws DatabaseException {\r
+ Layer0 l0 = Layer0.getInstance(graph);\r
+ List<Resource> path = new ArrayList<Resource>();\r
+ Resource r = obj;\r
+ while (r != null && !r.equals(model)) {\r
+ path.add(0, r);\r
+ r = graph.getPossibleObject(r, l0.PartOf);\r
+ }\r
+ return path;\r
+ }\r
+ \r
+ public static List<Resource> getDiagramPath(ReadGraph graph, Resource model, Resource obj) throws DatabaseException {\r
+ ModelingResources mod = ModelingResources.getInstance(graph);\r
+ List<Resource> path = getPath(graph, model, obj);\r
+ for (int i = path.size()-1; i >= 0; i--) {\r
+ if (graph.hasStatement(path.get(i),mod.CompositeToDiagram))\r
+ return path.subList(0, i+1);\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ public static String getCustomizedString(ReadGraph graph, Resource document, List<String> annotationContent) throws DatabaseException{\r
+ String label = "";\r
+ Variable doc = graph.adapt(document, Variable.class);\r
+ for (String path : annotationContent) {\r
+ if (path.startsWith("\"") && path.endsWith("\"")) {\r
+ label += path.substring(1,path.length()-1)+ " ";\r
+ } else {\r
+ Variable v = PredefinedVariables.getInstance().getVariable(graph, path, null, doc);\r
+ if (v != null) {\r
+ label += v.getValue(graph) + " ";\r
+ }\r
+ }\r
+ }\r
+ return label;\r
+ }\r
+}\r