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.ReadGraph;
18 import org.simantics.db.Resource;
19 import org.simantics.db.Session;
20 import org.simantics.db.Statement;
21 import org.simantics.db.VirtualGraph;
22 import org.simantics.db.WriteGraph;
23 import org.simantics.db.common.request.WriteRequest;
24 import org.simantics.db.exception.DatabaseException;
25 import org.simantics.db.layer0.util.ModelTransferableGraphSourceRequest;
26 import org.simantics.db.layer0.util.RemoverUtil;
27 import org.simantics.db.service.VirtualGraphSupport;
28 import org.simantics.issues.common.AllBatchIssueSources;
29 import org.simantics.issues.common.BatchIssueDescriptions;
30 import org.simantics.issues.common.BatchIssueSource;
31 import org.simantics.issues.common.BatchIssueValidationContext;
32 import org.simantics.issues.common.ComposedValidation;
33 import org.simantics.issues.common.IssueByList;
34 import org.simantics.issues.common.IssueConstants;
35 import org.simantics.issues.ontology.IssueResource;
36 import org.simantics.issues.preferences.IssuePreferenceUtil;
37 import org.simantics.layer0.Layer0;
38 import org.simantics.modeling.internal.Plugin;
39 import org.simantics.modeling.requests.CollectionRequest;
40 import org.simantics.modeling.requests.CollectionResult;
41 import org.simantics.modeling.requests.Node;
42 import org.simantics.utils.page.PageDesc;
44 import gnu.trove.set.hash.THashSet;
46 public class BatchValidations {
48 private static final boolean PERF = false;
50 public static Collection<Resource> fillConfig(IProgressMonitor monitor, Collection<Resource> models) throws DatabaseException {
51 final CollectionResult result = Simantics.getSession().syncRequest(new CollectionRequest(monitor, PageDesc.DEFAULT, models.toArray(Resource.NONE)));
53 return Collections.emptyList();
54 return toComposites(result.breadthFirstFlatten());
57 private static Collection<Resource> toComposites(Collection<Node> nodes) {
58 Collection<Resource> result = new ArrayList<Resource>(nodes.size());
59 for (Node n : nodes) {
60 Resource composite = n.getDefiningResources().resources[0];
61 Resource diagram = n.getDiagramResource();
62 if (composite != null && diagram != null)
63 result.add(composite);
68 public static Map<Resource, Set<Issue>> validate(IProgressMonitor monitor, BatchIssueSource source, BatchIssueValidationContext context) throws DatabaseException {
69 Session session = Simantics.getSession();
70 return session.syncRequest(new ComposedValidation(monitor, source, context));
78 * @throws DatabaseException
80 public static int store(final IProgressMonitor monitor,
81 final Resource source, final Map<Resource, Set<Issue>> issues)
82 throws DatabaseException {
83 return store(monitor, source, issues, Integer.MAX_VALUE);
90 * @param maxIssuesToWrite
91 * @return number of issues written (added)
92 * @throws DatabaseException
94 public static int store(final IProgressMonitor monitor,
95 final Resource source, final Map<Resource, Set<Issue>> issues,
96 final int maxIssuesToWrite) throws DatabaseException {
98 if (issues.isEmpty() || maxIssuesToWrite <= 0)
101 Session session = Simantics.getSession();
102 VirtualGraphSupport support = session.getService(VirtualGraphSupport.class);
103 VirtualGraph vg = support.getWorkspacePersistent(IssueConstants.ISSUE_VG);
104 final int[] writtenIssues = { 0 };
106 session.syncRequest(new WriteRequest(vg) {
109 public void perform(WriteGraph graph) throws DatabaseException {
111 for(Map.Entry<Resource, Set<Issue>> entry : issues.entrySet()) {
113 if (monitor.isCanceled())
116 Resource context = entry.getKey();
118 Set<Issue> current = entry.getValue();
119 Set<Issue> existing = graph.sync(new BatchIssueDescriptions(source, context));
121 if(!existing.equals(current)) {
123 Set<Issue> added = new THashSet<Issue>(current);
124 Set<Issue> removed = new THashSet<Issue>(existing);
125 added.removeAll(existing);
126 removed.removeAll(current);
128 for(Issue add : added) {
129 add.write(graph, source);
130 // Stop if write limit is reached.
131 if (++writtenIssues[0] >= maxIssuesToWrite)
134 for(Issue remove : removed) {
135 Resource issue = graph.sync(new IssueByList(source, remove));
137 // FIXME: when can this happen and what should be done in this case?
139 graph.deny(issue, Layer0.getInstance(graph).PartOf);
140 graph.deny(source, IssueResource.getInstance(graph).IssueSource_Manages, issue);
141 RemoverUtil.remove(graph, issue);
151 return writtenIssues[0];
155 public static void runAll(IProgressMonitor monitor, Resource model) throws DatabaseException {
156 runAll(monitor, model, model);
159 public static void runAll(IProgressMonitor monitor, Resource model, Resource resource) throws DatabaseException {
160 final Session session = Simantics.getSession();
161 final Collection<BatchIssueSource> validations = session.sync( new AllBatchIssueSources(model) );
162 SubMonitor progress = SubMonitor.convert(monitor, "Validate Model", 100*validations.size());
163 BatchIssueValidationContext context = new BatchIssueValidationContext();
164 context.domain = ModelTransferableGraphSourceRequest.getDomainOnly(session, monitor, resource);
165 context.contexts = fillConfig(progress, Collections.singletonList(resource));
166 int maxWrittenIssues = IssuePreferenceUtil.getPreferences().maxBatchIssuesToWrite;
167 int totalIssueCount = 0;
168 int writtenIssueCount = 0;
169 if (!context.contexts.isEmpty()) {
170 long t0 = System.nanoTime();
171 for(BatchIssueSource bis : validations) {
172 if (monitor.isCanceled())
174 long startTime = System.nanoTime();
176 System.out.println("validate " + bis);
177 Map<Resource, Set<Issue>> is = validate(progress.newChild(90, SubMonitor.SUPPRESS_NONE), bis, context);
178 int issueCount = count(is);
179 long validationTime = System.nanoTime();
181 System.out.println("store " + issueCount + " issues");
182 int wroteIssues = store(progress.newChild(10, SubMonitor.SUPPRESS_NONE), bis.getResource(), is, Math.max(0, maxWrittenIssues - writtenIssueCount));
183 totalIssueCount += issueCount;
184 writtenIssueCount += wroteIssues;
185 long writeTime = System.nanoTime();
187 System.out.println("validation time: " + ((validationTime-startTime)*1e-9) + " s");
188 System.out.println("issue store time: " + ((writeTime-validationTime)*1e-9) + " s");
191 long tf = System.nanoTime();
193 System.out.println("total validation time: " + ((tf-t0)*1e-9) + " s");
196 if (totalIssueCount > maxWrittenIssues) {
197 ILog log = Platform.getLog(Platform.getBundle(Plugin.PLUGIN_ID));
198 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 + "."));
206 @SuppressWarnings("rawtypes")
207 private static int count(Map map) {
209 for (Object obj : map.values()) {
210 if (obj instanceof Set<?>) {
211 Set<?> set = (Set<?>) obj;
212 result += set.size();
219 * Checks if the specified <code>resourceToCheckForLinks</code> is linked to
220 * anything else besides itself and <code>excludeLinksTo</code>.
223 * This is used to if an issue context is still valid. We consider any issue
224 * context that is not attached to something else besides its issue context to
225 * be an invalid issue. Assertions and L0.InstanceOf do not count as external
228 * @param graph database access handle
229 * @param resourceToCheckForLinks the resource to check for "external" links
230 * @param excludeLinksTo exclude links to this resource from evaluation
231 * @return <code>true</code> if there are links, <code>false</code> otherwise
232 * @throws DatabaseException
234 public static boolean isLinkedToOtherThan(ReadGraph graph, Resource resourceToCheckForLinks,
235 Resource excludeLinksTo)
236 throws DatabaseException
238 Layer0 L0 = Layer0.getInstance(graph);
239 for (Statement stm : graph.getStatements(resourceToCheckForLinks, L0.IsWeaklyRelatedTo)) {
240 if (stm.isAsserted(resourceToCheckForLinks))
242 if (stm.getPredicate().equals(L0.InstanceOf))
244 Resource o = stm.getObject();
245 if (o.equals(excludeLinksTo) || o.equals(resourceToCheckForLinks))