package org.jboss.fresh.shell.impl;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import org.apache.log4j.Logger;
import org.jboss.fresh.ctx.FlatContext;
import org.jboss.fresh.io.Buffer;
import org.jboss.fresh.io.BufferWriter;
import org.jboss.fresh.shell.BadCommandException;
import org.jboss.fresh.shell.Executable;
import org.jboss.fresh.shell.ExecutableRegistry;
import org.jboss.fresh.shell.ShellException;
import org.jboss.fresh.vfs.FileInfo;
import org.jboss.fresh.vfs.FileName;
import org.jboss.fresh.vfs.VFSException;
public class ShellRuntime {
private static final Logger log = Logger.getLogger(ShellRuntime.class);
public static final String PWD = "PWD";
String pwd = "/";
ShellImpl shell;
boolean interactive;
private PrintWriter wout;
private BufferWriter bwo;
private Buffer out;
//private LinkedList pathNames = new LinkedList();
private HashMap aliases = new HashMap();
private ExecutableRegistry registry = new DefaultExecutableRegistry();
public ShellRuntime(ShellImpl shell, boolean interactive) {
this.shell = shell;
this.interactive = interactive;
}
public void setRegistry(ExecutableRegistry registry) {
this.registry = registry;
}
protected ExecutableRegistry getRegistry() {
if (registry == null)
throw new IllegalArgumentException("Executable registry is null");
return registry;
}
public void init(Buffer shellout) {
try {
// create new Cache Object implementation
//shell.setCache(new SimpleMemCache());
shell.setContext(new FlatContext());
try {
if (shell.getVFS().exists(null, new FileName("/etc/shell/init.rc"), true))
shell.executeAsObject("run /etc/shell/init.rc"); // NullInput In case no redirects specified of course
} catch (Exception ex) {
log.error("Error while executing 'run /etc/shell/init.rc'", ex);
if (shellout != null)
shellout.put("init.rc returned an error: " + ex.toString() + " : " + (ex.getCause() == null ? "" : ex.getCause().toString()), 10000);
}
shell.setEnvProperty("VERSION", org.jboss.fresh.shell.impl.Version.getDescription());
} catch (Throwable t) {
log.error(t.getMessage(), t);
throw new RuntimeException("Init problems: " + t);
}
}
// Never call this directly if you want to set PWD. Only ShellImpl calls this method within
// its _setPWD()
public void setPWD(String path) {
//log.debug("[ShellRuntime] setPWD: " + path);
pwd = path;
/*
try {
rebuildPath(shell.getEnvProperty("PATH"));
} catch (Throwable ex) {
log.error(ex.getMessage(),ex);
}
*/
}
/*
public void setEnvProperty(String name, String value) {
//log.debug("[ShellRuntime] setEnvProperty: " + name + " - " + value);
if (name.equals("PATH")) {
rebuildPath(value);
}
}
private void rebuildPath(String value) {
//log.debug("[ShellRuntime] rebuildPath: " + value);
pathNames.clear();
if (value == null) return;
FileName pwdnm = new FileName(pwd);
StringTokenizer t = new StringTokenizer(value, ":");
while (t.hasMoreTokens()) {
try {
FileName tk = new FileName(t.nextToken());
if (!tk.isAbsolute()) {
tk = pwdnm.absolutize(tk);
}
pathNames.add(tk);
} catch (Exception ex) {
log.error(ex.getMessage(),ex);
}
}
}
*/
public String getPrompt() {
return "[" + pwd + "]";
}
public void setOutBuffer(Buffer out) {
this.out = out;
if (out == null) return;
bwo = new BufferWriter(out);
bwo.setTimeout(ShellImpl.PROC_INST_TIMEOUT);
wout = new PrintWriter(bwo, true);
}
public void started() {
// set the timeout so if client disconnects before reading from this buffer
// the thread running the process that we use to output shell messages
// will eventually be returned to the pool
//wout=new PrintWriter(new BufferedWriter(bwo));
if (out == null)
return;
wout.println(Version.getDescription());
wout.println("(c) JBoss");
}
public void prompt() {
//new Exception("ShellRuntime: writting PROMPT to shell out.").printStackTrace();
if (out == null) return;
wout.println();
wout.print(getPrompt());
wout.flush();
}
public Executable loadExe(String command) throws ShellException {
FileInfo inf = null;
try {
//log.debug("[ShellRuntime] Resolving filename to class");
FileName cmdnm = new FileName(command);
if (!cmdnm.isAbsolute()) {
String path = getPATH();
FileName pwdnm = new FileName(pwd);
StringTokenizer t = new StringTokenizer(path, ":");
while (t.hasMoreTokens()) {
try {
FileName dir = new FileName(t.nextToken());
if (!dir.isAbsolute()) {
dir = pwdnm.absolutize(dir);
}
FileName full = dir.absolutize(cmdnm);
// log.debug("[ShellRuntime] trying: " + full);
inf = shell.getVFS().getFileInfo(shell.getUserCtx(), full, false);
if (inf != null) { // got it!
// log.debug("[ShellRuntime] found file!");
break;
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
}
} else {
inf = shell.getVFS().getFileInfo(shell.getUserCtx(), cmdnm, false);
}
if (inf != null) {
String clazz = (String) inf.getAttributes().get("Class");
if (clazz == null) throw new ShellException("No Class attribute specified. (" + command + ")");
command = clazz;
}
Executable exe = getInternal(command);
if (exe != null) return exe;
} catch (ShellException ex) {
log.error(ex.getMessage(), ex);
Executable exe = getInternal(command);
if (exe != null) return exe;
throw ex;
} catch (VFSException ex) {
log.error(ex.getMessage(), ex);
throw new ShellException(ex.toString());
}
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class execls = null;
try {
execls = cl.loadClass(command);
} catch (ClassNotFoundException e) {
throw new BadCommandException("Unknown command.", command);
}
Executable exe;
try {
exe = (Executable) execls.newInstance();
} catch (InstantiationException e) {
throw new ShellException("Could not instantiate class: " + execls);
} catch (IllegalAccessException e) {
throw new ShellException("Not allowed to instantiate class: " + execls);
}
exe.setFileInfo(inf);
return exe;
}
private String getPATH() throws ShellException {
String ret;
Process p = Process.getThreadParent();
if (p != null) {
ret = p.getEnv().getEnvProperty("PATH");
} else {
ret = shell.getEnv().getEnvProperty("PATH");
}
if (ret == null)
ret = "";
return ret;
}
protected Executable getInternal(String command) {
return getRegistry().getExecutable(command);
}
public String unaliasCmdLine(String cmdline) {
// break cmdline by |
StringBuilder b = new StringBuilder();
StringTokenizer tkzr = new StringTokenizer(cmdline, "|", true);
while (tkzr.hasMoreTokens()) {
String tk = tkzr.nextToken();
if (tk.equals("|")) {
b.append(tk);
continue;
}
// now identify where first command begins and where it ends
// look for space first
int start = 0;
int end = tk.length();
for (int i = start; i < end && tk.charAt(i) == ' '; i++, start++) ;
int sp = tk.indexOf(" ", start + 1);
if (sp != -1)
end = sp;
sp = tk.indexOf("&", start + 1);
if (sp != -1 && sp < end)
end = sp;
sp = tk.indexOf(".", start + 1);
if (sp != -1 && sp < end)
end = sp;
sp = tk.indexOf("<", start + 1);
if (sp != -1 && sp < end)
end = sp;
sp = tk.indexOf(">", start + 1);
if (sp != -1 && sp < end)
end = sp;
b.append(tk.substring(0, start))
.append(unalias(tk.substring(start, end)))
.append(tk.substring(end));
}
return b.toString();
}
public String unalias(String cmd) {
Iterator it = aliases.entrySet().iterator();
while (it.hasNext()) {
Map.Entry ent = (Map.Entry) it.next();
if (ent.getKey().equals(cmd)) {
return (String) ent.getValue();
}
}
return cmd;
}
public void addAlias(String alias, String cmd) {
aliases.put(alias, cmd);
}
public String removeAlias(String alias) {
return (String) aliases.remove(alias);
}
public Map listAliases() {
return new TreeMap(aliases);
}
}