Package com.orientechnologies.orient.core.command.script

Source Code of com.orientechnologies.orient.core.command.script.OCommandExecutorScript

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed 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.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.orient.core.command.script;

import com.orientechnologies.common.collection.OMultiValue;
import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.command.OCommandExecutorAbstract;
import com.orientechnologies.orient.core.command.OCommandRequest;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordInternal;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordTx;
import com.orientechnologies.orient.core.exception.OCommandExecutionException;
import com.orientechnologies.orient.core.exception.OConcurrentModificationException;
import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.sql.OCommandSQLParsingException;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Executes Script Commands.
*
* @see OCommandScript
* @author Luca Garulli
*
*/
public class OCommandExecutorScript extends OCommandExecutorAbstract {
  protected OCommandScript request;

  public OCommandExecutorScript() {
  }

  @SuppressWarnings("unchecked")
  public OCommandExecutorScript parse(final OCommandRequest iRequest) {
    request = (OCommandScript) iRequest;
    return this;
  }

  public Object execute(final Map<Object, Object> iArgs) {
    return executeInContext(context, iArgs);
  }

  public Object executeInContext(final OCommandContext iContext, final Map<Object, Object> iArgs) {
    final String language = request.getLanguage();
    parserText = request.getText();

    if (language.equalsIgnoreCase("SQL"))
      // SPECIAL CASE: EXECUTE THE COMMANDS IN SEQUENCE
      return executeSQL();
    else
      return executeJsr223Script(language, iContext, iArgs);
  }

  public boolean isIdempotent() {
    return false;
  }

  protected Object executeJsr223Script(final String language, final OCommandContext iContext, final Map<Object, Object> iArgs) {
    ODatabaseRecordInternal db = ODatabaseRecordThreadLocal.INSTANCE.getIfDefined();
    if (db != null && !(db instanceof ODatabaseRecordTx))
      db = db.getUnderlying();

    final OScriptManager scriptManager = Orient.instance().getScriptManager();
    CompiledScript compiledScript = request.getCompiledScript();

    if (compiledScript == null) {
      ScriptEngine scriptEngine = scriptManager.getEngine(language);

      if (!(scriptEngine instanceof Compilable))
        throw new OCommandExecutionException("Language '" + language + "' does not support compilation");

      // COMPILE FUNCTION LIBRARY
      String lib = scriptManager.getLibrary(db, language);
      if (lib == null)
        lib = "";

      parserText = lib + parserText;

      Compilable c = (Compilable) scriptEngine;
      try {
        compiledScript = c.compile(parserText);
      } catch (ScriptException e) {
        scriptManager.getErrorMessage(e, parserText);
      }

      request.setCompiledScript(compiledScript);
    }

    final Bindings binding = scriptManager.bind(compiledScript.getEngine().getBindings(ScriptContext.ENGINE_SCOPE),
        (ODatabaseRecordTx) db, iContext, iArgs);

    try {
      final Object ob = compiledScript.eval(binding);

      return OCommandExecutorUtility.transformResult(ob);
    } catch (ScriptException e) {
      throw new OCommandScriptException("Error on execution of the script", request.getText(), e.getColumnNumber(), e);

    } finally {
      scriptManager.unbind(binding);
    }
  }

  // TODO: CREATE A REGULAR JSR223 SCRIPT IMPL
  protected Object executeSQL() {
    ODatabaseRecordInternal db = ODatabaseRecordThreadLocal.INSTANCE.getIfDefined();
    if (db != null && !(db instanceof ODatabaseRecordTx))
      db = db.getUnderlying();

    try {

      return executeSQLScript(db, parserText);

    } catch (IOException e) {
      throw new OCommandExecutionException("Error on executing command: " + parserText, e);
    }
  }

  @Override
  protected void throwSyntaxErrorException(String iText) {
    throw new OCommandScriptException("Error on execution of the script: " + iText, request.getText(), 0);
  }

