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;
}
}