com.github.nlloyd.hornofmongo.action.MongoScriptAction.java Source code

Java tutorial

Introduction

Here is the source code for com.github.nlloyd.hornofmongo.action.MongoScriptAction.java

Source

/**
 *  Copyright (c) 2013 Nick Lloyd
 *  
 *  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 com.github.nlloyd.hornofmongo.action;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.StringReader;

import org.apache.commons.lang3.StringUtils;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;

import com.github.nlloyd.hornofmongo.MongoScope;
import com.mongodb.MongoException;

/**
 * A concrete implementation of {@link MongoAction} that wraps a JavaScript
 * script for execution in either String, Reader, or File form.
 * 
 * @author nlloyd
 * 
 */
public class MongoScriptAction extends MongoAction {

    protected String scriptName = "anon";
    protected String scriptString = null;
    protected Reader scriptReader = null;

    public MongoScriptAction(MongoScope mongoScope, String script) {
        super(mongoScope);
        this.scriptString = script;
    }

    public MongoScriptAction(MongoScope mongoScope, File script) {
        super(mongoScope);
        this.scriptName = script.getName();
        try {
            this.scriptReader = new BufferedReader(new FileReader(script));
        } catch (FileNotFoundException e) {
            throw new MongoException("Attempted to execute non-existent file " + script.getAbsolutePath(), e);
        }
    }

    public MongoScriptAction(MongoScope mongoScope, Reader script) {
        super(mongoScope);
        this.scriptReader = script;
    }

    public MongoScriptAction(MongoScope mongoScope, String name, String script) {
        super(mongoScope);
        this.scriptName = name;
        this.scriptString = script;
    }

    public MongoScriptAction(MongoScope mongoScope, String name, File script) {
        super(mongoScope);
        this.scriptName = name;
        try {
            this.scriptReader = new BufferedReader(new FileReader(script));
        } catch (FileNotFoundException e) {
            throw new MongoException("Attempted to execute non-existent file " + script.getAbsolutePath(), e);
        }
    }

    public MongoScriptAction(MongoScope mongoScope, String name, Reader script) {
        super(mongoScope);
        this.scriptName = name;
        this.scriptReader = script;
    }

    /**
     * Uses the provided context to execute either a String script,
     * 
     * @see org.mozilla.javascript.ContextAction#run(org.mozilla.javascript.Context)
     */
    @Override
    public Object doRun(Context cx) {
        Object result = Undefined.instance;
        String script;
        if (StringUtils.isNotBlank(scriptString))
            script = scriptString;
        else {
            try {
                script = readFully(scriptReader);
            } catch (IOException e) {
                throw new MongoException("IOException when executing a script in Reader form.", e);
            }
        }

        // this could be a command like "use", "show", or "help" which must be a
        // one-liner without a semi-colon line terminator
        boolean wasCmd = false;
        if (isOneLine(script)) {
            script = script.trim();

            // special handling for: exit[;] and cls
            if (script.matches("^exit;?$")) {
                MongoScope.quit(cx, mongoScope, null, null);
                return result;
            } else if (script.equals("cls")) {
                MongoScope.clear(cx, mongoScope, null, null);
                return result;
            }

            String cmd = script;
            if (cmd.indexOf(' ') > 0)
                cmd = script.substring(0, cmd.indexOf(' '));
            if (cmd.indexOf('"') == -1) {
                StringBuilder cmdCheck = new StringBuilder();
                cmdCheck.append("__iscmd__ = shellHelper[\"");
                cmdCheck.append(cmd);
                cmdCheck.append("\"];");
                cx.evaluateString(mongoScope, cmdCheck.toString(), "(shellhelp1)", 0, null);
                if (Context.toBoolean(ScriptableObject.getProperty(mongoScope, "__iscmd__"))) {
                    StringBuilder cmdScript = new StringBuilder();
                    cmdScript.append("shellHelper( \"");
                    cmdScript.append(cmd);
                    cmdScript.append("\" , \"");
                    cmdScript.append(script.substring(cmd.length()));
                    cmdScript.append("\");");
                    try {
                        cx.evaluateString(mongoScope, cmdScript.toString(), "(shellhelp2)", 0, null);
                    } finally {
                        wasCmd = true;
                    }
                }
            }
        }

        if (!wasCmd) {
            result = cx.evaluateString(mongoScope, script, scriptName, 0, null);
        }

        return result;
    }

    /**
     * Borrowed from Rhino's Parser class.
     * 
     * @param reader
     * @return
     * @throws IOException
     */
    private String readFully(Reader reader) throws IOException {
        BufferedReader in = new BufferedReader(reader);
        try {
            char[] cbuf = new char[1024];
            StringBuilder sb = new StringBuilder(1024);
            int bytes_read;
            while ((bytes_read = in.read(cbuf, 0, 1024)) != -1) {
                sb.append(cbuf, 0, bytes_read);
            }
            return sb.toString();
        } finally {
            in.close();
        }
    }

    private boolean isOneLine(final String script) {
        LineNumberReader lnr = new LineNumberReader(new StringReader(script));
        try {
            @SuppressWarnings("unused")
            int lastRead;
            while ((lastRead = lnr.read()) != -1) {
            }
        } catch (IOException e) {
        }
        // 0 lines just means no line terminator in the string
        return lnr.getLineNumber() <= 1;
    }

}