package org.simantics.db.layer0.util; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.BinaryRead; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.ParametrizedPrimitiveRead; 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.specification.EnvironmentSpecification; import org.simantics.scl.compiler.module.repository.ImportFailureException; import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.runtime.RuntimeEnvironment; import org.simantics.scl.osgi.SCLOsgi; import org.simantics.scl.runtime.SCLContext; /** * Finds the runtime environment of a model or other index root. * * @author Hannu Niemistö * @author Antti Villberg */ public class RuntimeEnvironmentRequest2 extends BinaryRead { public RuntimeEnvironmentRequest2(Resource parameter, Resource parameter2) { super(parameter, parameter2); } protected void fillEnvironmentSpecification(EnvironmentSpecification environmentSpecification) { } static class UpdateListenerImpl implements 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()) { return; } getRuntimeEnvironment(environmentSpecification, callback, this); } final public static void getRuntimeEnvironment(EnvironmentSpecification environmentSpecification, Listener callback, UpdateListenerImpl listener) { try { SCLContext context = SCLContext.getCurrent(); RuntimeEnvironment env; Object graph = context.get("graph"); if(graph == null) try { env = SimanticsInternal.getSession().syncRequest(new Read() { @Override public RuntimeEnvironment perform(ReadGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.get("graph"); try { sclContext.put("graph", graph); return SCLOsgi.MODULE_REPOSITORY.createRuntimeEnvironment( environmentSpecification, callback.getClass().getClassLoader(), 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.createRuntimeEnvironment( environmentSpecification, callback.getClass().getClassLoader(), listener); callback.execute(env); } catch (ImportFailureException e) { callback.exception(new DatabaseException(e)); } } }; // This is needed to prevent garbage collection from collecting UpdateListenerImpls // -ModuleRepository only makes a weak reference to the listener final static Map map = new HashMap<>(); @Override public RuntimeEnvironment perform(ReadGraph graph) throws DatabaseException { final EnvironmentSpecification environmentSpecification = EnvironmentSpecification.of( "Builtin", "", "Prelude", "", "Simantics/All", ""); fillEnvironmentSpecification(environmentSpecification); Layer0 L0 = Layer0.getInstance(graph); Collection sclModules = graph.syncRequest(new ObjectsWithType(parameter, L0.ConsistsOf, L0.SCLModule)); for (Resource sclModule : sclModules) environmentSpecification.importModule(graph.getURI(sclModule), ""); Resource mainModule = Layer0Utils.getPossibleChild(graph, parameter2, "SCLMain"); if(mainModule != null) environmentSpecification.importModule(graph.getURI(mainModule), ""); return graph.syncRequest(new ParametrizedPrimitiveRead(environmentSpecification) { @Override public void register(ReadGraph graph, Listener procedure) { SCLContext context = SCLContext.getCurrent(); Object oldGraph = context.put("graph", graph); try { if(procedure.isDisposed()) { UpdateListenerImpl.getRuntimeEnvironment(parameter, procedure, null); } else { UpdateListenerImpl impl = new UpdateListenerImpl(parameter, procedure); impl.notifyAboutUpdate(); map.put(parameter, impl); } } finally { context.put("graph", oldGraph); } } @Override public void unregistered() { map.remove(parameter); } }); } @Override public int hashCode() { return 31*getClass().hashCode() + super.hashCode(); } public static void flush() { map.clear(); } }