From: Antti Villberg Date: Wed, 21 Aug 2019 12:26:18 +0000 (+0300) Subject: Improvements to constraint-based issues X-Git-Tag: v1.43.0~136^2~100^2 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F37%2F3137%2F8;p=simantics%2Fplatform.git Improvements to constraint-based issues gitlab #355 Change-Id: Ia6ab17a6850e4ad1600e739063797a330077d5f6 --- diff --git a/bundles/org.simantics.issues.common/META-INF/MANIFEST.MF b/bundles/org.simantics.issues.common/META-INF/MANIFEST.MF index dce26de31..7fe964225 100644 --- a/bundles/org.simantics.issues.common/META-INF/MANIFEST.MF +++ b/bundles/org.simantics.issues.common/META-INF/MANIFEST.MF @@ -12,7 +12,9 @@ Require-Bundle: org.simantics.issues;bundle-version="1.1.0", org.simantics.db.services;bundle-version="0.6.2", org.simantics;bundle-version="1.0.0", org.simantics.issues.ui.ontology;bundle-version="1.0.0", - org.slf4j.api + org.slf4j.api, + org.simantics.scl.db;bundle-version="0.1.3", + org.simantics.scl.runtime Export-Package: org.simantics.issues.common, org.simantics.issues.common.preferences Bundle-Vendor: VTT Technical Research Centre of Finland diff --git a/bundles/org.simantics.issues.common/adapters.xml b/bundles/org.simantics.issues.common/adapters.xml index 5cf4730d2..905c8d4bd 100644 --- a/bundles/org.simantics.issues.common/adapters.xml +++ b/bundles/org.simantics.issues.common/adapters.xml @@ -18,6 +18,11 @@ class="org.simantics.issues.common.DependencyTrackerBatchIssueSource"> + + + diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllActiveIssues.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllActiveIssues.java index 727280185..006e779d4 100644 --- a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllActiveIssues.java +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllActiveIssues.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 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 @@ -8,11 +8,11 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Reorganization *******************************************************************************/ package org.simantics.issues.common; -import gnu.trove.set.hash.THashSet; - +import java.util.List; import java.util.Set; import org.simantics.db.ReadGraph; @@ -20,12 +20,13 @@ import org.simantics.db.Resource; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.adapter.Instances; -import org.simantics.issues.ontology.IssueResource; -import org.simantics.layer0.Layer0; import org.simantics.operation.Layer0X; +import org.simantics.scl.db.SCLFunctions; +import org.simantics.scl.runtime.tuple.Tuple0; import org.simantics.simulation.ontology.SimulationResource; +import gnu.trove.set.hash.THashSet; + /** * @author Antti Villberg */ @@ -37,20 +38,23 @@ public class AllActiveIssues extends ResourceRead> { @Override public Set perform(ReadGraph graph) throws DatabaseException { - Layer0 L0 = Layer0.getInstance(graph); + Layer0X L0X = Layer0X.getInstance(graph); - IssueResource ISSUE = IssueResource.getInstance(graph); SimulationResource SIMU = SimulationResource.getInstance(graph); - Set result = new THashSet(); - Instances indexedIssues = graph.getPossibleAdapter(ISSUE.Issue, Instances.class); + Set result = new THashSet<>(); + for (Resource model : graph.syncRequest(new ObjectsWithType(resource, L0X.Activates, SIMU.Model))) { - for (Resource issue : graph.syncRequest(new ObjectsWithType(model, L0.ConsistsOf, ISSUE.Issue))) { - result.add(issue); - } - if (indexedIssues != null) - result.addAll(indexedIssues.find(graph, model)); + result.addAll(graph.syncRequest(new AllModelIssues(model, false))); } + + List libraries = SCLFunctions.evaluateDB("Simantics/SharedOntologies", "getSharedOntologies", Tuple0.INSTANCE); + + for (Resource library : libraries) { + result.addAll(graph.syncRequest(new AllModelIssues(library, false))); + } + return result; + } } diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllVisibleIssues.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllVisibleIssues.java index 35ad02351..cc0006d9c 100644 --- a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllVisibleIssues.java +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/AllVisibleIssues.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 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 @@ -8,31 +8,26 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Reorganization *******************************************************************************/ package org.simantics.issues.common; -import gnu.trove.map.hash.TObjectByteHashMap; -import gnu.trove.set.hash.THashSet; - -import java.util.Collection; -import java.util.Collections; +import java.util.List; import java.util.Set; -import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.BinaryRead; 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.db.layer0.variable.Variables; -import org.simantics.issues.common.preferences.IssuePrefs; -import org.simantics.issues.ontology.IssueResource; -import org.simantics.layer0.Layer0; import org.simantics.operation.Layer0X; +import org.simantics.scl.db.SCLFunctions; +import org.simantics.scl.runtime.tuple.Tuple0; import org.simantics.simulation.ontology.SimulationResource; +import gnu.trove.set.hash.THashSet; + /** * @author Tuukka Lehtonen */ @@ -48,73 +43,22 @@ public class AllVisibleIssues extends BinaryRead perform(ReadGraph graph) throws DatabaseException { - Layer0 L0 = Layer0.getInstance(graph); + Layer0X L0X = Layer0X.getInstance(graph); - IssueResource ISSUE = IssueResource.getInstance(graph); SimulationResource SIMU = SimulationResource.getInstance(graph); - - Resource project = Simantics.getProjectResource(); - boolean showHidden = false; - boolean showNormal = true; - boolean showUser = true; - if (project != null) { - showHidden = IssuePrefs.showHiddenIssues(graph, project); - showNormal = IssuePrefs.showNormalIssues(graph, project); - showUser = IssuePrefs.showUserIssues(graph, project); - } - - Instances issueIndex = graph.getPossibleAdapter(ISSUE.Issue, Instances.class); - - // Cache for source activeness. - // 0 == not in cache, 1 == false, 2 == true - TObjectByteHashMap sourceActivenessCache = new TObjectByteHashMap(); - - Set result = new THashSet(1013); + Set result = new THashSet<>(); for (Resource model : graph.syncRequest(new ObjectsWithType(parameter, L0X.Activates, SIMU.Model))) { - Collection modelIssues = graph.syncRequest(new ObjectsWithType(model, L0.ConsistsOf, ISSUE.Issue)); - Collection indexedIssues = issueIndex != null ? issueIndex.find(graph, model) : Collections.emptyList(); - Collection issues = !indexedIssues.isEmpty() ? new THashSet(modelIssues.size() + indexedIssues.size()) : modelIssues; - if (!indexedIssues.isEmpty()) { - issues.addAll(modelIssues); - issues.addAll(indexedIssues); - } - - for (Resource issue : issues) { - // Filter out unwanted material - boolean resolved = graph.hasStatement(issue, ISSUE.Resolved); - if (parameter2 && resolved) - continue; - boolean hidden = graph.hasStatement(issue, ISSUE.Hidden); - boolean user = graph.hasStatement(issue, ISSUE.UserIssue); - boolean normal = !hidden && !user; - if (!showHidden && hidden) - continue; - if (!showUser && user) - continue; - if (!showNormal && normal) - continue; - - Resource source = graph.getPossibleObject(issue, ISSUE.IssueSource_Manages_Inverse); - if (source != null) { - byte cache = sourceActivenessCache.get(source); - boolean active = cache == 2 ? true : false; - if (cache == 0) { - active = Boolean.TRUE.equals(graph.getPossibleRelatedValue(source, ISSUE.IssueSource_active)); - sourceActivenessCache.put(source, active ? (byte) 2 : (byte) 1); - } - if (!active) - continue; - } + result.addAll(graph.syncRequest(new ModelVisibleIssues(model, false))); + } - Variable var = Variables.getPossibleVariable(graph, issue); - if (var != null) - result.add(var); - } + List libraries = SCLFunctions.evaluateGraph("Simantics/SharedOntologies", "getSharedOntologies", graph, Tuple0.INSTANCE); + for (Resource library : libraries) { + result.addAll(graph.syncRequest(new ModelVisibleIssues(library, false))); } - // System.out.println("AllActiveIssues returned " + result.size()); return result; + } } diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/BatchValidations.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/BatchValidations.java new file mode 100644 index 000000000..080056088 --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/BatchValidations.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * Semantum Oy - Reorganization + *******************************************************************************/ +package org.simantics.issues.common; + +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.simantics.Simantics; +import org.simantics.db.Issue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.Statement; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.issues.ontology.IssueResource; +import org.simantics.layer0.Layer0; + +import gnu.trove.set.hash.THashSet; + +public class BatchValidations { + + private static final boolean PERF = false; + + public static Map> validate(IProgressMonitor monitor, BatchIssueSource source, BatchIssueValidationContext context) throws DatabaseException { + Session session = Simantics.getSession(); + return session.syncRequest(new ComposedValidation(monitor, source, context)); + } + + /** + * @param monitor + * @param source + * @param issues + * @return + * @throws DatabaseException + */ + public static int store(final IProgressMonitor monitor, + final Resource source, final Map> issues) + throws DatabaseException { + return store(monitor, source, issues, Integer.MAX_VALUE); + } + + /** + * @param monitor + * @param source + * @param issues + * @param maxIssuesToWrite + * @return number of issues written (added) + * @throws DatabaseException + */ + public static int store(final IProgressMonitor monitor, + final Resource source, final Map> issues, + final int maxIssuesToWrite) throws DatabaseException { + + if (issues.isEmpty() || maxIssuesToWrite <= 0) + return 0; + + Session session = Simantics.getSession(); + VirtualGraphSupport support = session.getService(VirtualGraphSupport.class); + VirtualGraph vg = support.getWorkspacePersistent(IssueConstants.ISSUE_VG); + final int[] writtenIssues = { 0 }; + + session.syncRequest(new WriteRequest(vg) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + + for(Map.Entry> entry : issues.entrySet()) { + + if (monitor.isCanceled()) + return; + + Resource context = entry.getKey(); + + Set current = entry.getValue(); + Set existing = graph.sync(new BatchIssueDescriptions(source, context)); + + if(!existing.equals(current)) { + + Set added = new THashSet(current); + Set removed = new THashSet(existing); + added.removeAll(existing); + removed.removeAll(current); + + for(Issue add : added) { + add.write(graph, source); + // Stop if write limit is reached. + if (++writtenIssues[0] >= maxIssuesToWrite) + return; + } + for(Issue remove : removed) { + Resource issue = graph.sync(new IssueByList(source, remove)); + if (issue == null) + // FIXME: when can this happen and what should be done in this case? + continue; + graph.deny(issue, Layer0.getInstance(graph).PartOf); + graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue); + RemoverUtil.remove(graph, issue); + } + + } + + } + + } + }); + + return writtenIssues[0]; + + } + + /** + * @param map + * @return + */ + @SuppressWarnings("rawtypes") + private static int count(Map map) { + int result = 0; + for (Object obj : map.values()) { + if (obj instanceof Set) { + Set set = (Set) obj; + result += set.size(); + } + } + return result; + } + + /** + * Checks if the specified resourceToCheckForLinks is linked to + * anything else besides itself and excludeLinksTo. + * + *

