]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / utils / BatchValidations.java
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java
new file mode 100644 (file)
index 0000000..3a033ef
--- /dev/null
@@ -0,0 +1,216 @@
+package org.simantics.modeling.utils;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.ILog;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Platform;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.Issue;\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.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest;\r
+import org.simantics.db.layer0.util.RemoverUtil;\r
+import org.simantics.db.service.VirtualGraphSupport;\r
+import org.simantics.issues.common.AllBatchIssueSources;\r
+import org.simantics.issues.common.BatchIssueDescriptions;\r
+import org.simantics.issues.common.BatchIssueSource;\r
+import org.simantics.issues.common.BatchIssueValidationContext;\r
+import org.simantics.issues.common.ComposedValidation;\r
+import org.simantics.issues.common.IssueByList;\r
+import org.simantics.issues.common.IssueConstants;\r
+import org.simantics.issues.ontology.IssueResource;\r
+import org.simantics.issues.preferences.IssuePreferenceUtil;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.internal.Plugin;\r
+import org.simantics.modeling.requests.CollectionRequest;\r
+import org.simantics.modeling.requests.CollectionResult;\r
+import org.simantics.modeling.requests.Node;\r
+import org.simantics.utils.page.PageDesc;\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+public class BatchValidations {\r
+\r
+       private static final boolean PERF = false;\r
+\r
+       public static Collection<Resource> fillConfig(IProgressMonitor monitor, Collection<Resource> models) throws DatabaseException {\r
+               final CollectionResult result = Simantics.getSession().syncRequest(new CollectionRequest(monitor, PageDesc.DEFAULT, models.toArray(Resource.NONE)));\r
+               if (result == null)\r
+                       return Collections.emptyList();\r
+               return toComposites(result.breadthFirstFlatten());\r
+       }\r
+\r
+       private static Collection<Resource> toComposites(Collection<Node> nodes) {\r
+               Collection<Resource> result = new ArrayList<Resource>(nodes.size());\r
+               for (Node n : nodes) {\r
+                       Resource composite = n.getDefiningResources().resources[0];\r
+                       Resource diagram = n.getDiagramResource();\r
+                       if (composite != null && diagram != null)\r
+                               result.add(composite);\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public static Map<Resource, Set<Issue>> validate(IProgressMonitor monitor, BatchIssueSource source, BatchIssueValidationContext context) throws DatabaseException {\r
+               Session session = Simantics.getSession();\r
+               return session.syncRequest(new ComposedValidation(monitor, source, context));\r
+       }\r
+\r
+       /**\r
+        * @param monitor\r
+        * @param source\r
+        * @param issues\r
+        * @return\r
+        * @throws DatabaseException\r
+        */\r
+       public static int store(final IProgressMonitor monitor,\r
+                       final Resource source, final Map<Resource, Set<Issue>> issues)\r
+                       throws DatabaseException {\r
+               return store(monitor, source, issues, Integer.MAX_VALUE);\r
+       }\r
+\r
+       /**\r
+        * @param monitor\r
+        * @param source\r
+        * @param issues\r
+        * @param maxIssuesToWrite\r
+        * @return number of issues written (added)\r
+        * @throws DatabaseException\r
+        */\r
+       public static int store(final IProgressMonitor monitor,\r
+                       final Resource source, final Map<Resource, Set<Issue>> issues,\r
+                       final int maxIssuesToWrite) throws DatabaseException {\r
+\r
+               if (issues.isEmpty() || maxIssuesToWrite <= 0)\r
+                       return 0;\r
+\r
+               Session session = Simantics.getSession();\r
+               VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);\r
+               VirtualGraph vg = support.getWorkspacePersistent(IssueConstants.ISSUE_VG);\r
+               final int[] writtenIssues = { 0 };\r
+\r
+               session.syncRequest(new WriteRequest(vg) {\r
+\r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+\r
+                               for(Map.Entry<Resource, Set<Issue>> entry : issues.entrySet()) {\r
+\r
+                                       if (monitor.isCanceled())\r
+                                               return;\r
+\r
+                                       Resource context = entry.getKey();\r
+\r
+                                       Set<Issue> current = entry.getValue();\r
+                                       Set<Issue> existing = graph.sync(new BatchIssueDescriptions(source, context));\r
+\r
+                                       if(!existing.equals(current)) {\r
+\r
+                                               Set<Issue> added = new THashSet<Issue>(current);\r
+                                               Set<Issue> removed = new THashSet<Issue>(existing);\r
+                                               added.removeAll(existing);\r
+                                               removed.removeAll(current);\r
+\r
+                                               for(Issue add : added) {\r
+                                                       add.write(graph, source);\r
+                                                       // Stop if write limit is reached.\r
+                                                       if (++writtenIssues[0] >= maxIssuesToWrite)\r
+                                                               return;\r
+                                               }\r
+                                               for(Issue remove : removed) {\r
+                                                       Resource issue = graph.sync(new IssueByList(source, remove));\r
+                                                       if (issue == null)\r
+                                                               // FIXME: when can this happen and what should be done in this case?\r
+                                                               continue;\r
+                                                       graph.deny(issue, Layer0.getInstance(graph).PartOf);\r
+                                                       graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue);\r
+                                                       RemoverUtil.remove(graph, issue);\r
+                                               }\r
+\r
+                                       }\r
+\r
+                               }\r
+\r
+                       }\r
+               });\r
+\r
+               return writtenIssues[0];\r
+\r
+       }\r
+\r
+       public static void runAll(IProgressMonitor monitor, Resource model) throws DatabaseException {\r
+               runAll(monitor, model, model);\r
+       }\r
+\r
+       public static void runAll(IProgressMonitor monitor, Resource model, Resource resource) throws DatabaseException {\r
+               final Session session = Simantics.getSession();\r
+               final Collection<BatchIssueSource> validations = session.sync( new AllBatchIssueSources(model) );\r
+               SubMonitor progress = SubMonitor.convert(monitor, "Validate Model", 100*validations.size());\r
+               BatchIssueValidationContext context = new BatchIssueValidationContext();\r
+               context.domain = ModelTransferableGraphSourceRequest.getDomainOnly(session, monitor, resource);\r
+               context.contexts = fillConfig(progress, Collections.singletonList(resource));\r
+               int maxWrittenIssues = IssuePreferenceUtil.getPreferences().maxBatchIssuesToWrite;\r
+               int totalIssueCount = 0;\r
+               int writtenIssueCount = 0;\r
+               if (!context.contexts.isEmpty()) {\r
+                       long t0 = System.nanoTime();\r
+                       for(BatchIssueSource bis : validations) {\r
+                               if (monitor.isCanceled())\r
+                                       return;\r
+                               long startTime = System.nanoTime();\r
+                               if (PERF)\r
+                                       System.out.println("validate " + bis);\r
+                               Map<Resource, Set<Issue>> is = validate(progress.newChild(90, SubMonitor.SUPPRESS_NONE), bis, context);\r
+                               int issueCount = count(is);\r
+                               long validationTime = System.nanoTime();\r
+                               if (PERF)\r
+                                       System.out.println("store " + issueCount + " issues");\r
+                               int wroteIssues = store(progress.newChild(10, SubMonitor.SUPPRESS_NONE), bis.getResource(), is, Math.max(0, maxWrittenIssues - writtenIssueCount));\r
+                               totalIssueCount += issueCount;\r
+                               writtenIssueCount += wroteIssues;\r
+                               long writeTime = System.nanoTime();\r
+                               if (PERF) {\r
+                                       System.out.println("validation time: " + ((validationTime-startTime)*1e-9) + " s");\r
+                                       System.out.println("issue store time: " + ((writeTime-validationTime)*1e-9) + " s");\r
+                               }\r
+                       }\r
+                       long tf = System.nanoTime();\r
+                       if (PERF) {\r
+                               System.out.println("total validation time: " + ((tf-t0)*1e-9) + " s");\r
+                       }\r
+               }\r
+               if (totalIssueCount > maxWrittenIssues) {\r
+                       ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID));\r
+                       log.log(new Status(IStatus.WARNING, Plugin.PLUGIN_ID, "Batch issue validation produced " + totalIssueCount + " issues which is more than it was allowed to write into the database. The write limit was " + maxWrittenIssues + "."));\r
+               }\r
+       }\r
+\r
+       /**\r
+        * @param map\r
+        * @return\r
+        */\r
+       @SuppressWarnings("rawtypes")\r
+       private static int count(Map map) {\r
+               int result = 0;\r
+               for (Object obj : map.values()) {\r
+                       if (obj instanceof Set<?>) {\r
+                               Set<?> set = (Set<?>) obj;\r
+                               result += set.size();\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+\r
+}\r