  protected Object executeSQLScript(ODatabaseRecord db, final String iText) throws IOException {
    Object lastResult = null;
    int maxRetry = 1;

    context.setVariable("transactionRetries", 0);

    for (int retry = 0; retry < maxRetry; retry++) {
      int txBegunAtLine = -1;
      int txBegunAtPart = -1;
      lastResult = null;

      final BufferedReader reader = new BufferedReader(new StringReader(iText));

      int line = 0;
      int linePart = 0;
      String lastLine;
      boolean txBegun = false;

      for (; line < txBegunAtLine; ++line)
        // SKIP PREVIOUS COMMAND AND JUMP TO THE BEGIN IF ANY
        lastLine = reader.readLine();

      for (; (lastLine = reader.readLine()) != null; ++line) {
        lastLine = lastLine.trim();

        final List<String> lineParts = OStringSerializerHelper.smartSplit(lastLine, ';');

        if (line == txBegunAtLine)
          // SKIP PREVIOUS COMMAND PART AND JUMP TO THE BEGIN IF ANY
          linePart = txBegunAtPart;
        else
          linePart = 0;

        for (; linePart < lineParts.size(); ++linePart) {
          final String lastCommand = lineParts.get(linePart);

          if (OStringSerializerHelper.startsWithIgnoreCase(lastCommand, "let ")) {
            final int equalsPos = lastCommand.indexOf('=');
            final String variable = lastCommand.substring("let ".length(), equalsPos).trim();
            final String cmd = lastCommand.substring(equalsPos + 1).trim();

            lastResult = db.command(new OCommandSQL(cmd).setContext(getContext())).execute();

            // PUT THE RESULT INTO THE CONTEXT
            getContext().setVariable(variable, lastResult);
          } else if (lastCommand.equalsIgnoreCase("begin")) {

            if (txBegun)
              throw new OCommandSQLParsingException("Transaction already begun");

            txBegun = true;
            txBegunAtLine = line;
            txBegunAtPart = linePart;

            db.begin();

          } else if (lastCommand.equalsIgnoreCase("rollback")) {

            if (!txBegun)
              throw new OCommandSQLParsingException("Transaction not begun");

            db.rollback();

            txBegun = false;
            txBegunAtLine = -1;
            txBegunAtPart = -1;

          } else if (OStringSerializerHelper.startsWithIgnoreCase(lastCommand, "commit")) {
            if (txBegunAtLine < 0)
              throw new OCommandSQLParsingException("Transaction not begun");

            if (lastCommand.length() > "commit ".length()) {
              String next = lastCommand.substring("commit ".length()).trim();
              if (OStringSerializerHelper.startsWithIgnoreCase(next, "retry ")) {
                next = next.substring("retry ".length()).trim();
                maxRetry = Integer.parseInt(next) + 1;
              }
            }

            try {
              db.commit();
            } catch (OConcurrentModificationException e) {
              context.setVariable("transactionRetries", retry);
              break;
            }

            txBegun = false;
            txBegunAtLine = -1;
            txBegunAtPart = -1;

          } else if (OStringSerializerHelper.startsWithIgnoreCase(lastCommand, "sleep ")) {

            final String sleepTimeInMs = lastCommand.substring("sleep ".length()).trim();
            try {
              Thread.sleep(Integer.parseInt(sleepTimeInMs));
            } catch (InterruptedException e) {
            }

          } else if (OStringSerializerHelper.startsWithIgnoreCase(lastCommand, "return ")) {

            final String variable = lastCommand.substring("return ".length()).trim();

            if (variable.equalsIgnoreCase("NULL"))
              lastResult = null;
            else if (variable.startsWith("$"))
              lastResult = getContext().getVariable(variable);
            else if (variable.startsWith("[") && variable.endsWith("]")) {
              // ARRAY - COLLECTION
              final List<String> items = new ArrayList<String>();

              OStringSerializerHelper.getCollection(variable, 0, items);
              final List<Object> result = new ArrayList<Object>(items.size());

              for (int i = 0; i < items.size(); ++i) {
                String item = items.get(i);

                Object res;
                if (item.startsWith("$"))
                  res = getContext().getVariable(item);
                else
                  res = item;

                if (OMultiValue.isMultiValue(res) && OMultiValue.getSize(res) == 1)
                  res = OMultiValue.getFirstValue(res);

                result.add(res);
              }
              lastResult = result;
            } else if (variable.startsWith("{") && variable.endsWith("}")) {
              // MAP
              final Map<String, String> map = OStringSerializerHelper.getMap(variable);
              final Map<Object, Object> result = new HashMap<Object, Object>(map.size());

              for (Map.Entry<String, String> entry : map.entrySet()) {
                // KEY
                String stringKey = entry.getKey();
                if (stringKey == null)
                  continue;

                stringKey = stringKey.trim();

                Object key;
                if (stringKey.startsWith("$"))
                  key = getContext().getVariable(stringKey);
                else
                  key = stringKey;

                if (OMultiValue.isMultiValue(key) && OMultiValue.getSize(key) == 1)
                  key = OMultiValue.getFirstValue(key);

                // VALUE
                String stringValue = entry.getValue();
                if (stringValue == null)
                  continue;

                stringValue = stringValue.trim();

                Object value;
                if (stringValue.toString().startsWith("$"))
                  value = getContext().getVariable(stringValue);
                else
                  value = stringValue;

                if (OMultiValue.isMultiValue(value) && OMultiValue.getSize(value) == 1)
                  value = OMultiValue.getFirstValue(value);

                result.put(key, value);
              }
              lastResult = result;
            } else
              lastResult = variable;

            // END OF THE SCRIPT
            return lastResult;

          } else if (lastCommand != null && lastCommand.length() > 0)
            lastResult = db.command(new OCommandSQL(lastCommand).setContext(getContext())).execute();
        }
      }
    }

    return lastResult;
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.command.script.OCommandExecutorScript

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.