+ * This is used to if an issue context is still valid. We consider any issue + * context that is not attached to something else besides its issue context to + * be an invalid issue. Assertions and L0.InstanceOf do not count as external + * links. + * + * @param graph database access handle + * @param resourceToCheckForLinks the resource to check for "external" links + * @param excludeLinksTo exclude links to this resource from evaluation + * @return true if there are links, false otherwise + * @throws DatabaseException + */ + public static boolean isLinkedToOtherThan(ReadGraph graph, Resource resourceToCheckForLinks, + Resource excludeLinksTo) + throws DatabaseException + { + Layer0 L0 = Layer0.getInstance(graph); + for (Statement stm : graph.getStatements(resourceToCheckForLinks, L0.IsWeaklyRelatedTo)) { + if (stm.isAsserted(resourceToCheckForLinks)) + continue; + if (stm.getPredicate().equals(L0.InstanceOf)) + continue; + Resource o = stm.getObject(); + if (o.equals(excludeLinksTo) || o.equals(resourceToCheckForLinks)) + continue; + + return true; + } + return false; + } + +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ConstraintIssueSource.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ConstraintIssueSource.java new file mode 100644 index 000000000..0b02c0e62 --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ConstraintIssueSource.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2019 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.issues.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.simantics.db.Issue; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.QueryMemoryWatcher; +import org.simantics.db.common.utils.Logger; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest.DomainOnlyProcessor; +import org.simantics.db.service.CollectionSupport; +import org.simantics.db.service.QueryControl; +import org.simantics.issues.ontology.IssueResource; +import org.simantics.layer0.Layer0; +import org.simantics.scl.db.SCLFunctions; +import org.simantics.scl.runtime.function.Function1; + +import gnu.trove.set.hash.THashSet; + +/** + * @author Antti Villberg + */ +public class ConstraintIssueSource implements BatchIssueSource { + + private final Resource resource; + + public ConstraintIssueSource(Resource resource) { + this.resource = resource; + } + + @Override + public Map> run(IProgressMonitor monitor, ReadGraph graph, BatchIssueValidationContext context) throws DatabaseException { + + Layer0 L0 = Layer0.getInstance(graph); + Set emptySet = Collections.emptySet(); + CollectionSupport cs = graph.getService(CollectionSupport.class); + Map> result = cs.createMap(Set.class); + monitor.setTaskName("Constraint analysis"); + + DomainOnlyProcessor domain = context.domain; + + int entityCount = domain.internals.size(); + + IssueResource ISSUE = IssueResource.getInstance(graph); + Resource type = graph.getSingleType(resource, ISSUE.IssueSource); + List>> validators = new ArrayList<>(); + for(Resource constraint : graph.getObjects(type, ISSUE.IssueSource_HasConstraint)) { + Function1> validator = graph.getRelatedValue2(constraint, L0.Constraint_Validator, constraint); + //Resource function = graph.getSingleObject(constraint, L0.Constraint_Validator); + validators.add(validator); + } + + QueryControl qc = graph.getService(QueryControl.class); + qc.flush(graph); + + // Allow this process to make 50k queries + QueryMemoryWatcher memory = new QueryMemoryWatcher(graph, 50000, 0.5, 300); + + SCLFunctions.runWithGraph(graph, () -> { + + int totalExaminedCount = 0; + int examinedCount = 1000; + + for(Resource r : domain.internals) { + + Set set = emptySet; + if (examinedCount >= 1000) { + monitor.subTask(contextProgressMessage(totalExaminedCount, entityCount)); + examinedCount = 0; + if(monitor.isCanceled()) return; + memory.maintain(); + } + for(Function1> validator : validators) { + try { + @SuppressWarnings("unchecked") + List issues = validator.apply(r);//(List)Functions.exec(graph, validator, graph, r); + if (issues != null && !issues.isEmpty()) { + if (set == emptySet) + set = new THashSet<>(); + set.addAll(issues); + } + } catch (Throwable t) { + Logger.defaultLogError(t); + } + } + ++totalExaminedCount; + ++examinedCount; + if(!set.isEmpty()) + result.put(r, set); + } + + }); + + return result; + + } + + private static String contextProgressMessage(int totalExaminedCount, int entityCount) { + StringBuilder sb = new StringBuilder(80) + .append("Validating resources").append(" ").append(100*totalExaminedCount / entityCount).append("% ready."); + return sb.toString(); + } + + @Override + public Resource getResource() { + return resource; + } + +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/Messages.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/Messages.java new file mode 100644 index 000000000..f68cf6204 --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/Messages.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2019 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.issues.common; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.simantics.issues.common.messages"; //$NON-NLS-1$ + public static String RunActiveValidations_MonitorPreparingResourcesForValidation; + public static String RunActiveValidations_ValidateModel; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ModelVisibleIssues.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ModelVisibleIssues.java new file mode 100644 index 000000000..28d3417e6 --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/ModelVisibleIssues.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2007, 2019 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 + * Semantum Oy - Reorganization + *******************************************************************************/ +package org.simantics.issues.common; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.BinaryRead; +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.db.layer0.variable.Variables; +import org.simantics.issues.common.preferences.IssuePrefs; +import org.simantics.issues.ontology.IssueResource; +import org.simantics.layer0.Layer0; +import org.simantics.operation.Layer0X; +import org.simantics.simulation.ontology.SimulationResource; + +import gnu.trove.map.hash.TObjectByteHashMap; +import gnu.trove.set.hash.THashSet; + +/** + * @author Tuukka Lehtonen + */ +public class ModelVisibleIssues extends BinaryRead> { + + public ModelVisibleIssues(Resource model) { + super(model, Boolean.FALSE); + } + + public ModelVisibleIssues(Resource model, boolean onlyUnresolved) { + super(model, onlyUnresolved); + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + + //System.err.println("ModelVisibleIssues for " + graph.getURI(parameter)); + + Layer0 L0 = Layer0.getInstance(graph); + IssueResource ISSUE = IssueResource.getInstance(graph); + + Resource project = Simantics.getProjectResource(); + boolean showHidden = false; + boolean showNormal = true; + boolean showUser = true; + if (project != null) { + showHidden = IssuePrefs.showHiddenIssues(graph, project); + showNormal = IssuePrefs.showNormalIssues(graph, project); + showUser = IssuePrefs.showUserIssues(graph, project); + } + + Instances issueIndex = graph.getPossibleAdapter(ISSUE.Issue, Instances.class); + + // Cache for source activeness. + // 0 == not in cache, 1 == false, 2 == true + TObjectByteHashMap sourceActivenessCache = new TObjectByteHashMap(); + + Set result = new THashSet<>(1013); + + Collection modelIssues = graph.syncRequest(new ObjectsWithType(parameter, L0.ConsistsOf, ISSUE.Issue)); + Collection indexedIssues = issueIndex != null ? issueIndex.find(graph, parameter) : Collections.emptyList(); + Collection issues = !indexedIssues.isEmpty() ? new THashSet(modelIssues.size() + indexedIssues.size()) : modelIssues; + if (!indexedIssues.isEmpty()) { + issues.addAll(modelIssues); + issues.addAll(indexedIssues); + } + + for (Resource issue : issues) { + // Filter out unwanted material + boolean resolved = graph.hasStatement(issue, ISSUE.Resolved); + if (parameter2 && resolved) + continue; + boolean hidden = graph.hasStatement(issue, ISSUE.Hidden); + boolean user = graph.hasStatement(issue, ISSUE.UserIssue); + boolean normal = !hidden && !user; + if (!showHidden && hidden) + continue; + if (!showUser && user) + continue; + if (!showNormal && normal) + continue; + + Resource source = graph.getPossibleObject(issue, ISSUE.IssueSource_Manages_Inverse); + if (source != null) { + byte cache = sourceActivenessCache.get(source); + boolean active = cache == 2 ? true : false; + if (cache == 0) { + active = Boolean.TRUE.equals(graph.getPossibleRelatedValue(source, ISSUE.IssueSource_active)); + sourceActivenessCache.put(source, active ? (byte) 2 : (byte) 1); + } + if (!active) + continue; + } + + Variable var = Variables.getPossibleVariable(graph, issue); + if (var != null) + result.add(var); + } + + // System.out.println("ModelVisibleIssues returned " + result.size()); + return result; + } + +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/RunActiveValidations.java b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/RunActiveValidations.java new file mode 100644 index 000000000..72a5f06df --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/RunActiveValidations.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2007, 2019 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 + * Semantum Oy - Reorganization + *******************************************************************************/ +package org.simantics.issues.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; +import org.simantics.Simantics; +import org.simantics.db.Issue; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.common.request.Queries; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PossibleActiveModel; +import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest; +import org.simantics.db.layer0.util.SessionGarbageCollection; +import org.simantics.issues.ontology.IssueResource; +import org.simantics.issues.preferences.IssuePreferenceUtil; + +/** + * @author Tuukka Lehtonen + */ +public class RunActiveValidations { + + public static void run(IProgressMonitor monitor) throws DatabaseException { + Resource model = Simantics.getSession().syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); + if (model != null) + run(monitor, model); + } + + public static void run(IProgressMonitor monitor, Resource model) throws DatabaseException { + + final Session session = Simantics.getSession(); + + // 1. query for which composites to run the validation + final Collection validations = new ArrayList<>(); + final BatchIssueValidationContext context = new BatchIssueValidationContext(); + + try { + toBatchIssueSources(session, + session.syncRequest(new SelectedModelBatchIssueSources(model)), + validations); + + SubMonitor.convert(monitor, Messages.RunActiveValidations_MonitorPreparingResourcesForValidation, 100); + context.contexts = Collections.singletonList(model); + context.domain = ModelTransferableGraphSourceRequest.getDomainOnly(session, monitor, model); + + if (monitor.isCanceled()) + throw new OperationCanceledException(); + + } finally { + monitor.done(); + } + + if (!validations.isEmpty() && !context.contexts.isEmpty()) + run(monitor, validations, context); + + } + + static Collection toBatchIssueSources(RequestProcessor processor, Collection sources, Collection result) throws DatabaseException { + for (Resource source : sources) { + BatchIssueSource bis = processor.syncRequest(Queries.adapt(source, BatchIssueSource.class, true)); + if (bis != null) + result.add(bis); + } + return result; + } + + public static void run(IProgressMonitor monitor, final Collection validations, final BatchIssueValidationContext context) throws DatabaseException { + SubMonitor progress = SubMonitor.convert(monitor, Messages.RunActiveValidations_ValidateModel, 100); + int maxWrittenIssues = IssuePreferenceUtil.getPreferences().maxBatchIssuesToWrite; + int writtenIssues = 0; + for (BatchIssueSource source : validations) { + Map> results = BatchValidations.validate(progress.newChild(90, SubMonitor.SUPPRESS_NONE), source, context); + if (progress.isCanceled()) + throw new OperationCanceledException(); + + Collection removed = Simantics.getSession().syncRequest(new ResourceRead>(source.getResource()) { + @Override + public Collection perform(ReadGraph graph) throws DatabaseException { + IssueResource ISSUE = IssueResource.getInstance(graph); + ArrayList result = new ArrayList<>(); + for (Resource issue : graph.syncRequest(new ManagedIssues(resource))) { + Resource list = graph.getSingleObject(issue, ISSUE.Issue_HasContexts); + List l = ListUtils.toList(graph, list); + if (l.size() > 0) { + Resource mainContext = l.get(0); + if (!BatchValidations.isLinkedToOtherThan(graph, mainContext, issue)) + result.add(mainContext); + } + } + return result; + } + }); + + for (Resource r : removed) { + results.put(r, Collections.emptySet()); + } + if (progress.isCanceled()) + throw new OperationCanceledException(); + + int wroteIssues = BatchValidations.store(progress.newChild(10, SubMonitor.SUPPRESS_NONE), source.getResource(), results, Math.max(0, maxWrittenIssues - writtenIssues)); + writtenIssues += wroteIssues; + + // Try to keep resource consumption down. + SessionGarbageCollection.gc(null, Simantics.getSession(), true, null); + + } + + } + +} diff --git a/bundles/org.simantics.issues.common/src/org/simantics/issues/common/messages.properties b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/messages.properties new file mode 100644 index 000000000..99646ca10 --- /dev/null +++ b/bundles/org.simantics.issues.common/src/org/simantics/issues/common/messages.properties @@ -0,0 +1,2 @@ +RunActiveValidations_MonitorPreparingResourcesForValidation=Preparing resources for validation +RunActiveValidations_ValidateModel=Validate Model diff --git a/bundles/org.simantics.issues.ontology/graph/Issue.pgraph b/bundles/org.simantics.issues.ontology/graph/Issue.pgraph index a819028de..e96923119 100644 --- a/bundles/org.simantics.issues.ontology/graph/Issue.pgraph +++ b/bundles/org.simantics.issues.ontology/graph/Issue.pgraph @@ -13,6 +13,7 @@ ISSUE.Functions : L0.Library ISSUE.IssueSourceType -- ISSUE.IssueSource.HasConstraint --> L0.Constraint -- ISSUE.IssueSource.Manages --> ISSUE.Issue -- ISSUE.IssueSource.Selected --> ISSUE.IssueSource -- ISSUE.IssueSource.active ==> "Boolean" -- ISSUE.ContinuousIssueSource.lastUpdateRevision --> L0.Long -- ISSUE.Issue.creationTime --> L0.String -- ISSUE.Issue.hider ==> "Maybe (Boolean -> Boolean)" -- ISSUE.Issue.hidden ==> "Boolean" -- ISSUE.Sources.DependencyTracker.HasType --> L0.Entity -- ISSUE.Sources.DependencyTracker.HasSearchType --> L0.Entity -- ISSUE.Sources.DependencyTracker.HasExtension --> L0.Function -- ISSUE.Sources.DependencyTracker.HasConstraint --> L0.Constraint +ISSUE = + +ISSUE.Sources.Relations () \ No newline at end of file diff --git a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/ConfigureIssueSources.java b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/ConfigureIssueSources.java index b168583e4..720b9d10b 100644 --- a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/ConfigureIssueSources.java +++ b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/ConfigureIssueSources.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 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 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Reorganization *******************************************************************************/ package org.simantics.issues.ui.handler; @@ -40,12 +41,13 @@ import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.PossibleActiveModel; import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.request.Write; import org.simantics.issues.common.IssueUtils; import org.simantics.issues.ontology.IssueResource; import org.simantics.layer0.Layer0; -import org.simantics.modeling.ModelingUtils; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.dialogs.ListDialog; @@ -67,176 +69,106 @@ public class ConfigureIssueSources extends AbstractHandler { checked = value; } } - - @Override - public Object execute(ExecutionEvent event) throws ExecutionException { - try { + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + try { + Resource indexRoot = Simantics.getSession().syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); + executeDefault(indexRoot); + } catch (DatabaseException e) { + throw new ExecutionException("Exception while showing validation configuration dialog", e); + } + return null; + } - final List sources = Simantics.getSession().syncRequest(new UniqueRead>() { + public static void executeDefault(Resource indexRoot) throws ExecutionException { - @Override - public List perform(ReadGraph graph) throws DatabaseException { - - Resource activeModel = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); - if(activeModel == null) return Collections.emptyList(); - - List result = new ArrayList(); - Layer0 L0 = Layer0.getInstance(graph); - IssueResource ISSUE = IssueResource.getInstance(graph); - for(Resource type : ModelingUtils.searchByType(graph, activeModel, ISSUE.IssueSourceType)) { - String name = NameUtils.getSafeLabel(graph, type); - boolean exists = graph.syncRequest(new PossibleObjectWithType(activeModel, L0.ConsistsOf, type)) != null; - boolean deprecated = graph.hasStatement(type, L0.Deprecated); - if(!exists && deprecated) continue; - result.add(new IssueSourceEntry(name, type, exists)); + if (indexRoot == null) + return; + + try { + final List sources = Simantics.getSession().syncRequest(new UniqueRead>() { + + @Override + public List perform(ReadGraph graph) throws DatabaseException { + + if(indexRoot == null) return Collections.emptyList(); + + List result = new ArrayList(); + Layer0 L0 = Layer0.getInstance(graph); + IssueResource ISSUE = IssueResource.getInstance(graph); + for(Resource type : QueryIndexUtils.searchByType(graph, indexRoot, ISSUE.IssueSourceType)) { + String name = NameUtils.getSafeLabel(graph, type); + boolean exists = graph.syncRequest(new PossibleObjectWithType(indexRoot, L0.ConsistsOf, type)) != null; + boolean deprecated = graph.hasStatement(type, L0.Deprecated); + boolean abstract_ = graph.hasStatement(type, L0.Abstract); + if(!exists && (deprecated || abstract_)) continue; + result.add(new IssueSourceEntry(name, type, exists)); + } + return result; } - return result; - } - - }); - - Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); - ListDialog dialog = new ListDialog( - shell, sources, - Messages.ConfigureIssueSources_SelectAvailableIssueSources, - Messages.ConfigureIssueSources_SelectedSourcesAddRemoveMsg) { - - protected CheckboxTableViewer createViewer(Composite composite) { - CheckboxTableViewer viewer = CheckboxTableViewer.newCheckList( - composite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); - final Table table = (Table)viewer.getControl(); - viewer.setCheckStateProvider(new ICheckStateProvider() { - + + }); + + Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + ListDialog dialog = new ListDialog( + shell, sources, + Messages.ConfigureIssueSources_SelectAvailableIssueSources, + Messages.ConfigureIssueSources_SelectedSourcesAddRemoveMsg) { + + protected CheckboxTableViewer createViewer(Composite composite) { + CheckboxTableViewer viewer = CheckboxTableViewer.newCheckList( + composite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); + viewer.setCheckStateProvider(new ICheckStateProvider() { @Override - public boolean isGrayed(Object arg0) { + public boolean isGrayed(Object o) { return false; } - @Override - public boolean isChecked(Object arg0) { - IssueSourceEntry entry = (IssueSourceEntry)arg0; + public boolean isChecked(Object o) { + IssueSourceEntry entry = (IssueSourceEntry)o; return entry.isChecked(); } - }); - viewer.addCheckStateListener(new ICheckStateListener() { - - @Override - public void checkStateChanged(CheckStateChangedEvent arg0) { - IssueSourceEntry entry = (IssueSourceEntry)arg0.getElement(); - entry.setChecked(arg0.getChecked()); - } + viewer.addCheckStateListener(e -> { + IssueSourceEntry entry = (IssueSourceEntry)e.getElement(); + entry.setChecked(e.getChecked()); }); - table.addSelectionListener(new SelectionListener () { - @Override - public void widgetSelected(SelectionEvent e) { - table.deselectAll(); - } - @Override - public void widgetDefaultSelected(SelectionEvent e) {} - }); - return viewer; - } - - }; - int result = dialog.open(); - if (result != Dialog.OK) - return null; - - Simantics.getSession().syncRequest(new WriteRequest() { - - @Override - public void perform(WriteGraph graph) throws DatabaseException { - - Resource activeModel = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); - if(activeModel == null) return; - + viewer.getTable().addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + viewer.getTable().deselectAll(); + })); + return viewer; + } + + }; + int result = dialog.open(); + if (result != Dialog.OK) + return; + + Simantics.getSession().syncRequest((Write) graph -> { + Layer0 L0 = Layer0.getInstance(graph); for(IssueSourceEntry entry : sources) { - Resource existing = graph.syncRequest(new PossibleObjectWithType(activeModel, L0.ConsistsOf, entry.getResource())); - + Resource existing = graph.syncRequest(new PossibleObjectWithType(indexRoot, L0.ConsistsOf, entry.getResource())); + if(existing == null && entry.isChecked()) { String name = NameUtils.getSafeLabel(graph, entry.getResource()); - IssueUtils.addIssueSource(graph, activeModel, entry.getResource(), name); + IssueUtils.addIssueSource(graph, indexRoot, entry.getResource(), name); } - + if(existing != null && !entry.isChecked()) { RemoverUtil.remove(graph, existing); } - + } - - } - - }); - -// try { -// PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() { -// @Override -// public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { -// try { -// purgeResolvedIssues(monitor); -// } catch (DatabaseException e) { -// throw new InvocationTargetException(e); -// } finally { -// monitor.done(); -// } -// } -// }); -// } catch (InvocationTargetException e) { -// ErrorLogger.defaultLogError(e); - } catch (DatabaseException e) { - ErrorLogger.defaultLogError(e); - } - return null; - } - -// private void purgeResolvedIssues(IProgressMonitor monitor) throws DatabaseException { -// Session session = Simantics.getSession(); -// final Resource project = Simantics.getProjectResource(); -// if (project == null) -// return; -// -// final SubMonitor mon = SubMonitor.convert(monitor, "Purging resolved issues...", 100); -// -// session.syncRequest(new DelayedWriteRequest() { -// @Override -// public void perform(WriteGraph graph) throws DatabaseException { -// graph.markUndoPoint(); -// IssueResource ISSUE = IssueResource.getInstance(graph); -// Set toBeRemoved = new HashSet(); -// Map sourceIsContinuous = new THashMap(); -// for (Resource activeIssue : graph.syncRequest(new AllActiveIssues(project))) { -// if (graph.hasStatement(activeIssue, ISSUE.Resolved)) { -// Resource managedBy = graph.getPossibleObject(activeIssue, ISSUE.IssueSource_Manages_Inverse); -// if (managedBy != null) { -// Boolean isContinuous = sourceIsContinuous.get(managedBy); -// if (isContinuous == null) { -// isContinuous = graph.isInstanceOf(managedBy, ISSUE.ContinuousIssueSource); -// sourceIsContinuous.put(managedBy, isContinuous); -// } -// if (isContinuous) -// continue; -// } -// toBeRemoved.add(activeIssue); -// } -// } -// -// mon.setTaskName("Purging " + toBeRemoved.size() + " resolved batch issues..."); -// mon.setWorkRemaining(toBeRemoved.size()); -// StringBuilder sb = new StringBuilder(); -// sb.append("Purged " + toBeRemoved.size() + " resolved batch issue(s)"); -// for (Resource remove : toBeRemoved) { -// //sb.append(NameUtils.getSafeLabel(graph, remove) + " "); -// RemoverUtil.remove(graph, remove); -// mon.worked(1); -// } -// Layer0Utils.addCommentMetadata(graph, sb.toString()); -// } -// }); -// } + + }); + } catch (DatabaseException e) { + ErrorLogger.defaultLogError(e); + } + + } } diff --git a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/RunActiveValidations.java b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/RunActiveValidations.java index 0ab0ef98c..efdba04d0 100644 --- a/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/RunActiveValidations.java +++ b/bundles/org.simantics.issues.ui/src/org/simantics/issues/ui/handler/RunActiveValidations.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management + * Copyright (c) 2007, 2019 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 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Reorganization *******************************************************************************/ package org.simantics.issues.ui.handler; @@ -57,12 +58,25 @@ public class RunActiveValidations extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { - Runnable postValidation = null; - run(postValidation); + try { + run(); + } catch (DatabaseException e) { + throw new ExecutionException("Error while running active validations", e); + } return null; } - public void run(Runnable postValidation) { + public static void run() throws DatabaseException { + Resource model = Simantics.getSession().syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); + if(model != null) + run(null); + } + + public static void run(Resource model) { + run(model, null); + } + + public static void run(Resource model, Runnable postValidation) { final Session session = Simantics.getSession(); @@ -77,8 +91,6 @@ public class RunActiveValidations extends AbstractHandler { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { - Resource model = session.sync(new PossibleActiveModel(Simantics.getProjectResource())); - if(model == null) return; toBatchIssueSources(session, session.syncRequest(new SelectedModelBatchIssueSources(model)), @@ -151,7 +163,7 @@ public class RunActiveValidations extends AbstractHandler { Resource list = graph.getSingleObject(issue, ISSUE.Issue_HasContexts); List l = ListUtils.toList(graph, list); if (l.size() > 0) { - Resource mainContext = l.get(0); + Resource mainContext = l.get(0); if (!BatchValidations.isLinkedToOtherThan(graph, mainContext, issue)) result.add(mainContext); } @@ -174,7 +186,7 @@ public class RunActiveValidations extends AbstractHandler { } } catch (OperationCanceledException e) { - throw e; + throw e; } catch (Exception e) { throw new InvocationTargetException(e); } finally { diff --git a/bundles/org.simantics.modeling/scl/Simantics/Issue.scl b/bundles/org.simantics.modeling/scl/Simantics/Issue.scl index e09297750..ee7e51e0b 100644 --- a/bundles/org.simantics.modeling/scl/Simantics/Issue.scl +++ b/bundles/org.simantics.modeling/scl/Simantics/Issue.scl @@ -1,20 +1,21 @@ include "Simantics/Entity" hiding (nameOf) import "Simantics/Model" +import "UI/Progress" import "http://www.simantics.org/Issue-1.2" as ISSUE type Issue = Resource type Severity = Resource - + issuesOf :: Model -> [Issue] issuesOf model = recurse ISSUE.Issue model where recurse t r = do - cs = children r + cs = children r issues = filter isIssue cs issueGrp = filter (not . isIssue) cs issues + concatMap (recurse t) issueGrp isIssue r = isInstanceOf r ISSUE.Issue - + importJava "org.simantics.issues.common.IssueUtils" where @JavaName newUserIssueForModel newUserIssueForModel :: Model -> String -> Severity -> [Resource] -> Issue @@ -25,4 +26,20 @@ userIssueAdvanced model label severity contexts = do importJava "org.simantics.issues.common.IssueUtils" where @JavaName newUserIssueForModel - userIssue :: () -> Issue \ No newline at end of file + userIssue :: () -> Issue + +importJava "org.simantics.db" where + @JavaName Issue + data IssueI + +importJava "org.simantics.db.layer0.validation.ValidationUtils" where + @JavaName validateConstraintsForDomain + validateDomain :: Resource -> [IssueI] + +importJava "org.simantics.modeling.utils.BatchValidations" where + @JavaName runAll + runAllBatchValidations :: ProgressMonitor -> Resource -> Resource -> () + +importJava "org.simantics.issues.common.RunActiveValidations" where + @JavaName run + runActiveValidations :: ProgressMonitor -> Resource -> () \ No newline at end of file diff --git a/bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java b/bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java index e20dfc471..d8f83e05f 100644 --- a/bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java +++ b/bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java @@ -1,3 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2019 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: + * Semantum Oy - initial API and implementation + *******************************************************************************/ package org.simantics.scl.db; import java.io.IOException; @@ -152,6 +163,18 @@ public class SCLFunctions { } } + public static void runWithGraph(Object graph, Runnable r) { + final SCLContext context = SCLContext.getCurrent(); + SCLContext.push(context); + Object oldGraph = context.put(GRAPH, graph); + try { + r.run(); + } finally { + context.put(GRAPH, oldGraph); + SCLContext.pop(); + } + } + private static Object[] NO_ARGS = new Object[] { Tuple0.INSTANCE }; public static void asyncRead(final Function f) throws DatabaseException {