package org.simantics.graph.compiler.internal.validation; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.Callable; import org.simantics.graph.compiler.GraphCompilerPreferences; import org.simantics.graph.compiler.ValidationMode; import org.simantics.graph.compiler.internal.ltk.Location; import org.simantics.graph.compiler.internal.ltk.Problem; import org.simantics.graph.compiler.internal.store.LocationStore; import org.simantics.graph.query.CompositeGraph; import org.simantics.graph.query.Path; import org.simantics.graph.query.Paths; import org.simantics.graph.query.Res; import org.simantics.graph.store.GraphStore; import org.simantics.graph.store.IdRes; import org.simantics.graph.utils.GraphExecutor; public class ValidateGraph implements Runnable { CompositeGraph graph; Collection problems; GraphStore store; GraphCompilerPreferences preferences; Paths paths; public ValidateGraph(CompositeGraph graph, Collection problems, GraphStore store, GraphCompilerPreferences preferences) { this.graph = graph; this.problems = problems; this.store = store; this.preferences = preferences; this.paths = graph.getPaths(); } private void emit(int id, ValidationMode mode, String message) { LocationStore locations = store.getStore(LocationStore.class); Location location = locations.getLocation(id); Problem problem = new Problem(location, message); synchronized(problems) { problems.add(problem); } } public void validate(int id, Res resource) { if(!graph.rawGetObjects(resource, paths.SubrelationOf).isEmpty()) { for(Res res : graph.rawGetObjects(resource, paths.InverseOf)) { if(resource instanceof IdRes && res instanceof Path) emit(id, ValidationMode.ERROR, "Resource " + resource + " doesn't have URI but its inverse has."); if(res instanceof IdRes && resource instanceof Path) { emit(store.resToId(res), ValidationMode.ERROR, "Resource " + res + " doesn't have URI but its inverse has."); } } } else { if(preferences.validateResourceHasType != ValidationMode.IGNORE) { if(!graph.rawGetObjects(resource, paths.InstanceOf).isEmpty()) { } else if(!graph.rawGetObjects(resource, paths.Inherits).isEmpty()) { } else emit(id, preferences.validateResourceHasType, "Resource " + resource + " does not have a type, it has to instantiate or inherit some other resource."); } } /*if(preferences.validateRelationRestrictions != ValidationMode.IGNORE) { store.statements.forStatementsWithSubject(id, new IStatementProcedure() { @Override public void execute(int s, int p, int o) { } }); }*/ } @Override public void run() { int resourceCount = store.identities.getResourceCount(); int segmentLength = Math.max(256, resourceCount / GraphExecutor.EXECUTOR_THREADS / 4 + 1); ArrayList> tasks = new ArrayList>(); for(int segmentStart_ = 0;segmentStart_ < resourceCount;segmentStart_ += segmentLength) { final int segmentStart = segmentStart_; final int segmentEnd = Math.min(segmentStart + segmentLength, resourceCount); tasks.add(new Callable() { @Override public Object call() { for(int id = segmentStart;id 1) { emit(id, ValidationMode.ERROR, "Resource " + res + " is already defined in dependencies, but it is marked new in this graph."); continue; } } else { if(graph.countOccurences(res) <= 1) { emit(id, ValidationMode.ERROR, "Resource " + res + " is not defined in dependencies and it is not marked new in this graph."); continue; } } } validate(id, res); } return null; } }); } try { GraphExecutor.EXECUTOR.invokeAll(tasks); } catch (InterruptedException e) { throw new RuntimeException(e); } } }