org.apache.manifoldcf.scriptengine.ScriptParser.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.manifoldcf.scriptengine.ScriptParser.java

Source

/* $Id$ */

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.manifoldcf.scriptengine;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.config.SocketConfig;
import org.apache.http.HttpStatus;
import org.apache.http.HttpException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.ParseException;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.io.*;
import java.nio.charset.Charset;

/** Class to parse various syntactical parts of a script and execute them.
*/
public class ScriptParser {
    /** The connection manager. */
    protected HttpClientConnectionManager connectionManager = null;

    /** The client instance */
    protected HttpClient httpClient = null;

    /** The lock for the httpclient factory */
    protected Integer httpClientLock = new Integer(0);

    /** The current variable context. */
    protected Map<String, ContextVariableReference> context = new HashMap<String, ContextVariableReference>();

    /** A table of commands that we know how to deal with. */
    protected Map<String, Command> commands = new HashMap<String, Command>();

    /** A table of "new" operations that we know how to deal with. */
    protected Map<String, NewOperation> newOperations = new HashMap<String, NewOperation>();

    public ScriptParser() {
    }

    /** Add a command.
    *@param commandName is the name of the command.
    *@param command is the command instance.
    */
    public void addCommand(String commandName, Command command) {
        commands.put(commandName, command);
    }

    /** Add a "new" operation.
    *@param operationName is the name of the operation.
    *@param operation is the operation to create.
    */
    public void addNewOperation(String operationName, NewOperation operation) {
        newOperations.put(operationName, operation);
    }

    /** Add a variable.
    */
    public void addVariable(String variableName, Variable v) throws ScriptException {
        ContextVariableReference cvr = new ContextVariableReference();
        cvr.setReference(v);
        context.put(variableName, cvr);
    }

    /** Execute script. */
    public void execute(TokenStream currentStream) throws ScriptException {
        if (parseStatements(currentStream))
            localError(currentStream, "Break command must be inside a loop");
        Token t = currentStream.peek();
        if (t != null)
            localError(currentStream, "Characters after end of script");
    }

    // Statement return codes
    protected static final int STATEMENT_NOTME = 0;
    protected static final int STATEMENT_ISME = 1;
    protected static final int STATEMENT_BREAK = 2;

    /** Parse and execute multiple statements.
    *@param currentStream is the token stream to parse.
    *@return true for a break signal.
    */
    public boolean parseStatements(TokenStream currentStream) throws ScriptException {
        boolean breakSignal = false;
        while (true) {
            if (breakSignal) {
                if (skipStatement(currentStream) == false)
                    break;
            } else {
                int result = parseStatement(currentStream);
                if (result == STATEMENT_NOTME)
                    break;
                if (result == STATEMENT_BREAK)
                    breakSignal = true;
            }
        }
        return breakSignal;
    }

    /** Skip multiple statements.
    *@param currentStream is the token stream to parse.
    */
    public void skipStatements(TokenStream currentStream) throws ScriptException {
        while (true) {
            if (skipStatement(currentStream) == false)
                break;
        }
    }

    /** Parse a single statement.
    *@param currentStream is the current token stream.
    *@return a signal indicating either NOTME, ISME, or BREAK.
    */
    protected int parseStatement(TokenStream currentStream) throws ScriptException {
        int rval = STATEMENT_ISME;

        Token command = currentStream.peek();
        if (command == null)
            return STATEMENT_NOTME;
        String commandString = command.getToken();
        if (commandString == null)
            return STATEMENT_NOTME;

        // Let's see if we know about this command.
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null) {
            Command c = commands.get(t.getToken());
            if (c != null) {
                // We do know about it.  So skip the command name and call the parse method.
                currentStream.skip();
                if (c.parseAndExecute(this, currentStream))
                    rval = STATEMENT_BREAK;
                else
                    rval = STATEMENT_ISME;
            } else
                return STATEMENT_NOTME;
        } else
            return STATEMENT_NOTME;

