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