History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/script/shell/Main.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/script/shell/Main.java+587−0
@@ -0,0 +1,587 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.tools.script.shell;
27+
28+import java.io.*;
29+import java.net.*;
30+import java.text.*;
31+import java.util.*;
32+import javax.script.*;
33+
34+/**
35+ * This is the main class for Java script shell.
36+ */
37+public class Main {
38+ /**
39+ * main entry point to the command line tool
40+ * @param args command line argument array
41+ */
42+ public static void main(String[] args) {
43+ // parse command line options
44+ String[] scriptArgs = processOptions(args);
45+
46+ // process each script command
47+ for (Command cmd : scripts) {
48+ cmd.run(scriptArgs);
49+ }
50+
51+ System.exit(EXIT_SUCCESS);
52+ }
53+
54+ // Each -e or -f or interactive mode is represented
55+ // by an instance of Command.
56+ private static interface Command {
57+ public void run(String[] arguments);
58+ }
59+
60+ /**
61+ * Parses and processes command line options.
62+ * @param args command line argument array
63+ */
64+ private static String[] processOptions(String[] args) {
65+ // current scripting language selected
66+ String currentLanguage = DEFAULT_LANGUAGE;
67+ // current script file encoding selected
68+ String currentEncoding = null;
69+
70+ // check for -classpath or -cp first
71+ checkClassPath(args);
72+
73+ // have we seen -e or -f ?
74+ boolean seenScript = false;
75+ // have we seen -f - already?
76+ boolean seenStdin = false;
77+ for (int i=0; i < args.length; i++) {
78+ String arg = args[i];
79+ if (arg.equals("-classpath") ||
80+ arg.equals("-cp")) {
81+ // handled already, just continue
82+ i++;
83+ continue;
84+ }
85+
86+ // collect non-option arguments and pass these as script arguments
87+ if (!arg.startsWith("-")) {
88+ int numScriptArgs;
89+ int startScriptArg;
90+ if (seenScript) {
91+ // if we have seen -e or -f already all non-option arguments
92+ // are passed as script arguments
93+ numScriptArgs = args.length - i;
94+ startScriptArg = i;
95+ } else {
96+ // if we have not seen -e or -f, first non-option argument
97+ // is treated as script file name and rest of the non-option
98+ // arguments are passed to script as script arguments
99+ numScriptArgs = args.length - i - 1;
100+ startScriptArg = i + 1;
101+ ScriptEngine se = getScriptEngine(currentLanguage);
102+ addFileSource(se, args[i], currentEncoding);
103+ }
104+ // collect script arguments and return to main
105+ String[] result = new String[numScriptArgs];
106+ System.arraycopy(args, startScriptArg, result, 0, numScriptArgs);
107+ return result;
108+ }
109+
110+ if (arg.startsWith("-D")) {
111+ String value = arg.substring(2);
112+ int eq = value.indexOf('=');
113+ if (eq != -1) {
114+ System.setProperty(value.substring(0, eq),
115+ value.substring(eq + 1));
116+ } else {
117+ if (!value.equals("")) {
118+ System.setProperty(value, "");
119+ } else {
120+ // do not allow empty property name
121+ usage(EXIT_CMD_NO_PROPNAME);
122+ }
123+ }
124+ continue;
125+ } else if (arg.equals("-?") || arg.equals("-help")) {
126+ usage(EXIT_SUCCESS);
127+ } else if (arg.equals("-e")) {
128+ seenScript = true;
129+ if (++i == args.length)
130+ usage(EXIT_CMD_NO_SCRIPT);
131+
132+ ScriptEngine se = getScriptEngine(currentLanguage);
133+ addStringSource(se, args[i]);
134+ continue;
135+ } else if (arg.equals("-encoding")) {
136+ if (++i == args.length)
137+ usage(EXIT_CMD_NO_ENCODING);
138+ currentEncoding = args[i];
139+ continue;
140+ } else if (arg.equals("-f")) {
141+ seenScript = true;
142+ if (++i == args.length)
143+ usage(EXIT_CMD_NO_FILE);
144+ ScriptEngine se = getScriptEngine(currentLanguage);
145+ if (args[i].equals("-")) {
146+ if (seenStdin) {
147+ usage(EXIT_MULTIPLE_STDIN);
148+ } else {
149+ seenStdin = true;
150+ }
151+ addInteractiveMode(se);
152+ } else {
153+ addFileSource(se, args[i], currentEncoding);
154+ }
155+ continue;
156+ } else if (arg.equals("-l")) {
157+ if (++i == args.length)
158+ usage(EXIT_CMD_NO_LANG);
159+ currentLanguage = args[i];
160+ continue;
161+ } else if (arg.equals("-q")) {
162+ listScriptEngines();
163+ }
164+ // some unknown option...
165+ usage(EXIT_UNKNOWN_OPTION);
166+ }
167+
168+ if (! seenScript) {
169+ ScriptEngine se = getScriptEngine(currentLanguage);
170+ addInteractiveMode(se);
171+ }
172+ return new String[0];
173+ }
174+
175+ /**
176+ * Adds interactive mode Command
177+ * @param se ScriptEngine to use in interactive mode.
178+ */
179+ private static void addInteractiveMode(final ScriptEngine se) {
180+ scripts.add(new Command() {
181+ public void run(String[] args) {
182+ setScriptArguments(se, args);
183+ processSource(se, "-", null);
184+ }
185+ });
186+ }
187+
188+ /**
189+ * Adds script source file Command
190+ * @param se ScriptEngine used to evaluate the script file
191+ * @param fileName script file name
192+ * @param encoding script file encoding
193+ */
194+ private static void addFileSource(final ScriptEngine se,
195+ final String fileName,
196+ final String encoding) {
197+ scripts.add(new Command() {
198+ public void run(String[] args) {
199+ setScriptArguments(se, args);
200+ processSource(se, fileName, encoding);
201+ }
202+ });
203+ }
204+
205+ /**
206+ * Adds script string source Command
207+ * @param se ScriptEngine to be used to evaluate the script string
208+ * @param source Script source string
209+ */
210+ private static void addStringSource(final ScriptEngine se,
211+ final String source) {
212+ scripts.add(new Command() {
213+ public void run(String[] args) {
214+ setScriptArguments(se, args);
215+ String oldFile = setScriptFilename(se, "<string>");
216+ try {
217+ evaluateString(se, source);
218+ } finally {
219+ setScriptFilename(se, oldFile);
220+ }
221+ }
222+ });
223+ }
224+
225+ /**
226+ * Prints list of script engines available and exits.
227+ */
228+ private static void listScriptEngines() {
229+ List<ScriptEngineFactory> factories = engineManager.getEngineFactories();
230+ for (ScriptEngineFactory factory: factories) {
231+ getError().println(getMessage("engine.info",
232+ new Object[] { factory.getLanguageName(),
233+ factory.getLanguageVersion(),
234+ factory.getEngineName(),
235+ factory.getEngineVersion()
236+ }));
237+ }
238+ System.exit(EXIT_SUCCESS);
239+ }
240+
241+ /**
242+ * Processes a given source file or standard input.
243+ * @param se ScriptEngine to be used to evaluate
244+ * @param filename file name, can be null
245+ * @param encoding script file encoding, can be null
246+ */
247+ private static void processSource(ScriptEngine se, String filename,
248+ String encoding) {
249+ if (filename.equals("-")) {
250+ BufferedReader in = new BufferedReader
251+ (new InputStreamReader(getIn()));
252+ boolean hitEOF = false;
253+ String prompt = getPrompt(se);
254+ se.put(ScriptEngine.FILENAME, "<STDIN>");
255+ while (!hitEOF) {
256+ getError().print(prompt);
257+ String source = "";
258+ try {
259+ source = in.readLine();
260+ } catch (IOException ioe) {
261+ getError().println(ioe.toString());
262+ }
263+ if (source == null) {
264+ hitEOF = true;
265+ break;
266+ }
267+ Object res = evaluateString(se, source, false);
268+ if (res != null) {
269+ res = res.toString();
270+ if (res == null) {
271+ res = "null";
272+ }
273+ getError().println(res);
274+ }
275+ }
276+ } else {
277+ FileInputStream fis = null;
278+ try {
279+ fis = new FileInputStream(filename);
280+ } catch (FileNotFoundException fnfe) {
281+ getError().println(getMessage("file.not.found",
282+ new Object[] { filename }));
283+ System.exit(EXIT_FILE_NOT_FOUND);
284+ }
285+ evaluateStream(se, fis, filename, encoding);
286+ }
287+ }
288+
289+ /**
290+ * Evaluates given script source
291+ * @param se ScriptEngine to evaluate the string
292+ * @param script Script source string
293+ * @param exitOnError whether to exit the process on script error
294+ */
295+ private static Object evaluateString(ScriptEngine se,
296+ String script, boolean exitOnError) {
297+ try {
298+ return se.eval(script);
299+ } catch (ScriptException sexp) {
300+ getError().println(getMessage("string.script.error",
301+ new Object[] { sexp.getMessage() }));
302+ if (exitOnError)
303+ System.exit(EXIT_SCRIPT_ERROR);
304+ } catch (Exception exp) {
305+ exp.printStackTrace(getError());
306+ if (exitOnError)
307+ System.exit(EXIT_SCRIPT_ERROR);
308+ }
309+
310+ return null;
311+ }
312+
313+ /**
314+ * Evaluate script string source and exit on script error
315+ * @param se ScriptEngine to evaluate the string
316+ * @param script Script source string
317+ */
318+ private static void evaluateString(ScriptEngine se, String script) {
319+ evaluateString(se, script, true);
320+ }
321+
322+ /**
323+ * Evaluates script from given reader
324+ * @param se ScriptEngine to evaluate the string
325+ * @param reader Reader from which is script is read
326+ * @param name file name to report in error.
327+ */
328+ private static Object evaluateReader(ScriptEngine se,
329+ Reader reader, String name) {
330+ String oldFilename = setScriptFilename(se, name);
331+ try {
332+ return se.eval(reader);
333+ } catch (ScriptException sexp) {
334+ getError().println(getMessage("file.script.error",
335+ new Object[] { name, sexp.getMessage() }));
336+ System.exit(EXIT_SCRIPT_ERROR);
337+ } catch (Exception exp) {
338+ exp.printStackTrace(getError());
339+ System.exit(EXIT_SCRIPT_ERROR);
340+ } finally {
341+ setScriptFilename(se, oldFilename);
342+ }
343+ return null;
344+ }
345+
346+ /**
347+ * Evaluates given input stream
348+ * @param se ScriptEngine to evaluate the string
349+ * @param is InputStream from which script is read
350+ * @param name file name to report in error
351+ */
352+ private static Object evaluateStream(ScriptEngine se,
353+ InputStream is, String name,
354+ String encoding) {
355+ BufferedReader reader = null;
356+ if (encoding != null) {
357+ try {
358+ reader = new BufferedReader(new InputStreamReader(is,
359+ encoding));
360+ } catch (UnsupportedEncodingException uee) {
361+ getError().println(getMessage("encoding.unsupported",
362+ new Object[] { encoding }));
363+ System.exit(EXIT_NO_ENCODING_FOUND);
364+ }
365+ } else {
366+ reader = new BufferedReader(new InputStreamReader(is));
367+ }
368+ return evaluateReader(se, reader, name);
369+ }
370+
371+ /**
372+ * Prints usage message and exits
373+ * @param exitCode process exit code
374+ */
375+ private static void usage(int exitCode) {
376+ getError().println(getMessage("main.usage",
377+ new Object[] { PROGRAM_NAME }));
378+ System.exit(exitCode);
379+ }
380+
381+ /**
382+ * Gets prompt for interactive mode
383+ * @return prompt string to use
384+ */
385+ private static String getPrompt(ScriptEngine se) {
386+ List<String> names = se.getFactory().getNames();
387+ return names.get(0) + "> ";
388+ }
389+
390+ /**
391+ * Get formatted, localized error message
392+ */
393+ private static String getMessage(String key, Object[] params) {
394+ return MessageFormat.format(msgRes.getString(key), params);
395+ }
396+
397+ // input stream from where we will read
398+ private static InputStream getIn() {
399+ return System.in;
400+ }
401+
402+ // stream to print error messages
403+ private static PrintStream getError() {
404+ return System.err;
405+ }
406+
407+ // get current script engine
408+ private static ScriptEngine getScriptEngine(String lang) {
409+ ScriptEngine se = engines.get(lang);
410+ if (se == null) {
411+ se = engineManager.getEngineByName(lang);
412+ if (se == null) {
413+ getError().println(getMessage("engine.not.found",
414+ new Object[] { lang }));
415+ System.exit(EXIT_ENGINE_NOT_FOUND);
416+ }
417+
418+ // initialize the engine
419+ initScriptEngine(se);
420+ // to avoid re-initialization of engine, store it in a map
421+ engines.put(lang, se);
422+ }
423+ return se;
424+ }
425+
426+ // initialize a given script engine
427+ private static void initScriptEngine(ScriptEngine se) {
428+ // put engine global variable
429+ se.put("engine", se);
430+
431+ // load init.<ext> file from resource
432+ List<String> exts = se.getFactory().getExtensions();
433+ InputStream sysIn = null;
434+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
435+ for (String ext : exts) {
436+ sysIn = cl.getResourceAsStream("com/sun/tools/script/shell/init." +
437+ ext);
438+ if (sysIn != null) break;
439+ }
440+ if (sysIn != null) {
441+ evaluateStream(se, sysIn, "<system-init>", null);
442+ }
443+ }
444+
445+ /**
446+ * Checks for -classpath, -cp in command line args. Creates a ClassLoader
447+ * and sets it as Thread context loader for current thread.
448+ *
449+ * @param args command line argument array
450+ */
451+ private static void checkClassPath(String[] args) {
452+ String classPath = null;
453+ for (int i = 0; i < args.length; i++) {
454+ if (args[i].equals("-classpath") ||
455+ args[i].equals("-cp")) {
456+ if (++i == args.length) {
457+ // just -classpath or -cp with no value
458+ usage(EXIT_CMD_NO_CLASSPATH);
459+ } else {
460+ classPath = args[i];
461+ }
462+ }
463+ }
464+
465+ if (classPath != null) {
466+ /* We create a class loader, configure it with specified
467+ * classpath values and set the same as context loader.
468+ * Note that ScriptEngineManager uses context loader to
469+ * load script engines. So, this ensures that user defined
470+ * script engines will be loaded. For classes referred
471+ * from scripts, Rhino engine uses thread context loader
472+ * but this is script engine dependent. We don't have
473+ * script engine independent solution anyway. Unless we
474+ * know the class loader used by a specific engine, we
475+ * can't configure correct loader.
476+ */
477+ ClassLoader parent = Main.class.getClassLoader();
478+ URL[] urls = pathToURLs(classPath);
479+ URLClassLoader loader = new URLClassLoader(urls, parent);
480+ Thread.currentThread().setContextClassLoader(loader);
481+ }
482+
483+ // now initialize script engine manager. Note that this has to
484+ // be done after setting the context loader so that manager
485+ // will see script engines from user specified classpath
486+ engineManager = new ScriptEngineManager();
487+ }
488+
489+ /**
490+ * Utility method for converting a search path string to an array
491+ * of directory and JAR file URLs.
492+ *
493+ * @param path the search path string
494+ * @return the resulting array of directory and JAR file URLs
495+ */
496+ private static URL[] pathToURLs(String path) {
497+ String[] components = path.split(File.pathSeparator);
498+ URL[] urls = new URL[components.length];
499+ int count = 0;
500+ while(count < components.length) {
501+ URL url = fileToURL(new File(components[count]));
502+ if (url != null) {
503+ urls[count++] = url;
504+ }
505+ }
506+ if (urls.length != count) {
507+ URL[] tmp = new URL[count];
508+ System.arraycopy(urls, 0, tmp, 0, count);
509+ urls = tmp;
510+ }
511+ return urls;
512+ }
513+
514+ /**
515+ * Returns the directory or JAR file URL corresponding to the specified
516+ * local file name.
517+ *
518+ * @param file the File object
519+ * @return the resulting directory or JAR file URL, or null if unknown
520+ */
521+ private static URL fileToURL(File file) {
522+ String name;
523+ try {
524+ name = file.getCanonicalPath();
525+ } catch (IOException e) {
526+ name = file.getAbsolutePath();
527+ }
528+ name = name.replace(File.separatorChar, '/');
529+ if (!name.startsWith("/")) {
530+ name = "/" + name;
531+ }
532+ // If the file does not exist, then assume that it's a directory
533+ if (!file.isFile()) {
534+ name = name + "/";
535+ }
536+ try {
537+ return new URL("file", "", name);
538+ } catch (MalformedURLException e) {
539+ throw new IllegalArgumentException("file");
540+ }
541+ }
542+
543+ private static void setScriptArguments(ScriptEngine se, String[] args) {
544+ se.put("arguments", args);
545+ se.put(ScriptEngine.ARGV, args);
546+ }
547+
548+ private static String setScriptFilename(ScriptEngine se, String name) {
549+ String oldName = (String) se.get(ScriptEngine.FILENAME);
550+ se.put(ScriptEngine.FILENAME, name);
551+ return oldName;
552+ }
553+
554+ // exit codes
555+ private static final int EXIT_SUCCESS = 0;
556+ private static final int EXIT_CMD_NO_CLASSPATH = 1;
557+ private static final int EXIT_CMD_NO_FILE = 2;
558+ private static final int EXIT_CMD_NO_SCRIPT = 3;
559+ private static final int EXIT_CMD_NO_LANG = 4;
560+ private static final int EXIT_CMD_NO_ENCODING = 5;
561+ private static final int EXIT_CMD_NO_PROPNAME = 6;
562+ private static final int EXIT_UNKNOWN_OPTION = 7;
563+ private static final int EXIT_ENGINE_NOT_FOUND = 8;
564+ private static final int EXIT_NO_ENCODING_FOUND = 9;
565+ private static final int EXIT_SCRIPT_ERROR = 10;
566+ private static final int EXIT_FILE_NOT_FOUND = 11;
567+ private static final int EXIT_MULTIPLE_STDIN = 12;
568+
569+ // default scripting language
570+ private static final String DEFAULT_LANGUAGE = "js";
571+ // list of scripts to process
572+ private static List<Command> scripts;
573+ // the script engine manager
574+ private static ScriptEngineManager engineManager;
575+ // map of engines we loaded
576+ private static Map<String, ScriptEngine> engines;
577+ // error messages resource
578+ private static ResourceBundle msgRes;
579+ private static String BUNDLE_NAME = "com.sun.tools.script.shell.messages";
580+ private static String PROGRAM_NAME = "jrunscript";
581+
582+ static {
583+ scripts = new ArrayList<Command>();
584+ engines = new HashMap<String, ScriptEngine>();
585+ msgRes = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
586+ }
587+}