Package io.apigee.trireme.core.modules

Source Code of io.apigee.trireme.core.modules.Process$EnvImpl

/**
* Copyright 2013 Apigee Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.apigee.trireme.core.modules;

import io.apigee.trireme.core.NodeModule;
import io.apigee.trireme.core.NodeRuntime;
import io.apigee.trireme.core.internal.ModuleRegistry;
import io.apigee.trireme.core.internal.NodeExitException;
import io.apigee.trireme.core.internal.ScriptRunner;
import io.apigee.trireme.core.Utils;
import io.apigee.trireme.core.internal.Platform;
import io.apigee.trireme.core.internal.Version;
import io.apigee.trireme.core.internal.handles.AbstractHandle;
import io.apigee.trireme.core.internal.handles.ConsoleHandle;
import io.apigee.trireme.core.internal.handles.JavaInputStreamHandle;
import io.apigee.trireme.core.internal.handles.JavaOutputStreamHandle;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.annotations.JSConstructor;
import org.mozilla.javascript.annotations.JSFunction;
import org.mozilla.javascript.annotations.JSGetter;
import org.mozilla.javascript.annotations.JSSetter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static io.apigee.trireme.core.ArgUtils.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* The Node process module done on top of the VM.
*/
public class Process
    implements NodeModule
{
    protected static final String OBJECT_NAME = "process";
    public static final String MODULE_NAME = "process";
    public static final String EXECUTABLE_NAME = "./node";
    /** We don't really know what the umask is in Java, so we set a reasonable default that the tests expected. */
    public static final int DEFAULT_UMASK = 022;

    private static final   long NANO = 1000000000L;
    protected static final Logger log  = LoggerFactory.getLogger(Process.class);

    private static final Pattern FILE_NAME_PATTERN =
        Pattern.compile("^((.*[/\\\\])|([^/\\\\]*))(.+)\\.node$");

    @Override
    public String getModuleName()
    {
        return MODULE_NAME;
    }

    @Override
    public Scriptable registerExports(Context cx, Scriptable scope, NodeRuntime runner)
        throws InvocationTargetException, IllegalAccessException, InstantiationException
    {
        ScriptableObject.defineClass(scope, ProcessImpl.class, false, true);
        ScriptableObject.defineClass(scope, EnvImpl.class, false, true);

        ProcessImpl exports = (ProcessImpl) cx.newObject(scope, ProcessImpl.CLASS_NAME);
        exports.setRunner(cx, runner);

        EnvImpl env = (EnvImpl) cx.newObject(scope, EnvImpl.CLASS_NAME);
        env.initialize(runner.getScriptObject().getEnvironment());
        exports.setEnv(env);

        // Put the object directly in the scope -- we only do this for modules that are always deployed
        // as global variables in the script.
        scope.put(OBJECT_NAME, scope, exports);
        return exports;
    }

    public static class ProcessImpl
        extends ScriptableObject
    {
        protected static final String CLASS_NAME = "_processClass";

        private Scriptable argv;
        private Scriptable env;
        private long startTime;
        private ScriptRunner runner;
        private Function submitTick;
        private boolean needTickCallback;
        private Function tickSpinnerCallback;
        private Function tickCallback;
        private boolean needImmediateCallback;
        private Function immediateCallback;
        private Function fatalException;
        private Function emit;
        private Object domain;
        private boolean exiting;
        private int umask = DEFAULT_UMASK;
        private boolean throwDeprecation;
        private boolean traceDeprecation;
        private String eval;
        private boolean printEval;
        private boolean forceRepl;
        private boolean connected;
        private Scriptable tickInfoBox;

        @JSConstructor
        @SuppressWarnings("unused")
        public static Object ProcessImpl(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)
        {
            ProcessImpl ret = new ProcessImpl();
            ret.startTime = System.currentTimeMillis();
            ret.tickInfoBox = cx.newArray(ret, 3);
            return ret;
        }

        @Override
        public String getClassName() {
            return CLASS_NAME;
        }

        public void setRunner(Context cx, NodeRuntime runner)
        {
            // This is a low-level module and it's OK to access low-level stuff
            this.runner = (ScriptRunner)runner;
        }

        @JSGetter("_eval")
        @SuppressWarnings("unused")
        public String getEval() {
            return eval;
        }

        @JSSetter("_eval")
        @SuppressWarnings("unused")
        public void setEval(String eval) {
            this.eval = eval;
        }

        @JSGetter("_print_eval")
        @SuppressWarnings("unused")
        public boolean isPrintEval() {
            return printEval;
        }

        @JSSetter("_print_eval")
        @SuppressWarnings("unused")
        public void setPrintEval(boolean eval) {
            this.printEval = eval;
        }

        @JSGetter("_forceRepl")
        @SuppressWarnings("unused")
        public boolean isForceRepl() {
            return forceRepl;
        }

        @JSSetter("_forceRepl")
        @SuppressWarnings("unused")
        public void setForceRepl(boolean force) {
            this.forceRepl = force;
        }

        @JSGetter("_tickInfoBox")
        @SuppressWarnings("unused")
        public Object getTickInfoBox() {
            return tickInfoBox;
        }

        @JSGetter("connected")
        @SuppressWarnings("undefined")
        public boolean isConnected() {
            return connected;
        }

        @JSSetter("connected")
        @SuppressWarnings("undefined")
        public void setConnected(boolean c) {
            this.connected = c;
        }

        @JSGetter("_childProcess")
        @SuppressWarnings("undefined")
        public boolean isChildProcess() {
            return runner.getScriptObject()._isChildProcess();
        }

        @JSSetter("_childProcess")
        @SuppressWarnings("undefined")
        public void setChildProcess(boolean child) {
            runner.getScriptObject()._setChildProcess(child);
        }

        /**
         * Implement process.binding. This works like the rest of the module loading but uses a different
         * namespace and a different cache.
         */
        @JSFunction
        @SuppressWarnings("unused")
        public static Object binding(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            String name = stringArg(args, 0);
            ProcessImpl proc = (ProcessImpl)thisObj;

            return proc.getInternalModule(name, cx);
        }

        public Object getInternalModule(String name, Context cx)
        {
            Object mod = runner.getCachedInternalModule(name);
            if (mod == null) {
                try {
                    mod = runner.initializeModule(name, ModuleRegistry.ModuleType.INTERNAL, cx, runner.getScriptScope());
                    if (log.isTraceEnabled()) {
                        log.trace("Creating new instance {} of internal module {}",
                                  System.identityHashCode(mod), name);
                    }
                    // Special handling of "buffer" and "native_module" which is available in more than one context
                    if ((mod == null) && (Buffer.MODULE_NAME.equals(name) || NativeModule.MODULE_NAME.equals(name))) {
                        return runner.require(name, cx);
                    }

                } catch (InvocationTargetException e) {
                    Throwable targetException = e.getTargetException();
                    throw new EvaluatorException("Error initializing module: " +
                            ((targetException != null) ?
                                    e.toString() + ": " + targetException.toString() :
                                    e.toString()));
                } catch (InstantiationException e) {
                    throw new EvaluatorException("Error initializing module: " + e.toString());
                 } catch (IllegalAccessException e) {
                    throw new EvaluatorException("Error initializing module: " + e.toString());
                }
                runner.cacheInternalModule(name, mod);
            } else if (log.isTraceEnabled()) {
                log.trace("Returning cached copy {} of internal module {}",
                          System.identityHashCode(mod), name);
            }
            return mod;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static void dlopen(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            Scriptable module = objArg(args, 0, Scriptable.class, true);
            String fileName = stringArg(args, 1);

            // This method is called anonymously by "module.js"
            ScriptRunner runner = getRunner(cx);

            Matcher m = FILE_NAME_PATTERN.matcher(fileName);
            if (!m.matches()) {
                throw Utils.makeError(cx, thisObj, "dlopen(" + fileName + "): Native module not supported");
            }

            String name = m.group(4);

            try {
                Object nativeMod = runner.initializeModule(name, ModuleRegistry.ModuleType.NATIVE, cx,
                                                           runner.getScriptScope());
                if (log.isTraceEnabled()) {
                    log.trace("Creating new instance {} of native module {}",
                              System.identityHashCode(nativeMod), name);
                }

                if (nativeMod == null) {
                    throw Utils.makeError(cx, thisObj, "dlopen(" + fileName + "): Native module not supported");
                }

                // We got passed a "module". Make the new native stuff the "exports"
                // on that module.
                module.put("exports", module, nativeMod);

            } catch (InvocationTargetException e) {
                Throwable targetException = e.getTargetException();
                throw new EvaluatorException("Error initializing module: " +
                                                 ((targetException != null) ?
                                                     e.toString() + ": " + targetException.toString() :
                                                     e.toString()));
            } catch (InstantiationException e) {
                throw new EvaluatorException("Error initializing module: " + e.toString());
            } catch (IllegalAccessException e) {
                throw new EvaluatorException("Error initializing module: " + e.toString());
            }
        }

        private Scriptable createStreamHandle(Context cx, AbstractHandle handle)
        {
            Scriptable module = (Scriptable)runner.requireInternal("java_stream_wrap", cx);
            return cx.newObject(module, "JavaStream", new Object[] { handle });
        }

        private Scriptable createConsoleHandle(Context cx, AbstractHandle handle)
        {
            Scriptable module = (Scriptable)runner.requireInternal("console_wrap", cx);
            return cx.newObject(module, "Console", new Object[] { handle });
        }

        /*
         * Special getters and setters for the underlying stdin/out/err streams. "trireme.js" will wrap them with
         * the actual stream objects when needed. These streams are set up based on the underlying input
         * and output streams.
         */
        @JSGetter("_stdoutHandle")
        @SuppressWarnings("unused")
        public Object getStdoutHandle()
        {
            Context cx = Context.getCurrentContext();

            AbstractHandle streamHandle;
            if ((runner.getStdout() == System.out) && ConsoleHandle.isConsoleSupported()) {
                streamHandle = new ConsoleHandle(runner);
                return createConsoleHandle(cx, streamHandle);
            } else {
                streamHandle = new JavaOutputStreamHandle(runner.getStdout());
                return createStreamHandle(cx, streamHandle);
            }
        }

        @JSGetter("_stderrHandle")
        @SuppressWarnings("unused")
        public Object getStderrHandle()
        {
            Context cx = Context.getCurrentContext();
            JavaOutputStreamHandle streamHandle = new JavaOutputStreamHandle(runner.getStderr());
            return createStreamHandle(cx, streamHandle);
        }

        /**
         * If no stream was set up, use this handle instead. trireme.js will pass it to net.socket to create
         * stdout.
         */
        @JSGetter("_stdinHandle")
        @SuppressWarnings("unused")
        public Object getStdinHandle()
        {
            Context cx = Context.getCurrentContext();

            AbstractHandle streamHandle;
            if ((runner.getStdin() == System.in) && ConsoleHandle.isConsoleSupported()) {
                streamHandle = new ConsoleHandle(runner);
                return createConsoleHandle(cx, streamHandle);
            } else {
                streamHandle = new JavaInputStreamHandle(runner.getStdin(), runner);
                return createStreamHandle(cx, streamHandle);
            }
        }

        @JSGetter("argv")
        @SuppressWarnings("unused")
        public Object getArgv()
        {
            return argv;
        }

        @JSSetter("argv")
        @SuppressWarnings("unused")
        public void setArgv(Scriptable argv)
        {
            this.argv = argv;
        }

        public void initializeArgv(String[] args)
        {
            Object[] argvArgs = new Object[args.length];
            for (int i = 0; i < args.length; i++) {
                argvArgs[i] = args[i];
            }
            argv = Context.getCurrentContext().newArray(this, argvArgs);
        }

        @JSGetter("execArgv")
        @SuppressWarnings("unused")
        public Object getExecArgv()
        {
            return Context.getCurrentContext().newArray(this, 0);
        }

        public void setEnv(EnvImpl env) {
            this.env = env;
        }

        @JSGetter("execPath")
        @SuppressWarnings("unused")
        public String getExecPath()
        {
            return EXECUTABLE_NAME;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public void abort()
            throws NodeExitException
        {
            throw new NodeExitException(NodeExitException.Reason.FATAL);
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static void chdir(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            String cd = stringArg(args, 0);
            ProcessImpl self = (ProcessImpl)thisObj;
            try {
                self.runner.setWorkingDirectory(cd);
            } catch (IOException ioe) {
                throw Utils.makeError(cx, self, ioe.toString());
            }
        }

        @JSFunction
        @SuppressWarnings("unused")
        public String cwd()
        {
            return runner.getWorkingDirectory();
        }

        @JSGetter("env")
        @SuppressWarnings("unused")
        public Scriptable getEnv()
        {
            return env;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static void reallyExit(Context cx, Scriptable thisObj, Object[] args, Function func)
            throws NodeExitException
        {
            ProcessImpl self = (ProcessImpl)thisObj;
            if (args.length >= 1) {
                int code = (Integer)Context.jsToJava(args[0], Integer.class);
                throw new NodeExitException(NodeExitException.Reason.NORMAL, code);
            } else {
                throw new NodeExitException(NodeExitException.Reason.NORMAL, 0);
            }
        }

        // TODO getgid
        // TODO setgid
        // TODO getuid
        // TODO setuid

        @JSGetter("version")
        @SuppressWarnings("unused")
        public String getVersion()
        {
            return "v" + runner.getRegistry().getImplementation().getVersion();
        }

        @JSGetter("versions")
        @SuppressWarnings("unused")
        public Object getVersions()
        {
            Scriptable env = Context.getCurrentContext().newObject(this);
            env.put("trireme", env, Version.TRIREME_VERSION);
            env.put("node", env, runner.getRegistry().getImplementation().getVersion());
            if (Version.SSL_VERSION != null) {
                env.put("ssl", env, Version.SSL_VERSION);
            }
            env.put("java", env, System.getProperty("java.version"));
            return env;
        }

        @JSGetter("config")
        @SuppressWarnings("unused")
        public Scriptable getConfig()
        {
            Scriptable c = Context.getCurrentContext().newObject(this);
            Scriptable vars = Context.getCurrentContext().newObject(this);
            c.put("variables", c, vars);
            return c;
        }

        @JSGetter("title")
        @SuppressWarnings("unused")
        public String getTitle()
        {
            return "trireme";
        }

        @JSSetter("title")
        @SuppressWarnings("unused")
        public void setTitle(String title)
        {
            // You can't set it
        }

        @JSGetter("arch")
        @SuppressWarnings("unused")
        public String getArch()
        {
            // This is actually the bitness of the JRE, not necessarily the system
            String arch = System.getProperty("os.arch");

            if (arch.equals("x86")) {
                return "ia32";
            } else if (arch.equals("x86_64")) {
                return "x64";
            }

            return arch;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static void _kill(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            int pid = intArg(args, 0);
            String signal = stringArg(args, 1, "TERM");
            if ("0".equals(signal)) {
                signal = null;
            }

            ProcessWrap.kill(cx, thisObj, pid, signal);
        }

        @JSGetter("pid")
        @SuppressWarnings("unused")
        public int getPid()
        {
            // Java doesn't give us the OS pid. However this is used for debug to show different Node scripts
            // on the same machine, so return a value that uniquely identifies this ScriptRunner.
            return System.identityHashCode(runner) % 65536;
        }

        /**
         * Send a message back to our parent process if there is one.
         */
        @JSFunction
        @SuppressWarnings("unused")
        public static void send(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            Object message = objArg(args, 0, Object.class, true);
            ProcessImpl self = (ProcessImpl)thisObj;

            if (!self.connected) {
                throw Utils.makeError(cx, thisObj, "IPC to the parent is disconnected");
            }
            if (self.runner.getParentProcess() == null) {
                throw Utils.makeError(cx, thisObj, "IPC is not enabled back to the parent");
            }

            // We have a parent, which has a reference to its own "child_process" object that
            // refers back to us. Put a message on THAT script's queue that came from us.
            ProcessWrap.ProcessImpl childObj = self.runner.getParentProcess();
            childObj.getRuntime().enqueueIpc(cx, message, childObj);
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static void disconnect(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            ProcessImpl self = (ProcessImpl)thisObj;

            if (self.runner.getParentProcess() == null) {
                throw Utils.makeError(cx, thisObj, "IPC is not enabled back to the parent");
            }

            ProcessWrap.ProcessImpl childObj = self.runner.getParentProcess();

            self.emit.call(cx, self.emit, thisObj, new Object[] { "disconnected" });
            self.connected = false;
            childObj.getRuntime().enqueueIpc(cx, ProcessWrap.IPC_DISCONNECT, childObj);
        }

        @JSGetter("_errno")
        @SuppressWarnings("unused")
        public Object getErrno()
        {
            return runner.getErrno();
        }

        @JSGetter("platform")
        @SuppressWarnings("unused")
        public String getPlatform()
        {
            if ((runner.getSandbox() != null) &&
                runner.getSandbox().isHideOSDetails()) {
                return "java";
            }
            return Platform.get().getPlatform();
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static Object memoryUsage(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            Runtime r = Runtime.getRuntime();
            Scriptable mem = cx.newObject(thisObj);
            mem.put("rss", mem, r.totalMemory());
            mem.put("heapTotal", mem, r.maxMemory());
            mem.put("heapUsed", mem,  r.totalMemory());
            return mem;
        }

        public void fireExit(Context cx, int code)
        {
            emit.call(cx, emit, this, new Object[] { "exit", code });
        }

        /**
         * This is a function in trireme.js that we will call when needing to execute a JavaScript
         * function directly. This lets us work around issues Rhino has with certain types of callbacks.
         */
        @JSSetter("_submitTick")
        @SuppressWarnings("unused")
        public void setSubmitTick(Function submit) {
            this.submitTick = submit;
        }

        @JSGetter("_submitTick")
        public Function getSubmitTick() {
            return submitTick;
        }

        /**
         * We use these functions when our own JS code needs to control whether the event loop stays alive.
         */
        @JSFunction("_pin")
        @SuppressWarnings("unused")
        public void pin()
        {
            runner.pin();
        }

        @JSFunction("_unpin")
        @SuppressWarnings("unused")
        public void unPin()
        {
            runner.unPin();
        }

        /**
         * trireme.js (aka node.js) calls this whenever nextTick is called and it thinks that we
         * don't know that it needs us to do stuff.
         */
        @JSFunction
        @SuppressWarnings("unused")
        public static void _needTickCallback(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            ProcessImpl self = (ProcessImpl)thisObj;
            self.needTickCallback = true;
        }

        /**
         * We call this from the main loop if we know that _needTickCallback was called.
         */
        public void callTickFromSpinner(Context cx)
        {
            // Reset this first because it's possible that we'll queue ticks while queuing ticks.
            needTickCallback = false;
            tickSpinnerCallback.call(cx, tickSpinnerCallback, this, ScriptRuntime.emptyArgs);
        }

        public boolean isNeedTickCallback() {
            return needTickCallback;
        }

        @JSSetter("emit")
        @SuppressWarnings("unused")
        public void setEmit(Function f) {
            this.emit = f;
        }

        @JSGetter("emit")
        @SuppressWarnings("unused")
        public Function getEmit() {
            return emit;
        }

        @JSSetter("_tickCallback")
        @SuppressWarnings("unused")
        public void setTickCallback(Function f) {
            this.tickCallback = f;
        }

        @JSGetter("_tickCallback")
        @SuppressWarnings("unused")
        public Function getTickCallback() {
            return tickCallback;
        }

        @JSSetter("_tickFromSpinner")
        @SuppressWarnings("unused")
        public void setTickSpinnerCallback(Function f) {
            this.tickSpinnerCallback = f;
        }

        @JSGetter("_tickFromSpinner")
        @SuppressWarnings("unused")
        public Function getTickSpinnerCallback() {
            return tickSpinnerCallback;
        }

        @JSSetter("_needImmediateCallback")
        @SuppressWarnings("unused")
        public void setNeedImmediateCallback(boolean n)
        {
            this.needImmediateCallback = n;
        }

        @JSGetter("_needImmediateCallback")
        @SuppressWarnings("unused")
        public boolean isNeedImmediateCallback()
        {
            return needImmediateCallback;
        }

        @JSSetter("_immediateCallback")
        @SuppressWarnings("unused")
        public void setImmediateCallback(Function f)
        {
            this.immediateCallback = f;
        }

        @JSGetter("_immediateCallback")
        @SuppressWarnings("unused")
        public Function getImmediateCallback()
        {
            return immediateCallback;
        }

        public boolean isCallbacksRequired() {
            return needImmediateCallback || needTickCallback;
        }

        public void callImmediateTasks(Context cx)
        {
            if (log.isTraceEnabled()) {
                log.trace("Calling immediate timer tasks");
            }
            immediateCallback.call(cx, immediateCallback, this, ScriptRuntime.emptyArgs);
            if (log.isTraceEnabled()) {
                log.trace("Immediate tasks done. needImmediateCallback = {}", needImmediateCallback);
            }
        }

        @JSGetter("_fatalException")
        @SuppressWarnings("unused")
        public Function getFatalException() {
            return fatalException;
        }

        @JSSetter("_fatalException")
        @SuppressWarnings("unused")
        public void setFatalException(Function f) {
            this.fatalException = f;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static Object umask(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            ProcessImpl self = (ProcessImpl)thisObj;
            if (args.length > 0) {
                int oldMask = self.umask;
                int newMask = octalOrHexIntArg(args, 0);
                self.umask = newMask;
                return Context.toNumber(oldMask);
            } else {
                return Context.toNumber(self.umask);
            }
        }

        public int getUmask()
        {
            return umask;
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static Object uptime(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            ProcessImpl self = (ProcessImpl)thisObj;
            long up = (System.currentTimeMillis() - self.startTime) / 1000L;
            return Context.javaToJS(up, thisObj);
        }

        @JSFunction
        @SuppressWarnings("unused")
        public static Object hrtime(Context cx, Scriptable thisObj, Object[] args, Function func)
        {
            long nanos = System.nanoTime();
            if (args.length == 1) {
                Scriptable arg = ensureScriptable(args[0]);
                if (!arg.has(0, arg) || !arg.has(1, arg)) {
                    throw new EvaluatorException("Argument must be an array");
                }
                long startSecs = (long)Context.toNumber(arg.get(0, arg));
                long startNs = (long)Context.toNumber(arg.get(1, arg));
                long startNanos = ((startSecs * NANO) + startNs);
                nanos -= startNanos;
            } else if (args.length > 1) {
                throw new EvaluatorException("Invalid arguments");
            }

            Object[] ret = new Object[2];
            ret[0] = (int)(nanos / NANO);
            ret[1] = (int)(nanos % NANO);
            return cx.newArray(thisObj, ret);
        }

        @JSGetter("features")
        @SuppressWarnings("unused")
        public Object getFeatures()
        {
            Scriptable features = Context.getCurrentContext().newObject(this);
            return features;
        }

        @JSGetter("domain")
        @SuppressWarnings("unused")
        public Object getDomain()
        {
            return domain;
        }

        @JSSetter("domain")
        @SuppressWarnings("unused")
        public void setDomain(Object d)
        {
            this.domain = d;
        }

        @JSGetter("_exiting")
        @SuppressWarnings("unused")
        public boolean isExiting()
        {
            return exiting;
        }

        @JSSetter("_exiting")
        @SuppressWarnings("unused")
        public void setExiting(boolean e)
        {
            this.exiting = e;
        }

        @JSSetter("throwDeprecation")
        @SuppressWarnings("unused")
        public void setThrowDeprecation(boolean d) {
            this.throwDeprecation = d;
        }

        @JSGetter("throwDeprecation")
        @SuppressWarnings("unused")
        public boolean isThrowDeprecation() {
            return throwDeprecation;
        }

        @JSSetter("traceDeprecation")
        @SuppressWarnings("unused")
        public void setTraceDeprecation(boolean d) {
            this.traceDeprecation = d;
        }

        @JSGetter("traceDeprecation")
        @SuppressWarnings("unused")
        public boolean isTraceDeprecation() {
            return traceDeprecation;
        }

        private static ScriptRunner getRunner(Context cx)
        {
            return (ScriptRunner) cx.getThreadLocal(ScriptRunner.RUNNER);
        }
    }

    public static class EnvImpl
            extends ScriptableObject
    {
        public static final String CLASS_NAME = "_Environment";

        @Override
        public String getClassName() {
            return CLASS_NAME;
        }

        void initialize(Map<String, String> env)
        {
            for (Map.Entry<String, String> ee : env.entrySet()) {
                this.put(ee.getKey(), this, ee.getValue());
            }
        }
    }

}
TOP

Related Classes of io.apigee.trireme.core.modules.Process$EnvImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.