+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();
+ }
+
+}