1 package org.simantics.modeling.utils;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Collection;
\r
5 import java.util.Collections;
\r
6 import java.util.Map;
\r
7 import java.util.Set;
\r
9 import org.eclipse.core.runtime.ILog;
\r
10 import org.eclipse.core.runtime.IProgressMonitor;
\r
11 import org.eclipse.core.runtime.IStatus;
\r
12 import org.eclipse.core.runtime.Platform;
\r
13 import org.eclipse.core.runtime.Status;
\r
14 import org.eclipse.core.runtime.SubMonitor;
\r
15 import org.simantics.Simantics;
\r
16 import org.simantics.db.Issue;
\r
17 import org.simantics.db.Resource;
\r
18 import org.simantics.db.Session;
\r
19 import org.simantics.db.VirtualGraph;
\r
20 import org.simantics.db.WriteGraph;
\r
21 import org.simantics.db.common.request.WriteRequest;
\r
22 import org.simantics.db.exception.DatabaseException;
\r
23 import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest;
\r
24 import org.simantics.db.layer0.util.RemoverUtil;
\r
25 import org.simantics.db.service.VirtualGraphSupport;
\r
26 import org.simantics.issues.common.AllBatchIssueSources;
\r
27 import org.simantics.issues.common.BatchIssueDescriptions;
\r
28 import org.simantics.issues.common.BatchIssueSource;
\r
29 import org.simantics.issues.common.BatchIssueValidationContext;
\r
30 import org.simantics.issues.common.ComposedValidation;
\r
31 import org.simantics.issues.common.IssueByList;
\r
32 import org.simantics.issues.common.IssueConstants;
\r
33 import org.simantics.issues.ontology.IssueResource;
\r
34 import org.simantics.issues.preferences.IssuePreferenceUtil;
\r
35 import org.simantics.layer0.Layer0;
\r
36 import org.simantics.modeling.internal.Plugin;
\r
37 import org.simantics.modeling.requests.CollectionRequest;
\r
38 import org.simantics.modeling.requests.CollectionResult;
\r
39 import org.simantics.modeling.requests.Node;
\r
40 import org.simantics.utils.page.PageDesc;
\r
42 import gnu.trove.set.hash.THashSet;
\r
44 public class BatchValidations {
\r
46 private static final boolean PERF = false;
\r
48 public static Collection<Resource> fillConfig(IProgressMonitor monitor, Collection<Resource> models) throws DatabaseException {
\r
49 final CollectionResult result = Simantics.getSession().syncRequest(new CollectionRequest(monitor, PageDesc.DEFAULT, models.toArray(Resource.NONE)));
\r
51 return Collections.emptyList();
\r
52 return toComposites(result.breadthFirstFlatten());
\r
55 private static Collection<Resource> toComposites(Collection<Node> nodes) {
\r
56 Collection<Resource> result = new ArrayList<Resource>(nodes.size());
\r
57 for (Node n : nodes) {
\r
58 Resource composite = n.getDefiningResources().resources[0];
\r
59 Resource diagram = n.getDiagramResource();
\r
60 if (composite != null && diagram != null)
\r
61 result.add(composite);
\r
66 public static Map<Resource, Set<Issue>> validate(IProgressMonitor monitor, BatchIssueSource source, BatchIssueValidationContext context) throws DatabaseException {
\r
67 Session session = Simantics.getSession();
\r
68 return session.syncRequest(new ComposedValidation(monitor, source, context));
\r
76 * @throws DatabaseException
\r
78 public static int store(final IProgressMonitor monitor,
\r
79 final Resource source, final Map<Resource, Set<Issue>> issues)
\r
80 throws DatabaseException {
\r
81 return store(monitor, source, issues, Integer.MAX_VALUE);
\r
88 * @param maxIssuesToWrite
\r
89 * @return number of issues written (added)
\r
90 * @throws DatabaseException
\r
92 public static int store(final IProgressMonitor monitor,
\r
93 final Resource source, final Map<Resource, Set<Issue>> issues,
\r
94 final int maxIssuesToWrite) throws DatabaseException {
\r
96 if (issues.isEmpty() || maxIssuesToWrite <= 0)
\r
99 Session session = Simantics.getSession();
\r
100 VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);
\r
101 VirtualGraph vg = support.getWorkspacePersistent(IssueConstants.ISSUE_VG);
\r
102 final int[] writtenIssues = { 0 };
\r
104 session.syncRequest(new WriteRequest(vg) {
\r
107 public void perform(WriteGraph graph) throws DatabaseException {
\r
109 for(Map.Entry<Resource, Set<Issue>> entry : issues.entrySet()) {
\r
111 if (monitor.isCanceled())
\r
114 Resource context = entry.getKey();
\r
116 Set<Issue> current = entry.getValue();
\r
117 Set<Issue> existing = graph.sync(new BatchIssueDescriptions(source, context));
\r
119 if(!existing.equals(current)) {
\r
121 Set<Issue> added = new THashSet<Issue>(current);
\r
122 Set<Issue> removed = new THashSet<Issue>(existing);
\r
123 added.removeAll(existing);
\r
124 removed.removeAll(current);
\r
126 for(Issue add : added) {
\r
127 add.write(graph, source);
\r
128 // Stop if write limit is reached.
\r
129 if (++writtenIssues[0] >= maxIssuesToWrite)
\r
132 for(Issue remove : removed) {
\r
133 Resource issue = graph.sync(new IssueByList(source, remove));
\r
135 // FIXME: when can this happen and what should be done in this case?
\r
137 graph.deny(issue, Layer0.getInstance(graph).PartOf);
\r
138 graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue);
\r
139 RemoverUtil.remove(graph, issue);
\r
149 return writtenIssues[0];
\r
153 public static void runAll(IProgressMonitor monitor, Resource model) throws DatabaseException {
\r
154 runAll(monitor, model, model);
\r
157 public static void runAll(IProgressMonitor monitor, Resource model, Resource resource) throws DatabaseException {
\r
158 final Session session = Simantics.getSession();
\r
159 final Collection<BatchIssueSource> validations = session.sync( new AllBatchIssueSources(model) );
\r
160 SubMonitor progress = SubMonitor.convert(monitor, "Validate Model", 100*validations.size());
\r
161 BatchIssueValidationContext context = new BatchIssueValidationContext();
\r
162 context.domain = ModelTransferableGraphSourceRequest.getDomainOnly(session, monitor, resource);
\r
163 context.contexts = fillConfig(progress, Collections.singletonList(resource));
\r
164 int maxWrittenIssues = IssuePreferenceUtil.getPreferences().maxBatchIssuesToWrite;
\r
165 int totalIssueCount = 0;
\r
166 int writtenIssueCount = 0;
\r
167 if (!context.contexts.isEmpty()) {
\r
168 long t0 = System.nanoTime();
\r
169 for(BatchIssueSource bis : validations) {
\r
170 if (monitor.isCanceled())
\r
172 long startTime = System.nanoTime();
\r
174 System.out.println("validate " + bis);
\r
175 Map<Resource, Set<Issue>> is = validate(progress.newChild(90, SubMonitor.SUPPRESS_NONE), bis, context);
\r
176 int issueCount = count(is);
\r
177 long validationTime = System.nanoTime();
\r
179 System.out.println("store " + issueCount + " issues");
\r
180 int wroteIssues = store(progress.newChild(10, SubMonitor.SUPPRESS_NONE), bis.getResource(), is, Math.max(0, maxWrittenIssues - writtenIssueCount));
\r
181 totalIssueCount += issueCount;
\r
182 writtenIssueCount += wroteIssues;
\r
183 long writeTime = System.nanoTime();
\r
185 System.out.println("validation time: " + ((validationTime-startTime)*1e-9) + " s");
\r
186 System.out.println("issue store time: " + ((writeTime-validationTime)*1e-9) + " s");
\r
189 long tf = System.nanoTime();
\r
191 System.out.println("total validation time: " + ((tf-t0)*1e-9) + " s");
\r
194 if (totalIssueCount > maxWrittenIssues) {
\r
195 ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID));
\r
196 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
204 @SuppressWarnings("rawtypes")
\r
205 private static int count(Map map) {
\r
207 for (Object obj : map.values()) {
\r
208 if (obj instanceof Set<?>) {
\r
209 Set<?> set = (Set<?>) obj;
\r
210 result += set.size();
\r