Use proper environment to resolve SCL types in ontology module 88/2288/3
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Tue, 9 Oct 2018 07:35:43 +0000 (10:35 +0300)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 10 Oct 2018 06:21:49 +0000 (09:21 +0300)
gitlab #131

Change-Id: I9b16546633d8d566cb3d38d48d609878e794eae3

bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/EnvironmentRequest.java [new file with mode: 0644]
bundles/org.simantics.modeling/src/org/simantics/modeling/scl/ontologymodule/OntologyModule.java
bundles/org.simantics.modeling/src/org/simantics/modeling/scl/ontologymodule/OntologyModuleSourceRepository.java
bundles/org.simantics.modeling/src/org/simantics/modeling/scl/ontologymodule/SCLRelationInfoRequest.java

diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/EnvironmentRequest.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/EnvironmentRequest.java
new file mode 100644 (file)
index 0000000..2e37ade
--- /dev/null
@@ -0,0 +1,148 @@
+package org.simantics.db.layer0.util;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ParametrizedPrimitiveRead;
+import org.simantics.db.common.request.UnaryRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.internal.SimanticsInternal;
+import org.simantics.db.procedure.Listener;
+import org.simantics.db.request.Read;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
+import org.simantics.scl.compiler.module.repository.ImportFailureException;
+import org.simantics.scl.compiler.module.repository.UpdateListener;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.utils.datastructures.Pair;
+
+/**
+ * Finds the environment of a model or other index root.
+ */
+public abstract class EnvironmentRequest extends UnaryRead<Resource, Pair<EnvironmentSpecification, Environment>> {
+
+    public EnvironmentRequest(Resource parameter) {
+        super(parameter);
+    }
+
+    protected abstract void fillEnvironmentSpecification(EnvironmentSpecification environmentSpecification);
+    protected abstract String getRootModuleName();
+
+    static class UpdateListenerImpl extends UpdateListener {
+
+        final EnvironmentSpecification environmentSpecification;
+        final Listener<Environment> callback;
+
+        UpdateListenerImpl(EnvironmentSpecification environmentSpecification, Listener<Environment> callback) {
+            this.environmentSpecification = environmentSpecification;
+            this.callback = callback;
+        }
+
+        @Override
+        public void notifyAboutUpdate() {
+            if(callback.isDisposed()) {
+                stopListening();
+                return;
+            }
+            getEnvironment(environmentSpecification, callback, this);
+        }
+    };     
+
+    public static void getEnvironment(EnvironmentSpecification environmentSpecification, Listener<Environment> callback, UpdateListenerImpl listener) {
+
+        try {
+
+            SCLContext context = SCLContext.getCurrent();
+
+            Environment env;
+            Object graph = context.get("graph");
+            if(graph == null)
+                try {
+                    env = SimanticsInternal.getSession().syncRequest(new Read<Environment>() {
+                        @Override
+                        public Environment perform(ReadGraph graph) throws DatabaseException {
+
+                            SCLContext sclContext = SCLContext.getCurrent();
+                            Object oldGraph = sclContext.get("graph");
+                            try {
+                                sclContext.put("graph", graph);
+                                return SCLOsgi.MODULE_REPOSITORY.createEnvironment(
+                                        environmentSpecification, listener);
+                            } catch (ImportFailureException e) {
+                                throw new DatabaseException(e);
+                            } catch (Throwable t) {
+                                throw new DatabaseException(t);
+                            } finally {
+                                sclContext.put("graph", oldGraph);
+                            }
+                        }
+                    });
+                } catch (DatabaseException e) {
+                    callback.exception(e);
+                    return;
+                }
+            else 
+                env = SCLOsgi.MODULE_REPOSITORY.createEnvironment(
+                        environmentSpecification, listener);
+            callback.execute(env);
+        } catch (ImportFailureException e) {
+            callback.exception(new DatabaseException(e));
+        }
+
+    }
+
+    @Override
+    public Pair<EnvironmentSpecification, Environment> perform(ReadGraph graph)
+            throws DatabaseException {
+        final EnvironmentSpecification environmentSpecification = EnvironmentSpecification.of(
+                "Builtin", "",
+                "StandardLibrary", "");
+        fillEnvironmentSpecification(environmentSpecification);
+        Resource mainModule = Layer0Utils.getPossibleChild(graph, parameter, getRootModuleName());
+        String mainModuleUri;
+        if(mainModule != null) {
+            mainModuleUri = graph.getURI(mainModule);
+            environmentSpecification.importModule(mainModuleUri, "");
+        }
+        else
+            mainModuleUri = graph.getURI(parameter) + "/#"; // Add something dummy to the model uri that cannot be in a real URI
+
+        return Pair.make(environmentSpecification, graph.syncRequest(new ParametrizedPrimitiveRead<String, Environment>(mainModuleUri) {
+
+            UpdateListenerImpl sclListener;
+
+            @Override
+            public void register(ReadGraph graph, Listener<Environment> procedure) {
+
+                SCLContext context = SCLContext.getCurrent();
+                Object oldGraph = context.put("graph", graph);
+                try {
+
+                    if(procedure.isDisposed()) {
+                        getEnvironment(environmentSpecification, procedure, null);
+                    } else {
+                        sclListener = new UpdateListenerImpl(environmentSpecification, procedure);
+                        sclListener.notifyAboutUpdate();
+                    }
+
+                } finally {
+                    context.put("graph", oldGraph);
+                }
+
+            }
+
+            @Override
+            public void unregistered() {
+                if(sclListener != null)
+                    sclListener.stopListening();
+            }
+
+        }));
+    }
+
+    @Override
+    public int hashCode() {
+        return 31*getClass().hashCode() + super.hashCode();
+    }
+
+}
index ec698e670514984fa42128d3211238d503a93a35..96ee4218236f1719a9888657c4a3b3ed5111b8a8 100644 (file)
@@ -2,7 +2,6 @@ package org.simantics.modeling.scl.ontologymodule;
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -12,8 +11,11 @@ import org.simantics.Simantics;
 import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
