/* * Copyright 2012 Jason Miller * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jj.repl; import static jj.application.AppLocation.AppBase; import static jj.server.ServerLocation.*; import io.netty.channel.ChannelHandlerContext; import java.io.IOException; import java.util.HashMap; import javax.inject.Inject; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import jj.resource.Location; import jj.script.AbstractScriptEnvironment; import jj.script.PendingKey; import jj.script.Global; import jj.script.module.RootScriptEnvironment; import jj.script.module.ScriptResource; import jj.util.Closer; /** * <p> * Execution environment for REPL connections. Main purpose is as a coordination * point for continuations and a parent for modules * * @author jason * */ class ReplScriptEnvironment extends AbstractScriptEnvironment<Void> implements RootScriptEnvironment<Void> { static final String NAME = "repl"; static final String BASE_REPL_SYSTEM = "base-repl-system.js"; private final CurrentReplChannelHandlerContext currentCtx; private final ScriptableObject global; private final ScriptableObject local; private final ScriptResource system; private final HashMap<PendingKey, ChannelHandlerContext> pendingContexts = new HashMap<>(); @Inject ReplScriptEnvironment( final Dependencies dependencies, final @Global ScriptableObject global, final CurrentReplChannelHandlerContext currentCtx ) { super(dependencies); this.currentCtx = currentCtx; this.global = global; this.local = configureInjectFunction( configureTimers( configureModuleObjects(NAME, createChainedScope(global)) ) ); system = resourceFinder.loadResource(ScriptResource.class, Assets, BASE_REPL_SYSTEM); assert system != null : "can't find " + BASE_REPL_SYSTEM + ", build is broken!"; system.addDependent(this); } @Override protected void captureContextForKey(PendingKey key) { pendingContexts.put(key, currentCtx.current()); } @Override protected Closer restoreContextForKey(PendingKey key) { ChannelHandlerContext ctx = pendingContexts.remove(key); assert ctx != null : "no ctx found to restore"; return currentCtx.enterScope(ctx); } @Override public Scriptable scope() { return local; } @Override public Script script() { return system.script(); } @Override public String scriptName() { return NAME; } @Override public String sha1() { return system.sha1(); } @Override public boolean needsReplacing() throws IOException { return false; } @Override protected boolean removeOnReload() { return false; } @Override public ScriptableObject global() { return global; } @Override public Location moduleLocation() { // maybe define a REPL base location where repl-only modules can live! // but only after modularity and the REPL lives alone return AppBase; } }