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