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