+import org.simantics.db.common.request.IndexRoot;
 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.EnvironmentRequest;
+import org.simantics.db.layer0.util.RuntimeEnvironmentRequest;
 import org.simantics.db.request.Read;
 import org.simantics.layer0.Layer0;
 import org.simantics.scl.compiler.common.names.Name;
@@ -30,7 +32,9 @@ import org.simantics.scl.compiler.elaboration.macros.MacroRule;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
+import org.simantics.scl.compiler.environment.Environment;
 import org.simantics.scl.compiler.environment.filter.NamespaceFilter;
+import org.simantics.scl.compiler.environment.specification.EnvironmentSpecification;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.LazyModule;
@@ -41,6 +45,7 @@ import org.simantics.scl.compiler.types.Types;
 import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
 import org.simantics.scl.compiler.types.kinds.Kinds;
 import org.simantics.scl.runtime.SCLContext;
+import org.simantics.utils.datastructures.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,6 +55,7 @@ import gnu.trove.procedure.TObjectProcedure;
 public class OntologyModule extends LazyModule {
     private static final Logger LOGGER = LoggerFactory.getLogger(OntologyModule.class);
     
+    public static final String SCL_TYPES_NAME = "SCLTypes";
     private static final String DB_MODULE = "Simantics/DB";
     private static final String VARIABLE_MODULE = "Simantics/Variable";
     private static final Collection<ImportDeclaration> DEPENDENCIES = Arrays.asList(
@@ -60,15 +66,38 @@ public class OntologyModule extends LazyModule {
     private static final TCon BROWSABLE = Types.con(DB_MODULE, "Browsable");
     private static final TCon VARIABLE = Types.con(VARIABLE_MODULE, "Variable");
     
-    Resource ontology;
-    String defaultLocalName;
-    THashMap<Resource,Map<String,Resource>> childMaps = new THashMap<Resource,Map<String,Resource>>();
+    private Resource ontology;
+    private String defaultLocalName;
+    private THashMap<Resource,Map<String,Resource>> childMaps = new THashMap<Resource,Map<String,Resource>>();
+    private List<ImportDeclaration> importDeclarations;
+    private Environment environment;
     
     public OntologyModule(ReadGraph graph, String moduleName) throws DatabaseException {
         super(moduleName);
         ontology = graph.getResource(moduleName);
         readDefaultLocalName(graph);
         childMaps.put(ontology, createLocalMap(graph, ontology));
+        Pair<EnvironmentSpecification, Environment> pair = graph.syncRequest(new Read<Pair<EnvironmentSpecification, Environment>>() {
+            @Override
+            public Pair<EnvironmentSpecification, Environment> perform(ReadGraph graph) throws DatabaseException {
+                Resource indexRoot = graph.syncRequest(new IndexRoot(ontology));
+                return graph.syncRequest(new EnvironmentRequest(indexRoot) {
+                    @Override
+                    protected void fillEnvironmentSpecification(EnvironmentSpecification environmentSpecification) {
+                        /*if(!moduleName.equals("http://www.simantics.org/Layer0-1.1")) { // Prevent cyclic dependencies
+                            environmentSpecification.importModule(DB_MODULE, "");
+                            environmentSpecification.importModule(VARIABLE_MODULE, "");
+                        }*/
+                    }
+                    @Override
+                    protected String getRootModuleName() {
+                        return SCL_TYPES_NAME;
+                    }
+                });
+            }
+        });
+        this.importDeclarations = pair.first.imports;
+        this.environment = pair.second;
     }
     
     private void readDefaultLocalName(ReadGraph graph) throws DatabaseException {
@@ -85,8 +114,7 @@ public class OntologyModule extends LazyModule {
 
     @Override
     public List<ImportDeclaration> getDependencies() {
-        //return DEPENDENCIES;
-        return Collections.emptyList();
+        return importDeclarations;
     }
     
     private static interface ResourceSearchResult {}
@@ -180,7 +208,7 @@ public class OntologyModule extends LazyModule {
     
     @FunctionalInterface
     private static interface ResourceFunctionGenerator {
-        SCLValue createValue(Name name, Resource resource);
+        SCLValue createValue(Name name, Resource resource, Environment environment);
     }
     
     private static class RelatedValueMacroRule implements MacroRule {
@@ -245,8 +273,8 @@ public class OntologyModule extends LazyModule {
     private final static HashMap<String, ResourceFunctionGenerator> VALUE_GENERATOR_MAP = new HashMap<>();
     static {
         TVar A = Types.var(Kinds.STAR);
-        VALUE_GENERATOR_MAP.put("value", (name, resource) -> {
-            SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
+        VALUE_GENERATOR_MAP.put("value", (name, resource, environment) -> {
+            SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource, environment);
             if(relationInfo == null)
                 return null;
             
@@ -255,8 +283,8 @@ public class OntologyModule extends LazyModule {
             value.setMacroRule(new RelatedValueMacroRule(resource, relationInfo, false));
             return value;
         });
-        VALUE_GENERATOR_MAP.put("possibleValue", (name, resource) -> {
-            SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
+        VALUE_GENERATOR_MAP.put("possibleValue", (name, resource, environment) -> {
+            SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource, environment);
             if(relationInfo == null)
                 return null;
             
@@ -284,7 +312,7 @@ public class OntologyModule extends LazyModule {
             if(generator == null)
                 return null;
             else
-                return generator.createValue(Name.create(getName(), name), resourceAndSuffix.resource);
+                return generator.createValue(Name.create(getName(), name), resourceAndSuffix.resource, environment);
         }
         else
             return null;
@@ -469,6 +497,7 @@ public class OntologyModule extends LazyModule {
         childMaps.clear();
         childMaps = null;
         ontology = null;
+        environment = null;
     }
     
     @Override
index 134b2b3d7e2acf0d803fa3612d4acefeafbe50bc..0b882efc3a89d87d1e2591516b43909ec96800cd 100644 (file)
@@ -8,9 +8,14 @@ import org.simantics.Simantics;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.common.request.UnaryRead;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.scl.compiler.errors.Failable;
+import org.simantics.scl.compiler.errors.Failure;
+import org.simantics.scl.compiler.errors.Success;
+import org.simantics.scl.compiler.module.Module;
+import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
+import org.simantics.scl.compiler.module.repository.ModuleRepository;
 import org.simantics.scl.compiler.module.repository.UpdateListener;
 import org.simantics.scl.compiler.source.ModuleSource;
-import org.simantics.scl.compiler.source.PrecompiledModuleSource;
 import org.simantics.scl.compiler.source.repository.ModuleSourceRepository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -22,15 +27,15 @@ public enum OntologyModuleSourceRepository implements ModuleSourceRepository {
     
     private static final Logger LOGGER = LoggerFactory.getLogger(OntologyModuleSourceRepository.class);
 
-       static class ModuleSourceRequest extends UnaryRead<String, ModuleSource> {
+       static class ModuleRequest extends UnaryRead<String, Module> {
 
-        public ModuleSourceRequest(String moduleName) {
+        public ModuleRequest(String moduleName) {
                        super(moduleName);
                }
 
                @Override
-        public ModuleSource perform(ReadGraph graph) throws DatabaseException {
-            return new PrecompiledModuleSource(new OntologyModule(graph, parameter), -1.0);
+        public Module perform(ReadGraph graph) throws DatabaseException {
+            return new OntologyModule(graph, parameter);
         }
 
     };
@@ -41,12 +46,33 @@ public enum OntologyModuleSourceRepository implements ModuleSourceRepository {
         if(!moduleName.startsWith("http://"))
             return null; // Don't do a graph request if this cannot be a resource
         
-        try {
-            return Simantics.getAvailableRequestProcessor().syncRequest(new ModuleSourceRequest(moduleName));
-        } catch(DatabaseException e) {
-            LOGGER.error("Failed to read ontology module " + moduleName + ".", e);
-            return null;
-        }
+        return new ModuleSource() {
+
+            @Override
+            public double getPriority() {
+                return -1.0;
+            }
+
+            @Override
+            public String getModuleName() {
+                return moduleName;
+            }
+
+            @Override
+            public ClassLoader getClassLoader() {
+                return getClass().getClassLoader();
+            }
+
+            @Override
+            public Failable<Module> compileModule(ModuleRepository environment, UpdateListener listener,
+                    ModuleCompilationOptions options) {
+                try {
+                    return new Success<Module>(Simantics.getAvailableRequestProcessor().syncRequest(new ModuleRequest(moduleName)));
+                } catch(DatabaseException e) {
+                    return new Failure(e);
+                }
+            }
+        };
     }
 
     @Override
index 6662463c5b50fc0613e62bd342cc64f2571202b9..e7ed5bd97d5691ea09deb4b36ca198b9be1154ca 100644 (file)
@@ -6,21 +6,23 @@ import org.simantics.databoard.Bindings;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.BinaryRead;
 import org.simantics.db.common.request.UnaryRead;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.layer0.Layer0;
+import org.simantics.scl.compiler.environment.Environment;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.top.SCLExpressionCompilationException;
 import org.simantics.scl.compiler.types.Type;
-import org.simantics.scl.compiler.types.Types;
-import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
 import org.simantics.scl.db.SCLCompilationRequestProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SCLRelationInfoRequest extends UnaryRead<Resource,SCLRelationInfo> {
+public class SCLRelationInfoRequest extends BinaryRead<Resource, Environment, SCLRelationInfo> {
     private static final Logger LOGGER = LoggerFactory.getLogger(SCLRelationInfoRequest.class);
     
-    private SCLRelationInfoRequest(Resource resource) {
-        super(resource);
+    private SCLRelationInfoRequest(Resource resource, Environment environment) {
+        super(resource, environment);
     }
 
     @Override
@@ -58,8 +60,8 @@ public class SCLRelationInfoRequest extends UnaryRead<Resource,SCLRelationInfo>
         
         Type type;
         try {
-            type = Types.parseType(valueType);
-        } catch (SCLTypeParseException e) {
+            type = Environments.getType(parameter2, valueType);
+        } catch (SCLExpressionCompilationException e) {
             LOGGER.warn("Couldn't parse the value type of relation {}. Definition was '{}'.", graph.getURI(parameter), valueType);
             return null;
         }
@@ -67,9 +69,9 @@ public class SCLRelationInfoRequest extends UnaryRead<Resource,SCLRelationInfo>
         return new SCLRelationInfo(type, name);
     }
     
-    public static SCLRelationInfo getRelationInfo(Resource resource) {
+    public static SCLRelationInfo getRelationInfo(Resource resource, Environment environment) {
         try {
-            return SCLCompilationRequestProcessor.getRequestProcessor().syncRequest(new SCLRelationInfoRequest(resource), TransientCacheListener.instance());
+            return SCLCompilationRequestProcessor.getRequestProcessor().syncRequest(new SCLRelationInfoRequest(resource, environment), TransientCacheListener.instance());
         } catch(DatabaseException e) {
             LOGGER.error("SCLRelationInfoRequest failed.", e);
             return null;