package org.jboss.fresh.shell.commands;
import org.jboss.fresh.io.BufferImpl;
import org.jboss.fresh.io.BufferWriter;
import org.jboss.fresh.io.PrintWriter2;
import org.jboss.fresh.shell.AbstractExecutable;
import org.jboss.fresh.shell.Executable;
import org.jboss.fresh.shell.impl.Process;
import org.jboss.fresh.shell.impl.ShellImpl;
import org.jboss.fresh.shell.impl.SystemShellImpl;
import org.jboss.fresh.util.LineFormat;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.*;
public class PsExe extends AbstractExecutable {
private static transient org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(PsExe.class);
PrintWriter pout;
SimpleDateFormat sdf_timepassed = new SimpleDateFormat("HH.mm.ss");
SimpleDateFormat sdf_time = new SimpleDateFormat("HH:mm:ss");
private static final String[] COLS_LONG = new String[]{"pid", "parent", "shour", "etime", "ptime", "state", "lused", "evict", "cinfo", "cmd"};
private static final String[] COLS_SHORT = new String[]{"pid", "parent", "shour", "etime", "ptime", "cmd"};
private boolean tracesOn;
private boolean parentTracesOn;
private boolean finished;
private boolean longForm;
private boolean alles;
private String order;
private TreeSet rows;
Map parentMap = new HashMap();
private LineFormat fmt;
/**
* Displays properties of all processes and sessions.
*/
public void process(String exepath, String[] params) throws Exception {
log.debug("entered");
pout = new PrintWriter2(new BufferedWriter(new BufferWriter(getStdOut())));
String[] invalids = getInvalidSwitches(args, "axflitT", new String[]{"--ex", "--help", "--order", "--out", "--full-thread-dump"});
alles = isSwitchActive(args, "a", null);
boolean xall = isSwitchActive(args, "x", null);
finished = isSwitchActive(args, "f", null);
longForm = isSwitchActive(args, "l", null);
String outproc = getSwitchValue(args, null, "--out");
order = getSwitchValue(args, null, "--order");
boolean idleShells = isSwitchActive(args, "i", null);
tracesOn = isSwitchActive(args, "t", null);
parentTracesOn = isSwitchActive(args, "T", null);
boolean fullThreadDump = isSwitchActive(args, null, "--full-thread-dump");
TableComparator comptor = null;
if ((invalids.length > 0)) {
StringBuffer sb = new StringBuffer("Unknown or invalid switch(es):");
for (int i = 0; i < invalids.length; i++) {
sb.append(" " + invalids[i]);
}
error(sb.toString());
return;
}
if (helpRequested()) {
StringBuffer sb = new StringBuffer();
sb.append("Usage: ps [-xaf] [--help]\r\n");
sb.append(" -a : display all information available\r\n");
sb.append(" -x : display processes for all sessions\r\n");
sb.append(" -l : display ids in long form\r\n");
sb.append(" -f : display finished but not yet gc-ed processes\r\n");
sb.append(" -t : display thread dump of every leaf child\r\n");
sb.append(" -T : display thread dump of every first child\r\n");
sb.append(" --full-thread-dump : display full thread dump - no process info\r\n");
sb.append(" --out : displays out buffer content as paramter you must pass him process id\r\n");
sb.append(" --help : this help\r\n");
error(sb.toString());
return;
}
if (outproc != null) {
SystemShellImpl ss = (SystemShellImpl) ((ShellImpl) getShell()).getSystemShell();
Process proc = ss.findProcess(outproc);
if (proc == null) {
Map m = ss.getShellMap();
Iterator it = m.entrySet().iterator();
while (it.hasNext()) {
Map.Entry ent = (Map.Entry) it.next();
ShellImpl shel = (ShellImpl) ent.getValue();
Map procs = shel.getProcesses();
proc = (Process) procs.get(outproc);
if (proc != null) break;
}
if (proc == null) {
error("No process for id: " + outproc);
return;
}
}
Object outb = proc.getOutputBuffer();
pout.println("Out buffer: " + outb + " [" + (outb == null ? "" : outb.getClass().getName()) + "]");
if (outb instanceof BufferImpl) {
List ls = ((BufferImpl) outb).getBufferCopy();
pout.println("\nContent: ");
pout.println(ls);
}
pout.flush();
return;
}
if(fullThreadDump) {
Set allTraces = Thread.getAllStackTraces().entrySet();
Iterator it = allTraces.iterator();
while(it.hasNext()) {
Map.Entry ent = (Map.Entry) it.next();
Thread key = (Thread) ent.getKey();
StackTraceElement [] traces = (StackTraceElement []) ent.getValue();
boolean netlight = false;
boolean plain = false;
boolean highlight = key.getState() != Thread.State.BLOCKED && key.getState() != Thread.State.TIMED_WAITING && key.getState() != Thread.State.WAITING;
if(highlight && traces.length > 0 &&
(("java.net.PlainSocketImpl".equals(traces[0].getClassName())
&& "socketAccept".equals(traces[0].getMethodName()))
|| ("java.net.SocketInputStream".equals(traces[0].getClassName())
&& "socketRead0".equals(traces[0].getMethodName())))
) {
netlight = true;
}
if(netlight) {
pout.print("\u001B[0;36m");
} else if(traces.length == 0) {
highlight = true;
pout.print("\u001B[0;31m");
} else if(highlight) {
plain = true;
pout.print("\u001B[1;33m");
}
pout.println(ent.getKey());
if(plain) {
pout.print("\u001B[0m\u001B[0;33m");
}
for(int i=0; i<traces.length; i++) {
pout.println(" " + traces[i]);
}
if(highlight)
pout.print("\u001B[0m");
}
pout.flush();
return;
}
if (order != null) {
try {
comptor = new TableComparator(order, (alles ? COLS_LONG : COLS_SHORT));
rows = new TreeSet(comptor);
} catch (Exception ex) {
error(ex.getMessage());
return;
}
}
//print("Processes: ");
// Let's list all info for all processes first
/*
Map m = ((ShellImpl) getShell()).getProcesses();
Iterator it = m.entrySet().iterator();
print("pID\tTime\tActive\tDone\tsessID\tType\tCmd\tErr");
while (it.hasNext()) {
Map.Entry me = (Map.Entry) it.next();
//log.debug("Key: " + me.getKey());
Process p = (Process) me.getValue();
print(p.getID() + "\t" +
elapsedTime(p.getStartTime()) + "\t" +
!p.isFinished() + "\t" +
p.canDispose() + "\t" +
getShell().getSessionID() + "\t" +
p.getClass().getName() + "\t" +
p.getCommandLine() + "\t" +
p.getThrowable());
}
*/
//print("Sessions:");
int idlen = longForm ? 40 : 10;
if (alles) {
fmt = new LineFormat(new int[]{idlen, idlen, 8, 8, 8, 5, 8, 7, 15, 3}, new String[]{"l", "l", "l", "l", "l", "l", "l", "l", "l"}, new int[]{0, 2, 2, 2, 2, 2, 2, 2, 2, 2});
print(fmt.print(COLS_LONG), 0);
} else {
fmt = new LineFormat(new int[]{idlen, idlen, 8, 8, 8, 3}, new String[]{"l", "l", "l", "l", "l", "l"}, new int[]{0, 2, 2, 2, 2, 2});
print(fmt.print(COLS_SHORT), 0);
}
//print("\n");
Iterator it = null;
Map procMap = null;
if (xall) {
procMap = ((SystemShellImpl) ((ShellImpl) getShell()).getSystemShell()).getShellMap();
//it = m.entrySet().iterator();
} else {
procMap = new HashMap();
procMap.put("0", getShell());
//it = m.entrySet().iterator();
}
HashSet singles = new HashSet();
// prepare hierarchies
it = procMap.entrySet().iterator();
while(it.hasNext()) {
Map.Entry ent = (Map.Entry)it.next();
ShellImpl shel = (ShellImpl) ent.getValue();
singles.add(shel);
Map pcs = shel.getProcesses();
Iterator it2 = pcs.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry me2 = (Map.Entry) it2.next();
//log.debug("Key: " + me.getKey());
if ("0".equals(me2.getKey())) continue;
Process p = (Process) me2.getValue();
if(p.getParent() != null) {
List childls = (List) parentMap.get(p.getParent().getID());
if(childls == null) {
childls = new LinkedList();
parentMap.put(p.getParent().getID(), childls);
}
childls.add(p);
} else {
List childls = (List) parentMap.get(shel.getSessionID());
if(childls == null) {
childls = new LinkedList();
parentMap.put(shel.getSessionID(), childls);
}
childls.add(p);
}
}
}
it = singles.iterator();
while (it.hasNext()) {
ShellImpl shi = (ShellImpl) it.next();
outputProcess(shi, null, 0, idleShells);
}
/*
//print("sessID");
while (it.hasNext()) {
Map.Entry me = (Map.Entry) it.next();
//log.debug("Key: " + me.getKey());
ShellImpl shel = (ShellImpl) me.getValue();
//print(p.getSessionID());
//shel.getSessionID();
Map pcs = shel.getProcesses();
Iterator it2 = pcs.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry me2 = (Map.Entry) it2.next();
//log.debug("Key: " + me.getKey());
if ("0".equals(me2.getKey())) continue;
Process p = (Process) me2.getValue();
StringBuffer state = new StringBuffer();
if (p.isFinished())
state.append("e");
else
state.append("E");
if (p.isDone())
state.append("w");
else
state.append(" ");
if (p.isComplete()) {
if (!finished) continue;
state.append("f");
} else
state.append(" ");
String uid = p.getID();
if(!longForm)
uid = truncID(uid);
String sessID = shel.getSessionID();
if(p.getParent() != null)
sessID = p.getParent().getID();
if(!longForm)
sessID = truncID(sessID);
if(p.getParent() != null)
sessID = "\\" + sessID;
if (alles) {
boolean nocinfo = shel.getClientAndProjectInfo().startsWith("cuser_unknown");
String evict = evictToGo(p);
String[] row = new String[]{uid, sessID, sdf_time.format(new Date(p.getStartTime())), p.getFinishTime() == 0 ? " -" : elapsedTime(p.getStartTime(), p.getFinishTime()), p.getFinishTime() == 0 ? elapsedTime(p.getStartTime(), 0) : elapsedTime(p.getStartTime(), p.getFinishTime()), state.toString(), p.getFinishTime() == 0 ? elapsedUsed(p.lastUsed()) : "--", evict, nocinfo ? " -" : shel.getClientAndProjectInfo(), p.getCommandLine() + " " + formatParams(p.getOriginalParams())};
if (order != null)
rows.add(row);
else
print(fmt.print(row));
} else {
String[] row = new String[]{uid, sessID, sdf_time.format(new Date(p.getStartTime())), p.getFinishTime() == 0 ? " -" : elapsedTime(p.getStartTime(), p.getFinishTime()), p.getFinishTime() == 0 ? elapsedTime(p.getStartTime(), 0) : elapsedTime(p.getStartTime(), p.getFinishTime()), p.getCommandLine() + " " + formatParams(p.getOriginalParams())};
if (order != null)
rows.add(row);
else
print(fmt.print(row));
}
}
}
if (order != null) {
it = rows.iterator();
while (it.hasNext()) {
print(fmt.print((String[]) it.next()));
}
}
*/
/*
print("All processes:");
m = ((SystemShellImpl) ((ShellImpl) getShell()).getSystemShell()).getProcMap();
it = m.entrySet().iterator();
print("pID\tTime\tActive\tsessID\tType\tCmd\tErr");
while (it.hasNext()) {
Map.Entry me = (Map.Entry) it.next();
//log.debug("Key: " + me.getKey());
Process p = (Process) me.getValue();
print(p.getID() + "\t" +
elapsedTime(p.getStartTime()) + "\t" +
!p.isFinished() + "\t" +
getShell().getSessionID() + "\t" +
p.getClass().getName() + "\t" +
p.getCommandLine() + "\t" +
p.getThrowable());
}
*/
pout.flush();
log.debug("done");
}
private void outputProcess(ShellImpl shel, Process p, int depth, boolean idleShells) throws Exception {
// if process has children
List children = (List) parentMap.get(p != null ? p.getID() : shel.getSessionID());
if(p == null && !idleShells && (children == null || children.isEmpty()))
return;
StringBuffer state = new StringBuffer();
if (p != null && p.isFinished()) {
if (!finished)
return;
state.append("e");
} else {
state.append("E");
}
if (p != null && p.isDone()) {
state.append("w");
} else {
state.append(" ");
}
if (p != null && p.isComplete()) {
if (!finished)
return;
state.append("f");
} else {
state.append(" ");
}
String uid = p != null ? p.getID() : shel.getSessionID();
if(!longForm)
uid = truncID(uid);
String sessID = null;
if(p != null) {
sessID = shel.getSessionID();
if(p.getParent() != null)
sessID = p.getParent().getID();
}
if(!longForm && sessID != null)
sessID = truncID(sessID);
if(sessID == null)
sessID = " -";
String cmdln = p == null ? "<shell-session> " + shel.getSessionID() : p.getCommandLine() + " " + formatParams(p.getOriginalParams());
if(depth > 0) {
StringBuffer deps = new StringBuffer();
for(int i=0; i<depth; i++)
deps.append(' ');
cmdln = deps + "\\- " + cmdln;
}
String[] row;
if (alles) {
boolean nocinfo = shel.getClientAndProjectInfo().indexOf("chost_unknown") != -1;
String evict = p != null ? evictToGo(p) : evictShellToGo(shel);
long stime = p != null ? p.getStartTime() : shel.getStartTime();
row = new String[]{uid,
sessID,
sdf_time.format(new Date(stime)),
p == null || p.getFinishTime() == 0
? " -" : elapsedTime(p.getStartTime(), p.getFinishTime()),
p == null ? " -" :
p.getFinishTime() == 0
? elapsedTime(p.getStartTime(), 0)
: elapsedTime(p.getStartTime(), p.getFinishTime()),
state.toString(),
p != null && p.getFinishTime() == 0
? elapsedUsed(p.lastUsed()) : "--",
evict,
nocinfo ? " -" : shel.getClientAndProjectInfo(),
cmdln};
} else {
row = new String[]{uid,
sessID,
p == null ? " -" : sdf_time.format(new Date(p.getStartTime())),
p == null || p.getFinishTime() == 0
? " -" : elapsedTime(p.getStartTime(), p.getFinishTime()),
p == null ? " -" :
p.getFinishTime() == 0
? elapsedTime(p.getStartTime(), 0)
: elapsedTime(p.getStartTime(), p.getFinishTime()),
cmdln};
}
// add stack trace
Thread t = p != null ? p.getThread() : null;
int activeChildren = 0;
if(children != null) {
Iterator it = children.iterator();
while(it.hasNext()) {
Process pcs = (Process) it.next();
if(!pcs.isFinished()) {
activeChildren++;
break;
}
}
}
if(((tracesOn && activeChildren == 0) ||
(parentTracesOn && p != null && p.getParent() == null))
&& p != null && t != null) {
StackTraceElement [] traces = t.getStackTrace();
StringBuffer sb = new StringBuffer("\r\n");
boolean found = false;
for(int i=0; i<traces.length; i++) {
Executable exu = p.getExecutable();
String exc = exu != null ? exu.getClass().getName() : null;
if(traces[i].getClassName().equals(exc)) {
found = true;
} else if(found) {
break;
}
sb.append("\r\n\t").append(String.valueOf(traces[i]));
}
if (order != null) {
row[row.length-1] = row[row.length-1] + sb;
rows.add(row);
} else {
print(fmt.print(row) + sb, depth);
}
} else {
if (order != null)
rows.add(row);
else
print(fmt.print(row), depth);
}
// if process has children
if(children != null) {
Iterator it = children.iterator();
while(it.hasNext()) {
Process pcs = (Process) it.next();
outputProcess(shel, pcs, depth+1, idleShells);
}
}
}
private String formatParams(String[] params) {
// TODO Auto-generated method stub
if(params == null)
return "";
StringBuffer sb = new StringBuffer();
for(int i=0; i<params.length; i++) {
if(i>0)
sb.append(' ');
sb.append(params[i]);
}
return sb.toString();
}
private String evictToGo(Process p) {
long proc_tout = 0;
try {
// be careful not to call getEnvProperty, because it updates lastUsed time and breaks gc of sessions
String str = (String) p.getEnv().getEnvProperty("PROCESS_TIMEOUT");
proc_tout = Long.parseLong(str);
} catch (Exception ex) {
}
if(proc_tout == 0)
proc_tout = ShellImpl.PROC_TIMEOUT;
long et = (proc_tout - (System.currentTimeMillis() - p.lastUsed()))/1000;
//return et > 0 ? sdf_timepassed.format(et) : "-"+sdf_timepassed.format(-et);
return (et > 0 ? "-" + String.valueOf(et): "+" + String.valueOf(-et)) + "s";
}
private String evictShellToGo(ShellImpl sh) {
long proc_tout = 0;
try {
// be careful not to call getEnvProperty, because it updates lastUsed time and breaks gc of sessions
String str = (String) sh.getEnv().getEnvProperty("SESSION_TIMEOUT");
proc_tout = Long.parseLong(str);
} catch (Exception ex) {
}
if(proc_tout == 0)
proc_tout = ShellImpl.SESS_TIMEOUT;
long et = (proc_tout - (System.currentTimeMillis() - sh.lastUsed()))/1000;
//return et > 0 ? sdf_timepassed.format(et) : "-"+sdf_timepassed.format(-et);
return (et > 0 ? "-" + String.valueOf(et): "+" + String.valueOf(-et)) + "s";
}
private String elapsedUsed(long ltime) {
if(ltime == 0)
ltime = System.currentTimeMillis();
return "-" + (String.valueOf((System.currentTimeMillis()-ltime) / 1000));
}
private String elapsedTime(long start, long stop) {
if (stop == 0) stop = System.currentTimeMillis();
long elapsed = stop - start;
Calendar c = Calendar.getInstance();
c.setTime(new Date(elapsed));
c.add(Calendar.HOUR_OF_DAY, -1);
//long secs=elapsed/1000;
return sdf_timepassed.format(c.getTime());
}
private void print(String val, int depth) {
//log.debug("[" + val + "]");
pout.println(val);
pout.flush();
}
private String truncID(String id) {
// suppose it's a GUID i.e. 2515C259-58BB-6A2A-11D8-5D1506E1772E
// we make it shorter by
// filtering out: ______XX___XX___XX___XX___________XX
StringBuffer sb = new StringBuffer();
//int [] pos = new int [] {6, 7, 11, 12, 16, 17, 21, 22, 34, 35};
for(int i=0; i<TRUNC_PAT.length; i++) {
sb.append(id.charAt(TRUNC_PAT[i]));
}
return sb.toString();
}
int [] TRUNC_PAT = new int [] {6, 7, 11, 12, 16, 17, 21, 22};
static class TableComparator implements Comparator {
int col = -1;
TableComparator(String row, String[] cols) {
for (int i = 0; i < cols.length; i++) {
if (cols[i].equals(row)) {
col = i;
break;
}
}
if (col == -1) throw new RuntimeException("Invalid row: " + row);
}
public int compare(Object o1, Object o2) {
String[] row1 = (String[]) o1;
String[] row2 = (String[]) o2;
//System.out.println("compare " + row1[col] + " to " + row2[col] + " : " + row1[col].compareTo(row2[col]));
return (row1[col].compareTo(row2[col]));
}
public boolean equals(Object obj) {
return obj == this;
}
}
}