All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.crsh.shell.impl.command.CRaSHSession Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 eXo Platform SAS.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.crsh.shell.impl.command;

import org.crsh.cli.impl.completion.CompletionMatch;
import org.crsh.command.CommandCreationException;
import org.crsh.command.RuntimeContext;
import org.crsh.command.CommandInvoker;
import org.crsh.command.ScriptException;
import org.crsh.command.ShellCommand;
import org.crsh.plugin.PluginContext;
import org.crsh.repl.REPL;
import org.crsh.shell.ErrorType;
import org.crsh.shell.Shell;
import org.crsh.shell.ShellProcess;
import org.crsh.shell.ShellProcessContext;
import org.crsh.shell.ShellResponse;
import org.crsh.repl.EvalResponse;
import org.crsh.lang.script.ScriptREPL;
import org.crsh.repl.REPLSession;
import org.crsh.text.Text;
import org.crsh.util.Safe;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CRaSHSession extends HashMap implements Shell, Closeable, RuntimeContext, REPLSession {

  /** . */
  static final Logger log = Logger.getLogger(CRaSHSession.class.getName());

  /** . */
  static final Logger accessLog = Logger.getLogger("org.crsh.shell.access");

  /** . */
  public final CRaSH crash;

  /** . */
  final Principal user;

  /** . */
  private REPL repl = ScriptREPL.getInstance();

  CRaSHSession(final CRaSH crash, Principal user) {
    // Set variable available to all scripts
    put("crash", crash);

    //
    this.crash = crash;
    this.user = user;

    //
    ClassLoader previous = setCRaSHLoader();
    try {
      for (CommandManager manager : crash.activeManagers.values()) {
        manager.init(this);
      }
    }
    finally {
      setPreviousLoader(previous);
    }
  }

  /**
   * Returns the current repl of this session.
   *
   * @return the current repl
   */
  public REPL getRepl() {
    return repl;
  }

  /**
   * Set the current repl of this session.
   *
   * @param repl the new repl
   * @throws NullPointerException if the repl is null
   */
  public void setRepl(REPL repl) throws NullPointerException {
    if (repl == null) {
      throw new NullPointerException("No null repl accepted");
    }
    this.repl = repl;
  }

  public Iterable getCommandNames() {
    return crash.getCommandNames();
  }

  public ShellCommand getCommand(String name) throws CommandCreationException {
    return crash.getCommand(name);
  }

  public PluginContext getContext() {
    return crash.context;
  }

  public Map getSession() {
    return this;
  }

  public Map getAttributes() {
    return crash.context.getAttributes();
  }

  public void close() {
    ClassLoader previous = setCRaSHLoader();
    try {
      for (CommandManager manager : crash.activeManagers.values()) {
        manager.destroy(this);
      }
    }
    finally {
      setPreviousLoader(previous);
    }
  }

  // Shell implementation **********************************************************************************************

  public String getWelcome() {
    ClassLoader previous = setCRaSHLoader();
    try {
      CommandManager groovy = crash.activeManagers.get("groovy");
      if (groovy != null) {
        return groovy.doCallBack(this, "welcome", "");
      } else {
        return "";
      }
    }
    finally {
      setPreviousLoader(previous);
    }
  }

  public String getPrompt() {
    ClassLoader previous = setCRaSHLoader();
    try {
      CommandManager groovy = crash.activeManagers.get("groovy");
      if (groovy != null) {
        return groovy.doCallBack(this, "prompt", "% ");
      } else {
        return "% ";
      }
    }
    finally {
      setPreviousLoader(previous);
    }
  }

  public ShellProcess createProcess(String request) {
    log.log(Level.FINE, "Invoking request " + request);
    String trimmedRequest = request.trim();
    final StringBuilder msg = new StringBuilder();
    final ShellResponse response;
    if ("bye".equals(trimmedRequest) || "exit".equals(trimmedRequest)) {
      response = ShellResponse.close();
    } else {
      EvalResponse r = repl.eval(this, request);
      if (r instanceof EvalResponse.Response) {
        EvalResponse.Response rr = (EvalResponse.Response)r;
        response = rr.response;
      } else {
        final CommandInvoker pipeLine = ((EvalResponse.Invoke)r).invoker;
        return new CRaSHProcess(this, request) {

          @Override
          ShellResponse doInvoke(final ShellProcessContext context) throws InterruptedException {
            CRaSHProcessContext invocationContext = new CRaSHProcessContext(CRaSHSession.this, context);
            try {
              pipeLine.invoke(invocationContext);
              return ShellResponse.ok();
            }
            catch (ScriptException e) {
              return build(e);
            } catch (Throwable t) {
              return build(t);
            } finally {
              Safe.close(invocationContext);
            }
          }

          private ShellResponse.Error build(Throwable throwable) {
            ErrorType errorType;
            if (throwable instanceof ScriptException || throwable instanceof UndeclaredThrowableException) {
              errorType = ErrorType.EVALUATION;
              Throwable cause = throwable.getCause();
              if (cause != null) {
                throwable = cause;
              }
            } else {
              errorType = ErrorType.INTERNAL;
            }
            String result;
            String msg = throwable.getMessage();
            if (throwable instanceof ScriptException) {
              if (msg == null) {
                result = request + ": failed";
              } else {
                result = request + ": " + msg;
              }
              return ShellResponse.error(errorType, result, throwable);
            } else {
              if (msg == null) {
                msg = throwable.getClass().getSimpleName();
              }
              if (throwable instanceof RuntimeException) {
                result = request + ": exception: " + msg;
              } else if (throwable instanceof Exception) {
                result = request + ": exception: " + msg;
              } else if (throwable instanceof java.lang.Error) {
                result = request + ": error: " + msg;
              } else {
                result = request + ": unexpected throwable: " + msg;
              }
              return ShellResponse.error(errorType, result, throwable);
            }
          }
        };
      }
    }
    return new CRaSHProcess(this, request) {
      @Override
      ShellResponse doInvoke(ShellProcessContext context) throws InterruptedException {
        if (msg.length() > 0) {
          try {
            context.write(Text.create(msg));
          }
          catch (IOException ignore) {
          }
        }
        return response;
      }
    };
  }

  /**
   * For now basic implementation
   */
  public CompletionMatch complete(final String prefix) {
    ClassLoader previous = setCRaSHLoader();
    try {
      return repl.complete(this, prefix);
    }
    finally {
      setPreviousLoader(previous);
    }
  }

  ClassLoader setCRaSHLoader() {
    Thread thread = Thread.currentThread();
    ClassLoader previous = thread.getContextClassLoader();
    thread.setContextClassLoader(crash.context.getLoader());
    return previous;
  }

  void setPreviousLoader(ClassLoader previous) {
    Thread.currentThread().setContextClassLoader(previous);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy