Package org.jboss.fresh.shell.impl

Source Code of org.jboss.fresh.shell.impl.ShellImpl

package org.jboss.fresh.shell.impl;

import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import org.jboss.fresh.events.EventBroadcaster;
import org.jboss.fresh.events.EventCentral;
import org.jboss.fresh.vfs.FileInfo;
import org.jboss.fresh.vfs.FileName;
import org.jboss.fresh.vfs.UserCtx;
import org.jboss.fresh.vfs.VFS;
import org.jboss.fresh.vfs.impl.LazyVFSOutputStream;
import org.jboss.fresh.vfs.impl.SecureVFS;
import org.jboss.fresh.vfs.impl.VFSInputStream;
import org.jboss.fresh.ctx.Context;
import org.jboss.fresh.io.Buffer;
import org.jboss.fresh.io.BufferImpl;
import org.jboss.fresh.io.BufferObjectReader;
import org.jboss.fresh.io.InBuffer;
import org.jboss.fresh.io.InputStreamBuffer;
import org.jboss.fresh.io.MemFileBufferImpl;
import org.jboss.fresh.io.MultiBufferObjectReader;
import org.jboss.fresh.io.NullBuffer;
import org.jboss.fresh.io.OutBuffer;
import org.jboss.fresh.io.OutputStreamBuffer;
import org.jboss.fresh.registry.RegistryContext;
import org.jboss.fresh.shell.EnvProperties;
import org.jboss.fresh.shell.Executable;
import org.jboss.fresh.shell.NoSuchProcessException;
import org.jboss.fresh.shell.ProcessInfo;
import org.jboss.fresh.shell.SessionTimeoutException;
import org.jboss.fresh.shell.Shell;
import org.jboss.fresh.shell.ShellException;
import org.jboss.fresh.shell.ShellIOException;
import org.jboss.fresh.shell.SystemShell;
import org.jboss.fresh.shell.ExecutableRegistry;
import org.jboss.fresh.shell.events.ShellEvent;
import org.jboss.fresh.shell.events.ShellEventBroadcaster;
import org.jboss.fresh.shell.parser.Cmd;
import org.jboss.fresh.shell.parser.CmdLines;
import org.jboss.fresh.shell.parser.ParseException;
import org.jboss.fresh.shell.parser.ShellCmdParser;
import org.jboss.fresh.util.StringUtils;
import org.apache.log4j.Logger;

/**
* @todo We need to clearly say that we are out of threads when we are out of threads.
*/
// We keep active job resources here.
// We keep open buffers and streams that write and read from them
// We keep active processes


//
// Writing/reading operations may not be implemented ideally in the current implementation
// There should probably be a BufferObjectReader/BufferObjectWriter in between . We should create it on demand and store it in Process.extra
// for bytes [] we would use BufferInputStream/BufferOutputStream
//
// There can be multiple RemoteShellImpl instances using the same ShellImpl object, so
// concurrent calls can be made on close(), read(), write() methods
//
// The result may be some other concurrent calls on this object.
//

public class ShellImpl implements Shell {

  private String uid;
  private boolean interactive;

  private UserCtx uctx;
  private SystemShellImpl sshell;
  private VFS vfs;

  //private Cache cache;
  private Context ctx;

  private Process active = null;
  private Buffer shellout;
//  private PrintWriter wout;
  private MultiBufferObjectReader outreader;

//  private Buffer shellin;
//  private int STD_BUF_SIZE=5;  // should be read from some ENV var.


  private static final String EVENT_SOURCE = "ShellImpl";
  private static final String EVENT_CLASS = "Shell";


  public static final long SESS_TIMEOUT = 1800000L;    // 30 min       //36000000L;  // 10 hrs
  public static final long PROC_TIMEOUT = 1200000L;    // 20 mins
  public static final long BUFFER_TIMEOUT = 1200000L;    // 20 mins

  public static final String STDINPROC_ID = "-1";
  public static final String STDIN_ID = "0";

  // Buffer limits
  public static final int BUF_MAX_SIZE = 10// should be read from some environment variable ... no executable can have it's setting for in or out greater than this
  public static final int IN_BUF_SIZE = 5, OUT_BUF_SIZE = 5; // test case only, should be determined by exe specific info

  // Timeout limits
  public static final long PROC_TIMEOUT_MAX = 300000L; // 5 min - should be read from some global variable ... no executable can have it's setting greater - meaning if non-zero value specified, no zero allowed on individual ...
  public static final long PROC_INST_TIMEOUT = 150000L; // test case only, should be determined by exe specific info

  // we could save this setting in a wrapped around stream/writer/reader
  // or we could save this satting with the process...

  private ShellRuntime runtime;
   private ExecutableRegistry registry;
  //private HashMap procmap=new HashMap();
  private Map procmap = Collections.synchronizedMap(new HashMap());

  private long startTime;
  private long lastUsed;
  private boolean closed = false;

    private long closureTime;
    private String closureReason;

    private static final Logger log = Logger.getLogger("org.jboss.fresh.shell.impl.ShellImpl");
  private static final Logger cmdlog = Logger.getLogger("org.jboss.fresh.shell.impl.ShellImpl.CMD");


  private EventBroadcaster eb;
  private EventCentral ec;

  private EnvProperties props = new EnvProperties();

    SimpleDateFormat sdf_date = new SimpleDateFormat("yyyy-MM-dd");
  SimpleDateFormat sdf_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    SimpleDateFormat sdf_time_millis = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    private static ThreadLocal preparedProcess = new ThreadLocal();
   
