587 lines · 20.8 KB · Java
RawDownload
/* * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.script.shell; import java.io.*;import java.net.*;import java.text.*;import java.util.*;import javax.script.*; /** * This is the main class for Java script shell. */public class Main {    /**     * main entry point to the command line tool     * @param args command line argument array     */    public static void main(String[] args) {        // parse command line options        String[] scriptArgs = processOptions(args);         // process each script command        for (Command cmd : scripts) {            cmd.run(scriptArgs);        }         System.exit(EXIT_SUCCESS);    }     // Each -e or -f or interactive mode is represented    // by an instance of Command.    private static interface Command {        public void run(String[] arguments);    }     /**     * Parses and processes command line options.     * @param args command line argument array     */    private static String[] processOptions(String[] args) {        // current scripting language selected        String currentLanguage = DEFAULT_LANGUAGE;        // current script file encoding selected        String currentEncoding = null;         // check for -classpath or -cp first        checkClassPath(args);         // have we seen -e or -f ?        boolean seenScript = false;        // have we seen -f - already?        boolean seenStdin = false;        for (int i=0; i < args.length; i++) {            String arg = args[i];            if (arg.equals("-classpath") ||                    arg.equals("-cp")) {                // handled already, just continue                i++;                continue;            }             // collect non-option arguments and pass these as script arguments            if (!arg.startsWith("-")) {                int numScriptArgs;                int startScriptArg;                if (seenScript) {                    // if we have seen -e or -f already all non-option arguments                    // are passed as script arguments                    numScriptArgs = args.length - i;                    startScriptArg = i;                } else {                    // if we have not seen -e or -f, first non-option argument                    // is treated as script file name and rest of the non-option                    // arguments are passed to script as script arguments                    numScriptArgs = args.length - i - 1;                    startScriptArg = i + 1;                    ScriptEngine se = getScriptEngine(currentLanguage);                    addFileSource(se, args[i], currentEncoding);                }                // collect script arguments and return to main                String[] result = new String[numScriptArgs];                System.arraycopy(args, startScriptArg, result, 0, numScriptArgs);                return result;            }             if (arg.startsWith("-D")) {                String value = arg.substring(2);                int eq = value.indexOf('=');                if (eq != -1) {                    System.setProperty(value.substring(0, eq),                            value.substring(eq + 1));                } else {                    if (!value.equals("")) {                        System.setProperty(value, "");                    } else {                        // do not allow empty property name                        usage(EXIT_CMD_NO_PROPNAME);                    }                }                continue;            } else if (arg.equals("-?") || arg.equals("-help")) {                usage(EXIT_SUCCESS);            } else if (arg.equals("-e")) {                seenScript = true;                if (++i == args.length)                    usage(EXIT_CMD_NO_SCRIPT);                 ScriptEngine se = getScriptEngine(currentLanguage);                addStringSource(se, args[i]);                continue;            } else if (arg.equals("-encoding")) {                if (++i == args.length)                    usage(EXIT_CMD_NO_ENCODING);                currentEncoding = args[i];                continue;            } else if (arg.equals("-f")) {                seenScript = true;                if (++i == args.length)                    usage(EXIT_CMD_NO_FILE);                ScriptEngine se = getScriptEngine(currentLanguage);                if (args[i].equals("-")) {                    if (seenStdin) {                        usage(EXIT_MULTIPLE_STDIN);                    } else {                        seenStdin = true;                    }                    addInteractiveMode(se);                } else {                    addFileSource(se, args[i], currentEncoding);                }                continue;            } else if (arg.equals("-l")) {                if (++i == args.length)                    usage(EXIT_CMD_NO_LANG);                currentLanguage = args[i];                continue;            } else if (arg.equals("-q")) {                listScriptEngines();            }            // some unknown option...            usage(EXIT_UNKNOWN_OPTION);        }         if (! seenScript) {            ScriptEngine se = getScriptEngine(currentLanguage);            addInteractiveMode(se);        }        return new String[0];    }     /**     * Adds interactive mode Command     * @param se ScriptEngine to use in interactive mode.     */    private static void addInteractiveMode(final ScriptEngine se) {        scripts.add(new Command() {            public void run(String[] args) {                setScriptArguments(se, args);                processSource(se, "-", null);            }        });    }     /**     * Adds script source file Command     * @param se ScriptEngine used to evaluate the script file     * @param fileName script file name     * @param encoding script file encoding     */    private static void addFileSource(final ScriptEngine se,            final String fileName,            final String encoding) {        scripts.add(new Command() {            public void run(String[] args) {                setScriptArguments(se, args);                processSource(se, fileName, encoding);            }        });    }     /**     * Adds script string source Command     * @param se ScriptEngine to be used to evaluate the script string     * @param source Script source string     */    private static void addStringSource(final ScriptEngine se,            final String source) {        scripts.add(new Command() {            public void run(String[] args) {                setScriptArguments(se, args);                String oldFile = setScriptFilename(se, "<string>");                try {                    evaluateString(se, source);                } finally {                    setScriptFilename(se, oldFile);                }            }        });    }     /**     * Prints list of script engines available and exits.     */    private static void listScriptEngines() {        List<ScriptEngineFactory> factories = engineManager.getEngineFactories();        for (ScriptEngineFactory factory: factories) {            getError().println(getMessage("engine.info",                    new Object[] { factory.getLanguageName(),                            factory.getLanguageVersion(),                            factory.getEngineName(),                            factory.getEngineVersion()            }));        }        System.exit(EXIT_SUCCESS);    }     /**     * Processes a given source file or standard input.     * @param se ScriptEngine to be used to evaluate     * @param filename file name, can be null     * @param encoding script file encoding, can be null     */    private static void processSource(ScriptEngine se, String filename,            String encoding) {        if (filename.equals("-")) {            BufferedReader in = new BufferedReader                    (new InputStreamReader(getIn()));            boolean hitEOF = false;            String prompt = getPrompt(se);            se.put(ScriptEngine.FILENAME, "<STDIN>");            while (!hitEOF) {                getError().print(prompt);                String source = "";                try {                    source = in.readLine();                } catch (IOException ioe) {                    getError().println(ioe.toString());                }                if (source == null) {                    hitEOF = true;                    break;                }                Object res = evaluateString(se, source, false);                if (res != null) {                    res = res.toString();                    if (res == null) {                        res = "null";                    }                    getError().println(res);                }            }        } else {            FileInputStream fis = null;            try {                fis = new FileInputStream(filename);            } catch (FileNotFoundException fnfe) {                getError().println(getMessage("file.not.found",                        new Object[] { filename }));                        System.exit(EXIT_FILE_NOT_FOUND);            }            evaluateStream(se, fis, filename, encoding);        }    }     /**     * Evaluates given script source     * @param se ScriptEngine to evaluate the string     * @param script Script source string     * @param exitOnError whether to exit the process on script error     */    private static Object evaluateString(ScriptEngine se,            String script, boolean exitOnError) {        try {            return se.eval(script);        } catch (ScriptException sexp) {            getError().println(getMessage("string.script.error",                    new Object[] { sexp.getMessage() }));                    if (exitOnError)                        System.exit(EXIT_SCRIPT_ERROR);        } catch (Exception exp) {            exp.printStackTrace(getError());            if (exitOnError)                System.exit(EXIT_SCRIPT_ERROR);        }         return null;    }     /**     * Evaluate script string source and exit on script error     * @param se ScriptEngine to evaluate the string     * @param script Script source string     */    private static void evaluateString(ScriptEngine se, String script) {        evaluateString(se, script, true);    }     /**     * Evaluates script from given reader     * @param se ScriptEngine to evaluate the string     * @param reader Reader from which is script is read     * @param name file name to report in error.     */    private static Object evaluateReader(ScriptEngine se,            Reader reader, String name) {        String oldFilename = setScriptFilename(se, name);        try {            return se.eval(reader);        } catch (ScriptException sexp) {            getError().println(getMessage("file.script.error",                    new Object[] { name, sexp.getMessage() }));                    System.exit(EXIT_SCRIPT_ERROR);        } catch (Exception exp) {            exp.printStackTrace(getError());            System.exit(EXIT_SCRIPT_ERROR);        } finally {            setScriptFilename(se, oldFilename);        }        return null;    }     /**     * Evaluates given input stream     * @param se ScriptEngine to evaluate the string     * @param is InputStream from which script is read     * @param name file name to report in error     */    private static Object evaluateStream(ScriptEngine se,            InputStream is, String name,            String encoding) {        BufferedReader reader = null;        if (encoding != null) {            try {                reader = new BufferedReader(new InputStreamReader(is,                        encoding));            } catch (UnsupportedEncodingException uee) {                getError().println(getMessage("encoding.unsupported",                        new Object[] { encoding }));                        System.exit(EXIT_NO_ENCODING_FOUND);            }        } else {            reader = new BufferedReader(new InputStreamReader(is));        }        return evaluateReader(se, reader, name);    }     /**     * Prints usage message and exits     * @param exitCode process exit code     */    private static void usage(int exitCode) {        getError().println(getMessage("main.usage",                new Object[] { PROGRAM_NAME }));                System.exit(exitCode);    }     /**     * Gets prompt for interactive mode     * @return prompt string to use     */    private static String getPrompt(ScriptEngine se) {        List<String> names = se.getFactory().getNames();        return names.get(0) + "> ";    }     /**     * Get formatted, localized error message     */    private static String getMessage(String key, Object[] params) {        return MessageFormat.format(msgRes.getString(key), params);    }     // input stream from where we will read    private static InputStream getIn() {        return System.in;    }     // stream to print error messages    private static PrintStream getError() {        return System.err;    }     // get current script engine    private static ScriptEngine getScriptEngine(String lang) {        ScriptEngine se = engines.get(lang);        if (se == null) {            se = engineManager.getEngineByName(lang);            if (se == null) {                getError().println(getMessage("engine.not.found",                        new Object[] { lang }));                        System.exit(EXIT_ENGINE_NOT_FOUND);            }             // initialize the engine            initScriptEngine(se);            // to avoid re-initialization of engine, store it in a map            engines.put(lang, se);        }        return se;    }     // initialize a given script engine    private static void initScriptEngine(ScriptEngine se) {        // put engine global variable        se.put("engine", se);         // load init.<ext> file from resource        List<String> exts = se.getFactory().getExtensions();        InputStream sysIn = null;        ClassLoader cl = Thread.currentThread().getContextClassLoader();        for (String ext : exts) {            sysIn = cl.getResourceAsStream("com/sun/tools/script/shell/init." +                    ext);            if (sysIn != null) break;        }        if (sysIn != null) {            evaluateStream(se, sysIn, "<system-init>", null);        }    }     /**     * Checks for -classpath, -cp in command line args. Creates a ClassLoader     * and sets it as Thread context loader for current thread.     *     * @param args command line argument array     */    private static void checkClassPath(String[] args) {        String classPath = null;        for (int i = 0; i < args.length; i++) {            if (args[i].equals("-classpath") ||                    args[i].equals("-cp")) {                if (++i == args.length) {                    // just -classpath or -cp with no value                    usage(EXIT_CMD_NO_CLASSPATH);                } else {                    classPath = args[i];                }            }        }         if (classPath != null) {            /* We create a class loader, configure it with specified             * classpath values and set the same as context loader.             * Note that ScriptEngineManager uses context loader to             * load script engines. So, this ensures that user defined             * script engines will be loaded. For classes referred             * from scripts, Rhino engine uses thread context loader             * but this is script engine dependent. We don't have             * script engine independent solution anyway. Unless we             * know the class loader used by a specific engine, we             * can't configure correct loader.             */            ClassLoader parent = Main.class.getClassLoader();            URL[] urls = pathToURLs(classPath);            URLClassLoader loader = new URLClassLoader(urls, parent);            Thread.currentThread().setContextClassLoader(loader);        }         // now initialize script engine manager. Note that this has to        // be done after setting the context loader so that manager        // will see script engines from user specified classpath        engineManager = new ScriptEngineManager();    }     /**     * Utility method for converting a search path string to an array     * of directory and JAR file URLs.     *     * @param path the search path string     * @return the resulting array of directory and JAR file URLs     */    private static URL[] pathToURLs(String path) {        String[] components = path.split(File.pathSeparator);        URL[] urls = new URL[components.length];        int count = 0;        while(count < components.length) {

Lines 1–500 of 587.