        Token semi = currentStream.peek();
        if (semi == null || semi.getPunctuation() == null || !semi.getPunctuation().equals(";"))
            syntaxError(currentStream, "Missing semicolon");
        currentStream.skip();
        return rval;
    }

    /** Skip a single statement.
    *@param currentStream is the current token stream.
    *@return true if a statement was detected, false otherwise.
    */
    protected boolean skipStatement(TokenStream currentStream) throws ScriptException {
        Token command = currentStream.peek();
        if (command == null)
            return false;
        String commandString = command.getToken();
        if (commandString == null)
            return false;

        // Let's see if we know about this command.
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null) {
            Command c = commands.get(t.getToken());
            if (c != null) {
                // We do know about it.  So skip the command name and call the parse method.
                currentStream.skip();
                c.parseAndSkip(this, currentStream);
                // Fall through
            } else
                return false;
        } else
            return false;

        Token semi = currentStream.peek();
        if (semi == null || semi.getPunctuation() == null || !semi.getPunctuation().equals(";"))
            syntaxError(currentStream, "Missing semicolon");
        currentStream.skip();
        return true;
    }

    /** Evaluate an expression.
    *@param currentStream is the token stream to parse.
    *@return a VariableReference object if an expression was detected, null otherwise.
    */
    public VariableReference evaluateExpression(TokenStream currentStream) throws ScriptException {
        // Look for pipe operations
        VariableReference vr = evaluateExpression_1(currentStream);
        if (vr == null)
            return null;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("||")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_1(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '||'");
                vr = resolveMustExist(currentStream, vr).doublePipe(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("|")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_1(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '|'");
                vr = resolveMustExist(currentStream, vr).pipe(v.resolve());
            } else
                break;
        }
        return vr;
    }

    /** Skip an expression.
    *@param currentStream is the token stream to parse.
    *@return true if an expression was detected, false otherwise.
    */
    public boolean skipExpression(TokenStream currentStream) throws ScriptException {
        // Look for pipe operations
        if (skipExpression_1(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("||")) {
                currentStream.skip();
                if (skipExpression_1(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '||'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("|")) {
                currentStream.skip();
                if (skipExpression_1(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '|'");
            } else
                break;
        }
        return true;
    }

    protected VariableReference evaluateExpression_1(TokenStream currentStream) throws ScriptException {
        // Look for ampersand operations
        VariableReference vr = evaluateExpression_2(currentStream);
        if (vr == null)
            return null;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("&&")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_2(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '&&'");
                vr = resolveMustExist(currentStream, vr).doubleAmpersand(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("&")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_2(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '&'");
                vr = resolveMustExist(currentStream, vr).ampersand(v.resolve());
            } else
                break;
        }
        return vr;
    }

    protected boolean skipExpression_1(TokenStream currentStream) throws ScriptException {
        // Look for ampersand operations
        if (skipExpression_2(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("&&")) {
                currentStream.skip();
                if (skipExpression_2(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '&&'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("&")) {
                currentStream.skip();
                if (skipExpression_2(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '&'");
            } else
                break;
        }
        return true;
    }

    protected VariableReference evaluateExpression_2(TokenStream currentStream) throws ScriptException {
        // Look for exclamation operations
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("!")) {
            currentStream.skip();
            VariableReference v = evaluateExpression_2(currentStream);
            if (v == null)
                syntaxError(currentStream, "Missing expression after '!'");
            return resolveMustExist(currentStream, v).unaryExclamation();
        }
        return evaluateExpression_3(currentStream);
    }

    protected boolean skipExpression_2(TokenStream currentStream) throws ScriptException {
        // Look for exclamation operations
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("!")) {
            currentStream.skip();
            if (skipExpression_2(currentStream) == false)
                syntaxError(currentStream, "Missing expression after '!'");
            return true;
        }
        return skipExpression_3(currentStream);
    }

    protected VariableReference evaluateExpression_3(TokenStream currentStream) throws ScriptException {
        // Look for comparison operations
        VariableReference vr = evaluateExpression_4(currentStream);
        if (vr == null)
            return null;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("==")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '=='");
                vr = resolveMustExist(currentStream, vr).doubleEquals(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("!=")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '!='");
                vr = resolveMustExist(currentStream, vr).exclamationEquals(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '<'");
                vr = resolveMustExist(currentStream, vr).lesserAngle(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '>'");
                vr = resolveMustExist(currentStream, vr).greaterAngle(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<=")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '<='");
                vr = resolveMustExist(currentStream, vr).lesserAngleEquals(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">=")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_4(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '>='");
                vr = resolveMustExist(currentStream, vr).greaterAngleEquals(v.resolve());
            } else
                break;
        }
        return vr;
    }

    protected boolean skipExpression_3(TokenStream currentStream) throws ScriptException {
        // Look for comparison operations
        if (skipExpression_4(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("==")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '=='");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("!=")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '!='");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '<'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '>'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<=")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '<='");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">=")) {
                currentStream.skip();
                if (skipExpression_4(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '>='");
            } else
                break;
        }
        return true;
    }

    protected VariableReference evaluateExpression_4(TokenStream currentStream) throws ScriptException {
        // Look for +/- operations
        VariableReference vr = evaluateExpression_5(currentStream);
        if (vr == null)
            return null;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("+")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_5(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '+'");
                vr = resolveMustExist(currentStream, vr).plus(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("-")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_5(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '-'");
                vr = resolveMustExist(currentStream, vr).minus(v.resolve());
            } else
                break;
        }
        return vr;
    }

    protected boolean skipExpression_4(TokenStream currentStream) throws ScriptException {
        // Look for +/- operations
        if (skipExpression_5(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("+")) {
                currentStream.skip();
                if (skipExpression_5(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '+'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("-")) {
                currentStream.skip();
                if (skipExpression_5(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '-'");
            } else
                break;
        }
        return true;
    }

    protected VariableReference evaluateExpression_5(TokenStream currentStream) throws ScriptException {
        // Look for *// operations
        VariableReference vr = evaluateExpression_6(currentStream);
        if (vr == null)
            return null;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("*")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_6(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '*'");
                vr = resolveMustExist(currentStream, vr).asterisk(v.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("/")) {
                currentStream.skip();
                VariableReference v = evaluateExpression_6(currentStream);
                if (v == null)
                    syntaxError(currentStream, "Missing expression after '/'");
                vr = resolveMustExist(currentStream, vr).slash(v.resolve());
            } else
                break;
        }
        return vr;
    }

    protected boolean skipExpression_5(TokenStream currentStream) throws ScriptException {
        // Look for *// operations
        if (skipExpression_6(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("*")) {
                currentStream.skip();
                if (skipExpression_6(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '*'");
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("/")) {
                currentStream.skip();
                if (skipExpression_6(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '/'");
            } else
                break;
        }
        return true;
    }

    protected VariableReference evaluateExpression_6(TokenStream currentStream) throws ScriptException {
        // Look for - operations
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("-")) {
            currentStream.skip();
            VariableReference v = evaluateExpression_6(currentStream);
            if (v == null)
                syntaxError(currentStream, "Missing expression after '-'");
            return resolveMustExist(currentStream, v).unaryMinus();
        }
        return parseVariableReference(currentStream);
    }

    protected boolean skipExpression_6(TokenStream currentStream) throws ScriptException {
        // Look for - operations
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("-")) {
            currentStream.skip();
            if (skipExpression_6(currentStream) == false)
                syntaxError(currentStream, "Missing expression after '-'");
            return true;
        }
        return skipVariableReference(currentStream);
    }

    protected VariableReference parseVariableReference(TokenStream currentStream) throws ScriptException {
        // variable_reference -> 'isnull' variable_reference
        // variable_reference -> variable_reference_0
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null && t.getToken().equals("isnull")) {
            currentStream.skip();
            VariableReference reference = parseVariableReference(currentStream);
            if (reference == null)
                syntaxError(currentStream, "Missing variable reference");
            return new VariableBoolean(reference.isNull());
        } else
            return parseVariableReference_0(currentStream);
    }

    protected boolean skipVariableReference(TokenStream currentStream) throws ScriptException {
        // variable_reference -> 'isnull' variable_reference
        // variable_reference -> variable_reference_0
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null && t.getToken().equals("isnull")) {
            currentStream.skip();
            if (skipVariableReference(currentStream) == false)
                syntaxError(currentStream, "Missing variable reference");
            return true;
        } else
            return skipVariableReference_0(currentStream);
    }

    protected VariableReference parseVariableReference_0(TokenStream currentStream) throws ScriptException {
        // variable_reference -> variable_reference '[' expression ']'
        // variable_reference -> variable_reference.property_name
        // variable_reference -> variable_reference_1

        VariableReference vr = parseVariableReference_1(currentStream);
        if (vr == null)
            return vr;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("[")) {
                currentStream.skip();
                VariableReference expression = evaluateExpression(currentStream);
                if (expression == null)
                    syntaxError(currentStream, "Missing expression after '['");
                Variable v = resolveMustExist(currentStream, vr);
                t = currentStream.peek();
                if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("]"))
                    syntaxError(currentStream, "Missing ']'");
                currentStream.skip();
                vr = v.getIndexed(expression.resolve());
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(".")) {
                currentStream.skip();
                t = currentStream.peek();
                if (t == null || t.getToken() == null)
                    syntaxError(currentStream, "Need attribute name");
                Variable v = resolveMustExist(currentStream, vr);
                currentStream.skip();
                vr = v.getAttribute(t.getToken());
            } else
                break;
        }

        return vr;
    }

    protected VariableReference parseVariableReference_1(TokenStream currentStream) throws ScriptException {
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("(")) {
            currentStream.skip();
            VariableReference rval = evaluateExpression(currentStream);
            if (rval == null)
                syntaxError(currentStream, "Missing expression after '('");
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(")"))
                syntaxError(currentStream, "Missing ')'");
            currentStream.skip();
            return rval;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("[")) {
            currentStream.skip();
            VariableArray va = new VariableArray();
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("]")) {
                while (true) {
                    VariableReference vr = evaluateExpression(currentStream);
                    if (vr == null)
                        syntaxError(currentStream, "Missing expression in array initializer");
                    va.insertAt(vr.resolve(), null);
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("]"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return va;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("{")) {
            currentStream.skip();
            VariableConfiguration va = new VariableConfiguration();
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("}")) {
                while (true) {
                    VariableReference vr = evaluateExpression(currentStream);
                    if (vr == null)
                        syntaxError(currentStream, "Missing expression in configuration object initializer");
                    va.insertAt(vr.resolve(), null);
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("}"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return va;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<<")) {
            currentStream.skip();
            // Parse the node type
            VariableReference nodeTypeRef = evaluateExpression(currentStream);
            if (nodeTypeRef == null)
                syntaxError(currentStream, "Missing node type");
            Variable nodeType = resolveMustExist(currentStream, nodeTypeRef);
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":"))
                syntaxError(currentStream, "Missing ':'");
            currentStream.skip();

            VariableConfigurationNode va = new VariableConfigurationNode(nodeType.getStringValue());

            // Parse the node value
            VariableReference nodeValueRef = evaluateExpression(currentStream);
            if (nodeValueRef == null)
                syntaxError(currentStream, "Missing node value");
            Variable nodeValue = resolveMustExist(currentStream, nodeValueRef);
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":"))
                syntaxError(currentStream, "Missing ':'");
            currentStream.skip();

            va.getAttribute(Variable.ATTRIBUTE_VALUE).setReference(nodeValue);

            // Parse the attributes
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":")) {
                while (true) {
                    VariableReference vr = evaluateExpression(currentStream);
                    if (vr == null)
                        syntaxError(currentStream,
                                "Missing name expression in configurationnode attribute initializer");
                    Variable attrName = resolveMustExist(currentStream, vr);
                    t = currentStream.peek();
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("="))
                        syntaxError(currentStream, "Missing '='");
                    currentStream.skip();
                    vr = evaluateExpression(currentStream);
                    if (vr == null)
                        syntaxError(currentStream,
                                "Missing value expression in configurationnode attribute initializer");
                    va.getAttribute(attrName.getStringValue()).setReference(vr.resolve());
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(":"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();

            // Parse the children
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(">>")) {
                while (true) {
                    VariableReference vr = evaluateExpression(currentStream);
                    if (vr == null)
                        syntaxError(currentStream, "Missing expression in configurationnode object initializer");
                    va.insertAt(vr.resolve(), null);
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">>"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return va;
        }

        return parseVariableReference_2(currentStream);
    }

    protected VariableReference parseVariableReference_2(TokenStream currentStream) throws ScriptException {
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null) {
            currentStream.skip();
            String variableName = t.getToken();
            if (variableName.equals("true"))
                return new VariableBoolean(true);
            else if (variableName.equals("false"))
                return new VariableBoolean(false);
            else if (variableName.equals("null"))
                return new NullVariableReference();
            else if (variableName.equals("new")) {
                // Parse the new operation name
                t = currentStream.peek();
                if (t == null || t.getToken() == null)
                    syntaxError(currentStream, "Missing 'new' operation name");
                String operationName = t.getToken();
                // Look up operation
                NewOperation newOperation = newOperations.get(operationName);
                if (newOperation == null)
                    syntaxError(currentStream, "New operation type is unknown");
                currentStream.skip();
                return newOperation.parseAndCreate(this, currentStream);
            } else {
                // Look up variable reference in current context
                ContextVariableReference x = context.get(variableName);
                if (x == null) {
                    x = new ContextVariableReference();
                    context.put(variableName, x);
                }
                return x;
            }
        } else if (t != null && t.getString() != null) {
            currentStream.skip();
            return new VariableString(t.getString());
        } else if (t != null && t.getFloat() != null) {
            currentStream.skip();
            return new VariableFloat(new Double(t.getFloat()).doubleValue());
        } else if (t != null && t.getInteger() != null) {
            currentStream.skip();
            return new VariableInt(Integer.parseInt(t.getInteger()));
        } else
            return null;
    }

    protected boolean skipVariableReference_0(TokenStream currentStream) throws ScriptException {
        if (skipVariableReference_1(currentStream) == false)
            return false;
        while (true) {
            Token t = currentStream.peek();
            if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("[")) {
                currentStream.skip();
                if (skipExpression(currentStream) == false)
                    syntaxError(currentStream, "Missing expression after '['");
                t = currentStream.peek();
                if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("]"))
                    syntaxError(currentStream, "Missing ']'");
                currentStream.skip();
            } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(".")) {
                currentStream.skip();
                t = currentStream.peek();
                if (t == null || t.getToken() == null)
                    syntaxError(currentStream, "Need property name");
                currentStream.skip();
            } else
                break;
        }

        return true;
    }

    protected boolean skipVariableReference_1(TokenStream currentStream) throws ScriptException {
        Token t = currentStream.peek();
        if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("(")) {
            currentStream.skip();
            if (skipExpression(currentStream) == false)
                syntaxError(currentStream, "Missing expression after '('");
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(")"))
                syntaxError(currentStream, "Missing ')'");
            currentStream.skip();
            return true;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("[")) {
            currentStream.skip();
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("]")) {
                while (true) {
                    if (skipExpression(currentStream) == false)
                        syntaxError(currentStream, "Missing expression in array initializer");
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("]"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return true;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("{")) {
            currentStream.skip();
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("}")) {
                while (true) {
                    if (skipExpression(currentStream) == false)
                        syntaxError(currentStream, "Missing expression in configuration object initializer");
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("}"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return true;
        } else if (t != null && t.getPunctuation() != null && t.getPunctuation().equals("<<")) {
            currentStream.skip();
            // Parse the node type
            if (skipExpression(currentStream) == false)
                syntaxError(currentStream, "Missing node type");
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":"))
                syntaxError(currentStream, "Missing ':'");
            currentStream.skip();

            // Parse the node value
            if (skipExpression(currentStream) == false)
                syntaxError(currentStream, "Missing node value");
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":"))
                syntaxError(currentStream, "Missing ':'");
            currentStream.skip();

            // Parse the attributes
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(":")) {
                while (true) {
                    if (skipExpression(currentStream) == false)
                        syntaxError(currentStream,
                                "Missing name expression in configurationnode attribute initializer");
                    t = currentStream.peek();
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals("="))
                        syntaxError(currentStream, "Missing '='");
                    currentStream.skip();
                    if (skipExpression(currentStream) == false)
                        syntaxError(currentStream,
                                "Missing value expression in configurationnode attribute initializer");
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(":"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();

            // Parse the children
            t = currentStream.peek();
            if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(">>")) {
                while (true) {
                    if (skipExpression(currentStream) == false)
                        syntaxError(currentStream, "Missing expression in configurationnode object initializer");
                    t = currentStream.peek();
                    if (t != null && t.getPunctuation() != null && t.getPunctuation().equals(">>"))
                        break;
                    if (t == null || t.getPunctuation() == null || !t.getPunctuation().equals(","))
                        syntaxError(currentStream, "Missing ','");
                    currentStream.skip();
                }
            }
            currentStream.skip();
            return true;
        }

        return skipVariableReference_2(currentStream);
    }

    protected boolean skipVariableReference_2(TokenStream currentStream) throws ScriptException {
        Token t = currentStream.peek();
        if (t != null && t.getToken() != null) {
            currentStream.skip();
            if (t.getToken().equals("new")) {
                // Parse the new operation name
                t = currentStream.peek();
                if (t == null || t.getToken() == null)
                    syntaxError(currentStream, "Missing 'new' operation name");
                String operationName = t.getToken();
                // Look up operation
                NewOperation newOperation = newOperations.get(operationName);
                if (newOperation == null)
                    syntaxError(currentStream, "New operation type is unknown");
                currentStream.skip();
                newOperation.parseAndSkip(this, currentStream);
            }
            return true;
        } else if (t != null && t.getString() != null) {
            currentStream.skip();
            return true;
        } else if (t != null && t.getFloat() != null) {
            currentStream.skip();
            return true;
        } else if (t != null && t.getInteger() != null) {
            currentStream.skip();
            return true;
        }

        return false;
    }

    public static void syntaxError(TokenStream currentStream, String message) throws ScriptException {
        localError(currentStream, "Syntax error: " + message);
    }

    public static Variable resolveMustExist(TokenStream currentStream, VariableReference vr)
            throws ScriptException {
        Variable v = vr.resolve();
        if (v == null)
            localError(currentStream, "Expression cannot be null");
        return v;
    }

    public static void localError(TokenStream currentStream, String message) throws ScriptException {
        Token t = currentStream.peek();
        if (t == null)
            throw new ScriptException(message + ", at end of file");
        else
            t.throwException(message + ": " + t);
    }

    public static String convertToString(HttpResponse httpResponse) throws IOException {
        HttpEntity entity = httpResponse.getEntity();
        if (entity != null) {
            InputStream is = entity.getContent();
            try {
                Charset charSet;
                try {
                    ContentType ct = ContentType.get(entity);
                    if (ct == null)
                        charSet = StandardCharsets.UTF_8;
                    else
                        charSet = ct.getCharset();
                } catch (ParseException e) {
                    charSet = StandardCharsets.UTF_8;
                }
                char[] buffer = new char[65536];
                Reader r = new InputStreamReader(is, charSet);
                Writer w = new StringWriter();
                try {
                    while (true) {
                        int amt = r.read(buffer);
                        if (amt == -1)
                            break;
                        w.write(buffer, 0, amt);
                    }
                } finally {
                    w.flush();
                }
                return w.toString();
            } finally {
                is.close();
            }
        }
        return "";
    }

    public HttpClient getHttpClient() {
        synchronized (httpClientLock) {
            if (httpClient == null) {
                int socketTimeout = 900000;
                int connectionTimeout = 300000;

                connectionManager = new PoolingHttpClientConnectionManager();

                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

                RequestConfig.Builder requestBuilder = RequestConfig.custom().setCircularRedirectsAllowed(true)
                        .setSocketTimeout(socketTimeout).setStaleConnectionCheckEnabled(false)
                        .setExpectContinueEnabled(true).setConnectTimeout(connectionTimeout)
                        .setConnectionRequestTimeout(socketTimeout);

                httpClient = HttpClients.custom().setConnectionManager(connectionManager).setMaxConnTotal(1)
                        .disableAutomaticRetries().setDefaultRequestConfig(requestBuilder.build())
                        .setDefaultSocketConfig(
                                SocketConfig.custom().setTcpNoDelay(true).setSoTimeout(socketTimeout).build())
                        .setDefaultCredentialsProvider(credentialsProvider)
                        //.setSSLSocketFactory(myFactory)
                        .setRequestExecutor(new HttpRequestExecutor(socketTimeout))
                        .setRedirectStrategy(new DefaultRedirectStrategy()).build();

            }
        }
        return httpClient;
    }

    public static void main(String[] argv) {
        // Usage: ScriptParser [<filename> [arg1 [arg2 ...]]

        ScriptParser sp = new ScriptParser();

        // Initialize script parser with the appropriate commands.
        sp.addCommand("break", new BreakCommand());
        sp.addCommand("print", new PrintCommand());
        sp.addCommand("if", new IfCommand());
        sp.addCommand("while", new WhileCommand());
        sp.addCommand("set", new SetCommand());
        sp.addCommand("insert", new InsertCommand());
        sp.addCommand("remove", new RemoveCommand());
        sp.addCommand("error", new ErrorCommand());
        sp.addCommand("wait", new WaitCommand());

        sp.addCommand("GET", new GETCommand());
        sp.addCommand("PUT", new PUTCommand());
        sp.addCommand("DELETE", new DELETECommand());
        sp.addCommand("POST", new POSTCommand());

        // Add the new operations we need
        sp.addNewOperation("configuration", new NewConfiguration());
        sp.addNewOperation("configurationnode", new NewConfigurationNode());
        sp.addNewOperation("url", new NewURL());
        sp.addNewOperation("connectionname", new NewConnectionName());
        sp.addNewOperation("array", new NewArray());
        sp.addNewOperation("dictionary", new NewDictionary());
        sp.addNewOperation("queryarg", new NewQueryArgument());

        try {
            Reader reader;
            if (argv.length >= 1) {
                File inputFile = new File(argv[0]);
                reader = new InputStreamReader(new FileInputStream(inputFile), StandardCharsets.UTF_8);
                VariableArray va = new VariableArray();
                int i = 0;
                while (i < argv.length - 1) {
                    String arg = argv[i + 1];
                    va.insertAt(new VariableString(arg), null);
                    i++;
                }
                sp.addVariable("__args__", va);
                TokenStream ts = new BasicTokenStream(reader);
                sp.execute(ts);
            } else {
                reader = new InputStreamReader(System.in);

                while (true) {
                    TokenStream ts = new BasicTokenStream(reader);
                    try {
                        sp.execute(ts);
                        break;
                    } catch (ScriptException e) {
                        System.out.println("Error: " + e.getMessage());
                        if (ts.peek() == null)
                            break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
            System.exit(2);
        }
    }

}