[jboss-cvs] JBossAS SVN: r88114 - in projects/fresh/trunk: fresh-ssh and 4 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Fri May 1 19:18:15 EDT 2009
Author: ctomc
Date: 2009-05-01 19:18:15 -0400 (Fri, 01 May 2009)
New Revision: 88114
Added:
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java
Removed:
projects/fresh/trunk/fresh-ssh/etc/
projects/fresh/trunk/fresh-ssh/src/main/java/com/
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/parsek/
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/
Modified:
projects/fresh/trunk/etc/fresh/ssh/platform.xml
projects/fresh/trunk/etc/fresh/ssh/server.xml
projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java
Log:
FRESH-2 configuration for ssh is now loaded from classpath
Modified: projects/fresh/trunk/etc/fresh/ssh/platform.xml
===================================================================
--- projects/fresh/trunk/etc/fresh/ssh/platform.xml 2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/etc/fresh/ssh/platform.xml 2009-05-01 23:18:15 UTC (rev 88114)
@@ -4,9 +4,9 @@
-->
<PlatformConfiguration>
<!-- The process provider for executing and redirecting a process -->
- <NativeProcessProvider>org.jboss.fresh.ssh.cp2.SSHShell</NativeProcessProvider>
+ <NativeProcessProvider>org.jboss.fresh.ssh.SSHShell</NativeProcessProvider>
<!-- The authentication provider for authenticating users and obtaining user information -->
- <NativeAuthenticationProvider>org.jboss.fresh.ssh.cp2.Cp2AuthenticationProvider</NativeAuthenticationProvider>
+ <NativeAuthenticationProvider>org.jboss.fresh.ssh.Cp2AuthenticationProvider</NativeAuthenticationProvider>
<!-- The file system provider for SFTP -->
<NativeFileSystemProvider>org.jboss.fresh.vfs</NativeFileSystemProvider>
<!-- Native settings which may be used by the process or authentication provider -->
Modified: projects/fresh/trunk/etc/fresh/ssh/server.xml
===================================================================
--- projects/fresh/trunk/etc/fresh/ssh/server.xml 2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/etc/fresh/ssh/server.xml 2009-05-01 23:18:15 UTC (rev 88114)
@@ -4,16 +4,16 @@
-->
<ServerConfiguration>
<!-- Path to server private key file - you need to generate it in advance of course. -->
- <ServerHostKey PrivateKeyFile="../fresh/ssh/priv.skk" />
+ <ServerHostKey PrivateKeyFile="priv.skk" />
<!-- Possible values for these are: ... -->
<!--Subsytem Type="" Name="" Provider="" /-->
<!-- The file system provider for SFTP -->
- <AuthenticationBanner>../fresh/ssh/hello.txt</AuthenticationBanner>
+ <!--AuthenticationBanner>hello.txt</AuthenticationBanner--> <!-- currently doesnt work becouse of issues with loading-->
<MaxConnections>3</MaxConnections>
<MaxAuthentications>3</MaxAuthentications>
- <ListenAddress>192.168.2.35</ListenAddress>
+ <ListenAddress>127.0.0.1</ListenAddress>
<Port>2022</Port>
<CommandPort>2024</CommandPort>
<TerminalProvider>vt100</TerminalProvider>
@@ -25,7 +25,7 @@
<RequiredAuthentication>password</RequiredAuthentication>
- <AuthorizationFile>../fresh/ssh/authorization.xml</AuthorizationFile>
+ <AuthorizationFile>authorization.xml</AuthorizationFile>
<UserConfigDirectory>users</UserConfigDirectory>
<AllowTcpForwarding>false</AllowTcpForwarding>
Modified: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java 2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -1,7 +1,11 @@
package org.jboss.fresh.deployer;
+import org.jboss.fresh.ssh.DaemonStarter;
+import org.jboss.logging.Logger;
+
public class SSHService extends ServiceModule implements SSHServiceMBean {
+ private static final Logger log = Logger.getLogger(SSHService.class);
private Thread th = null;
private String home;
private String ssjndi;
@@ -32,11 +36,11 @@
//System.setProperty("sshtools.home", home);
//com.sshtools.j2ssh.SshServer.main(new String [] {"-start"});
try {
- org.jboss.fresh.ssh.cp2.DaemonStarter.setConfigDir(home);
- org.jboss.fresh.ssh.cp2.DaemonStarter.setSystemShellJNDI(ssjndi);
- org.jboss.fresh.ssh.cp2.DaemonStarter.initialize();
+ DaemonStarter.setConfigDir(home);
+ DaemonStarter.setSystemShellJNDI(ssjndi);
+ DaemonStarter.initialize();
} catch (Exception ex) {
- ex.printStackTrace();
+ log.error("could not start ssh service",ex);
}
}
};
@@ -45,7 +49,7 @@
public void doStop() {
try {
- org.jboss.fresh.ssh.cp2.DaemonStarter.stop("Stop command issued");
+ DaemonStarter.stop("Stop command issued");
} catch (java.io.IOException ex) {
throw new RuntimeException(ex);
}
Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/Cp2AuthenticationProvider.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,80 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.NativeAuthenticationProvider;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * @version 1.0
+ */
+
+public class Cp2AuthenticationProvider extends NativeAuthenticationProvider {
+
+ private static Logger log = Logger.getLogger(Cp2AuthenticationProvider.class);
+ private static Cp2AuthenticationProvider instance;
+ private Properties p = new Properties();
+
+
+ public Cp2AuthenticationProvider() {
+ super();
+
+ File users = null;
+ try {
+ users = new File(System.getProperty("sshtools.home") + File.separator + "conf" + File.separator + "users.conf");
+ p.load(new FileInputStream(users));
+ } catch (Exception ex) {
+ log.warn("Could not open users file: " + users);
+ }
+ }
+
+ public String getHomeDirectory(String username) {
+ return "/";
+ }
+
+ //for now a hard coded path is returned
+ public String getHomeDirectory(String username, Map tokens) {
+ return System.getProperty("sshtools.home");
+ }
+
+ public boolean logonUser(String username, String password, Map tokens) {
+
+// if (username.equals("root") && password.equals("root")){
+// log.info(username + " has passed authentication");
+// return true;
+ String reguserpass = p.getProperty(username);
+ if (reguserpass != null && reguserpass.equals(password)) {
+ return true;
+ } else {
+ log.info(username + " has failed authentication");
+ return false;
+ }
+ }
+
+ public boolean logonUser(String username, Map tokens) {
+ return true;
+ }
+
+
+ public boolean changePassword(String username, String oldpass, String newpass) {
+ return false;
+ }
+
+ public void logoffUser() {
+
+ }
+
+ public boolean logonUser(String user) {
+ return true;
+ }
+
+ public boolean logonUser(String user, String pass) {
+ return true;
+ }
+
+
+}
\ No newline at end of file
Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/Cp2VFSProvider.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,463 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.InvalidHandleException;
+import com.sshtools.daemon.platform.NativeFileSystemProvider;
+import com.sshtools.daemon.platform.PermissionDeniedException;
+import com.sshtools.daemon.platform.UnsupportedFileOperationException;
+import com.sshtools.j2ssh.io.UnsignedInteger32;
+import com.sshtools.j2ssh.io.UnsignedInteger64;
+import com.sshtools.j2ssh.sftp.FileAttributes;
+import com.sshtools.j2ssh.sftp.SftpFile;
+import org.apache.log4j.Logger;
+import org.jboss.fresh.registry.RegistryContext;
+import org.jboss.fresh.shell.SystemShell;
+import org.jboss.fresh.vfs.*;
+
+import java.io.EOFException;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class Cp2VFSProvider extends NativeFileSystemProvider {
+
+ private static final Logger log = Logger.getLogger(Cp2VFSProvider.class);
+
+ private int fileid = 1;
+ private DecimalFormat fmt;
+
+ HashMap openfiles = new HashMap();
+ VFS vfs;
+
+ FileName root;
+
+ private synchronized String getKey() {
+ return fmt.format(fileid++);
+ }
+
+ public Cp2VFSProvider() {
+
+
+ try {
+ fmt = new DecimalFormat("00000000");
+
+ RegistryContext ctx = new RegistryContext();
+ SystemShell ssh = (SystemShell) ctx.lookup("java:/CP2/SystemShell");
+ vfs = ssh.getVFS();
+ log.info("Successfully initialized vfs: " + vfs);
+
+ root = new FileName("/");
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ throw new RuntimeException(e);
+ }
+
+ }
+
+
+ /**
+ * true if file exists, false otherwise
+ */
+ public boolean fileExists(String path) throws IOException {
+ //log.error("fileExists : " + path);
+ return true;
+ }
+
+
+ /**
+ * Ugibam ampak mislim da pomeni to:
+ * in: ../../boo/foo out: /boo/foo
+ * in: tmp/../dev out: dev
+ */
+ public String getCanonicalPath(String path) throws IOException, FileNotFoundException {
+ //log.error("getCanonicalPath : " + path);
+ FileName fname = new FileName(path);
+ return fname.toString();
+ }
+
+
+ /**
+ * Ugibam ampak mislim da pomeni to:
+ * in: ../../boo/foo out: /home/user/../../boo/foo
+ * in: tmp/../dev out: /root/tmp/../dev
+ */
+ public String getRealPath(String path) throws FileNotFoundException {
+ //log.error("getRealPath : " + path);
+ FileName fname = root.absolutize(path);
+ return fname.toString();
+ }
+
+
+ /**
+ * creates the specified directory and returns true or false depending on success
+ */
+ public boolean makeDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("makeDirectory : " + path);
+ return true;
+ }
+
+
+ /**
+ * FileAttributes je zelo o�itno struktura z datote�nimi atributi.
+ * <p/>
+ * From http://www.openssh.org/txt/draft-ietf-secsh-filexfer-02.txt
+ * <p/>
+ * When
+ * sending it to the server, the flags field specifies which attributes
+ * are included, and the server will use default values for the
+ * remaining attributes (or will not modify the values of remaining
+ * attributes). When receiving attributes from the server, the flags
+ * specify which attributes are included in the returned data. The
+ * server normally returns all attributes it knows about.
+ * <p/>
+ * uint32 flags
+ * uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
+ * uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ * uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ * uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+ * uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
+ * uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
+ * uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+ * string extended_type
+ * string extended_data
+ * ... more extended data (extended_type - extended_data pairs),
+ * so that number of pairs equals extended_count
+ */
+ public FileAttributes getFileAttributes(String path) throws IOException, FileNotFoundException {
+ //log.error("getFileAttributes : " + path);
+
+ FileInfo inf = vfs.getFileInfo(null, new FileName(path), true);
+ if (inf == null) throw new FileNotFoundException(path);
+
+ return info2Attrs(inf);
+ }
+
+
+ /**
+ * FileAttributes je zelo o�itno struktura z datote�nimi atributi. Vsak file ima o�itno file descriptor ki je v obliki byte [].
+ */
+ public FileAttributes getFileAttributes(byte[] handle) throws IOException, InvalidHandleException {
+ //log.error("getFileAttributes 2 : " + new String(handle));
+
+ String shandle = new String(handle);
+
+ FileData data = (FileData) openfiles.get(shandle);
+ if (data == null) throw new FileNotFoundException(String.valueOf(data.name));
+
+
+ return info2Attrs(data.info);
+ }
+
+
+ /**
+ * Dobi file handle za directory path
+ */
+ public byte[] openDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("openDirectory : " + path);
+
+ byte[] key = getKey().getBytes();
+
+ FileData data = new FileData();
+ data.originalName = path;
+ data.name = root.absolutize(path);
+ data.info = vfs.getFileInfo(null, data.name, false);
+
+ if (data.info == null) throw new FileNotFoundException(String.valueOf(data.name));
+
+ openfiles.put(new String(key), data);
+ return key;
+ }
+
+
+ /**
+ * Zlistaj vsebino direktorijev. Posamezen file predstavi z SftpFile strukturo. Za input poda handle, ki enozna�no identificira
+ */
+ public SftpFile[] readDirectory(byte[] handle) throws InvalidHandleException, EOFException, IOException {
+
+ String shandle = new String(handle);
+
+ //log.error("readDirectory : " + shandle);
+
+ FileData data = (FileData) openfiles.get(shandle);
+//log.error("chkp: 2");
+ if (data == null) throw new InvalidHandleException(shandle);
+//log.error("chkp: 3");
+ if (data.done) throw new EOFException();
+//log.error("chkp: 4");
+ List ls = vfs.list(null, data.name, false);
+ if (ls == null) return null;
+//log.error("chkp: 5");
+
+
+ SftpFile[] lesfiches = new SftpFile[ls.size()];
+
+ Iterator it = ls.iterator();
+ for (int i = 0; it.hasNext(); i++) {
+ FileInfo finfo = (FileInfo) it.next();
+ lesfiches[i] = new SftpFile(finfo.getFileName().getName(), info2Attrs(finfo));
+ }
+
+ data.done = true;
+
+ return lesfiches;
+ }
+
+
+ /**
+ * Odpri file. Flags opredeljujejo ali samo za branje ali tudi za pisanje. FileAttributes ne vem �emu slu�ijo
+ * Vrnjen handle predstavlja odprt file.
+ */
+ public byte[] openFile(String path, UnsignedInteger32 flags, FileAttributes attrs) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("openFile : " + path + ", flags: " + flags + ", attrs: " + attrs);
+
+ byte[] key = getKey().getBytes();
+
+ try {
+ FileData data = new FileData();
+ data.originalName = path;
+ data.name = new FileName(path);
+ data.info = vfs.getFileInfo(null, data.name, false);
+
+//log.error("info = " + data.info);
+
+ if ((flags.intValue() & 0x01) == 0x01) {
+ // read
+ if (data.info == null) throw new FileNotFoundException(String.valueOf(data.name));
+ } else {
+ // write
+ if (data.info == null) {
+ FileInfo finf = new FileInfo(data.name, FileInfo.TYPE_FILE);
+ finf.setMime("x-application/octet-stream");
+ Date date = new Date();
+ finf.setCreateDate(date);
+ finf.setLastModified(date);
+//log.error("creating file: " + finf);
+ String tag = vfs.createFile(null, finf);
+ finf.setTag(tag);
+ data.info = finf;
+ }
+ }
+//log.error("Putting key: " + new String(key) + " : " + data.info);
+ openfiles.put(new String(key), data);
+ } catch (VFSException ex) {
+ if (ex.getCause() instanceof IOException) throw (IOException) ex.getCause();
+ if (ex.getCause() instanceof RuntimeException) throw (RuntimeException) ex.getCause();
+ IOException e = new IOException("Operation failed");
+ e.initCause(ex);
+ throw e;
+ }
+
+ return key;
+ }
+
+
+ /**
+ * Beri iz odprtega file - specificiran je offset v file in dol�ina. Vrne�
+ * Vrnjen byte[] vsebuje podatke iz file-a
+ */
+ public byte[] readFile(byte[] handle, UnsignedInteger64 offset, UnsignedInteger32 len) throws InvalidHandleException, EOFException, IOException {
+
+ String shandle = new String(handle);
+
+ //log.error("readFile +++ : " + shandle + ", offs: " + offset + ", len: " + len);
+
+ long loffset = offset.longValue();
+ int ilen = len.intValue();
+
+ FileData data = (FileData) openfiles.get(shandle);
+//log.error("chkp: 2");
+ if (data == null) throw new InvalidHandleException(shandle);
+//log.error("chkp: 3");
+ if (data.done) throw new EOFException();
+//log.error("chkp: 4");
+ FileOpInfo op = new FileOpInfo();
+ op.filename = data.name;
+ op.offset = loffset;
+ op.tag = data.info.getTag();
+
+ FileReadInfo read = vfs.read(null, op);
+
+ if (read == null) throw new EOFException();
+
+ if (read.buf.length > ilen) {
+ byte[] buf = new byte[ilen];
+ System.arraycopy(read.buf, 0, buf, 0, ilen);
+ }
+
+ if (loffset + ilen >= data.info.getLength())
+ data.done = true;
+
+ return read.buf;
+ }
+
+
+ /**
+ * Pi�i v odprti file - specificiran je offset v file kjer za�ni, buffer, offset v bufferju in dol�ina v bufferju
+ */
+ public void writeFile(byte[] handle, UnsignedInteger64 offset, byte[] data, int off, int len) throws InvalidHandleException, IOException {
+
+ String shandle = new String(handle);
+
+ //log.error("writeFile: " + shandle + ", offs: " + offset + ", off: " + off + ", len: " + len);
+ //log.error("data: " + new String(data));
+ //log.error("payload: " + new String(data, off, len));
+
+ FileData dat = (FileData) openfiles.get(shandle);
+ if (dat == null) throw new InvalidHandleException(shandle);
+
+ FileOpInfo op = new FileOpInfo();
+
+ op.filename = dat.name;
+ op.offset = offset.longValue();
+ op.tag = dat.info.getTag();
+
+ byte[] buf = null;
+
+ if (off == 0 && len == data.length) {
+ buf = data;
+ } else {
+ buf = new byte[len];
+ System.arraycopy(data, off, buf, 0, len);
+ }
+
+ op.buf = buf;
+
+ try {
+ vfs.write(null, op);
+
+ } catch (VFSException ex) {
+ if (ex.getCause() instanceof IOException) throw (IOException) ex.getCause();
+ if (ex.getCause() instanceof RuntimeException) throw (RuntimeException) ex.getCause();
+ IOException iox = new IOException();
+ iox.initCause(ex);
+ throw iox;
+ }
+ }
+
+
+ /**
+ * Zapri odprt file - sprosti resurse
+ */
+ public void closeFile(byte[] handle) throws InvalidHandleException, IOException {
+ //log.error("closeFile: " + new String(handle));
+ }
+
+
+ /**
+ * Izbri�i file
+ */
+ public void removeFile(String path) throws PermissionDeniedException, IOException, FileNotFoundException {
+ //log.error("removeFile: " + path);
+ }
+
+
+ /**
+ * Preimenuj file
+ */
+ public void renameFile(String oldpath, String newpath) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("renameFile: " + oldpath + " to " + newpath);
+ }
+
+
+ /**
+ * Odstrani direktorij
+ */
+ public void removeDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("removeDirectory: " + path);
+ }
+
+
+ /**
+ * Nastavi atribute file-a
+ */
+ public void setFileAttributes(String path, FileAttributes attrs) throws PermissionDeniedException, IOException, FileNotFoundException {
+ //log.error("setFileAttributes: " + path + ", attrs: " + attrs);
+ }
+
+
+ /**
+ * Nastavi atribute odprtega file-a
+ */
+ public void setFileAttributes(byte[] handle, FileAttributes attrs) throws PermissionDeniedException, IOException, InvalidHandleException {
+ //log.error("setFileAttributes: " + new String(handle) + ", attrs: " + attrs);
+ }
+
+
+ /**
+ * Resolvaj symbolic link
+ */
+ public SftpFile readSymbolicLink(String path) throws UnsupportedFileOperationException, FileNotFoundException, IOException, PermissionDeniedException {
+ //log.error("readSymbolicLink: " + path);
+ SftpFile file = new SftpFile("/hokuspokus3");
+ return file;
+ }
+
+
+ /**
+ * Ustvari simboli�en link
+ */
+ public void createSymbolicLink(String link, String target) throws UnsupportedFileOperationException, FileNotFoundException, IOException, PermissionDeniedException {
+ //log.error("createSymbolicLink: " + link + " -> " + target);
+ }
+
+
+ public String getDefaultPath(String username) {
+ //log.error("getDefaultPath: " + username);
+ return "/";
+ }
+
+
+ /**
+ * Preveri, ali lahko user dostopa s specificiranimi permissioni do specificiranega file-a
+ */
+ public void verifyPermissions(String username, String path, String permissions) throws PermissionDeniedException, FileNotFoundException, IOException {
+ //log.error("verifyPermissions: user:" + username + ", path: " + path + ", perms: " + permissions);
+ }
+
+
+ static class FileData {
+ String originalName;
+ FileName name;
+ FileInfo info;
+ boolean done;
+ }
+
+
+ static FileAttributes info2Attrs(FileInfo inf) {
+ FileAttributes attrs = new FileAttributes();
+ attrs.setSize(new UnsignedInteger64(String.valueOf(inf.getLength())));
+ //log.error("set size: " + attrs.getSize());
+
+ //long permissions = 0;
+ //if(inf.isFile()) {
+ // permissions |= FileAttributes.S_IFREG;
+ //} else if(inf.isDirectory()) {
+ // permissions |= FileAttributes.S_IFDIR;
+ //}
+
+ //attrs.setPermissions(new UnsignedInteger32(permissions));
+ attrs.setPermissionsFromMaskString("0777");
+ //log.error("set permissions: " + attrs.getPermissions());
+
+ long perms = attrs.getPermissions().longValue();
+ if (inf.isFile()) {
+ perms |= FileAttributes.S_IFREG;
+ } else if (inf.isDirectory()) {
+ perms |= FileAttributes.S_IFDIR;
+ } else if (inf.isLink()) {
+ perms |= FileAttributes.S_IFLNK;
+ }
+
+ attrs.setPermissions(new UnsignedInteger32(String.valueOf(perms)));
+
+
+ UnsignedInteger32 time = new UnsignedInteger32(String.valueOf(inf.getLastModified().getTime()/1000L));
+ attrs.setTimes(time, time);
+
+ return attrs;
+
+ }
+}
\ No newline at end of file
Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/DaemonStarter.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,63 @@
+/*
+ * Created on 2004.5.9
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.SshDaemon;
+import com.sshtools.common.configuration.XmlConfigurationContext;
+import com.sshtools.daemon.configuration.XmlServerConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationLoader;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+
+import java.io.IOException;
+
+
+/**
+ * @author Marko Strukelj
+ * @author Tomaz Cerar
+ *
+ */
+public class DaemonStarter extends SshDaemon {
+
+ private static String rootDir = "";
+ private static String systemShellJNDI = "";
+
+ public static void setConfigDir(String dir) {
+ rootDir = dir;
+ }
+
+ public static void setSystemShellJNDI(String ss){
+ systemShellJNDI = ss;
+ }
+
+ public static void initialize() throws IOException, ConfigurationException {
+
+ FreshXmlServerConfigurationContext context = new FreshXmlServerConfigurationContext();
+ context.setServerConfigurationResource("server.xml");
+ context.setPlatformConfigurationResource("platform.xml");
+ ConfigurationLoader.initialize(false, context);
+
+
+
+
+ FreshXmlConfigurationContext context2 = new FreshXmlConfigurationContext();
+ context2.setFailOnError(false);
+ context2.setAPIConfigurationResource("sshtools.xml");
+ context2.setAutomationConfigurationResource("automation.xml");
+ ConfigurationLoader.initialize(false, context2);
+
+
+
+
+ if(systemShellJNDI!=null && !systemShellJNDI.trim().equals(""))
+ SSHShell.setSystemShellJNDI(systemShellJNDI);
+
+ start();
+ }
+
+
+}
Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,23 @@
+package org.jboss.fresh.ssh;
+
+import org.jboss.logging.Logger;
+import org.xml.sax.SAXException;
+import com.sshtools.daemon.configuration.PlatformConfiguration;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:01
+ * @modifiedBy $Author$
+ */
+public class FreshPlatformConfiguration extends PlatformConfiguration {
+ private static final Logger log = Logger.getLogger(FreshPlatformConfiguration.class);
+
+ public FreshPlatformConfiguration(InputStream inputStream) throws SAXException, ParserConfigurationException, IOException {
+ super(inputStream);
+ }
+}
Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,113 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.configuration.ServerConfiguration;
+import com.sshtools.j2ssh.transport.publickey.InvalidSshKeyException;
+import com.sshtools.j2ssh.transport.publickey.SshPrivateKey;
+import com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile;
+import org.jboss.fresh.io.IOUtils;
+import org.jboss.logging.Logger;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:32
+ * @modifiedBy $Author$
+ */
+public class FreshServerConfiguration extends ServerConfiguration {
+ private static final Logger log = Logger.getLogger(FreshServerConfiguration.class);
+ private String currentElement;
+ private Map<String, SshPrivateKey> serverKeys;
+
+ public FreshServerConfiguration(InputStream in) throws SAXException, ParserConfigurationException, IOException {
+ super(in);
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qname, Attributes attrs) throws SAXException {
+ if (currentElement != null) {
+ if (currentElement.equals("ServerConfiguration")) {
+
+ if (qname.equals("ServerHostKey")) {
+ String privateKey = attrs.getValue("PrivateKeyFile");
+
+ if (privateKey == null) {
+ throw new SAXException(
+ "Required attributes missing from <ServerHostKey> element");
+ }
+
+ log.debug("ServerHostKey PrivateKeyFile=" + privateKey);
+
+
+ /*File f = new File(privateKey);
+
+ if (!f.exists()) {
+ privateKey = ConfigurationLoader.getConfigurationDirectory() +
+ privateKey;
+ f = new File(privateKey);
+ }*/
+
+ try {
+ InputStream keyStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(privateKey);
+
+
+ if (keyStream != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IOUtils.copy(keyStream, baos);
+ byte[] keyBytes = baos.toByteArray();
+ keyStream.close();
+ baos.close();
+ SshPrivateKeyFile pkf = SshPrivateKeyFile.parse(keyBytes);
+ SshPrivateKey key = pkf.toPrivateKey(null);
+ serverKeys.put(key.getAlgorithmName(), key);
+ } else {
+ log.warn("Private key file '" + privateKey +
+ "' could not be found");
+ }
+ } catch (InvalidSshKeyException ex) {
+ log.warn("Failed to load private key '" + privateKey, ex);
+ } catch (IOException ioe) {
+ log.warn("Failed to load private key '" + privateKey,
+ ioe);
+ }
+ } else {
+ super.startElement(uri, localName, qname, attrs);
+ }
+ }
+ } else {
+ super.startElement(uri, localName, qname, attrs);
+ }
+
+ currentElement = qname;
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qname) throws SAXException {
+ if (currentElement != null) {
+ if (!currentElement.endsWith("ServerHostKey")) {
+ super.endElement(uri, localName, qname);
+ }
+ currentElement = null;
+ }
+ }
+
+ @Override
+ public void reload(InputStream in) throws SAXException, ParserConfigurationException, IOException {
+ serverKeys = new HashMap<String, SshPrivateKey>();
+ super.reload(in);
+ currentElement = null;
+ }
+
+ public Map getServerHostKeys() {
+ return serverKeys;
+ }
+}
+
Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,114 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.common.automate.AutomationConfiguration;
+import com.sshtools.common.configuration.SshAPIConfiguration;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import com.sshtools.j2ssh.configuration.ConfigurationLoader;
+
+import org.jboss.logging.Logger;
+
+import java.util.HashMap;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-01 23:52
+ * @modifiedBy $Author$
+ */
+public class FreshXmlConfigurationContext implements ConfigurationContext {
+ private static final Logger log = Logger.getLogger(FreshXmlConfigurationContext.class);
+
+
+ HashMap<Class, Object> configurations = new HashMap<Class, Object>();
+ String apiResource = "sshtools.xml";
+ String automationResource = "automation.xml";
+ private boolean failOnError = false;
+
+ /**
+ * Creates a new XmlConfigurationContext object.
+ */
+ public FreshXmlConfigurationContext() {
+ }
+
+ /**
+ * @param apiResource
+ */
+ public void setAPIConfigurationResource(String apiResource) {
+ this.apiResource = apiResource;
+ }
+
+ /**
+ * @param automationResource
+ */
+ public void setAutomationConfigurationResource(String automationResource) {
+ this.automationResource = automationResource;
+ }
+
+ /**
+ * @param failOnError
+ */
+ public void setFailOnError(boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ /**
+ * @throws ConfigurationException
+ */
+ public void initialize() throws ConfigurationException {
+
+ if (apiResource != null) {
+ try {
+ SshAPIConfiguration x = new SshAPIConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+ apiResource));
+ configurations.put(com.sshtools.j2ssh.configuration.SshAPIConfiguration.class,
+ x);
+ } catch (Exception ex) {
+ if (failOnError) {
+ throw new ConfigurationException(ex.getMessage());
+ } else {
+ log.info(apiResource + " could not be found: " +
+ ex.getMessage());
+ }
+ }
+ }
+
+ if (automationResource != null) {
+ try {
+ AutomationConfiguration y = new AutomationConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+ automationResource));
+ configurations.put(com.sshtools.common.automate.AutomationConfiguration.class,
+ y);
+ } catch (Exception ex) {
+ if (failOnError) {
+ throw new ConfigurationException(ex.getMessage());
+ } else {
+ log.info(automationResource + " could not be found: " +
+ ex.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * @param cls
+ * @return
+ */
+ public boolean isConfigurationAvailable(Class cls) {
+ return configurations.containsKey(cls);
+ }
+
+ /**
+ * @param cls
+ * @return
+ * @throws ConfigurationException
+ */
+ public Object getConfiguration(Class cls) throws ConfigurationException {
+ if (configurations.containsKey(cls)) {
+ return configurations.get(cls);
+ } else {
+ throw new ConfigurationException(cls.getName() +
+ " configuration not available");
+ }
+ }
+}
Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,100 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.configuration.PlatformConfiguration;
+import com.sshtools.daemon.configuration.ServerConfiguration;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import org.jboss.logging.Logger;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.HashMap;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:00
+ * @modifiedBy $Author$
+ */
+public class FreshXmlServerConfigurationContext implements ConfigurationContext {
+ private static final Logger log = Logger.getLogger(FreshXmlServerConfigurationContext.class);
+
+ HashMap<Class, DefaultHandler> configurations = new HashMap<Class, DefaultHandler>();
+ String serverResource = null;
+ String platformResource = null;
+ boolean failOnError = true;
+
+
+ /**
+ * @param serverResource
+ */
+ public void setServerConfigurationResource(String serverResource) {
+ this.serverResource = serverResource;
+ }
+
+ /**
+ * @param platformResource
+ */
+ public void setPlatformConfigurationResource(String platformResource) {
+ this.platformResource = platformResource;
+ }
+
+ /**
+ * @param failOnError
+ */
+ public void setFailOnError(boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ /**
+ * @throws ConfigurationException
+ */
+ public void initialize() throws ConfigurationException {
+ if (serverResource != null) {
+ try {
+ ServerConfiguration y = new FreshServerConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+ serverResource));
+ configurations.put(ServerConfiguration.class, y);
+ } catch (Exception ex) {
+ log.error("could not init server configuration ", ex);
+ if (failOnError) {
+
+ throw new ConfigurationException(ex.getMessage());
+ }
+ }
+ }
+
+ if (platformResource != null) {
+ try {
+ PlatformConfiguration z = new FreshPlatformConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+ platformResource));
+ configurations.put(PlatformConfiguration.class, z);
+ } catch (Exception ex) {
+ if (failOnError) {
+ throw new ConfigurationException(ex.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * @param cls
+ * @return
+ */
+ public boolean isConfigurationAvailable(Class cls) {
+ return configurations.containsKey(cls);
+ }
+
+ /**
+ * @param cls
+ * @return
+ * @throws ConfigurationException
+ */
+ public Object getConfiguration(Class cls) throws ConfigurationException {
+ if (configurations.containsKey(cls)) {
+ return configurations.get(cls);
+ } else {
+ throw new ConfigurationException(cls.getName() +
+ " configuration not available");
+ }
+ }
+}
Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/SSHShell.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java 2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,1772 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.NativeProcessProvider;
+import com.sshtools.j2ssh.SshThread;
+import org.apache.log4j.Logger;
+import org.jboss.fresh.cpii.services.PoolRunner;
+import org.jboss.fresh.io.Buffer;
+import org.jboss.fresh.io.BufferInputStream;
+import org.jboss.fresh.io.EOLFixInputStream;
+import org.jboss.fresh.io.PrintWriter2;
+import org.jboss.fresh.registry.RegistryContext;
+import org.jboss.fresh.shell.ProcessInfo;
+import org.jboss.fresh.shell.ShellException;
+import org.jboss.fresh.shell.ShellOutputStream;
+import org.jboss.fresh.shell.SystemShell;
+import org.jboss.fresh.shell.impl.ShellImpl;
+
+import javax.naming.NamingException;
+import java.io.*;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class SSHShell extends NativeProcessProvider {
+
+ static final int SHELL_MODE = 0;
+ static final int PROCESS_MODE = 1;
+
+ static final int OVERWRITE = 0;
+ static final int INSERT = 1;
+
+ static private String ssjndi = "java:/FRESH/SystemShell";
+ static private String homeDir = "../fresh/users";
+ static private int MAX_HISTORY_SIZE = 200;
+
+ static final Logger log = Logger.getLogger(SSHShell.class);
+
+ // default mode
+ int mode = SHELL_MODE;
+ boolean mustExit = false;
+ int insMode = INSERT;
+
+ Throwable lastError;
+
+ // processes command line input of this shell
+ LineEditor editor;
+ InMasterOutputStream masterIn;
+ OutMasterInputStream masterOut;
+ StdErrorInputStream stdErr;
+
+ ShellImpl shell;
+
+ ProcessInfo iproc;
+
+ String user = "unknown";
+ String host = "localhost";
+
+ int screen_rows;
+ int screen_cols;
+
+ //static PoolImpl pool;
+
+ public static void setSystemShellJNDI(String name) {
+ ssjndi = name;
+ }
+
+
+ public SSHShell() {
+
+ try {
+ user = SshThread.getCurrentThread().getUsername();
+ } catch (Throwable th) {
+ log.error("Failed to retrieve username: ", th);
+ }
+
+ try {
+ host = InetAddress.getLocalHost().getHostName();
+ int dot = host.indexOf(".");
+ if (dot != -1) host = host.substring(0, dot);
+ } catch (UnknownHostException ex) {
+ log.error("Failed to retrieve hostname: ", ex);
+ }
+
+ StringBuffer errMessage = new StringBuffer();
+
+ try {
+ RegistryContext ctx = new RegistryContext();
+ SystemShell ssh = (SystemShell) ctx.lookup(ssjndi);
+ shell = (ShellImpl) ssh.startSession(null, false);
+
+ // go to root directory
+ try {
+ shell.executeAsObject("cd /");
+ } catch (ShellException ex) {
+ log.warn("Error while setting current dir to /: ", ex);
+ errMessage.append("Failed to set current dir to /\r\n");
+ }
+
+
+ File profile = getHomeFile(".profile");
+ try {
+ if (profile != null)
+ shell.executeAsObject("exec --ex &< " + profile.getAbsolutePath());
+ } catch (ShellException e) {
+ log.warn("Error while executing .profile: " + profile, e);
+ errMessage.append("Failed to execute .profile\r\n");
+ }
+
+ log.info("Successfully initialized shell: " + shell);
+
+ } catch (NamingException e) {
+ log.error("Exception while initializin SSHShell: ", e);
+ throw new RuntimeException(e);
+ } catch (ShellException e) {
+ log.error("Exception while initializin SSHShell: ", e);
+ throw new RuntimeException(e);
+ }
+
+
+ masterIn = new InMasterOutputStream();
+ masterOut = new OutMasterInputStream();
+ stdErr = new StdErrorInputStream();
+
+ editor = new LineEditor();
+
+ //setupThreadPool();
+
+ if (errMessage.length() > 0)
+ masterOut.addBytes(errMessage.toString().getBytes());
+ }
+
+
+ public File getHomeFile(String fname) {
+
+ String hUser = user;
+ if (hUser == null || hUser.length() == 0)
+ hUser = "root";
+
+ File userDir = new File(homeDir, hUser);
+ if (!userDir.isDirectory()) {
+ if (!userDir.mkdirs())
+ log.warn("Home directory for user " + user + " does not exist and could not be created.");
+ }
+
+ if (userDir.isDirectory()) {
+ File tfile = new File(userDir, fname);
+ if (tfile.isFile())
+ return tfile;
+ }
+
+ return null;
+ }
+
+
+ public InputStream getInputStream() throws IOException {
+ return masterOut;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return masterIn;
+ }
+
+ public InputStream getStderrInputStream() throws IOException {
+ return stdErr;
+ }
+
+ public void kill() {
+ log.info("#### kill called");
+ closeShell();
+ }
+
+ public boolean stillActive() {
+ // active until shell is closed
+ log.debug("stillActive ? " + (!mustExit && !masterOut.isClosed()));
+ return !mustExit && !masterOut.isClosed();
+
+ }
+
+ public int waitForExitCode() {
+ // this thread needs to block until we are closed
+ synchronized (this) {
+ while (true) {
+ if (stillActive()) {
+ try {
+ log.debug("Exit WAIT");
+ wait();
+ log.debug("Exit WAKEUP");
+ } catch (InterruptedException ex) {
+ log.info("ExitCode 1");
+ return 1;
+ }
+ } else {
+ log.info("ExitCode 0");
+ return 0;
+ }
+ }
+ }
+ }
+
+ public void closeShell() {
+ mustExit = true;
+
+ if (masterOut != null) masterOut.close();
+ if (stdErr != null) stdErr.close();
+
+ synchronized (this) {
+ notifyAll();
+ }
+
+ //pool.stop();
+ }
+
+ public String getDefaultTerminalProvider() {
+ return "VT320";
+ }
+
+ public boolean createProcess(String command, Map environment) throws IOException {
+ return true;
+ }
+
+ public void start() throws IOException {
+ // we are fully input driven and input is pushed to us - so we are event driven
+ // no thread required
+ }
+
+ public boolean supportsPseudoTerminal(String term) {
+ return true;
+ }
+
+ public boolean allocatePseudoTerminal(
+ String term,
+ int cols,
+ int rows,
+ int width,
+ int height,
+ String modes) {
+
+ setTerminalDimensions(cols, rows, width, height);
+ return true;
+ }
+
+ public void setTerminalDimensions(int cols, int rows, int width, int height) {
+
+ screen_rows = rows;
+ screen_cols = cols;
+
+ if (shell != null) try {
+ shell.setEnvProperty("SCREEN_ROWS", String.valueOf(screen_rows));
+ shell.setEnvProperty("SCREEN_COLS", String.valueOf(screen_cols));
+ } catch (Exception ex) {
+ log.warn("Failed to set new screen size to shell's ENV: ", ex);
+ }
+
+ }
+
+ public InputStream getProcessInputStream() {
+ log.debug("getProcessInputStream called");
+ return null;
+ }
+
+ public OutputStream getProcessOutputStream() {
+ log.debug("getProcessOutputStream called");
+ return null;
+ }
+
+
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
+
+ void prompt() {
+ StringBuffer prompt = new StringBuffer();
+
+ if (masterOut.lastChar != 10) {
+ prompt.append("\r\n");
+ masterOut.lastChar = 0;
+ }
+
+ prompt.append("[").append(sdf.format(new Date())).append("] ").append(user).append("@").append(host).append(" ");
+ String fullname = "#err#";
+ try {
+ fullname = shell.getEnvProperty("PWD");
+ } catch (Throwable ex) {
+ log.error("Failed to get PWD:", ex);
+ }
+
+ int lidx = fullname.lastIndexOf("/");
+ if (lidx != -1 && fullname.length() > 1) fullname = fullname.substring(lidx + 1);
+ prompt.append(fullname).append(" ").append("# ");
+
+ masterOut.addBytes(prompt.toString().getBytes());
+ }
+
+
+ void cancelProcess() {
+ if (iproc == null) return;
+ Buffer buf = null;
+
+ try {
+ buf = shell.getBuffer(iproc.procid, 1);
+ if (buf != null) buf.close();
+ } catch (Exception ex) {
+ log.info("Exception while closing stdin buffer for: " + iproc.procid, ex);
+ }
+
+ try {
+ buf = shell.getBuffer(iproc.procid, 2);
+ if (buf != null) buf.close();
+ } catch (Exception ex) {
+ log.info("Exception while closing stdout buffer for: " + iproc.procid, ex);
+ }
+
+ }
+
+
+ void writeError(Throwable th) {
+ if (th instanceof org.jboss.fresh.shell.SessionTimeoutException) {
+ closeShell();
+ return;
+ }
+
+ lastError = th;
+
+ while (th.getCause() != null) th = th.getCause();
+
+ masterOut.addBytes(th.toString().getBytes());
+ masterOut.addBytes("\r\n".getBytes());
+ }
+
+ void writeStackTrace(Throwable th) {
+ StringWriter sw = new StringWriter();
+ PrintWriter2 pw = new PrintWriter2(sw);
+ th.printStackTrace(pw);
+ pw.println();
+ pw.close();
+
+ masterOut.addBytes(sw.toString().getBytes());
+ //masterOut.addBytes("\r\n".getBytes());
+ prompt();
+ }
+
+ class LineEditor {
+
+ // history list
+ ArrayList<StringBuffer> history = new ArrayList<StringBuffer>();
+
+ // actively edited history items - modified during up down and edit
+ HashMap<Integer, StringBuffer> activeEdit = new HashMap<Integer, StringBuffer>();
+
+ // history item being edited. the last is always a current line
+ int hidx = 0;
+
+ // contains current state of the line being edited
+ StringBuffer linebuf = new StringBuffer();
+
+ // carret position - from 0 (before first character) to linebuf.length()
+ // (after last character)
+ int carret = 0;
+
+ // if we don't receive a complete character code we end processing at
+ // the next event and keep intermediary state in here
+ byte[] unprocessed = new byte[5];
+
+ //position in the unprocessed buffer where the next character will be added
+ // it is normally 0, only if in previous run possible incomplete byte sequence
+ // was identified this value will be > 0
+ int charsPos = 0;
+
+ private String multilineEOF;
+
+ private StringBuffer multilineBuffer;
+
+ private boolean foundEOF;
+
+ LineEditor() {
+
+ // load history from file - file to use is dependent on username used
+ File historyFile = getHomeFile(".history");
+ if (historyFile != null) {
+ BufferedReader rd = null;
+ try {
+ LinkedList<StringBuffer> nuHistory = new LinkedList<StringBuffer>();
+ rd = new BufferedReader(new InputStreamReader(new FileInputStream(historyFile), "UTF-8"));
+ for (String line = rd.readLine(); line != null; line = rd.readLine()) {
+ if (line.trim().length() != 0) {
+ nuHistory.add(new StringBuffer(line));
+ if (nuHistory.size() > MAX_HISTORY_SIZE)
+ nuHistory.removeFirst();
+ }
+ }
+ history.addAll(nuHistory);
+ } catch (Exception ex) {
+ log.warn("Failed to read .history file");
+ }
+ }
+
+ // current line is always also the last history item
+ addHistory(linebuf);
+ hidx = history.size() - 1;
+
+ prompt();
+ }
+
+
+ private void addHistory(StringBuffer val) {
+ history.add(val);
+ // if history size iz greater than max, cut off the head
+ int clearSize = (int) (MAX_HISTORY_SIZE * 0.2);
+ if (history.size() > MAX_HISTORY_SIZE + clearSize) {
+ ArrayList<StringBuffer> nuHistory = new ArrayList<StringBuffer>(MAX_HISTORY_SIZE + clearSize + 1);
+ for (int i = 0; i < MAX_HISTORY_SIZE; i++)
+ nuHistory.add(history.get(clearSize + i));
+ history = nuHistory;
+ }
+ }
+
+ private void setOverwriteMode() {
+ insMode = OVERWRITE;
+ }
+
+ private void setInsertMode() {
+ insMode = INSERT;
+ }
+
+ // this method returns necessary bytes to the client to reflect user's input
+ private void addChar(byte val) {
+ // we need to check carret location
+ // if carret is at the end of the line then we just send back the char
+ // otherwise we need to rewrite the whole line with the character
+ // and position back the carret
+ try {
+ byte[] aval = new byte[]{val};
+ int diff = linebuf.length() - carret;
+ if (diff > 0) {
+ if (insMode == OVERWRITE) {
+ linebuf.setCharAt(carret, new String(aval, "ISO8859_1").charAt(0));
+ } else {
+ linebuf.insert(carret, new String(aval, "ISO8859_1"));
+ }
+
+ byte[] bcv = linebuf.substring(carret, linebuf.length()).getBytes("ISO8859_1");
+
+ byte[] bf = new byte[bcv.length - 1];
+ for (int i = 0; i < bf.length; i++) {
+ bf[i] = 0x08;
+ }
+
+ carret++;
+ masterOut.addBytes(bcv);
+ masterOut.addBytes(bf);
+ } else {
+ if (insMode != INSERT)
+ setInsertMode();
+ linebuf.append(new String(aval, "ISO8859_1"));
+ carret++;
+ // write to out
+ masterOut.addBytes(aval);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private void shiftChars(int len) {
+ System.arraycopy(unprocessed, len, unprocessed, 0, unprocessed.length - len);
+ charsPos -= len;
+ }
+
+ // this method scans unprocessed buffer and tries to identify any control
+ // byte sequences it reacts accordingly
+ private void processInput() {
+ // if buffer starts with 1b then it's a control sequence
+ // if it's already longer than 3 then it ends with 7e
+ int i = 0;
+
+ while (charsPos > i) {
+ if (unprocessed[i] == (byte) 0x1b) {
+ if (charsPos > i + 1) {
+ if (unprocessed[i + 1] == (byte) 0x5b) {
+ if (charsPos > i + 2) {
+ if (unprocessed[i + 2] == (byte) 0x44) {
+ // 1b 5b 44 : LEFT ARROW
+ leftArrow();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x43) {
+ // 1b 5b 43 : RIGHT ARROW
+ rightArrow();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x41) {
+ // 1b 5b 41 : UP ARROW
+ upArrow();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x42) {
+ // 1b 5b 42 : DOWN ARROW
+ downArrow();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x46) {
+ // 1b 5b 46 : END
+ end();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x48) {
+ // 1b 5b 48 : HOME
+ home();
+ shiftChars(3);
+ } else if (unprocessed[i + 2] == (byte) 0x32) {
+ if (charsPos > i + 3) {
+ //if(unprocessed[i+3] == (byte) 0x7e) {
+ // INSERT
+ // ignore it
+ shiftChars(4);
+ //}
+ //} else {
+ // i += 4;
+ }
+ } else if (unprocessed[i + 2] == (byte) 0x33) {
+ if (charsPos > i + 3) {
+ if (unprocessed[i + 3] == (byte) 0x7e) {
+ del();
+ shiftChars(4);
+ } else {
+ shiftChars(4); // ignore
+ }
+ } else {
+ i += 4;
+ }
+ } else if (unprocessed[i + 2] == (byte) 0x34) {
+ if (charsPos > i + 3) {
+ if (unprocessed[i + 3] == (byte) 0x7e) {
+ end();
+ shiftChars(4);
+ } else {
+ shiftChars(4); // ignore
+ }
+ } else {
+ i += 4;
+ }
+ } else if (unprocessed[i + 2] == (byte) 0x31) {
+ if (charsPos > i + 3) {
+ if (unprocessed[i + 3] == (byte) 0x7e) {
+ home();
+ shiftChars(4);
+ } else {
+ shiftChars(4); // ignore
+ }
+ } else {
+ i += 4;
+ }
+ } else if (unprocessed[i + 2] == (byte) 0x35) {
+ if (charsPos > i + 3) {
+ if (unprocessed[i + 3] == (byte) 0x7e) {
+ pgup();
+ shiftChars(4);
+ } else {
+ shiftChars(4); // ignore
+ }
+ } else {
+ i += 4;
+ }
+ } else if (unprocessed[i + 2] == (byte) 0x36) {
+ if (charsPos > i + 3) {
+ if (unprocessed[i + 3] == (byte) 0x7e) {
+ pgdown();
+ shiftChars(4);
+ } else {
+ shiftChars(4); // ignore
+ }
+ } else {
+ i += 4;
+ }
+ } else {
+ // treat them as regular chars
+ // wait for the next round
+ //addChar(unprocessed[i]);
+ //addChar(unprocessed[i+1]);
+ //addChar(unprocessed[i+2]);
+ i += 3;
+ }
+ } else {
+ // wait for the next pass
+ i += 2;
+ }
+ } else if (unprocessed[i + 1] == (byte) 0x4f) {
+ // function keys
+ // just ignore
+ shiftChars(2);
+ } else {
+ // we don't know about it - just ignore
+ shiftChars(2);
+ }
+ } else {
+ // wait for the next pass
+ i += 1;
+ }
+ } else if (unprocessed[i] == (byte) 0x7f) {
+ backspace();
+ shiftChars(1);
+ } else if (unprocessed[i] == (byte) 0x0d) {
+// if(charsPos > i+1 && unprocessed[i+1] == (byte) 0x0a) {
+// shiftChars(2);
+// } else {
+ shiftChars(1);
+// }
+ ret();
+// } else if(unprocessed[i] == (byte) 0x0a) {
+
+ } else if (unprocessed[i] == (byte) 0x08) {
+ // this is left_arrow with overwrite
+ // meaning that any characters added are not inserted but
+ // overwrite the previous characters
+ // when it comes to the end of line normal insert is restored
+ setOverwriteMode();
+ leftArrow();
+ shiftChars(1);
+ } else if (unprocessed[i] == (byte) 0x04) { // ctrl-D
+ shiftChars(1);
+ foundEOF = true;
+ ret();
+ } else {
+ // for all we know this is a regular character
+ // and move carret
+ log.debug("char: " + unprocessed[i]);
+ addChar(unprocessed[i]);
+ shiftChars(1);
+ }
+
+ }
+ }
+
+ void leftArrow() {
+ if (carret > 0) {
+ carret -= 1;
+ masterOut.addByte(0x08);
+ } else {
+ masterOut.addByte(0x07);
+ }
+ }
+
+ void rightArrow() {
+ if (carret < linebuf.length()) {
+ //carret+=1;
+ try {
+ masterOut.addBytes(String.valueOf(linebuf.charAt(carret++)).getBytes("ISO8859_1"));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ } else {
+ masterOut.addByte(0x07);
+ }
+ }
+
+ void upArrow() {
+
+ if (hidx == 0) return;
+
+ if (hidx < history.size() - 1) {
+ activeEdit.put(new Integer(hidx), linebuf);
+ }
+
+ hidx--;
+ if (hidx >= history.size())
+ hidx = history.size() - 1;
+
+ StringBuffer prev = activeEdit.get(new Integer(hidx));
+ if (prev == null) {
+ prev = new StringBuffer(history.get(hidx).toString());
+ }
+
+ byte[] buf = new byte[carret + 3 + prev.length()];
+ int i = 0;
+ // back to beginning of line
+ for (; i < carret; i++) {
+ buf[i] = 0x08;
+ }
+
+ // end of line
+ buf[i++] = 0x1b;
+ buf[i++] = 0x5b;
+ buf[i++] = 0x4b;
+
+ linebuf = prev;
+
+ try {
+ // new string
+ System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ carret = linebuf.length();
+ masterOut.addBytes(buf);
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+ //masterOut.addBytes(new byte[] {0x0a});
+ }
+
+ void downArrow() {
+ if (hidx >= history.size() - 1) return;
+
+ activeEdit.put(new Integer(hidx), linebuf);
+ hidx++;
+
+ StringBuffer next = null;
+
+ if (hidx == history.size() - 1) {
+ next = history.get(hidx);
+ } else {
+ next = activeEdit.get(new Integer(hidx));
+ if (next == null) {
+ next = new StringBuffer(history.get(hidx).toString());
+ }
+ }
+
+ byte[] buf = new byte[carret + 3 + next.length()];
+ int i = 0;
+ // back to beginning of line
+ for (; i < carret; i++) {
+ buf[i] = 0x08;
+ }
+
+ // end of line
+ buf[i++] = 0x1b;
+ buf[i++] = 0x5b;
+ buf[i++] = 0x4b;
+
+ linebuf = next;
+
+ // new string
+ try {
+ System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ carret = linebuf.length();
+ masterOut.addBytes(buf);
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+ //masterOut.addBytes(new byte[] {0x0a});
+ }
+
+ void pgup() {
+ if (hidx == 0) return;
+
+ if (hidx < history.size() - 1) {
+ activeEdit.put(new Integer(hidx), linebuf);
+ }
+
+ hidx = 0;
+
+ StringBuffer prev = activeEdit.get(new Integer(hidx));
+ if (prev == null) {
+ prev = new StringBuffer(history.get(hidx).toString());
+ }
+
+ byte[] buf = new byte[carret + 3 + prev.length()];
+ int i = 0;
+ // back to beginning of line
+ for (; i < carret; i++) {
+ buf[i] = 0x08;
+ }
+
+ // end of line
+ buf[i++] = 0x1b;
+ buf[i++] = 0x5b;
+ buf[i++] = 0x4b;
+
+ linebuf = prev;
+
+ try {
+ // new string
+ System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ carret = linebuf.length();
+ masterOut.addBytes(buf);
+ }
+
+ void pgdown() {
+ if (hidx >= history.size() - 1) return;
+
+ activeEdit.put(new Integer(hidx), linebuf);
+ hidx = history.size() - 1;
+
+ StringBuffer next = null;
+
+ if (hidx == history.size() - 1) {
+ next = history.get(hidx);
+ } else {
+ next = activeEdit.get(new Integer(hidx));
+ if (next == null) {
+ next = new StringBuffer(history.get(hidx).toString());
+ }
+ }
+
+ byte[] buf = new byte[carret + 3 + next.length()];
+ int i = 0;
+ // back to beginning of line
+ for (; i < carret; i++) {
+ buf[i] = 0x08;
+ }
+
+ // end of line
+ buf[i++] = 0x1b;
+ buf[i++] = 0x5b;
+ buf[i++] = 0x4b;
+
+ linebuf = next;
+
+ // new string
+ try {
+ System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ carret = linebuf.length();
+ masterOut.addBytes(buf);
+ }
+
+ void end() {
+ // redraw from carret to end
+ int ocarret = carret;
+ carret = linebuf.length();
+ try {
+ masterOut.addBytes(linebuf.substring(ocarret, carret).getBytes("ISO8859_1"));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ }
+
+ void home() {
+ // go from carret to beginning of line
+ byte[] buf = new byte[carret];
+
+ // back to beginning of line
+ for (int i = 0; i < carret; i++) {
+ buf[i] = 0x08;
+ }
+
+ carret = 0;
+ masterOut.addBytes(buf);
+ }
+
+ void backspace() {
+
+ if (carret == 0) return;
+
+ int diff = linebuf.length() - carret;
+ byte[] buf = new byte[diff * 2 + 4];
+
+ buf[0] = 0x08;
+ try {
+ System.arraycopy(linebuf.substring(carret).getBytes("ISO8859_1"), 0, buf, 1, diff);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ buf[diff + 1] = 0x1b;
+ buf[diff + 2] = 0x5b;
+ buf[diff + 3] = 0x4b;
+
+ for (int i = diff + 4; i < buf.length; i++) {
+ buf[i] = 0x08;
+ }
+
+ carret--;
+
+ // linebuf also needs to be modified
+ linebuf.deleteCharAt(carret);
+
+ masterOut.addBytes(buf);
+ }
+
+ void del() {
+ // write back from carret+1 to the end stop then back
+ if (carret == linebuf.length()) return;
+
+ linebuf.deleteCharAt(carret);
+
+ int diff = linebuf.length() - carret;
+ byte[] buf = new byte[diff * 2 + 3];
+
+ try {
+ System.arraycopy(linebuf.substring(carret).getBytes("ISO8859_1"), 0, buf, 0, diff);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ buf[diff] = 0x1b;
+ buf[diff + 1] = 0x5b;
+ buf[diff + 2] = 0x4b;
+
+ for (int i = diff + 3; i < buf.length; i++) {
+ buf[i] = 0x08;
+ }
+
+ masterOut.addBytes(buf);
+ }
+
+ void ret() {
+ // for now only cmdline editing is supported - no stdin multiline editing
+ //home();
+
+ end();
+ boolean multiLineFinished = false;
+ boolean multiLineStarted = false;
+
+ String cmd = linebuf.toString().trim();
+ if (multilineEOF != null) {
+ // check if this is the last line - equal to multilineEOF
+ if (cmd.equals(multilineEOF)) {
+ // found it - don't add it to buffer
+ multiLineFinished = true;
+ cmd = multilineBuffer.toString();
+ } else if (foundEOF) {
+ // CTRL-D was pressed
+ foundEOF = false;
+ multiLineFinished = true;
+ multilineBuffer.append(cmd);
+ cmd = multilineBuffer.toString();
+ } else {
+ // add line to multiline buffer
+ multilineBuffer.append(cmd).append("\r\n");
+ // print a newline prompt
+ //printNewLinePrompt(masterOut);
+ }
+ } else {
+ // see if the line ends with << something
+ multilineEOF = checkMultiline(cmd);
+
+ if (multilineEOF != null) {
+ multiLineStarted = true;
+ multilineBuffer = new StringBuffer(cmd).append("\r\n");
+ //printNewLinePrompt(masterOut);
+ }
+ }
+
+ if (hidx != history.size() - 1) {
+ StringBuffer sb = history.get(history.size() - 1);
+ sb.setLength(0);
+ sb.append(linebuf);
+ }
+
+ // this line prevents empty lines in history and repetition
+
+ if (multilineEOF == null || multiLineStarted) {
+ if ((history.size() > 1 && cmd.equals(history.get(history.size() - 2).toString())) || "".equals(cmd))
+ history.remove(history.size() - 1);
+ else
+ logHistory(cmd);
+
+ linebuf = new StringBuffer();
+ addHistory(linebuf);
+ hidx = history.size() - 1;
+ } else {
+ linebuf = new StringBuffer();
+ }
+
+ activeEdit.clear();
+ carret = 0;
+
+
+ //masterOut.addBytes(new byte [] {0x1b, 0x5b, 0x4b});
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+ masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+ //masterOut.addBytes(new byte[] {0x0d, 0x0a});
+ masterOut.addBytes(new byte[]{0x0d, 0x0a});
+ masterOut.lastChar = 10;
+
+ if (multilineEOF == null) {
+
+ if ("exit".equals(cmd)) {
+ /*
+ try {
+ masterOut.close();
+ } catch(Exception ex) {
+ log.warn("Failed to close masterOut: ", ex);
+ }
+
+ try {
+ masterIn.close();
+ } catch(Exception ex) {
+ log.warn("Failed to close masterIn: ", ex);
+ }
+ */
+
+ closeShell();
+ return;
+ } else if ("err".equals(cmd)) {
+ if (lastError != null) writeStackTrace(lastError);
+ return;
+ }
+ }
+
+ if (multilineEOF == null || multiLineFinished) {
+ multilineEOF = null;
+ log.debug("call processCommand: " + cmd);
+ try {
+ processCommand(cmd);
+ log.debug("done calling: " + cmd);
+ } catch (Throwable th) {
+ writeError(th);
+ prompt();
+ }
+
+ } else {
+ printNewLinePrompt(masterOut);
+ }
+ //prompt();
+ }
+
+ private String checkMultiline(String cmd) {
+ int pos = cmd.lastIndexOf("<<");
+ if (pos == -1)
+ return null;
+
+ // we found it. Now we need to check if it's inside quotes
+ // it's a simple and incomplete check but should suffice
+ String ending = cmd.substring(pos + 2).trim();
+ if (ending.indexOf("\"") != -1 || ending.indexOf("'") != -1)
+ return null;
+
+ return ending;
+ }
+
+ private void printNewLinePrompt(OutMasterInputStream masterOut) {
+ masterOut.addBytes(new byte[]{0x3e, 0x20}); // for now hardcoded to "> "
+ }
+
+
+ /**
+ * @param cmd
+ */
+ private void logHistory(String cmd) {
+
+ if ("exit".trim().equals(cmd))
+ return;
+
+ String hUser = user;
+ if (hUser == null || hUser.length() == 0)
+ hUser = "root";
+
+ File userDir = new File(homeDir, hUser);
+ File historyFile = new File(userDir, ".history");
+
+ RandomAccessFile raf = null;
+ try {
+ raf = new RandomAccessFile(historyFile, "rw");
+ } catch (Exception ex) {
+ if (!userDir.isDirectory()) {
+ if (!userDir.mkdirs())
+ return;
+ }
+ }
+
+ if (raf == null) {
+ log.warn("Failed to open .history");
+ return;
+ }
+
+ try {
+ raf.seek(raf.length());
+ raf.write(new String(cmd + System.getProperty("line.separator")).getBytes("UTF-8"));
+ } catch (Exception ex) {
+ log.warn("Failed to write to .history");
+ } finally {
+ try {
+ raf.close();
+ } catch (Exception ex) {
+ }
+ }
+ }
+
+
+ PoolRunner runner;
+ RunnerJob rjob = new RunnerJob();
+ ProcessInfo pinf;
+
+ class RunnerJob implements Runnable {
+
+ String cmd;
+ boolean phaseTwo;
+ boolean onePhased;
+ boolean ready = true;
+
+ RunnerJob() {
+ }
+
+ public void setCommand(String cmd) {
+ this.cmd = cmd;
+ phaseTwo = false;
+ onePhased = false;
+ ready = false;
+ }
+
+ public void toPhaseTwo() {
+ phaseTwo = true;
+ }
+
+ public boolean ready() {
+ return ready;
+ }
+
+ public void run() {
+ try {
+ start(cmd);
+ } catch (Throwable th) {
+ //new Exception("Run CATCH").printStackTrace();
+ ready = true;
+ onePhased = true;
+ writeError(th);
+ prompt();
+ }
+ }
+
+ public void start(String cmd) throws Exception {
+//System.out.println(" Start ENTERED : " + cmd);
+ if (!phaseTwo) {
+ pinf = shell.prepareExecution(cmd);
+ if (pinf == null) {
+ onePhased = true;
+ ready = true;
+ prompt();
+ return;
+ }
+
+ BufferInputStream ins = new BufferInputStream(shell.getBuffer(pinf.procid, 1));
+ //ins.setTimeout(250);
+ ins.setAsyncMode(true);
+
+ //InputStream ins = new ShellInputStream(shell, pinf.procid);
+ OutputStream outs = new ShellOutputStream(shell, pinf.procid);
+
+ iproc = pinf;
+ masterOut.setInputStream(ins);
+ masterIn.setOutputStream(outs);
+ } else {
+//System.out.println(" >>Complete execution : " + cmd);
+ shell.completeExecution();
+ ready = true;
+//System.out.println(" <<Complete execution : " + cmd);
+ }
+//System.out.println(" Start EXITED : " + cmd);
+ }
+ }
+
+
+ void processCommand(String cmd) throws Exception {
+
+// if("SINGLE".equals(shell.getEnvProperty("TMODE"))) {
+ /*
+ if(runner != null)
+ throw new RuntimeException("Internal error: overlapping execution");
+ */
+
+
+ /*
+
+ runner = (PoolRunner) pool.checkout();
+ runner.setPoolAutoReturn(false);
+ try {
+ rjob.setCommand(cmd);
+ runner.joinJob(rjob, "SSH Thread");
+ rjob.toPhaseTwo();
+
+ runner.setPoolAutoReturn(true);
+ runner.runJob(rjob, "SSH Thread");
+ } catch(Exception ex) {
+ runner.returnToPool();
+ ex.printStackTrace();
+ } finally {
+ runner = null;
+ }
+
+ */
+
+
+ /*
+
+ runner = (PoolRunner) pool.checkout();
+ try {
+ rjob.setCommand(cmd);
+ runner.joinJob(rjob, "SSH Thread");
+ rjob.toPhaseTwo();
+
+ runner = (PoolRunner) pool.checkout();
+ runner.runJob(rjob, "SSH Thread");
+
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ } finally {
+ runner = null;
+ }
+
+ */
+
+ if (runner == null) {
+ runner = new PoolRunner();
+ }
+
+ //while(!rjob.ready() || masterOut.isDelegateMode()) { //
+ // Thread.sleep(200);
+ // shell.getBuffer(pinf.procid, 1).put("A", 10000);
+ //}
+
+ rjob.setCommand(cmd);
+ runner.joinJob(rjob, "SSH Thread");
+ if (!rjob.onePhased) {
+ rjob.toPhaseTwo();
+ runner.runJob(rjob, "SSH Thread");
+ //runner.joinJob(rjob, "SSH Thread");
+ }
+
+ // FIXED: - uncommenting the following line causes clients to freeze
+ // The reason is that this code is executed inside j2ssh callback method that sends bytes that client typed into
+ // the console. Only one callback is executed at a time, until this method returns there will be no other callbacks called.
+ // But masterOut needs to have it's callback called to determine if executable has completed. Threrefore the following
+ // line will block forever since completion will never be detected.
+ //masterOut.waitCompletion();
+/*
+ runner = (PoolRunner) pool.checkout();
+System.out.println("Runner CHECKOUT: " + runner);
+ runner.setPoolAutoReturn(false);
+ try {
+ rjob.setCommand(cmd);
+ runner.joinJob(rjob, "SSH Thread");
+
+ //runner = (PoolRunner) pool.checkout();
+System.out.println("Runner CHECKOUT: " + runner);
+
+ rjob.toPhaseTwo();
+
+ // it's a tricky thing. A part of you wants to use returnToPool() in finally
+ // But you shouldn't because it's only to be used in combination
+ // with joinJob() - if you use runJob() you have to set
+ // autoreturn to true before running runJob to make it be
+ // returned to pool afterwards
+ // if exception occurs - it's due to our error - but in this case
+ // runner won't be returned to pool so we have to do it explicitly
+ runner.setPoolAutoReturn(true);
+ runner.runJob(rjob, "SSH Thread");
+
+ } catch(Exception ex) {
+ runner.returnToPool();
+ ex.printStackTrace();
+ } finally {
+ runner = null;
+ }
+// }
+*/
+ }
+
+
+ // this is input from stdin
+ // we are in command mode otherwise we wouldn't receive this
+ public void addByte(int b) {
+ // buffer should never be full here - that would be an internal error
+ // add it to buffer first
+ unprocessed[charsPos++] = (byte) b;
+
+ // check if it's a control character or something else
+ processInput();
+
+ // process chars
+ //linebuf.append(new String(new byte[] {(byte)b}, "ISO8859_1"));
+ }
+
+ public void addBytes(byte[] buf, int offs, int len) {
+ //
+ for (int i = 0; i < len;) {
+ // in bounds for destination
+ int free = unprocessed.length - charsPos;
+ if (free > len) free = len;
+
+ // in bounds for source
+ if (free > buf.length - offs - i) free = buf.length - offs - i;
+
+ System.arraycopy(buf, offs + i, unprocessed, charsPos, free);
+ i += free;
+ charsPos += free;
+
+ processInput();
+ }
+ }
+ }
+
+
+ /*
+ * This one also decides whether to put a charater on to editor or not
+ * based on current shell mode - command or process
+ * If CTRL-C and process mode - then it tries to kill the process
+ * If CTRL-D and process mode - then it switches to command mode
+ */
+ class InMasterOutputStream extends OutputStream {
+
+ boolean closed = false;
+ boolean delegateMode = false;
+ OutputStream delegate;
+ long lastCheck = 0;
+
+ public void setOutputStream(OutputStream out) {
+ delegate = out;
+ delegateMode = out != null;
+ }
+
+ public boolean toBufferMode() {
+ boolean wasOn = delegateMode;
+ delegateMode = false;
+ delegate = null;
+ return wasOn;
+ }
+
+ public void write(int b) throws IOException {
+ if (log.isDebugEnabled()) log.debug("write: " + b);
+ if (closed) throw new EOFException();
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+ try {
+ if (b == 3) { // ESC
+ delegate.close();
+ cancelProcess();
+ toBufferMode();
+ return;
+ }
+
+ delegate.write(b);
+ } catch (EOFException ex) {
+ toBufferMode();
+ } catch (Throwable ex) {
+ writeError(ex);
+ }
+ return;
+ }
+
+ checkLastUsed();
+ editor.addByte(b);
+ }
+
+ public void write(byte[] buf) throws IOException {
+ write(buf, 0, buf.length);
+ }
+
+ public void write(byte[] buf, int offs, int len) throws IOException {
+ if (log.isDebugEnabled()) log.debug("write: " + new String(buf, offs, len));
+ if (closed) throw new EOFException();
+
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+ try {
+ for (int i = 0; i < len; i++) {
+ if (buf[i + offs] == 3) { // ESC
+ if (i > 0) {
+ delegate.write(buf, offs, i);
+ }
+ delegate.close();
+ cancelProcess();
+ toBufferMode();
+ return;
+ }
+ }
+
+ delegate.write(buf, offs, len);
+ } catch (EOFException ex) {
+ toBufferMode();
+ } catch (Throwable ex) {
+ writeError(ex);
+ }
+
+ return;
+ }
+ checkLastUsed();
+ editor.addBytes(buf, offs, len);
+ }
+
+ public void flush() throws IOException {
+ log.debug("flush");
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+ try {
+ delegate.flush();
+ } catch (EOFException ex) {
+ toBufferMode();
+ } catch (Throwable ex) {
+ writeError(ex);
+ }
+
+ }
+ }
+
+ public void close() throws IOException {
+ log.debug("close");
+ if (closed) return;
+
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+ try {
+ delegate.close();
+ } catch (EOFException ex) {
+ toBufferMode();
+ } catch (Throwable ex) {
+ writeError(ex);
+ }
+
+ }
+
+ closed = true;
+
+ closeShell();
+
+ }
+
+ private void checkLastUsed() {
+ long now = System.currentTimeMillis();
+ if (now - lastCheck > 10000) {
+ try {
+ shell.using();
+ } catch (Exception ex) {
+ try {
+ close();
+ } catch (Exception e) {
+ log.warn("Exception occured while closing due to session timeout", e);
+ }
+ }
+ lastCheck = now;
+ }
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+ }
+
+
+ class OutMasterInputStream extends InputStream {
+
+ boolean closed = false;
+ boolean delegateMode = false;
+ BufferInputStream delegate;
+ InputStream delegateReal;
+
+ int lastChar = -1;
+
+ // output buffer - client can stop reading occasionally so it's best
+ // to have a buffer zone for line editor's output
+ byte[] buff = new byte[8192];
+
+ // position where the next read from buffer will occur
+ int offs = 0;
+
+ // position where the next write to buffer will occur
+ int len = 0;
+
+ boolean waiting = false;
+
+
+ // put this master out to delegate mode - will not read line editor's output
+ // but process's output
+ public void setInputStream(BufferInputStream in) {
+ delegate = in;
+ delegateReal = new EOLFixInputStream(in);
+ delegateMode = in != null;
+ }
+
+ boolean isDelegateMode() {
+ return delegateMode;
+ }
+
+ public boolean toBufferMode() {
+ boolean wasOn = delegateMode;
+ delegateMode = false;
+ delegate = null;
+ delegateReal = null;
+ prompt();
+ masterIn.toBufferMode();
+ return wasOn;
+ }
+
+ private void shrink() {
+ if (len > 0 && len == offs) {
+ offs = 0;
+ len = 0;
+ }
+ }
+
+ synchronized void addByte(int aval) {
+ shrink();
+ int togo = buff.length - len; // togo is how many bytes can be written
+
+ if (togo > 0) {
+ buff[len++] = (byte) aval;
+ }
+
+ notify();
+ }
+
+ void addBytes(byte[] abuf) {
+ addBytes(abuf, 0, abuf.length);
+ }
+
+ // this method writes to the buffer at the end of current content
+ synchronized void addBytes(byte[] abuf, int aoffs, int alen) {
+
+ shrink();
+ int togo = buff.length - len; // togo is how many bytes can be written
+ // to buffer before it is full
+ if (togo > alen) {
+ togo = alen;
+ }
+
+ System.arraycopy(abuf, aoffs, buff, len, togo);
+
+ len += togo; // adjust buffer's length to reflect ...
+ notify(); // notify a possible thread waiting on read
+ }
+
+ public int read() throws IOException {
+ log.debug("read");
+ while (!closed) {
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+
+ synchronized (this) {
+ if (offs < len) {
+
+ //System.out.println(new String(new byte [] { buff[offs] }) + " :: " + StringUtils.toBytesString(new byte [] { buff[offs] }));
+ return (int) buff[offs++];
+ }
+ }
+
+ try {
+ // since we have nothing to return and we read one byte
+ // we will wait indefinately
+ delegate.setTimeout(Integer.MAX_VALUE);
+ delegate.setAsyncMode(false);
+ int b = delegateReal.read();
+ if (b != -1) {
+ lastChar = b;
+ //System.out.println(new String("" + (char)b) + " :: " + StringUtils.toBytesString(new byte [] {(byte)b}));
+ return b;
+ }
+ toBufferMode();
+ } catch (Exception ex) {
+ writeError(ex);
+ toBufferMode();
+ //ex.printStackTrace();
+ }
+ }
+
+ synchronized (this) {
+ if (offs < len) { // there is something to read
+ return (int) buff[offs++];
+ }
+
+ try {
+ waiting = true;
+ wait();
+ } catch (InterruptedException ex) {
+ ex.printStackTrace();
+ } finally {
+ waiting = false;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ public int read(byte[] buf) throws IOException {
+ return read(buf, 0, buf.length);
+ }
+
+ //
+ // com.sshtools.j2ssh.io.IOStreamConnector calls this method but always
+ // with aoffs==0 and alen==1, which is ridiculous from our point of view
+ // but makes sense because this way there is no issue with buffers
+ // In order to have performance, we must do our buffering in here
+ // when reading from delegate InputStream
+ //
+ public int read(byte[] abuf, int aoffs, int alen) throws IOException {
+ log.debug("read byte[]");
+ while (!closed) {
+
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+
+ synchronized (this) {
+ shrink();
+ if (offs == len) {
+ int togo = buff.length - len; // togo is how many bytes can be written
+ try {
+ // read as much as you can in quarter second
+ //delegate.setTimeout(250);
+ delegate.setAsyncMode(true);
+
+ int rb = 0;
+ while (rb == 0) {
+ log.debug("Delegate read");
+ rb = delegateReal.read(buff, offs, togo);
+ }
+
+ if (rb == -1) {
+ toBufferMode();
+ } else {
+ len += rb;
+ lastChar = buff[offs + rb - 1];
+ }
+ } catch (Exception ex) {
+ writeError(ex);
+ toBufferMode();
+ //ex.printStackTrace();
+ }
+ }
+
+ int togo = len - offs;
+ if (togo > 0) {
+ togo = togo < alen ? togo : alen;
+
+ System.arraycopy(buff, offs, abuf, aoffs, togo);
+ if (log.isDebugEnabled())
+ log.debug("read " + togo + " bytes. (" + offs + " : " + len + ") -> " + (offs + togo));
+ if (log.isDebugEnabled())
+ log.debug(new String(buff, offs, togo) + " [" + org.jboss.fresh.util.StringUtils.toBytesString(new String(buff, offs, togo)) + "]");
+
+// UNCOMMENT HERE FOR DEBUGGING
+//log.error(" #### " + new String(abuf, aoffs, togo) + " [\n\n" + org.jboss.fresh.util.StringUtils.toBytesString(new String(abuf, aoffs, togo)) + "\n\n]");
+ offs += togo;
+ //System.out.println(new String(abuf, aoffs, togo) + " :: " + StringUtils.toBytesString(abuf, aoffs, togo));
+
+ return togo;
+ }
+ }
+/*
+ try {
+ int b = delegate.read(abuf, aoffs, alen);
+log.error("read " + b + " bytes (aoffs: " + aoffs + ", alen: " + alen + ")");
+log.error("Stack trace: ", new Exception("Throw me out"));
+ if(b!=-1) return b;
+ toBufferMode();
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+*/
+ }
+
+ synchronized (this) {
+ if (offs < len) {
+ int diff = len - offs; // new available output
+ if (alen > diff) alen = diff; // min(alen, diff)
+ System.arraycopy(buff, offs, abuf, aoffs, alen);
+ if (log.isDebugEnabled())
+ log.debug("read " + alen + " bytes. (" + offs + " : " + len + ") -> " + (offs + alen));
+ if (log.isDebugEnabled())
+ log.debug(new String(buff, offs, alen) + " [" + org.jboss.fresh.util.StringUtils.toBytesString(new String(buff, offs, alen)) + "]");
+// UNCOMMENT HERE FOR DEBUGGING
+//log.error(" #### " + new String(abuf, aoffs, alen) + " [\r\n\r\n" + org.jboss.fresh.util.StringUtils.toBytesString(new String(abuf, aoffs, alen)) + "\r\n\r\n]");
+ offs += alen;
+ return alen;
+ }
+
+ try {
+ waiting = true;
+ wait();
+ } catch (InterruptedException ex) {
+ ex.printStackTrace();
+ } finally {
+ waiting = false;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ public int available() throws IOException {
+ log.debug("available");
+ if (closed) throw new EOFException();
+
+ if (delegateMode) {
+ log.debug(" --- delegateMode on");
+ if (len - offs > 0) return len - offs;
+ return delegateReal.available();
+ }
+
+ return len - offs;
+ }
+
+ public void waitCompletion() throws IOException {
+ // make sure client reads everything available
+ while (available() > 0 || delegateMode) {
+ try {
+ synchronized (this) {
+ if (waiting)
+ notify();
+ }
+ Thread.sleep(200);
+ } catch (InterruptedException ex) {
+ throw (IOException) new java.io.InterruptedIOException().initCause(ex);
+ }
+ }
+ }
+
+ public synchronized void close() {
+ closed = true;
+ notifyAll();
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+
+ }
+
+/*
+ static class StdErrorInputStream extends InputStream {
+
+ public int read() {
+ return -1;
+ }
+
+ public int read(byte [] buf) {
+ return -1;
+ }
+
+ public int read(byte [] bug, int offs, int len) {
+ return -1;
+ }
+
+ public int available() {
+ return 0;
+ }
+
+ public void close() {
+ }
+ }
+*/
+
+ static class StdErrorInputStream extends InputStream {
+
+ boolean closed = false;
+
+ public synchronized int read() {
+ try {
+ if (!closed) wait();
+ } catch (InterruptedException ex) {
+ }
+
+ return -1;
+ }
+
+ public synchronized int read(byte[] buf) {
+ return read(buf, 0, buf.length);
+ }
+
+ public synchronized int read(byte[] bug, int offs, int len) {
+ try {
+ if (!closed) wait();
+ } catch (InterruptedException ex) {
+ }
+ return -1;
+ }
+
+ public int available() {
+ return 0;
+ }
+
+ public synchronized void close() {
+ closed = true;
+ notifyAll();
+ }
+ }
+
+}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list