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.common.utils.CommonDBUtils; 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.layer0.Layer0; 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Finds the environment of a model or other index root. */ public abstract class EnvironmentRequest extends UnaryRead> { private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentRequest.class); 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 callback; UpdateListenerImpl(EnvironmentSpecification environmentSpecification, Listener 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 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() { @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) { LOGGER.error("Finding environment failed", e); callback.exception(e); return; } else env = SCLOsgi.MODULE_REPOSITORY.createEnvironment( environmentSpecification, listener); callback.execute(env); } catch (ImportFailureException e) { LOGGER.error("Finding environment failed", e); callback.exception(new DatabaseException(e)); } } @Override public Pair perform(ReadGraph graph) throws DatabaseException { final EnvironmentSpecification environmentSpecification = EnvironmentSpecification.of( "Builtin", "", "StandardLibrary", ""); fillEnvironmentSpecification(environmentSpecification); Resource mainModule = CommonDBUtils.getPossibleChild(graph, parameter, getRootModuleName()); String mainModuleUri; if(mainModule != null) { mainModuleUri = graph.getURI(mainModule); environmentSpecification.importModule(mainModuleUri, ""); Layer0 L0 = Layer0.getInstance(graph); for(Resource l : graph.getObjects(parameter, L0.IsLinkedTo)) { mainModule = CommonDBUtils.getPossibleChild(graph, l, "SCLMain"); if(mainModule != null) environmentSpecification.importModule(graph.getURI(mainModule), ""); } } else mainModuleUri = graph.getURI(parameter) + "/#"; // Add something dummy to the model uri that cannot be in a real URI try { return Pair.make(environmentSpecification, graph.syncRequest(new ParametrizedPrimitiveRead(mainModuleUri) { UpdateListenerImpl sclListener; @Override public void register(ReadGraph graph, Listener 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(); } })); } catch(DatabaseException e) { LOGGER.error("Environment request failed", e); throw e; } } @Override public int hashCode() { return 31*getClass().hashCode() + super.hashCode(); } }