package org.simantics.modeling.scl.issue; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.procedure.adapter.SyncListenerAdapter; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingUtils; import org.simantics.scl.compiler.errors.CompilationError; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.osgi.issues.SCLIssueProviderFactory; import org.simantics.scl.osgi.issues.SCLIssueProviderFactory.SCLIssueProvider; import org.simantics.scl.osgi.issues.SCLIssuesTableEntry; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.function.Function1; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.ui.workbench.action.DefaultActions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SCLExpressionIssueProvider implements SCLIssueProvider { public static class SCLExpressionIssueProviderFactory implements SCLIssueProviderFactory { @Override public SCLIssueProvider getSCLIssueProvider() { return new SCLExpressionIssueProvider(); } } private static final Logger LOGGER = LoggerFactory.getLogger(SCLExpressionIssueProvider.class); private List currentIssues = new ArrayList<>(); private boolean disposed = false; SCLExpressionIssueProvider() { } @Override public void listenIssues(Runnable callback) { Simantics.getSession().asyncRequest(new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Set indexRoots = new TreeSet(); for(Resource ontology : Layer0Utils.listOntologies(graph)) { if (graph.isInstanceOf(ontology, L0.SharedOntology)) { indexRoots.add(ontology); } } for(Resource child : graph.getObjects(Simantics.getProjectResource(), L0.ConsistsOf)) { if (graph.isInstanceOf(child, L0.IndexRoot)) { indexRoots.add(child); } } StructuralResource2 STR = StructuralResource2.getInstance(graph); List results = new ArrayList<>(); for (Resource ontology : indexRoots) { List components = ModelingUtils.searchByTypeShallow(graph, ontology, STR.Component); for (Resource component : components) { for (Resource predicate : graph.getPredicates(component)) { if (graph.isSubrelationOf(predicate, L0.HasProperty)) { for (Resource object : graph.getObjects(component, predicate)) { if (graph.isInstanceOf(object, L0.SCLValue)) { Resource type = graph.getPossibleType(object, L0.SCLValue); Variable typeVariable = Variables.getVariable(graph, type); Function1 func = typeVariable.getPossiblePropertyValue(graph, "validator"); if (func == null) { // No validator available if (LOGGER.isTraceEnabled()) LOGGER.trace("No validator available for " + typeVariable.getURI(graph)); continue; } Variable componentVariable = Variables.getVariable(graph, component); Variable propertyVariable = componentVariable.getProperty(graph, predicate); SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.get("graph"); try { sclContext.put("graph", graph); String validatorValue = func.apply(propertyVariable); if (validatorValue != null && !validatorValue.isEmpty()) { results.add(new SCLIssuesTableEntry(propertyVariable.getURI(graph), new CompilationError(Locations.NO_LOCATION, validatorValue.replace("\n", " "))) { @Override public void openLocation() { openResource(Display.getCurrent().getActiveShell(), component); } }); } } catch (Throwable t) { LOGGER.error("Failed to invoke type validator function " + func, t); } finally { sclContext.put("graph", oldGraph); } } } } } } } return results; } }, new SyncListenerAdapter>() { @Override public void execute(ReadGraph graph, List result) { synchronized (currentIssues) { currentIssues.clear(); currentIssues.addAll(result); } if (callback != null) callback.run(); } @Override public void exception(ReadGraph graph, Throwable t) { LOGGER.error("Could not get SCL issues", t); } @Override public boolean isDisposed() { return disposed; } }); } @Override public List getIssues() { synchronized (currentIssues) { List results = new ArrayList<>(currentIssues); return results; } } @Override public void dispose() { disposed = true; } private static void openResource(Shell shell, Resource resource) { DefaultActions.performDefaultAction(shell, new StructuredSelection(resource)); } }