  // SysShell assigned shell session id
  public ShellImpl(String id, boolean interactive, SystemShellImpl sysshell, UserCtx uctx, VFS vfs) {
    this.interactive = interactive;
    uid = id;
    this.uctx = uctx;
    sshell = sysshell;
    this.vfs = vfs;
    props = new EnvProperties(System.getProperties());
    // I don't really see when shellin would be of any use.
    //shellin=new BufferImpl();
    //shellin.setMaxSize(STD_BUF_SIZE);

    if (interactive) {
      ProcessGroup stdproc = new ProcessGroup(STDINPROC_ID, null, null);

      shellout = new BufferImpl();
      // CAREFUL HERE: If you print too much to out at the very beginning - in terms of objects
      // you will deadlock
      //shellout.setMaxSize(1);
      shellout.setMaxSize(20);
      stdproc.setOutputBuffer(shellout);
      stdproc.setIOTimeout(PROC_INST_TIMEOUT);
      procmap.put(STDINPROC_ID, stdproc);

      outreader = new MultiBufferObjectReader(null, shellout);

//log.debug("Shellout buffer: " + shellout);
    }

    runtime = new ShellRuntime(this, interactive);
    runtime.setOutBuffer(shellout);

    // we need user, we need to set pwd
    String home = "/home/mare";
    props.setProperty("PWD", home);
    runtime.setPWD(home);

    props.setProperty("SystemShell.startTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(sshell.getStartTime()));

    // we had to set path first. Without it exes run without FileInfo in the init() phase.
    runtime.init(shellout);
    runtime.started();


    runtime.prompt();

//    wout.close();

    startTime = System.currentTimeMillis();
  }

   public void setRegistry(ExecutableRegistry registry)
   {
      if (registry != null)
      {
         runtime.setRegistry(registry);
      }
   }

   private EventBroadcaster getEventBroadcaster() {

    Context ctx = getContext();
    EventCentral evc = (EventCentral) ctx.get("EventCentral");
    if (evc == ec) {
      return eb;
    }

    synchronized(this) {
      if (evc == ec) {
        return eb;
      }

      if(evc == null) {
        // we cause unregister event
        if (eb != null) {
          eb.close();
        }
        eb = null;
        ec = null;
        return null;
      }

      String compid = null;

      if(eb!=null) {
        // we don't cause unregister event - just another register event
        compid = eb.getComponentID();
        eb.close();
        eb = new ShellEventBroadcaster(evc, this, EVENT_SOURCE, eb.getComponentID());
      } else {
        eb = new ShellEventBroadcaster(evc, this, EVENT_SOURCE);
      }

      ec = evc;
    }

    return eb;
  }


  public void setVFS(VFS vfs) {
    this.vfs = vfs;
  }

  public String getSessionID() {
    return uid;
  }

  public Process getProcess(Object id) {
    return (Process) procmap.get(id);
  }

  public SystemShell getSystemShell() {
    return sshell;
  }

  public String getClientInfo() throws ShellException {
    String cuser = _getEnvProperty("cp2.client.user");
    String capp = _getEnvProperty("cp2.client.app");
    String chost = _getEnvProperty("cp2.client.host");

    if (cuser == null) {
      cuser = "cuser_unknown";
    }
    if (chost == null) {
      chost = "chost_unknown";
    }
    if (capp == null) {
      capp = "capp_unknown";
    }

    return cuser + "@" + chost + " [" + capp + "] ";
  }

  public String getClientAndProjectInfo() throws ShellException {
    String cuser = _getEnvProperty("cp2.client.user");
    String capp = _getEnvProperty("cp2.client.app");
    String chost = _getEnvProperty("cp2.client.host");

    if (cuser == null) {
      cuser = "cuser_unknown";
    }
    if (chost == null) {
      chost = "chost_unknown";
    }
    if (capp == null) {
      capp = "capp_unknown";
    }

    String project = _getEnvProperty("PROJECT");
    if (project == null) {
      project = "";
    }

    return cuser + "@" + chost + " [" + capp + "] [" + project + "] ";
  }

  public ProcessInfo execute(String cmdline) throws ShellException {
    preStartTimeoutCheck();
    return _execute(cmdline, true, true, false);
  }

  public ProcessInfo prepareExecution(String cmdline) throws ShellException {
    preStartTimeoutCheck();
    return _execute(cmdline, null, true, true, false, true);
  }

  public ProcessInfo execute(String cmdline, List input) throws ShellException {
    preStartTimeoutCheck();
    return _execute(cmdline, input, true, true, false, false);
  }

  public ProcessInfo _execute(String cmdline) throws ShellException {
    return _execute(cmdline, true, true, false);
  }

  public ProcessInfo execute(String cmdline, boolean ui) throws ShellException {
    preStartTimeoutCheck();
    return _execute(cmdline, true, true, ui);
  }

  public ProcessInfo execute(String cmdline, List input, boolean ui) throws ShellException {
    preStartTimeoutCheck();
    return _execute(cmdline, input, true, true, ui, false);
  }

  public ProcessInfo _execute(String cmdline, boolean ui) throws ShellException {
    return _execute(cmdline, true, true, ui);
  }

  public ProcessInfo execute(String cmdline, boolean hasin, boolean hasout) throws ShellException {
    return _execute(cmdline, hasin, hasout, false);
  }

  public ProcessInfo execute(String cmdline, boolean hasin, boolean hasout, boolean ui) throws ShellException {
    return _execute(cmdline, hasin, hasout, ui);
  }

  public ProcessInfo _execute(String cmdline, boolean hasin, boolean hasout, boolean ui) throws ShellException {
    return _execute(cmdline, null, hasin, hasout, ui, false);
  }
 
  public ProcessInfo _execute(String cmdline, List input, boolean hasin, boolean hasout, boolean ui, boolean prepareOnly) throws ShellException {

    try {
            preStartTimeoutCheck();

            if (cmdline == null || cmdline.length() == 0) {
        runtime.prompt();
        return null;
      }

            cmdline = convertCharset(cmdline);

            if (cmdline.equals("exit")) {
                closureReason = "Client issued 'exit'";
                close();
        return null;
      } else if(cmdline.equals("tsingle")) {
        _setEnvProperty("TMODE", "SINGLE");
        return null;
      } else if(cmdline.equals("tmulti")) {
        _setEnvProperty("TMODE", null);
        return null;
      }

//log.debug("log: " + log);
            String [] lines = cutInput(cmdline);
            cmdline = lines[0];
           
      cmdline = cmdline.trim();
      String cuser = _getEnvProperty("cp2.client.user");
      String chost = _getEnvProperty("cp2.client.host");
      String capp = null;

      String project = _getEnvProperty("PROJECT");
      if (project == null) {
        project = "";
      }

      if(cuser != null || chost != null) {
        capp = _getEnvProperty("cp2.client.app");

        if (cuser == null) {
          cuser = "cuser_unknown";
        }
        if (chost == null) {
          chost = "chost_unknown";
        }
        if (capp == null) {
          capp = "capp_unknown";
        }

        cmdlog.info(cuser + "@" + chost + " [" + capp + "] [" + project + "] " + cmdline);
      } else {
        cmdlog.info("[" + project + "] " + cmdline);
      }

      HistoryItem hi = addHistory(_getEnvProperty("PROJECT"), cuser, capp, chost, cmdline);
            cmdline = StringUtils.unescapeJavaX(cmdline);
            cmdline = runtime.unaliasCmdLine(cmdline);
            ShellCmdParser parser = new ShellCmdParser(cmdline);
      LinkedList job = new LinkedList();

      CmdLines cmdLines = parser.parse();

      cmdLines = resolveVars(cmdLines);
      cmdLines.setStdInLines(lines[1]);
      cmdLines.setStdInput(input);
     
      Iterator it = cmdLines.iterator();
      while (it.hasNext()) {
        Cmd cmd = (Cmd) it.next();
        makeProcess(cmdLines, cmd, job, hasin, hasout, ui);
      }

      if (job.size() > 1) {
        ProcessGroup p = sshell.createProcessGroup(job);
        if (p == null) {
          throw new ShellException("[ShellImpl][execute] Failed to create ProcessGroup.");
        }
        InBuffer ib = ((Process) job.getFirst()).getInputBuffer();
        OutBuffer ob = ((Process) job.getLast()).getOutputBuffer();
        p.setRedirected(((Process) job.getLast()).isRedirected());

//log.debug("PRocessGroup ib: " + ib);
//log.debug("PRocessGroup ob: " + ob);
        p.setInputBuffer(ib);
        p.setOutputBuffer(ob);
        p.setCommandLine(cmdline);


        if (active == null) {
          active = p;
        }

//      if(interactive) {
//        outreader.replacePrimaryBuffer(ob);
//      }

        procmap.put(p.getID(), p);
        p.setUserInitiated(ui);

        hi.setProcessID(p.getID());

                // We don't use it anywhere - WRONG - we use it when NoProcessForID Exceptions occur
                LinkedList chs = hi.getChildren();
        LinkedList ls = p.getProcessList();
        it = ls.iterator();
        while(it.hasNext()) {
          Process cp = (Process) it.next();
          chs.add(cp);
        }

        if (!prepareOnly) {
          p.start(); // We have a problem with concurrent modification on job
        } else {
          preparedProcess.set(p);
        }
       
        ProcessInfo pinfo = new ProcessInfo();
        pinfo.procid = p.getID();
        pinfo.inbuf_maxsize = ib.getMaxSize();
        pinfo.outbuf_maxsize = ob.getMaxSize();
        return pinfo;
      } else {
        Process p = (Process) job.getFirst();
//    System.out.println("Putting the process in the procmap: " + p.getID() + " : " + p);

        InBuffer ib = p.getInputBuffer();
        OutBuffer ob = p.getOutputBuffer();

//log.debug("PRocess ib: " + ib);
//log.debug("PRocess ob: " + ob);

        if (active == null) {
          active = p;
        }
//      if(interactive) {
//        outreader.replacePrimaryBuffer(ob);
//      }

//      System.out.println("ACTIVE SET: " + active);

        procmap.put(p.getID(), p);
//log.debug("***\n***[execute] Created process " + p.getID() + "\n***");
        log.debug("Created process " + p.getID());

        p.setUserInitiated(ui);

        hi.setProcessID(p.getID());
        hi.getChildren().add(p);

        if (!prepareOnly) {
          p.start();
        } else {
          preparedProcess.set(p);
        }
       
//    System.out.println("Started the process.");

        ProcessInfo pinfo = new ProcessInfo();
        pinfo.procid = p.getID();
        pinfo.inbuf_maxsize = ib.getMaxSize();
        pinfo.outbuf_maxsize = ob.getMaxSize();
        return pinfo;
      }
    } catch (SessionTimeoutException ex) {
            throw new SessionTimeoutException("Exception executing: " + cmdline + " - " + ex.getMessage());
        } catch (ParseException ex) {
      log.error("Exception occured during parsing of the command line!", ex);
      throw new ShellException("Exception occured during parsing of the command line!", ex, cmdline);
    }
    // now we have several processes in the job list.
    // we still need to run them all.
    // If

    // we need to interpret the command line
    // that is - we need to parse it
    // first command can be an internal command like cd
    // or it can be an executable

    // If not internal command:
    // we need to determine if executable with the specified name exists
    // executable name is a relative name or an absolute name
    // if absolute name we resolve it relative to all components of the PATH
    // until we find the first one that matches the pattern.
    // It's clear that we need VFS to be able to give us the list of all executables in the specified directory.
    //
    // (For starters we can put them all in the /bin directory and expect only name.)
    //
    // When we locate an executable, we need to allocate stdin and stdout Buffers for it.
    // Then we need to set ENV to it

    // We need to allocate a Process
    // We then put the Process in the process map allocating an uid along the way.
    // We then start a process and return an uid to the process.

    // --------------------
    // Let's just run an executable
    // ok, we associate it with the exepath, we set user
    // we allocate in/out buffers
    // we set Buffers on the exe
    // we store it in the Process
    // we store the process in our process map
    // we run the process/executable
    // we return process id. (process id is what? shouldn't SystemShell create a process for us?)
    // (If we create processes ourselves then there is no way to go to one central place and say
    // kill process number 10. Which is a process started by some user in his shell.)
    // To have this sort of control, we need the central to have access to the Process and say kill
    // on it.

  }

  /**
   * To be used in conjunction with prepareExecution
   * @throws ShellException
   */
  public void completeExecution() throws ShellException {
//System.out.println("        completeExecution entered");
    preStartTimeoutCheck();
    //System.out.println("        completeExecution 1");
    Process p = (Process) preparedProcess.get();
    //System.out.println("        completeExecution 2    p == " + p);
    if(p == null) {
      //new Exception("No prepared process found").printStackTrace();
      throw new ShellException("No prepared process found - was prepareExecution() called in this thread?");
    }
    //System.out.println("        completeExecution 3");
    preparedProcess.remove();
//System.out.println("      *Calling Process.start()");
    p.start();
  }

 
    private String[] cutInput(String cmdline) {

      int idx = cmdline.indexOf("\n");
     
      if(idx != -1) {
          int e1 = idx;

        for(int i=idx-1; i>=0; i--) {
          char c = cmdline.charAt(i);
          if(c != '\r') {
            e1 = i+1;
            break;
          }
        }

        return new String[] {cmdline.substring(0, e1), (idx == cmdline.length()-1) ? "" : cmdline.substring(idx+1)};
      }
     
      return new String[] {cmdline, null};
  }



  private String convertCharset(String cmdline) throws ShellException {
        // check environment settings
        String enc = getEnvProperty("TERMINAL_ENC");
    if (enc == null) {
      return cmdline;
    }

        try {
            return new String(new String(cmdline).getBytes("ISO8859_1"), enc);
        } catch(IOException ex) {
            setEnvProperty("TERMINAL_ENC_ERROR", "Unsupported charset: " + enc);
        }

        return cmdline;
    }

    public HistoryItem addHistory(String project, String cuser, String capp, String chost, String cmdline) {

        HistoryItem hitem = new HistoryItem(project, cuser, capp, chost, cmdline);

        History h = (History) ctx.get("History");
        if(h == null) {
            h = new History();
            ctx.put("History", h);
        }

        h.add(hitem);

        Context actx = (Context) ctx.get("AppContext");
        if(actx == null) {
            log.debug("AppContext not available");
        } else {
            h = (History) actx.get("History");
            if(h == null) {
                h = new History();
                actx.put("History", h);
            }

            h.add(hitem);
        }

        // would be nice to have a wrapper that returns null and throws no exceptions
        try {
            actx = (Context) new RegistryContext().lookup("java:/FRESH/GlobalContext");
        } catch(Exception ex) {
        }

        if(actx == null) {
            log.debug("GlobalContext not available");
        } else {
            h = (History) actx.get("History");
            if(h == null) {
                h = new History();
                actx.put("History", h);
            }

            h.add(hitem);
        }

        return hitem;
    }

  public HistoryItem getHistoryItem(String id) {
log.info("id: " + id);
    HistoryItem ti = null;
    Context c = ctx;
    for(int i=0; i<3; i++) {
log.info("i: " + i + ", ctx: " + c);
          HashMap map = new HashMap();

          c.loadMappings(map);

          java.util.TreeMap sm = new java.util.TreeMap(map);
          Iterator it0 = sm.entrySet().iterator();
          while (it0.hasNext()) {
            Map.Entry ent = (Map.Entry) it0.next();
            log.info(ent.getKey() + "\t=\t" + ent.getValue() + "\t" + ent.getValue().getClass().getName());
          }


      History h = (History) c.get("History");
      Iterator it = h.list().iterator();
      while(it.hasNext()) {
        HistoryItem hi = (HistoryItem) it.next();
        log.info("compare: " + hi.getProcessID() + "  vs. " + id);
        if(hi.getProcessID().equals(id)) {
          ti = hi;
          break;
          //Iterator it2 = hi.getChildren().iterator;
          //while(it2.hasNext()) {
          //  Process p = (Process) it.next();
          //}
        }
      }

      if(ti == null) {
        if(i==0) {
          c = (Context) ctx.get("AppContext");
          if(c == null) {
            try {
              c = (Context) new RegistryContext().lookup("java:/FRESH/GlobalContext");
            } catch(Exception ex) {}
            i++;
          }
        } else if(i==1) {

          try {
            c = (Context) new RegistryContext().lookup("java:/FRESH/GlobalContext");
          } catch(Exception ex) {}
          if (c == null) {
            i++;
          }
        }
      }
    }


    return ti;
  }



  public ProcessInfo execute(Executable exe, String exepath, String[] params) throws ShellException {

        try {
            preStartTimeoutCheck();
        } catch(SessionTimeoutException ex) {
            StringBuffer sb = new StringBuffer(exepath);
            if(params != null) {
                for(int i=0; i<params.length; i++) {
                    sb.append(" \'").append(params[i]).append('\'');
                }
            }
            throw new SessionTimeoutException("Exception executing: " + sb + " - " + ex.getMessage() );
        }

        Process p = sshell.createProcess(this);

    long ptimeout = PROC_INST_TIMEOUT;

    p.setIOTimeout(ptimeout);
    p.setExecutable(exe);
    exe.setProcess(p);
    exe.setShell(this);

    p.setCommandLine(null);    // don't know what to do with this
    p.setParams(params);
    p.setExePath(exepath);
    p.setInputBuffer(exe.getStdIn());
    p.setOutputBuffer(exe.getStdOut());

    procmap.put(p.getID(), p);
//log.debug("***\n***[execute2] Created process " + p.getID() + "\n***");
    log.debug("Created process " + p.getID());
    p.setUserInitiated(false); // what does it mean again ?
    p.start();
    //log.debug("Started the process.");

    ProcessInfo pinfo = new ProcessInfo();
    pinfo.procid = p.getID();
    pinfo.inbuf_maxsize = exe.getStdIn().getMaxSize();
    pinfo.outbuf_maxsize = exe.getStdOut().getMaxSize();
    return pinfo;
  }



  public Process createProcess(Executable exe, String [] params, String path, boolean useThreadPool) throws ShellException {

        try {
            preStartTimeoutCheck();
        } catch(SessionTimeoutException ex) {
            StringBuffer sb = new StringBuffer(path);
            if(params != null) {
                for(int i=0; i<params.length; i++) {
                    sb.append(" \'").append(params[i]).append('\'');
                }
            }
            throw new SessionTimeoutException("Exception executing: " + sb + " - " + ex.getMessage() );
        }

        Process p = sshell.createProcess(this, useThreadPool);

    long ptimeout = PROC_INST_TIMEOUT;

    p.setIOTimeout(ptimeout);
    p.setExecutable(exe);
    exe.setProcess(p);

    StringBuffer cmdline = new StringBuffer();
    cmdline.append(path == null ? "<cmd>" : path);
    if(params!=null) {
      for(int i=0; i<params.length; i++) {
        cmdline.append(" ").append(params[i]);
      }
    }

    p.setCommandLine(cmdline.toString());
    p.setParams(params);
    p.setExePath(path);
    p.setInputBuffer(exe.getStdIn());
    p.setOutputBuffer(exe.getStdOut());

    procmap.put(p.getID(), p);
    log.debug("Created process " + p.getID());
    p.setUserInitiated(false); // what does it mean again ?

    return p;
  }

  private CmdLines resolveVars(CmdLines cmds) throws ShellException {

    LinkedList cmdsl = new LinkedList();

    Iterator it = cmds.iterator();
    while (it.hasNext()) {
      Cmd cmd = (Cmd) it.next();
      String scmd = cmd.getExec();
      // we leave cmd as it is.

      String[] params = cmd.getParams();
      LinkedList ops = new LinkedList();
      // we process each one - look for $ then look for eof or space.
      // we try resolve $ if can't then leave it as it is.
//log.debug("cmdline parameters: ");
      for (int i = 0; i < params.length; i++) {

        String c = params[i];
//log.debug("*** " + c);

// in here we do several things. We resolve env vars only if " or without
// we do pathname expansion if not " or ' and *, ? or [ is present



/*
        if(c.startsWith("'")) {
          if(c.endsWith("'")) {
            ops.add(c.substring(1, c.length()-1));
            continue;
          } else {
            ops.add(c.substring(1, c.length()));
            continue;
          }
        }

        if(c.endsWith("'")) {
          ops.add(c.substring(0, c.length()-1));
          continue;
        }
*/

// if starts with " and ends with " then we need to remove that
// if it does not end with " then we treat it as if it is not within quotes

        if (c.startsWith("'") && c.endsWith("'") && c.length() > 1) {
          ops.add(c.substring(1, c.length() - 1));
          continue;
        }

        StringBuffer outc = new StringBuffer();
        StringTokenizer st = new StringTokenizer(c, "$ ", true);
        boolean isVar = false;
        while (st.hasMoreTokens()) {
          String t = st.nextToken();
//log.debug("[SSH] : t: " + t);
          if (t.equals("$")) {
            isVar = true;
//log.debug("[SSH] : found $");
          } else {
            if (isVar) {
              // lookup t
              String p = null;
              int j = 0;
              StringBuffer psmp = new StringBuffer();
//log.debug("[SSH] : init psmp: " + psmp);
              for (j = 0; j < t.length() && p == null; j++) {
//log.debug("[SSH] : trying " + psmp);
                psmp.append(t.charAt(j));
                p = getEnvProperty(cmd, psmp.toString());
              }

              if (p == null) {
//log.debug("[SSH] : no property for this name");
                outc.append("$").append(t);
              } else {
//log.debug("[SSH] : found property: " + p);
                outc.append(p);
                if (j < t.length()) {
//log.debug("[SSH] : appending a remnant: " + t.substring(j, t.length()));
                  outc.append(t.substring(j, t.length()));
                }
              }

              isVar = false;
            } else {
              outc.append(t);
            }
          }
        }
        c = outc.toString();


        if (c.startsWith("\"") && c.endsWith("\"") && c.length() > 1) {
          ops.add(c.substring(1, c.length() - 1));
          continue;
        }

        if (c.indexOf("?") != -1 || c.indexOf("*") != -1 || (c.indexOf("[") != -1 && c.indexOf("]") != -1)) {
//          System.out.println("It's a pattern! : " + c);
          try {
            FPExpand fpe = new FPExpand(this);
            fpe.expand(c);
            Vector vx = fpe.getMatches();
            Iterator itx = vx.iterator();
            while (itx.hasNext()) {
              ops.add(((FileInfo) itx.next()).getFileName().toString());
            }
          } catch (Exception ex) {
            log.error("Could not expand", ex);
          }

          continue;
        }


        ops.add(c);
      }

      String[] pout = new String[ops.size()];
      Iterator it2 = ops.iterator();
      for (int i = 0; it2.hasNext(); i++) {
        pout[i] = (String) it2.next();
      }

      //cmdsl.add(new Cmd(scmd, pout, null, null));
      cmd.setParams(pout);
      cmdsl.add(cmd);
    }

    cmds.setCmds(cmdsl);
    return cmds;
  }

    private void makeProcess(CmdLines cmdl, Cmd cmd, LinkedList joblist, boolean hasin, boolean hasout, boolean ui) throws ShellException {

    String command = cmd.getExec();
    String exepath = "/bin/" + command;
    String[] params = cmd.getParams();

    int inbufmax = IN_BUF_SIZE;
    int outbufmax = OUT_BUF_SIZE;

    Properties env = _getEnvProperties();

    String ibs = getEnvProperty("IN_BUF_SIZE");
    if (ibs != null) {
      try {
        inbufmax = Integer.parseInt(ibs);
      } catch (Exception ex) {
        log.error("Problem while reading buffer", ex);
      }
    }

    String obs = getEnvProperty("OUT_BUF_SIZE");
    if (obs != null) {
      try {
        outbufmax = Integer.parseInt(obs);
      } catch (Exception ex) {
        log.error("Problem while wrinting buffer", ex);
      }
    }

    long ptimeout = PROC_INST_TIMEOUT;

    if (inbufmax > BUF_MAX_SIZE) {
      inbufmax = BUF_MAX_SIZE;
    }

    if (PROC_TIMEOUT_MAX != 0) {
      if (ptimeout == 0 || ptimeout > PROC_TIMEOUT_MAX) {
        ptimeout = PROC_TIMEOUT_MAX;
      }
    }

    Executable exe = runtime.loadExe(command);



    // Exe is ok, we have created it.

//    System.out.println("Successfully loaded executable.");

    // Now we ask sysshell to create process.
//    System.out.println("Creating new process ...");
    Process p = sshell.createProcess(this);
    setupEnv(cmd, p);

    p.setIOTimeout(ptimeout);

//    System.out.println("Created process: " + p);

    // We only create in buffer if we are the first, otherwise we simply use
    // previous exe's output buffer. To know if we are first it would help to have
    // access to job list
    InBuffer in = null;
    if (joblist.size() == 0) {

      if (cmdl.getSLStdInRedir() != null) {
        try {
          InputStreamBuffer bin = new InputStreamBuffer(new FileInputStream(cmdl.getSLStdInRedir()), cmdl.isSLInObjMode());
          bin.setProperties(env);
          in = bin;
        } catch (IOException ex) {
          throw new ShellException("Exception occured while initializing input buffer: " + ex.toString());
        }

      } else if (cmdl.getStdInRedir() != null) {
        try {
          //in=new InputStreamBuffer(new VFSInputStream(new SecureVFS(vfs, uctx), cmdl.getStdInRedir()), cmdl.isInObjMode());
          if(cmdl.getStdInLines() != null) {
            String enc = env.getProperty("ENC");
            ByteArrayInputStream bain;
            if(enc != null) {
              bain = new ByteArrayInputStream(cmdl.getStdInLines().getBytes("ENC"));
            } else {
              bain = new ByteArrayInputStream(cmdl.getStdInLines().getBytes());
            }
            InputStreamBuffer bin = new InputStreamBuffer(bain, false);
            bin.setProperties(env);
            in = bin;
           
          } else {
            FileName fname = new FileName(cmdl.getStdInRedir());
            if (fname.isRelative()) {
              fname = new FileName(getEnvProperty("PWD")).absolutize(fname);
            }
            InputStreamBuffer bin = new InputStreamBuffer(new VFSInputStream(new SecureVFS(vfs, uctx), fname.toString()), cmdl.isInObjMode());
            bin.setProperties(env);
            in = bin;
          }

        } catch (IOException ex) {
          throw new ShellException("Exception occured while initializing input buffer: " + ex.toString());
        }

      }


      if (in == null) {
//log.debug("No output redirect setup...");
        if (hasin) {
          if (!"SINGLE".equals(getEnvProperty("TMODE"))) {
            in = new BufferImpl();
          } else {
            in = new MemFileBufferImpl();
          }
          // here we set whatever is maxsize for inputbuffer for this executable - we have this set
          // as attribute on the file or something ...
          // FIXME
          List input = cmdl.getStdInput();
          if(input != null) {
            in.setMaxSize(input.size());
            try {
              ((Buffer)in).putBuffer(new LinkedList(input), 1000);
              in.close();
            } catch (IOException ex) {
              throw new ShellException("Exception occured while initializing input buffer: " + ex.toString());
            }
          }
          in.setMaxSize(inbufmax); // should be a variable

        } else {
          in = new NullBuffer();
        }
      }

    } else {
//log.debug("Piping in previous out...");
      Object o_in = ((Process) joblist.getLast()).getOutputBuffer();
      if (!(o_in instanceof InBuffer)) {
        throw new ShellException("Invalid pipe chain. Trying to read from write-only buffer.");
      }
      in = (InBuffer) o_in;
    }

//log.debug("\n\nin = " + in);

    OutBuffer out = null;

    if (cmdl.size() == joblist.size() + 1) {

      if (cmdl.getSLStdOutRedir() != null) {
        try {
          OutputStreamBuffer bout = new OutputStreamBuffer(new FileOutputStream(cmdl.getSLStdOutRedir(), cmdl.getSLAppend()), cmdl.isSLOutObjMode());
          bout.setProperties(env);
          out = bout;
          p.setRedirected(true);
        } catch (IOException ex) {
          throw new ShellException("Exception occured while initializing output buffer: " + ex.toString());
        }

      } else if (cmdl.getStdOutRedir() != null) {
        try {
          ////out=new OutputStreamBuffer(new VFSOutputStream(new SecureVFS(vfs, uctx), cmdl.getStdOutRedir(), cmdl.getAppend()), cmdl.isOutObjMode());

          //if(TxSupport.isActive()) throw new ShellException("Illegal state - inside transaction.");
          //TxSupport.begin();
          try {
            FileName fname = new FileName(cmdl.getStdOutRedir());
            if (fname.isRelative()) {
              fname = new FileName(getEnvProperty("PWD")).absolutize(fname);
            }
            OutputStreamBuffer bout = new OutputStreamBuffer(new LazyVFSOutputStream(new SecureVFS(vfs, uctx), fname.toString(), cmdl.getAppend()), cmdl.isOutObjMode());
            bout.setProperties(env);
            out = bout;
            p.setRedirected(true);
            //TxSupport.commit();
          } catch (Exception ex) {
            //TxSupport.rollback();
            throw ex;
          }
        } catch (Exception ex) {
          log.error("Exception occured while initializing output buffer: ", ex);
          throw new ShellException("Exception occured while initializing output buffer: " + ex.toString());
        }
      }
    }
//log.debug("\n\nout = " + out);
    if (out == null) {
      if (hasout) {
        if (!"SINGLE".equals(getEnvProperty("TMODE"))) {
          out = new BufferImpl();
        } else {
          out = new MemFileBufferImpl();
        }
       
        // here we set whatever is maxsize for inputbuffer for this executable - we have this set
        // as attribute on the file or something ...
        // FIXME
        out.setMaxSize(outbufmax); //  should be a variable

      } else {
        out = new NullBuffer();
      }

      if ((cmdl.size() == joblist.size() + 1) && ui && interactive) {
        procmap.put(STDIN_ID, p);
        outreader.replacePrimaryBuffer((InBuffer) out);
      }
    }

//log.debug("\n\nfinal out = " + out);
    p.setInputBuffer(in);
    p.setOutputBuffer(out);

//    System.out.println("Set allocated resurces on executable ...");
//log.debug("exe stdin = " + in);
//log.debug("exe stdout = " + out);

    exe.setStdIn(in);
    exe.setStdOut(out);
    exe.setShell(this);

//    System.out.println("Setting executable on Process ...");
    p.setExecutable(exe);
    exe.setProcess(p);

    p.setCommandLine(command);
    p.setParams(params);
    p.setOriginalParams(cmd.getOriginalParams());
    p.setExePath(exepath);

    joblist.add(p);

  }



  private void setupEnv(Cmd cmd, Process p) throws ShellException {
    Map enviro = cmd.getEnvironment();
    if(enviro != null) {
      Iterator eit = enviro.entrySet().iterator();
      EnvProperties penv = p.getEnv();
      while(eit.hasNext()) {
        Map.Entry ent = (Map.Entry) eit.next();
        penv.setEnvProperty((String) ent.getKey(), (String) ent.getValue());
      }
    }
  }

/*
  public String executeAsString(String cmdline) throws ShellException {
    // Similar to above. The difference is only when we start the process.
    // We start it and join it - wait for it to finish
    // Then we take its result as String and return it.
    // It's all done in one remote call.
    return null;
  }

  public String executeAsString(String cmdline, boolean ui) throws ShellException {
    return null;
  }
*/
  public Object executeAsObject(String cmdline) throws ShellException {
    preStartTimeoutCheck();
    return _executeAsObject(cmdline, null, false);
  }

  public Object executeAsObject(String cmdline, List input) throws ShellException {
    preStartTimeoutCheck();
    return _executeAsObject(cmdline, input, false);
  }

  public Object executeAsObject(String cmdline, boolean ui) throws ShellException {
    preStartTimeoutCheck();
    return _executeAsObject(cmdline, null, ui);
  }

  public Object executeAsObject(String cmdline, List input, boolean ui) throws ShellException {
    preStartTimeoutCheck();
    return _executeAsObject(cmdline, input, ui);
  }

  public Object _executeAsObject(String cmdline, List input, boolean ui) throws ShellException {
    // similar to above only this time we take results as Object and return
    // an object. The above is really a flavor of this and not vice versa.

    // start executable. set up nullbuffer on its stdi
    try {
      ProcessInfo pinfo = _execute(cmdline, input, false, true, ui, false); // NullInput In case no redirects specified of course

      // read one object from its std out
//      System.out.println(">>>BUFFER : " + getBuffer(pinfo.procid, 1));
      InBuffer buf = null;
      try {
        buf = getBuffer(pinfo.procid, 1);
      } catch(org.jboss.fresh.shell.NoSuchProcessException ex) {
        return null;
      }

      BufferObjectReader in = new BufferObjectReader(buf); // get out buffer

      in.setTimeout((int) BUFFER_TIMEOUT);

      Object retObj = null;
      while (!in.isFinished()) { // �e ho�emo, da sa izvede do konca moramo prebrati vse  -  dokler se ne zapre.
        try {

          if (retObj == null) {
//log.debug("########\n\n\n\\n Timeout: " + in.getTimeout());
            retObj = in.readObject()// read it
          } else {
//log.debug("########\n\n\n\\n Timeout_1: " + in.getTimeout());
            in.readObject()// dump it
          }
        } catch (IOException ex) {
//log.debug("[ShellImpl] executeAsObject:");
          log.error(ex.getMessage(), ex);
        }
      }

      // DON'T close std out. It's not our business to close stdout.
      //in.close();

      // return that object
      return retObj;
    } catch (ShellException ex) {
      log.error(ex.getMessage(), ex);
      throw ex;
    } catch (Throwable t) {
      log.error(t.getMessage(), t);
      throw new ShellException(t);
    }
  }

  public EnvProperties getEnv() {
    return props;
  }

  public Properties getEnvProperties() throws ShellException {
    used();
    return props.getEnvProperties();
  }

  public Properties _getEnvProperties() throws ShellException {
        return props._getEnvProperties();
  }

  public void setEnvProperty(String name, String value) throws ShellException {
    used();
    props._setEnvProperty(name, value);
  }

  public void _setEnvProperty(String name, String value) throws ShellException {
    props._setEnvProperty(name, value);
    //runtime.setEnvProperty(name, value);
  }

  public String getEnvProperty(String name) throws ShellException {
    used();
    return props._getEnvProperty(name);
  }

    private String getEnvProperty(Cmd cmd, String name) throws ShellException {
        Object val = cmd.getEnvironment().get(name);
        if (val == null)
            return getEnvProperty(name);
        else
            return String.valueOf(val);
    }

  public String _getEnvProperty(String name) throws ShellException {
        return props._getEnvProperty(name);
  }

  public ShellRuntime getRuntime() {
    return runtime;
  }

  /* (non-Javadoc)
   * @see org.jboss.fresh.shell.Shell#setROEnvProperty(java.lang.String, java.lang.String)
   */
  public synchronized void setROEnvProperty(String name, String value)
      throws ShellException {
    props.setROEnvProperty(name, value);
  }

  public LinkedList readBuffer(String id, int maxsize) throws IOException {

    Process p = null;

/*
    if(id.equals(STDIN_ID)) {
      if(active==null) {
        return readBuffer(STDINPROC_ID, maxsize);
      } else {
        return readBuffer(active.getID(), maxsize);
      }
    }
*/
    try {
//log.debug(" --- Shell Impl --- readBuffer() entered.");
      //used();
      if (id.equals(STDIN_ID)) {
        if (!interactive) {
          throw new NoSuchProcessException("No process for STDIN. Session is not in interactive mode.");
        }
//        System.out.println("OH NO !  id = " + id);
        LinkedList retobj = outreader.readBuffer(maxsize);
//        System.out.println("<<<<<<<<");
        p = (Process) procmap.get(id);
        if (p != null) {
          p.using();
        }

        return retobj;
      }

      p = (Process) procmap.get(id);
      if (p == null) {
        // let's find process data for id
        HistoryItem ti = getHistoryItem(id);
        throw new NoSuchProcessException("No process for id: " + id + " (" + (ti == null ? " No info available for process" : ti.toString()) + ")");
      }

      p.using();
      // we need an input stream around outputbuffer
      // we need to save it like together with the Process
      InBuffer b = (InBuffer) p.getOutputBuffer();
//      System.out.println("ShellImpl: read() : getting from buffer: " + b);

      // if(list.size()>b.getMaxSize()) throw new ShellIOException("Buffer sent by client exeeds the communicated maximum size.");

      LinkedList list = b.getBuffer(p.getIOTimeout(), maxsize);
      if (p.isRedirected() && b.isClosed()) {
        p.markCompleted();
      }

      if (log.isDebugEnabled()) {
        log.debug(" --- Shell Impl --- readBuffer() " + list);
      }

      return list;
    } catch (EOFException ex) {
//log.debug(" --- Shell Impl --- readBuffer() EOFException caught...");
      if (p != null && p.getThrowable() != null) {
//log.debug(" --- Shell Impl --- readBuffer() throwing throwable...");
        throw new ShellIOException(p.getThrowable());
      } else {
//log.debug(" --- Shell Impl --- readBuffer() throwing EOFException...");
        throw ex;
      }
    } catch (IOException ex) {
      throw ex;
    } catch (Exception ex) {
//log.debug(" --- Shell Impl --- readBuffer() Exception caught...");
      log.error(ex.getMessage(), ex);
//log.debug("Throwing ShellException... " + ex.getMessage());
      throw new ShellIOException(ex);
    }
  }

  public Object read(String id) throws IOException {

    // get the process with this ID
    // get the ObjectReader wrapped around stdout Buffer of the process
    // read next object from it and return it. It's supposed to be of type byte []
    // if we employ buffer pooling then maybe what we get is some other object and we need to extract
    // byte [] from it and return buffer to the pool.

    // read is done in sync fashion.
//    System.out.println("ShellImpl: read() : retrieving process for id " + id);
    Process p = null;
/*
    if(id.equals(STDIN_ID)) {
      if(active==null) {
        return read(STDINPROC_ID);
      } else {
        return read(active.getID());
      }
    }
*/
    try {
      //used();
      if (id.equals(STDIN_ID)) {
        if (!interactive) {
          throw new NoSuchProcessException("No process for STDIN. Session is not in interactive mode.");
        }
//        System.out.println("OH NO SHIT!  id = " + id);
        Object retobj = outreader.readObject();
//        System.out.println("<<<<<<<<");
        p = (Process) procmap.get(id);
        if (p != null) {
          p.using();
        }
        return retobj;
      }

      p = (Process) procmap.get(id);
      if (p == null) {
        // let's find process data for id
        HistoryItem ti = getHistoryItem(id);
        throw new NoSuchProcessException("No process for id: " + id + " (" + (ti == null ? " No info available for process" : ti.toString()) + ")");
      }

      p.using();
      // we need an input stream around outputbuffer
      // we need to save it like together with the Process
      InBuffer b = (InBuffer) p.getOutputBuffer();
//      System.out.println("ShellImpl: read() : getting from buffer: " + b);

      Object obj = b.get(p.getIOTimeout());

      if (log.isDebugEnabled()) {
        log.debug(" --- Shell Impl --- read() " + obj);
      }

      return obj;
      // This is not quite ok. We need Wrap exception to throw ...
    } catch (EOFException ex) {
      if (p.getThrowable() != null) {
        throw new ShellIOException(p.getThrowable());
      } else {
        throw ex;
      }
    } catch (Exception ex) {
      log.error(ex.getMessage(), ex);
//log.debug("Throwing ShellException... " + ex.getMessage());
      throw new ShellIOException(ex);
    }

  }

  public void writeBuffer(String id, LinkedList list) throws IOException {

    // check to see if size of list is within limits - we need to get input buffer of the process
//log.debug(" --- Shell Impl --- writeBuffer() " + list );
//Iterator it=list.iterator();
//while(it.hasNext()) {
//  System.out.println("  " + it.next());
//}
    Process p = null;
    try {
      //used();
      p = (Process) procmap.get(id);
      if (p == null) {
        // let's find process data for id
        HistoryItem ti = getHistoryItem(id);
        throw new NoSuchProcessException("No process for id: " + id + " (" + (ti == null ? " No info available for process" : ti.toString()) + ")");
      }

      p.using();
      // we need an input stream around outputbuffer
      // we need to save it like together with the Process
      OutBuffer b = (OutBuffer) p.getInputBuffer();
//      System.out.println("ShellImpl: read() : getting from buffer: " + b);
            if(b == null) {
          if (!p.isDone()) {
            throw new EOFException("StdIn not available any more (funny: process not done yet)");
          } else {
            throw new EOFException("StdIn not available any more (process done executing)");
          }
            }
      if (list.size() > b.getMaxSize()) {
        throw new ShellException("Buffer sent by client exeeds the communicated maximum size.");
      }

      b.putBuffer(list, p.getIOTimeout());
    } catch (EOFException ex) {
      if (p.getThrowable() != null) {
        throw new ShellIOException(p.getThrowable());
      } else {
        throw ex;
      }
    } catch (Exception ex) {
      log.error(ex.getMessage(), ex);
//log.debug("Throwing ShellException... " + ex.getMessage());
      throw new ShellIOException(ex);
    }
  }

  public void write(String id, Object obj) throws IOException {

//log.debug(" --- Sell Impl --- write() " + obj );
    Process p = null;
    try {
      //used();
      p = (Process) procmap.get(id);
      if (p == null) {
        // let's find process data for id
        HistoryItem ti = getHistoryItem(id);
        throw new NoSuchProcessException("No process for id: " + id + " (" + (ti == null ? " No info available for process" : ti.toString()) + ")");
      }

      p.using();
      // we need an input stream around outputbuffer
      // we need to save it like together with the Process
      OutBuffer b = (OutBuffer) p.getInputBuffer();
//      System.out.println("ShellImpl: read() : getting from buffer: " + b);
            if(b == null) {
          if (!p.isDone()) {
            throw new EOFException("StdIn not available any more (funny: process not done yet)");
          } else {
            throw new EOFException("StdIn not available any more (process done executing)");
          }
            }


      boolean res = b.put(obj, 0);
      if (!res) {
        throw new IOException("Timeout while trying to write in the buffer: " + b);
      }
    } catch (EOFException ex) {
      if (p.getThrowable() != null) {
        throw new ShellIOException(p.getThrowable());
      } else {
        throw ex;
      }
    } catch (Exception ex) {
      log.error(ex.getMessage(), ex);
//log.debug("Throwing ShellException... " + ex.getMessage());
      throw new ShellIOException(ex);
    }
  }


  public Buffer getBuffer(String procid, int bufid) throws ShellException {
    //used();
    // get process
    Process p = null;
    p = (Process) procmap.get(procid);

    if (p == null) {
      // let's find process data for id
      HistoryItem ti = getHistoryItem(procid);
      throw new NoSuchProcessException("No process for id: " + procid + " (" + (ti == null ? " No info available for process" : ti.toString()) + ")");
    }

    p.using();
    // we need an input stream around outputbuffer
    // we need to save it like together with the Process
    if (bufid == 0) {
      return (Buffer) p.getInputBuffer();
    } else if (bufid == 1) {
      return (Buffer) p.getOutputBuffer();
    } else {
      throw new ShellException("Illegal buffer id : " + bufid);
    }
  }


  // stream ids: 0: stdin, 1: stdout
  public void close(String id, int streamid) throws IOException {
    //try {
    //  used();
    //} catch (ShellException ex) {
    //  throw new ShellIOException(ex);
    //}

    Process p = (Process) procmap.get(id);

    // No need to throw exception. So process does not exist, so what. Effectively it means all buffers are closed on it.
    // The intended operation is not necessary.
    //if(p==null) throw new ShellIOException(new NoSuchProcessException("No process for id: " + id));
    if (p == null) {
      return;
    }
    try {
      p.using();
    } catch (ShellException ex) {
      //throw new ShellIOException(ex);
    }

    if (streamid == 0) {
      // close stdin
      InBuffer b = p.getInputBuffer();
//log.debug("[shell-impl] ********* closing " + b);
      log.debug("closing input " + b);
      if (b != null) {
        b.close();
      }
    } else if (streamid == 1) {
      OutBuffer b = p.getOutputBuffer();
//log.debug("[shell-impl] ********* closing " + b);
      log.debug("closing output " + b);
      // closeAndDiscard explicitly tells OutBuffer that nothing will
      // be read from it any more. Not even what it may still have inside.
      b.closeAndDiscard();
    } else {
      throw new ShellIOException(new ShellException("Wrong stream id: " + streamid));
    }
  }


  public String getPrompt() {
    return "$>";
  }

// we need to make sure we don't remove it if it hasn't been completely read yet.
// if it hasn't been read yet, then closure of outputstream removes it.
// but what method would that be?
// What we have to do is tag it so we know we only wait for buffer to be closed.
// Then when buffer is closed, we remove it. If buffer is closed we can remove it here
  public boolean removeProcess(String id) {

    // Don't see any reason for calling this here
    //used();

    Process p = (Process) procmap.get(id);
//log.debug("ShellImpl : removeProcess() : " + id + " p: " + p);
    if (p != null) {
      // now we know the process has ended and we reset active to null
//log.debug("ShellImpl : removeProcess() : p.getOutputBuffer(): " + p.getOutputBuffer());
//log.debug("ShellImpl : removeProcess() : is closed?: " + p.getOutputBuffer().isClosed());

      if (p.getOutputBuffer().isClosed() && !p.isRedirected()) {
//        System.out.println("ShellImpl: removeProcess: buffer " + p.getOutputBuffer() + " is closed.");
        procmap.remove(id);
//log.debug("***\n***[removeProcess] Remove request. Removed process: " + id + "\n***");
        log.debug("Remove request.  Removed process: " + id);
        active = null;
//        System.out.println("ShellImpl: removeProcess: ACTIVE SET: " + active);
//        wout=new PrintWriter(new BufferedWriter(new BufferWriter(shellout)));
//        wout.close();
      }

      if (interactive && p.isUserInitiated()) {
        runtime.prompt();
      }

    } else {
//log.debug("ShellImpl : removeProcess() : NO SUCH PROCESS");
    }

    return p == null;

  }

  public VFS getVFS() throws ShellException {
    return vfs;
  }


  public UserCtx getUserCtx() throws ShellException {
    return uctx;
  }

  public void setPWD(String path) {
    // executeAsObject("cd " + path);
  }

  public void _setPWD(String path) {
    props.setProperty("PWD", path);
    runtime.setPWD(path);
  }


  // sysshell contains a reference to us. We need to tell it to clean us completely
  public void close() throws ShellException {

//log.debug("CLOSING SHELL SESSION");
    sshell.closeSession(uid);

    // make sure the following line is called last
    closed = true;
        closureTime = System.currentTimeMillis();

        StringBuffer stack = new StringBuffer();
        StackTraceElement [] trace = Thread.currentThread().getStackTrace();
        if(trace != null && trace.length > 2) {
            for(int i=2; i<trace.length; i++) {
                stack.append("\t").append(trace[i]).append("\r\n");
            }
        }
        closureReason = "method close() called on shell at: " + stack;
        // unregister eventBroadcaster
    if (eb != null) {
      eb.close();
    }

  }


  // kill any active jobs, dispose of any resources ...
  // NEVER CALL THIS ONE DIRECTLY. ONLY SysShell CAN CALL IT. ALWAYS USE close() INSTEAD.
  public void dispose() {
    // enumeriraj skozi procmap in pozapri vse in streame in vse out streame.

    // let's help a little - let's close all the in buffers of all the processes:
    // and system out also.


    try {
      EventBroadcaster eb = getEventBroadcaster();
      if (eb != null) {
        eb.dispatchEvent(new ShellEvent(EVENT_CLASS, "shellDispose", this));
      }
    } catch (Exception ex) {
      log.error(ex.getMessage(), ex);
    }

    try {
      if (interactive) {
//log.debug("[shell impl] dispose: closing " + shellout);
        log.debug("dispose: closing shellout " + shellout);
        shellout.close();
      }

      Map procs;
      synchronized(procmap) {
         procs = new HashMap(procmap);
      }
      Iterator it = procs.values().iterator();
      while (it.hasNext()) {
        Process p = (Process) it.next();
        InBuffer b = p.getInputBuffer();
//log.debug("[shell impl] dispose: closing in " + b);
        log.debug("dispose: closing in " + b);
        if (b != null) {
          b.close();
        }
        OutBuffer b2 = p.getOutputBuffer();
//log.debug("[shell impl] dispose: closing out " + b);
        log.debug("dispose: closing out " + b2);
        if (b2 != null) {
          b2.close();
        }
      }
    } catch (IOException ex) {
      log.error(ex.getMessage(), ex);
    }

  }

  public Map getProcesses() {
    synchronized(procmap) {
      return Collections.unmodifiableMap(new HashMap(procmap));
    }
  }

  // check every process we know of
  public void doGC() {
    long now = System.currentTimeMillis();
    long sess_tout = SESS_TIMEOUT;
    long proc_tout = PROC_TIMEOUT;

    String str;
    try {
      // be careful not to call getEnvProperty, because it updates lastUsed time and breaks gc of sessions
      str = (String) props.getEnvProperty("SESSION_TIMEOUT");
      sess_tout = Long.parseLong(str);
    } catch (Exception ex) {
    }

// DEBUG DEBUG DEBUG - throw this out NOW
//sess_tout = 60000l;
//log.debug("--- Session TIMEOUT : " + sess_tout);

    try {
      // be careful not to call getEnvProperty, because it updates lastUsed time and breaks gc of sessions
      str = (String) props.getEnvProperty("PROCESS_TIMEOUT");
      proc_tout = Long.parseLong(str);
    } catch (Exception ex) {
    }


    Map map = null;
    synchronized(procmap) {
       map = new HashMap(procmap);
    }
    Iterator it = map.values().iterator();
    while (it.hasNext()) {
      Process p = (Process) it.next();
      long t = p.lastUsed();

      if (now - t > proc_tout) {
        //log.debug("[ShellImpl] doGC : Process timed out : " + p.getID());
        log.info("Process timed out : " + p.getID());
        if (p.isFinished()) {
          sshell.endProcess(p.getID());
        } else {
          Executable e = p.getExecutable();
          if (e != null) {
            e.sendMessage("KILL");
          }
        }
        procmap.remove(p.getID());
        //log.debug("***\n***[doGC] Process timed out. (" + proc_tout + ")  Removed process " + p.getID() + "\n***");
        log.debug("Process timed out. (" + proc_tout + ")  Removed process " + p.getID());
      } else if (p.isRedirected() ? p.isMarkedComplete() && p.canDispose() : p.canDispose()) {
        procmap.remove(p.getID());
        //log.debug("***\n***[doGC] Process has finished. Removed process " + p.getID() + "\n***");
        log.debug("Process has finished. Removed process " + p.getID());
      }
    }

        checkTimedOut(now, sess_tout);
    }

    private void checkTimedOut(long now, long sess_tout) {
        long l = lastUsed();

     if (l == 0) {
       return;
     }
       
        //log.debug("[ShellImpl] doGC : Session last used: " + l + " vs. now: " + now + " (" + (now-l) + ")");
        if (now - l > sess_tout) {
            //log.debug("[ShellImpl] doGC : Session timed out : " + uid);
            try {
                closureReason = "Shell session timed out (inactive for: " + (now - l) + "ms,  timeout set to: " + sess_tout + "ms)" ;
                close();
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }

    private void preStartTimeoutCheck() throws ShellException {
        long sess_tout = SESS_TIMEOUT;

        try {
            // be careful not to call getEnvProperty, because it updates lastUsed time and breaks gc of sessions
            String str = (String) props.getEnvProperty("SESSION_TIMEOUT");
            sess_tout = Long.parseLong(str);
        } catch (Exception ex) {
        }

        checkTimedOut(System.currentTimeMillis(), sess_tout);

        used();
    }


    public void used() throws ShellException {

     if (closed) {
       throw new SessionTimeoutException("Shell instance has been closed at " + sdf_time.format(new Date(closureTime)) + "  -  " + closureReason);
     }
//log.debug("#$#$# used: ");
//log.info("used()");
//new Exception().printStackTrace();
        lastUsed = System.currentTimeMillis();
//    System.out.println("used");
    }

  public long lastUsed() {
    return lastUsed;
  }

  public Executable loadExe(String command) throws ShellException {
    return runtime.loadExe(command);
  }
/*
  public Cache getCache() {
    return cache;
  }

  public void setCache(Cache c) {
    this.cache=c;
  }
*/
  public Context getContext() {
    return ctx;
  }

  public void setContext(Context c) {
    this.ctx = c;
  }

  public void using() throws ShellException {
    used();
  }

  public long getStartTime() {
    return startTime;
  }

  public boolean isValid() {
    try {
      using();
    } catch (Exception ex) {
      return false;
    }
    return true;
  }
}
TOP

Related Classes of org.jboss.fresh.shell.impl.ShellImpl

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.