]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/utils/BatchValidations.java
91d85aed2593b00097f75f29a5dc0cc6240bf484
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / utils / BatchValidations.java
1 package org.simantics.modeling.utils;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Map;
7 import java.util.Set;
8
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;
41
42 import gnu.trove.set.hash.THashSet;
43
44 public class BatchValidations {
45
46         private static final boolean PERF = false;
47
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)));
50                 if (result == null)
51                         return Collections.emptyList();
52                 return toComposites(result.breadthFirstFlatten());
53         }
54
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);
62                 }
63                 return result;
64         }
65
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));
69         }
70
71         /**
72          * @param monitor
73          * @param source
74          * @param issues
75          * @return
76          * @throws DatabaseException
77          */
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);
82         }
83
84         /**
85          * @param monitor
86          * @param source
87          * @param issues
88          * @param maxIssuesToWrite
89          * @return number of issues written (added)
90          * @throws DatabaseException
91          */
92         public static int store(final IProgressMonitor monitor,
93                         final Resource source, final Map<Resource, Set<Issue>> issues,
94                         final int maxIssuesToWrite) throws DatabaseException {
95
96                 if (issues.isEmpty() || maxIssuesToWrite <= 0)
97                         return 0;
98
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 };
103
104                 session.syncRequest(new WriteRequest(vg) {
105
106                         @Override
107                         public void perform(WriteGraph graph) throws DatabaseException {
108
109                                 for(Map.Entry<Resource, Set<Issue>> entry : issues.entrySet()) {
110
111                                         if (monitor.isCanceled())
112                                                 return;
113
114                                         Resource context = entry.getKey();
115
116                                         Set<Issue> current = entry.getValue();
117                                         Set<Issue> existing = graph.sync(new BatchIssueDescriptions(source, context));
118
119                                         if(!existing.equals(current)) {
120
121                                                 Set<Issue> added = new THashSet<Issue>(current);
122                                                 Set<Issue> removed = new THashSet<Issue>(existing);
123                                                 added.removeAll(existing);
124                                                 removed.removeAll(current);
125
126                                                 for(Issue add : added) {
127                                                         add.write(graph, source);
128                                                         // Stop if write limit is reached.
129                                                         if (++writtenIssues[0] >= maxIssuesToWrite)
130                                                                 return;
131                                                 }
132                                                 for(Issue remove : removed) {
133                                                         Resource issue = graph.sync(new IssueByList(source, remove));
134                                                         if (issue == null)
135                                                                 // FIXME: when can this happen and what should be done in this case?
136                                                                 continue;
137                                                         graph.deny(issue, Layer0.getInstance(graph).PartOf);
138                                                         graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue);
139                                                         RemoverUtil.remove(graph, issue);
140                                                 }
141
142                                         }
143
144                                 }
145
146                         }
147                 });
148
149                 return writtenIssues[0];
150
151         }
152
153         public static void runAll(IProgressMonitor monitor, Resource model) throws DatabaseException {
154                 runAll(monitor, model, model);
155         }
156
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())
171                                         return;
172                                 long startTime = System.nanoTime();
173                                 if (PERF)
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();
178                                 if (PERF)
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();
184                                 if (PERF) {
185                                         System.out.println("validation time: " + ((validationTime-startTime)*1e-9) + " s");
186                                         System.out.println("issue store time: " + ((writeTime-validationTime)*1e-9) + " s");
187                                 }
188                         }
189                         long tf = System.nanoTime();
190                         if (PERF) {
191                                 System.out.println("total validation time: " + ((tf-t0)*1e-9) + " s");
192                         }
193                 }
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 + "."));
197                 }
198         }
199
200         /**
201          * @param map
202          * @return
203          */
204         @SuppressWarnings("rawtypes")
205         private static int count(Map map) {
206                 int result = 0;
207                 for (Object obj : map.values()) {
208                         if (obj instanceof Set<?>) {
209                                 Set<?> set = (Set<?>) obj;
210                                 result += set.size();
211                         }
212                 }
213                 return result;
214         }
215
216 }