001package org.jszip.rhino;
002
003import org.apache.commons.lang3.StringUtils;
004import org.apache.maven.plugin.logging.Log;
005import org.codehaus.plexus.util.IOUtil;
006import org.jszip.pseudo.io.ProxyPseudoFile;
007import org.jszip.pseudo.io.PseudoFile;
008import org.jszip.pseudo.io.PseudoFileInputStream;
009import org.jszip.pseudo.io.PseudoFileOutputStream;
010import org.jszip.pseudo.io.PseudoFileReader;
011import org.jszip.pseudo.io.PseudoFileSystem;
012import org.jszip.pseudo.io.PseudoFileWriter;
013import org.mozilla.javascript.Context;
014import org.mozilla.javascript.Function;
015import org.mozilla.javascript.NativeJavaPackage;
016import org.mozilla.javascript.NativeJavaTopPackage;
017import org.mozilla.javascript.ScriptRuntime;
018import org.mozilla.javascript.Scriptable;
019import org.mozilla.javascript.ScriptableObject;
020import org.mozilla.javascript.tools.shell.Global;
021
022import java.io.IOException;
023import java.io.InputStream;
024
025/**
026 * @author stephenc
027 * @since 29/01/2013 22:51
028 */
029public class GlobalFunctions {
030    /**
031     * Print the string values of its arguments.
032     * <p/>
033     * This method is defined as a JavaScript function. Note that its arguments
034     * are of the "varargs" form, which allows it to handle an arbitrary number
035     * of arguments supplied to the JavaScript function.
036     */
037    public static void print(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
038        StringBuilder builder = new StringBuilder();
039        for (int i = 0; i < args.length; i++) {
040            if (i > 0) {
041                builder.append(" ");
042            }
043
044            // Convert the arbitrary JavaScript value into a string form.
045            String s = Context.toString(args[i]);
046
047            builder.append(s);
048        }
049        Log log = (Log) cx.getThreadLocal(Log.class);
050        if (log != null) {
051            for (String line : builder.toString().split("(\\r\\n?)|(\\n\\r?)")) {
052                log.info(line);
053            }
054        }
055    }
056
057    /**
058     * Print the string values of its arguments.
059     * <p/>
060     * This method is defined as a JavaScript function. Note that its arguments
061     * are of the "varargs" form, which allows it to handle an arbitrary number
062     * of arguments supplied to the JavaScript function.
063     */
064    public static void debug(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
065        StringBuilder builder = new StringBuilder();
066        for (int i = 0; i < args.length; i++) {
067            if (i > 0) {
068                builder.append(" ");
069            }
070
071            // Convert the arbitrary JavaScript value into a string form.
072            String s = Context.toString(args[i]);
073
074            builder.append(s);
075        }
076        Log log = (Log) cx.getThreadLocal(Log.class);
077        if (log != null) {
078            for (String line : builder.toString().split("(\\r\\n?)|(\\n\\r?)")) {
079                log.debug(line);
080            }
081        }
082    }
083
084    /**
085     * Print the string values of its arguments.
086     * <p/>
087     * This method is defined as a JavaScript function. Note that its arguments
088     * are of the "varargs" form, which allows it to handle an arbitrary number
089     * of arguments supplied to the JavaScript function.
090     */
091    public static void warn(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
092        StringBuilder builder = new StringBuilder();
093        for (int i = 0; i < args.length; i++) {
094            if (i > 0) {
095                builder.append(" ");
096            }
097
098            // Convert the arbitrary JavaScript value into a string form.
099            String s = Context.toString(args[i]);
100
101            builder.append(s);
102        }
103        Log log = (Log) cx.getThreadLocal(Log.class);
104        if (log != null) {
105            for (String line : builder.toString().split("(\\r\\n?)|(\\n\\r?)")) {
106                log.warn(line);
107            }
108        }
109    }
110
111    /**
112     * Print the string values of its arguments.
113     * <p/>
114     * This method is defined as a JavaScript function. Note that its arguments
115     * are of the "varargs" form, which allows it to handle an arbitrary number
116     * of arguments supplied to the JavaScript function.
117     */
118    public static void quit(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
119        final int exitCode = args.length == 0 ? 0 : ScriptRuntime.toInt32(args[0]);
120        final Log log = (Log) cx.getThreadLocal(Log.class);
121        cx.putThreadLocal(ExitCodeHolder.class, new ExitCodeHolder(exitCode));
122        if (exitCode > 0) {
123            if (log != null) {
124                log.debug("Script exit code = " + exitCode);
125            }
126        } else {
127            if (log != null) {
128                log.debug("Script exit code = " + exitCode);
129            }
130        }
131
132    }
133
134    /**
135     * The readFile reads the given file content and convert it to a string
136     * using the specified character coding or default character coding if
137     * explicit coding argument is not given.
138     * <p>
139     * Usage:
140     * <pre>
141     * readFile(filePath)
142     * readFile(filePath, charCoding)
143     * </pre>
144     * The first form converts file's context to string using the default
145     * character coding.
146     */
147    public static Object readFile(Context cx, Scriptable thisObj, Object[] args,
148                                  Function funObj)
149        throws IOException
150    {
151        if (args.length == 0) {
152            throw Context.reportRuntimeError("Bad arguments supplied to readFile()");
153        }
154        String path = ScriptRuntime.toString(args[0]);
155        String charCoding = null;
156        if (args.length >= 2) {
157            charCoding = ScriptRuntime.toString(args[1]);
158        }
159
160        final PseudoFile file = PseudoFileSystem.current().getPseudoFile(path);
161        InputStream inputStream = null;
162        try {
163            inputStream = new PseudoFileInputStream(file);
164            return charCoding == null ? IOUtil.toString(inputStream) : IOUtil.toString(inputStream, charCoding);
165        } finally {
166            IOUtil.close(inputStream);
167        }
168    }
169
170
171    public static void setExitCode(int exitCode) {
172        Context.getCurrentContext().putThreadLocal(ExitCodeHolder.class, new ExitCodeHolder(exitCode));
173    }
174
175    public static Integer getExitCode() {
176        final Context context = Context.getCurrentContext();
177        if (context != null) {
178            ExitCodeHolder result = (ExitCodeHolder) context.getThreadLocal(ExitCodeHolder.class);
179            context.putThreadLocal(GlobalFunctions.ExitCodeHolder.class, null);
180            return result == null ? null : result.getExitCode();
181        }
182        return null;
183    }
184
185    public static Scriptable createPseudoFileSystemScope(Global global, Context context) {
186        Scriptable scope = context.newObject(global);
187        scope.setPrototype(global);
188        scope.setParentScope(null);
189
190        NativeJavaTopPackage $packages = (NativeJavaTopPackage) global.get("Packages");
191        NativeJavaPackage $java = (NativeJavaPackage) $packages.get("java");
192        NativeJavaPackage $java_io = (NativeJavaPackage) $java.get("io");
193
194        ProxyNativeJavaPackage proxy$java = new ProxyNativeJavaPackage($java);
195        ProxyNativeJavaPackage proxy$java_io = new ProxyNativeJavaPackage($java_io);
196        proxy$java_io.put("File", global, get(global, "Packages." + ProxyPseudoFile.class.getName()));
197        proxy$java_io.put("FileInputStream", global,
198                get(global, "Packages." + PseudoFileInputStream.class.getName()));
199        proxy$java_io.put("FileOutputStream", global,
200                get(global, "Packages." + PseudoFileOutputStream.class.getName()));
201        proxy$java_io.put("FileReader", global,
202                get(global, "Packages." + PseudoFileReader.class.getName()));
203        proxy$java_io.put("FileWriter", global,
204                get(global, "Packages." + PseudoFileWriter.class.getName()));
205        proxy$java.put("io", global, proxy$java_io);
206        global.defineProperty("java", proxy$java, ScriptableObject.DONTENUM);
207        return scope;
208    }
209
210    public static Object get(Scriptable scope, String name) {
211        Scriptable cur = scope;
212        for (String part : StringUtils.split(name, ".")) {
213            Object next = cur.get(part, scope);
214            if (next instanceof Scriptable) {
215                cur = (Scriptable) next;
216            } else {
217                return null;
218            }
219        }
220        return cur;
221    }
222
223    private static class ExitCodeHolder {
224        private final int exitCode;
225
226        private ExitCodeHolder(int exitCode) {
227            this.exitCode = exitCode;
228        }
229
230        public int getExitCode() {
231            return exitCode;
232        }
233
234    }
235
236
237}