|
按照上面的JCA架构以及代码重用基本准则,我们将创建以下项目:
(a) API
- ybxiang-ssh2-ra-api: SSH Resource Adapter接口
- ybxiang-ssh2-ejb-api: EJB(用于查询Resource Adapter)接口
(b) API实现和JMX application
- ybxiang-ssh2-ra-app: SSH Resource Adapter接口的实现。需要借助ra.xml来安装Resource Adapter。
- ybxiang-ssh2-ejb-app: EJB(用于查询Resource Adapter)接口的实现。可以用Java Annotation把EJB服务发布到JBoss,也可以用jboss-ejb.xml文件发布。
- ybxiang-ssh2-jmx-app: 创建MBean(用于查询Resource Adapter的Connection),用jboss-service.xml文件部署该MBean到MBean Server中。
(c) 数据源
- ybxiang-ssh2-ds: 数据源配置,用于把SSH Resource Adapter发布成JNDI服务,JNDI名字为:“java:/AmsSSHAdapter”
(d) 客户端
- ybxiang-ssh2-ejb-client: 访问EJB,JNDI名字:SSH2Executor/remote
- ybxiang-ssh2-jmx-client: Java程序访问JBoss JMX RMI Adapter。
这些项目之间的依赖关系如下: 注:对应的VISIO 文件: ybxiang-ssh2-projects.dependencies.vsd
|
|
|
|
|
|
|
2.2 ybxiang-ssh2-ejb-api这里仅仅实现了一个常用的方法。 package com.ybxiang.ssh2.ejb.api;
import javax.ejb.Remote;
import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;
@Remote public interface ISSH2Executor{ public static final String JNDI_NAME = "SSH2Executor/remote"; public void executeWithoutWait(SSHConnectionRequestInfo info,String command,String directory); }
|
|
|
3.1 ybxiang-ssh2-ra-app
ra.xml<?xml version="1.0" encoding="UTF-8"?><connector version="1.5" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"> <display-name>SSH2 Adapter</display-name> <vendor-name>Xiang YingBing</vendor-name> <eis-type>SSH2 System</eis-type> <resourceadapter-version>1.0</resourceadapter-version> <license> <description>LGPL</description> <license-required>false</license-required> </license> <resourceadapter>
<resourceadapter-class>com.ybxiang.ssh2.ra.app.SSHResourceAdapter</resourceadapter-class> <outbound-resourceadapter> <connection-definition>
<managedconnectionfactory-class>com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory</managedconnectionfactory-class> <!-- <config-property>
<config-property-name>xxx</config-property-name>
<config-property-type>xxx</config-property-type>
<config-property-value>xxx</config-property-value> </config-property> -->
<connectionfactory-interface>com.ybxiang.ssh2.ra.api.ISSHConnectionFactory</connectionfactory-interface>
<connectionfactory-impl-class>com.ybxiang.ssh2.ra.app.SSHConnectionFactory</connectionfactory-impl-class>
<connection-interface>com.ybxiang.ssh2.ra.api.ISSHConnection</connection-interface>
<connection-impl-class>com.ybxiang.ssh2.ra.app.SSHConnection</connection-impl-class>
<!--
<connection-impl-class>com.ybxiang.ssh2.ra.app.SSHManagedConnection</connection-impl-class>
--> </connection-definition> <transaction-support>NoTransaction</transaction-support> <authentication-mechanism>
<authentication-mechanism-type>BasicPassword</authentication-mechanism-type>
<credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface> </authentication-mechanism>
<!--
<reauthentication-support>true</reauthentication-support>
--> <reauthentication-support>false</reauthentication-support> </outbound-resourceadapter> <!-- <security-permission> <description>...</description> <security-permission-spec> permission java.io.FilePermission "/tmp/db/fs_store/*", "read,write"; </security-permission-spec> </security-permission> --> </resourceadapter></connector>
类关系图:
注:VISIO绘图文件: ybxiang-ssh2-ra-app-class.relation.vsd
|
SSHResourceAdapter.javapublic class SSHResourceAdapter implements ResourceAdapter { public static final Logger log = Logger.getLogger(SSHResourceAdapter.class.getName()); public void start(javax.resource.spi.BootstrapContext arg0) throws javax.resource.spi.ResourceAdapterInternalException{ log.info("start() > arg0="+arg0); log.info("start() > You should initialize something here if necessary."); }...}
|
SSHManagedConnectionFactory.javapublic class SSHManagedConnectionFactory implements ManagedConnectionFactory { public static final Logger log = Logger.getLogger(SSHManagedConnectionFactory.class.getName()); // create Connection Factory public Object createConnectionFactory() throws ResourceException { log.info("createConnectionFactory()"); return new SSHConnectionFactory(this, null); } public Object createConnectionFactory(ConnectionManager cm) throws ResourceException { log.info("createConnectionFactory("+cm+")"); return new SSHConnectionFactory(this, cm); } // Managed Connection public ManagedConnection createManagedConnection(Subject arg0, ConnectionRequestInfo info) throws ResourceException { log.info("createManagedConnection("+arg0+","+info+")"); return new SSHManagedConnection((SSHConnectionRequestInfo) info); }
public ManagedConnection matchManagedConnections(Set set, Subject sbj,
ConnectionRequestInfo info) throws ResourceException { SSHConnectionRequestInfo requestInfo = (SSHConnectionRequestInfo) info; log.info("matchManagedConnections("+set+"."+sbj+","+info+")"); for (Object item : set) { SSHManagedConnection conn = (SSHManagedConnection) item; SSHConnectionRequestInfo info2 = conn.getConnectionRequestInfo(); if(requestInfo.equals(info2)){ return conn; } } log.warn("return no matched ManagedConnection (null)"); return null; } public PrintWriter getLogWriter() throws ResourceException { log.info("getLogWriter()"); return null; } public void setLogWriter(PrintWriter arg0) throws ResourceException { log.info("setLogWriter("+arg0+")"); }}
|
SSHConnectionFactory.javapublic class SSHConnectionFactory implements ISSHConnectionFactory{ public static final Logger log = Logger.getLogger(SSHConnectionFactory.class.getName()); private Reference m_reference; private ManagedConnectionFactory managedConnectionFactory; private ConnectionManager connectionManager;
public SSHConnectionFactory(ManagedConnectionFactory
managedConnectionFactory,ConnectionManager connectionManager){ log.info("SSHConnectionFactory constructor..."); //super(); this.managedConnectionFactory = managedConnectionFactory; this.connectionManager = connectionManager; } public ISSHConnection createConnection(SSHConnectionRequestInfo info) throws ResourceException{ log.info("createConnection("+info+")"); if (this.connectionManager == null) {
log.debug("No connection manager found, returning
non-pooled connection"); return new SSHConnection(new SSHManagedConnection(info),info); }else{ return (SSHConnection) connectionManager.allocateConnection(managedConnectionFactory, info); } } public Reference getReference() throws NamingException { log.info("getReference()"); return m_reference; } public void setReference(Reference reference) { log.info("setReference("+reference+")"); m_reference = reference; } }上面红色代码将调用 SSHManagedConnectionFactory的方法: public ManagedConnection createManagedConnection(Subject arg0, ConnectionRequestInfo info)
得到SSHManagedConnection后,执行SSHManagedConnection.getConnection(ConnectionRequestInfo info) : public Object getConnection(Subject arg0, ConnectionRequestInfo arg1) throws ResourceException { log.info("getConnection("+arg0+","+arg1+")"); return new SSHConnection(this,info); }
|
SSHManagedConnection.javapublic class SSHManagedConnection implements ManagedConnection { public static final Logger log = Logger.getLogger(SSHManagedConnection.class.getName()); private static final String TRANSACTIONS_NOT_SUPPORTED_ERROR = "Transactions not supported";
private final SSHConnectionRequestInfo info; private PrintWriter m_out; private List<ConnectionEventListener> listeners = new LinkedList<ConnectionEventListener>();
public SSHManagedConnection(SSHConnectionRequestInfo info) throws ResourceException{ log.info("{hashCode("+this.hashCode()+")} > "+"SSHManagedConnection("+info+")"); this.info = info; }
public Object getConnection(Subject arg0, ConnectionRequestInfo arg1) throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getConnection("+arg0+","+arg1+")"); return new SSHConnection(this,info); }
public void destroy() throws ResourceException {
log.info("{hashCode("+this.hashCode()+")} >
"+"destroy()"); }
public void cleanup() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"cleanup()"); }
public void associateConnection(Object arg0) throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"associateConnection("+arg0+")"); }
public void addConnectionEventListener(ConnectionEventListener arg0) { log.info("{hashCode("+this.hashCode()+")} > "+"addConnectionEventListener("+arg0+")"); listeners.add(arg0); }
public void removeConnectionEventListener(ConnectionEventListener arg0) {
log.info("{hashCode("+this.hashCode()+")} >
"+"removeConnectionEventListener("+arg0+")"); listeners.remove(arg0); }
public javax.transaction.xa.XAResource getXAResource() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getXAResource()"); throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR); }
public LocalTransaction getLocalTransaction() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getLocalTransaction()"); throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR); }
public ManagedConnectionMetaData getMetaData() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getMetaData()"); return new SSHManagedConnectionMetaData(); }
public PrintWriter getLogWriter() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getLogWriter()"); return this.m_out; }
public void setLogWriter(PrintWriter arg0) throws ResourceException {
log.info("{hashCode("+this.hashCode()+")} >
"+"setLogWriter(java.io.PrintWriter "+arg0+")"); this.m_out = arg0; } //this method is called by SSHManagedConnectionFactory public SSHConnectionRequestInfo getConnectionRequestInfo() { log.info("{hashCode("+this.hashCode()+")} > "+"getConnectionRequestInfo()"); return this.info; } //called by SSHConnection to close related event listeners public void closeEventListener(SSHConnection sshConnection){ ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); event.setConnectionHandle(sshConnection); // Iterator<ConnectionEventListener> list = listeners.iterator(); while (list.hasNext()) { ConnectionEventListener listener = (ConnectionEventListener) list.next(); listener.connectionClosed(event); } } }
|
|
SSHConnection.javapublic class SSHConnection implements ISSHConnection{ public static final Logger log = Logger.getLogger(SSHConnection.class.getName()); private static final String CONNECTION_NOT_INITIALIZED_ERROR = "SSH connection not initalized"; private static final String FINAL_CLOSE_ERROR = "Close in final block threw exception";
private final SSHConnectionRequestInfo info; private ch.ethz.ssh2.Connection ethz_ssh2_connection; private SSHManagedConnection sshManagedConnection;
public SSHConnection(SSHManagedConnection
sshManagedConnection,SSHConnectionRequestInfo info)throws
ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"SSHConnection constructor..."); this.sshManagedConnection = sshManagedConnection; this.info = sshManagedConnection.getConnectionRequestInfo(); try { initConnection(); } catch (Exception e) { log.error(e); throw new ResourceException(e); } } public SSHCommandResult execute(String command, String directory,long timeout) {
log.info("{hashCode("+this.hashCode()+")} >
"+"execute("+command+", "+directory+","+timeout+")"); try{ Session sess = spawn(command,directory); return getSessionResults(sess,timeout); }catch(Exception e){ log.error(e); return null; } }
public void execute(ISSHProcessOutputHandler handler, String command, String directory) {
log.info("{hashCode("+this.hashCode()+")} >
"+"execute(ISSHProcessOutputHandler handler, String command, String
directory)"); try{ Session sess = spawn(command,directory); getSessionResults(sess, handler); }catch(Exception e){ log.error(e); } }
public void executeWithoutWait(String command, String directory) {
log.info("{hashCode("+this.hashCode()+")} >
"+"executeWithoutWait("+command+", "+directory+")"); try{ spawn(command,directory); }catch(Exception e){ log.error(e); } }
/** * TODO: * should pass string(example:sessioinID) as parameter instead of ch.ethz.ssh2.Session, * because ch.ethz.ssh2.Session does NOT implement java.io. */ public boolean isDone(Object sess) { log.info("{hashCode("+this.hashCode()+")} > "+"isDone(Object sess)"); return isSessionDone((Session)sess); }
/** * This method will be called by JBoss automatically. */ public void close() { log.info("{hashCode("+this.hashCode()+")} > "+"close()"); sshManagedConnection.closeEventListener(this); // log.info("{hashCode("+this.hashCode()+")} > "+"Close SSH connection"); if (ethz_ssh2_connection != null) { ethz_ssh2_connection.close(); ethz_ssh2_connection = null; } }
|
/******************************[private helper methods ]******************************/ private void initConnection()throws Exception{
log.debug("initConnection():Creating a SSH
Connection with Public Key : " + info.keyFilePath + ", HostName:" +
info.hostName); ethz_ssh2_connection = new ch.ethz.ssh2.Connection(info.hostName); ethz_ssh2_connection.connect(); // if(info.keyFilePath!=null){
log.debug("Authenticating SSH Connection with Public Key : " +
info.keyFilePath);
if (ethz_ssh2_connection.authenticateWithPublicKey(info.userName, new
File(info.keyFilePath), info.keyFilePassword) == false){
throw new Exception("Authentication
failed.");
}
}else{
ethz_ssh2_connection.authenticateWithPassword(info.userName,info.password); } } /** * Caller should remember the returned Session if he want to get the result later(not now). */ private Session spawn(String command, String directory) throws IOException { String newCommand = command; if(directory !=null ){ newCommand = "cd "+directory+" && "+command; } // Session sess = null; if (ethz_ssh2_connection != null) { sess = ethz_ssh2_connection.openSession(); log.debug("executing command " + newCommand); sess.execCommand(newCommand); } else { log.error(CONNECTION_NOT_INITIALIZED_ERROR); throw new IOException(CONNECTION_NOT_INITIALIZED_ERROR); } return sess; }
|
/******************************[static helper methods ]******************************/ public static boolean isSessionDone(Session sess) { return (sess.getExitStatus() != null); } /** * @param outputHandler implemented by the caller */
public static void getSessionResults(Session sess,
ISSHProcessOutputHandler outputHandler) throws IOException
{ try {
outputHandler.processOutput(sess.getStdout(), sess.getStderr()); sess.waitForCondition(ChannelCondition.EXIT_STATUS, 10000); int status = sess.getExitStatus(); log.debug("status is " + status); } finally { if (sess != null) { try { sess.close(); } catch (Exception ignore) {
log.error(FINAL_CLOSE_ERROR); } } } } /** * Read stdout and error stream from session by yourself. * TODO: how to return result before timeout??? */
public static SSHCommandResult getSessionResults(Session sess,long
timeout) throws IOException { SSHCommandResult sshCmdRes = new SSHCommandResult("", -1); try { boolean testingTimeout = false; if(testingTimeout){
sess.waitForCondition(ChannelCondition.EXIT_STATUS, timeout); int status = sess.getExitStatus();
log.debug("status is " + status);
if(status==ChannelCondition.STDOUT_DATA||status==ChannelCondition.STDERR_DATA||status==ChannelCondition.TIMEOUT
){ return null; }else{
//Now, it is NOT timeout, Let's read result. } } // StringBuffer sbStdout = new StringBuffer(); //1.read stdout
InputStream stdout = new ch.ethz.ssh2.StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); while (true) { String line = br.readLine(); if (line == null) { break; } sbStdout.append(line).append("\n"); } log.debug("output " + sbStdout.toString()); //2.read error stream
InputStream errorStream = new StreamGobbler(sess.getStderr());
BufferedReader errorBR = new BufferedReader(new
InputStreamReader(errorStream)); StringBuffer errorSB = new StringBuffer(); while (true) { String line = errorBR.readLine(); if (line == null) { break; } errorSB.append(line).append("\n"); } log.debug("Error " + errorSB.toString()); //wait 10 seconds for status is set correctly by the session. sess.waitForCondition(ChannelCondition.EXIT_STATUS, 10000); int status = sess.getExitStatus(); log.debug("status is " + status); //now return. sshCmdRes.status=status; sshCmdRes.result = sbStdout.toString(); sshCmdRes.error = errorSB.toString(); } finally { if (sess != null) { try { sess.close(); } catch (Exception ignore) {
log.error(FINAL_CLOSE_ERROR); } } } return sshCmdRes; }
}
|
|
|
3.2 ybxiang-ssh2-jmx-app
只提供最简单的业务方法: public void executeWithoutWait(SSHConnectionRequestInfo info, String command,String directory); 注意:JMX的接口和实现的定义需要遵守很多规矩,参见: JBoss5.1.0 > JMX
SSHServiceMBean.java
package com.ybxiang.ssh2.jmx;
import javax.naming.NamingException;
import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;
/** * All interface names of JMX MBeans must end with "MBean" * @author yingbinx * */ public interface SSHServiceMBean extends org.jboss.system.ServiceMBean{
public void executeWithoutWait(SSHConnectionRequestInfo info, String
command,String directory); }
|
|
SSHService.javapackage com.ybxiang.ssh2.jmx;
import javax.naming.InitialContext;
import com.ybxiang.ssh2.jmx.SSHServiceMBean;
import com.ybxiang.ssh2.ra.api.ISSHConnection;
import com.ybxiang.ssh2.ra.api.ISSHConnectionFactory;
import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;
import com.ybxiang.ssh2.ra.api.Logger;
public class SSHService extends org.jboss.system.ServiceMBeanSupport implements SSHServiceMBean {
public static final Logger log = Logger.getLogger(SSHService.class.getName());
public void executeWithoutWait(SSHConnectionRequestInfo info, String command, String directory) {
ISSHConnection connection = null;
try {
InitialContext ctx = new InitialContext();
Object ref = ctx.lookup(ISSHConnectionFactory.JNDI_NAME);//"java:/AmsSSHAdapter"
ISSHConnectionFactory cf = (ISSHConnectionFactory) ref;
connection = cf.createConnection(info);
connection.executeWithoutWait(command,directory);
} catch (Exception e) {
log.error("Failed during JNDI access"+e);
}finally{
try{
//connection.close();//JBoss will close it.
}catch(Exception e){
log.error("Failed during Close SSHConnection"+e);
}
}
}
//TO BE CONTINUED
|
// //you can override bellow life cycle mehtods:
// @Override
// public void create() throws Exception {
// super.create();
// }
// @Override
// public void start() throws Exception {
// super.start();
// }
// @Override
// public void stop() {
// super.stop();
// }
// @Override
// public void destroy() {
// super.destroy();
// }
// //...
}
|
|
|
3.3 ybxiang-ssh2-ejb-app
Connection不执行close()的情况下,容器会自己帮忙执行! SSH2Executor.javapackage com.ybxiang.ssh2.ejb.app;import javax.ejb.Stateless;import javax.naming.InitialContext;import org.apache.log4j.Logger;import com.ybxiang.ssh2.ejb.api.ISSH2Executor;import com.ybxiang.ssh2.ra.api.ISSHConnection;import com.ybxiang.ssh2.ra.api.ISSHConnectionFactory;import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;@Statelesspublic class SSH2Executor implements ISSH2Executor{ Logger log = Logger.getLogger(SSH2Executor.class); public void executeWithoutWait(SSHConnectionRequestInfo info,String command,String directory){ ISSHConnection connection = null; try { InitialContext ctx = new InitialContext(); Object ref = ctx.lookup(ISSHConnectionFactory.JNDI_NAME);//"java:/AmsSSHAdapter" ISSHConnectionFactory cf = (ISSHConnectionFactory) ref; connection = cf.createConnection(info); connection.executeWithoutWait(command,directory); } catch (Exception e) { log.error("Failed during JNDI access", e); }finally{ try{ //connection.close();//JBoss will close it. }catch(Exception e){ log.error("Failed during Close SSHConnection", e); } } }}
|
|
|
4. ybxiang-ssh2-ds 分析注意, - JNDI名字为“AmsSSHAdapter”。
- <rar-name>的值必须是真正部署的rar文件的完整名字,这里为“ybxiang-ssh2-ra-app.rar”
<!DOCTYPE connection-factories PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN" "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd"><connection-factories> <no-tx-connection-factory> <jndi-name>AmsSSHAdapter</jndi-name> <rar-name>ybxiang-ssh2-ra-app.rar</rar-name>
<connection-definition>com.ybxiang.ssh2.ra.api.ISSHConnectionFactory</connection-definition> <!-- <config-property name="xxx" type="xxx">xxx</config-property> --> <min-pool-size>3</min-pool-size> <max-pool-size>4</max-pool-size> <blocking-timeout-millis>5000</blocking-timeout-millis> <idle-timeout-minutes>10</idle-timeout-minutes> <!-- <application-managed-security/> --> </no-tx-connection-factory></connection-factories>
|
|
|
|
5.Client 代码这里。我们有3种方式来间接访问我们的SSH Resource Adapter。 把D:\java\jboss-5.1.0.GA\client中所有jars设置到ybxiang-ssh2-jmx-client的"java build path/Libraries" 把D:\java\jboss-5.1.0.GA\client中所有jars设置到ybxiang-ssh2-ejb-client的"java build path/Libraries"
|
5.1 WEB Browser访问JBOSS JMX HTML ADAPTER不需要任何代码。演示在后面。
|
5.2 ybxiang-ssh2-jmx-clientpackage com.ybxiang.ssh2.jmx.client;
import java.util.Properties;
import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.ObjectName; import javax.naming.InitialContext;
import org.jboss.jmx.adaptor.rmi.RMIAdaptor;
import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;
public class JMXBrowser { public static final String RMIAdaptor_JNDI_NAME = "jmx/invoker/RMIAdaptor"; // public static final String JNDIViewMBean_ObjectName = "jboss:service=JNDIView"; public static final String SSHServiceMBean_ObjectName = "com.ybxiang.ssh2:service=SSHService"; public static void main(String[] args) throws Exception { //demoJNDIViewMBean(); executeSSH2CommandAtHome();//在家时的工作环境 //executeSSH2CommandAtCompany();//在公司时的环境 }
/************************[test methods]**************************/ public static void demoJNDIViewMBean() throws Exception{ printMBeanInfo(JNDIViewMBean_ObjectName); ////// RMIAdaptor server = getJBossRMIAdaptor(); ObjectName objName = new ObjectName(JNDIViewMBean_ObjectName); // Invoke the list(boolean) op String[] sig = { "boolean" }; Object[] opArgs = { Boolean.TRUE }; Object result = server.invoke(objName, "list", opArgs, sig); //
System.out.println("JNDIView.list(true) output:\n" +
result); } public static void executeSSH2CommandAtHome()throws Exception{ printMBeanInfo(SSHServiceMBean_ObjectName); //
//Invoke public void
executeWithoutWait(SSHConnectionRequestInfo info, String command,String
directory); RMIAdaptor server = getJBossRMIAdaptor(); String[] sig = { SSHConnectionRequestInfo.class.getName(), "java.lang.String", "java.lang.String" }; Object[] opArgs = {
new
SSHConnectionRequestInfo("192.168.1.101","root","ybxiang"), "mkdir ybxiangsshJMXtest", "/tmp" }; Object result = server.invoke( new ObjectName(SSHServiceMBean_ObjectName), "executeWithoutWait", opArgs, sig); } public static void executeSSH2CommandAtCompany()throws Exception{ printMBeanInfo(SSHServiceMBean_ObjectName); //
//Invoke public void
executeWithoutWait(SSHConnectionRequestInfo info, String command,String
directory); RMIAdaptor server = getJBossRMIAdaptor(); String[] sig = { SSHConnectionRequestInfo.class.getName(), "java.lang.String", "java.lang.String" }; Object[] opArgs = {
new
SSHConnectionRequestInfo("135.251.246.180","ems00","emsems"), "mkdir ybxiangsshJMXtest", "/home/ems00" }; Object result = server.invoke( new ObjectName(SSHServiceMBean_ObjectName), "executeWithoutWait", opArgs, sig); }
|
/************************[static helper methods]**************************/ public static InitialContext getJBossInitialContext() throws Exception{ Properties properties = new Properties(); properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces"); properties.put("java.naming.provider.url","localhost:1099");
return new
InitialContext(properties);
} public static RMIAdaptor getJBossRMIAdaptor()throws Exception{ InitialContext ic = getJBossInitialContext(); return (RMIAdaptor) ic.lookup(RMIAdaptor_JNDI_NAME); } public static void printMBeanInfo(String strObjectName)throws Exception{ RMIAdaptor server = getJBossRMIAdaptor(); // ObjectName objName = new ObjectName(strObjectName); MBeanInfo info = server.getMBeanInfo(objName); System.out.println("Class: " + info.getClassName()); MBeanOperationInfo[] opInfo = info.getOperations(); System.out.println("Operations: "); for (int i = 0; i < opInfo.length; i++) { MBeanOperationInfo op = opInfo[i]; String returnType = op.getReturnType(); String opName = op.getName(); System.out.print(" + " + returnType + " " + opName + "("); MBeanParameterInfo[] params = op.getSignature(); for (int j = 0; j < params.length; j++) { MBeanParameterInfo paramInfo = params[j]; String pname = paramInfo.getName(); String type = paramInfo.getType(); if (pname.equals(type)) { System.out.print(type); } else {
System.out.print(type + " " + pname); } if (j < params.length - 1) { System.out.print(','); } } System.out.println(")"); } }}
|
5.3 ybxiang-ssh2-ejb-clientEJBClient.javapublic class EJBClient { public static void main(String args[]) throws Exception { Context context = getInitialContext(); ISSH2Executor executor = (ISSH2Executor)context.lookup(ISSH2Executor.JNDI_NAME); executeAtHome(executor);//在家时的测试环境 //executeAtCompany(executor);//在公司时的测试环境 } public static InitialContext getInitialContext() throws Exception{ Properties properties = new Properties(); properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces"); properties.put("java.naming.provider.url","localhost:1099");
return new
InitialContext(properties);
} public static void executeAtHome(ISSH2Executor executor)throws Exception{ SSHConnectionRequestInfo info = new SSHConnectionRequestInfo("192.168.1.101","root","ybxiang"); executor.executeWithoutWait(info, "mkdir ybxiangsshtest", "/tmp"); } public static void executeAtCompany(ISSH2Executor executor)throws Exception{ SSHConnectionRequestInfo info = new SSHConnectionRequestInfo("135.251.246.180","ems00","emsems"); executor.executeWithoutWait(info, "mkdir ybxiangsshtest", "/home/ems00"); } }
|
|
|
6. 部署/日志部署目录:D:\java\jboss-5.1.0.GA\server\all\deploy
|
|
6.2 启动JBoss日志如下: ...02:26:13,781
INFO [ServerImpl] JBoss (Microcontainer) [5.1.0.GA (build:
SVNTag=JBoss_5_1_0_GA date=200905221634)] Started in 1m:30s:500ms
|
6.3 部署ybxiang-ssh2-ra-app.rar导出:

结果:

相关日志: 02:28:49,578 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHResourceAdapter>start() > arg0=org.jboss.resource.deployers.RARDeployment@113335102:28:49,578 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHResourceAdapter>start() > You should initialize something here if necessary.
|
6.4部署ybxiang-ssh2-ds.xml把ybxiang-ssh2-ds.xml拷贝到D:\java\jboss-5.1.0.GA\server\all\deploy 就可以了。 相关日志: 02:30:52,828
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>setLogWriter(org.jboss.logging.util.LoggerPluginWriter@1121216) 02:30:52,843 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createConnectionFactory(org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy@9df864) 02:30:52,859 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnectionFactory>SSHConnectionFactory constructor... 02:30:52,859
INFO [ConnectionFactoryBindingService] Bound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' to JNDI name 'java:AmsSSHAdapter'提示:“ java:AmsSSHAdapter”查询出来的reference是“ SSHConnectionFactory”
|
6.5 部署ybxiang-ssh2-ejb-app.jar02:33:23,187
INFO [Ejb3DependenciesDeployer] Encountered deployment
AbstractVFSDeploymentContext@370280{vfszip:/D:/java/jboss-5.1.0.GA/server/all/deploy/ybxiang-ssh2-ejb.jar/}02:33:23,187
INFO [Ejb3DependenciesDeployer] Encountered deployment
AbstractVFSDeploymentContext@370280{vfszip:/D:/java/jboss-5.1.0.GA/server/all/deploy/ybxiang-ssh2-ejb.jar/}02:33:23,328 INFO [JBossASKernel] Created KernelDeployment for: ybxiang-ssh2-ejb.jar02:33:23,328 INFO [JBossASKernel] installing bean: jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB302:33:23,328 INFO [JBossASKernel] with dependencies:02:33:23,328 INFO [JBossASKernel] and demands:02:33:23,328 INFO [JBossASKernel] jboss.ejb:service=EJBTimerService02:33:23,328 INFO [JBossASKernel] and supplies:02:33:23,328 INFO [JBossASKernel] Class:com.ybxiang.ssh2.ejb.api.ISSH2Executor02:33:23,328 INFO [JBossASKernel] jndi:SSH2Executor/remote-com.ybxiang.ssh2.ejb.api.ISSH2Executor02:33:23,328 INFO [JBossASKernel] jndi:SSH2Executor/remote02:33:23,328 INFO [JBossASKernel] Added bean(jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB3) to KernelDeployment of: ybxiang-ssh2-ejb.jar02:33:23,328
INFO [EJB3EndpointDeployer] Deploy
AbstractBeanMetaData@18be861{name=jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB3_endpoint
bean=...}02:33:23,390 INFO [SessionSpecContainer] Starting jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB302:33:23,390 INFO [EJBContainer] STARTED EJB: com.ybxiang.ssh2.ejb.app.SSH2Executor ejbName: SSH2Executor02:33:23,406 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI: SSH2Executor/remote - EJB3.x Default Remote Business Interface SSH2Executor/remote-com.ybxiang.ssh2.ejb.api.ISSH2Executor - EJB3.x Remote Business Interface
提示:- “jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB3”这是EJB对应的JMX service的名字。
- 其它EJB如果依赖这个EJB,那么可以用Java注解或者在xml配置文件中用<depends>jboss.j2ee:jar=ybxiang-ssh2-ejb.jar,name=SSH2Executor,service=EJB3</depends>元素指定依赖。
|
6.6 导出并部署ybxiang-ssh2-jmx-app导出到临时目录“D:”,然后另外命名后缀为为sar的文件:


|
|
|
|
|
7.1 web 浏览器用web浏览器打开地址:http://localhost:8080/jmx-console/,如下:  
|
点击"service=SSHService"连接,进入页面:
由
于“p1
com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo”
没有设置PropertyMapper,所以无法直接把string传递进去转化为
com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo对象。 TODO:可以解决这个问题。
|
|
7.2 JMX Client访问
日志: [xiang]: 连接工厂首次被调用创建连接,..INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null) [xiang]: 下面将按照ybxiang-ssh2-ds.xml的定义连续创建3个ManagedConnection,在第一个ManagedConnection创建完毕后,立刻让它创建SSHConnection [xiang]:#1 SSHManagedConnection..INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)..INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14538030)} > SSHManagedConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)//构造函数..INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14538030)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@1d6f2be[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@ddd52e handles=0
lastUse=1309783924265 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])[xiang]:在第一个ManagedConnection创建完毕后,立刻让它创建SSHConnection..INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14538030)} > getConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null) [xiang]:#2 SSHManagedConnection..INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)..INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(1059336)}
>
SSHManagedConnection(hostName=192.168.1.101;userName=root;
keyFilePath=null;keyFilePassword=null)//构造函数..INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(1059336)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@137a99e[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@102a08 handles=0
lastUse=1309783924265 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])[xiang]:#3 SSHManagedConnection..INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)..INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15506763)}
>
SSHManagedConnection(hostName=192.168.1.101;userName=root;
keyFilePath=null;keyFilePassword=null)//构造函数..INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15506763)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@4ad8a3[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@ec9d4b handles=0
lastUse=1309783924265 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])[xiiang]:第一个ManagedConnection 构造的 SSHConnection, 该SSHConnection又在initConnection()方法中构造真正的对资源访问的连接,这里为ch.ethz.ssh2.Connection。..INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(1655734)} > SSHConnection constructor.....INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14538030)} > getConnectionRequestInfo()..DEBUG:
com.ybxiang.ssh2.ra.app.SSHConnection>initConnection():Creating a
SSH Connection with Public Key : null, HostName:192.168.1.101..INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(1655734)} > executeWithoutWait(mkdir ybxiangsshJMXtest, /tmp)..DEBUG: com.ybxiang.ssh2.ra.app.SSHConnection>executing command cd /tmp && mkdir ybxiangsshJMXtest
总共3个SSHManagedConnection,hashCode: 14538030 1059336 15506763
|
再次运行:20:58:30,140
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)20:58:30,140
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@ec9d4b].null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)[xiang]:
我们可以看见,SSHManagedConnectionFactory现在查询旧的SSHManagedConnection,而不是继续构造
SSHManagedConnection!!!没有看见SSHManagedConnection的构造函数被调用![xiang]:从下面的代码可以看出,查询出的旧的SSHManagedConnection(15506763)被挑选出来,创建SSHConnection。20:58:30,140 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15506763)} > getConnectionRequestInfo()20:58:30,140 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15506763)} > getConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)20:58:30,140 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(24953499)} > SSHConnection constructor...20:58:30,140 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15506763)} > getConnectionRequestInfo()20:58:30,140
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHConnection>initConnection():Creating a SSH
Connection with Public Key : null, HostName:192.168.1.10120:58:30,500
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(24953499)} >
executeWithoutWait(mkdir ybxiangsshJMXtest, /tmp)20:58:30,500 INFO [STDOUT] DEBUG: com.ybxiang.ssh2.ra.app.SSHConnection>executing command cd /tmp && mkdir ybxiangsshJMXtest
|
结果: -bash-3.2$ ls ams
deployIDM.sh Desktop eclipse maven
SET.AMS_ENV.sh tempfile test tmp workspace
ybxiangsshJMXtest -bash-3.2$ 成功!
|
闲置测试:已知:第一次运行时,SSHManagedConnection(14538030)被取用
第一次运行时,SSHManagedConnection(15506763)被取用
因为ybxiang-ssh2-ds.xml 中配置有<idle-timeout-minutes>10</idle-timeout-minutes>元素,所以我们等待10分钟,可以看见jboss server打印出日志: 21:04:31,203 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(1059336)} > destroy()[xiang:] 从上面的日志可以看出,第三个SSHManagedConnection(1059336)一直没有被使用过。它的闲置时间最长。它首先被销毁了!
[xiang:] 从下面的日志可以看出,SSHManagedConnectionFactory立刻又创建了1个SSHManagedConnection,连接池里面保持3个!
21:04:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)21:04:31,203 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(19745928)} > SSHManagedConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)/ /构造函数21:04:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(19745928)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@fbb1d8[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@12d4c88 handles=0
lastUse=1309784671203 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])
|
继续闲置半小时: [xiang:]最后创建的那个SSHManagedConnection(19745928)一直没有使用过,所以首先销毁它。21:19:31,203 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(19745928)} > destroy()[xiang:]立即又创建一个(6387368),使pool里面保持最低3个。21:19:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)21:19:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(6387368)} >
SSHManagedConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)21:19:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(6387368)} >
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@b5441b[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@6176a8 handles=0
lastUse=1309785571203 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])[xiang:]最后创建的那个SSHManagedConnection(6387368)一直没有使用过,销毁它。21:34:31,203 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(6387368)} > destroy()[xiang:]立即又创建一个(26679346),使pool里面保持最低3个。21:34:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>createManagedConnection(null,hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)21:34:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(26679346)}
>
SSHManagedConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)21:34:31,203
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(26679346)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@b57c75[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1971832 handles=0
lastUse=1309786471203 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@daa846
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@15db93c])[xiang:]最后创建的那个SSHManagedConnection(26679346)一直没有使用过,销毁它。21:49:31,203 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(26679346)} > destroy()...循环!我们发现,我们最初占用的2个SSHManagedConnection(14538030)和SSHManagedConnection(15506763)一直没有被销毁,因为我们一直没有释放它!这就是性能被耗尽的一个根源。
|
最后,我们再连续运行JMXBrowser 2次,最后一次发现,无法得到连接了: 22:16:50,250
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null)22:16:55,250 ERROR [STDERR] ERROR: com.ybxiang.ssh2.jmx.SSHService>Failed during JNDI accessjavax.resource.ResourceException: Unable to get managed connection for AmsSSHAdapter这正好验证了,最大pool size为4! 这个问题会在后面解决:调用SSHManagedConnection.cleanup()能使得对应的SSHManagedConnection被放回connection pool。
|
关闭JBoss: ... 2011-07-04 22:22:09,515 INFO
[org.jboss.ejb3.session.SessionSpecContainer] (JBoss Shutdown Hook)
Stopping
jboss.j2ee:jar=ybxiang-ssh2-ejb-app.jar,name=SSH2Executor,service=EJB3 2011-07-04
22:22:09,531 INFO [org.jboss.ejb3.EJBContainer] (JBoss Shutdown Hook)
STOPPED EJB: com.ybxiang.ssh2.ejb.app.SSH2Executor ejbName: SSH2Executor 2011-07-04
22:22:10,734 INFO
[org.jboss.resource.connectionmanager.ConnectionFactoryBindingService]
(JBoss Shutdown Hook) Unbound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=JmsXA' from JNDI name
'java:JmsXA' ... 2011-07-04 22:22:13,062 INFO
[org.jboss.resource.connectionmanager.ConnectionFactoryBindingService]
(JBoss Shutdown Hook) Unbound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' from
JNDI name 'java:AmsSSHAdapter' ... 2011-07-04 22:22:13,125 INFO
[STDOUT] (JBoss Shutdown Hook) INFO:
com.ybxiang.ssh2.ra.app.SSHResourceAdapter>stop() > You should
destory something here if necessary. ... 可以发现,没有被放回连接池的SSHManagedConnection,没有被执行cleanup()/destroy() 方法!
现在,我们应认识到
不应该在SSHConnection里面执行 对真正的连向资源的连接(ch.ethz.ssh2.Connection)的
管理(创建/清理)动作,而是在SSHManagedConnection里面的destroy()里面执行!SSHConnection只是业务连接。
我们在后面修复该问题。
|
|
7.3 运行EJB client重新部署ybxiang-ssh2-ds.xml【从deploy目录删除,然后重新拷贝进来】 运行EJBClient.java时,我们发现server端日志比上面的JMXBrowser执行时的日志多出下面一段(注意,我们没有显式的在代码中执行SSHConnection.close()方法): ...16:11:42,406
INFO [CachedConnectionManager] Closing a connection for
you. Please close them yourself:
com.ybxiang.ssh2.ra.app.SSHConnection@1664dc8java.lang.Throwable: STACKTRACE
at
org.jboss.resource.connectionmanager.CachedConnectionManager.registerConnection(CachedConnectionManager.java:278)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:524)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:941) at com.ybxiang.ssh2.ra.app.SSHConnectionFactory.createConnection(SSHConnectionFactory.java:34) at com.ybxiang.ssh2.ejb.app.SSH2Executor.executeWithoutWait(SSH2Executor.java:24) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ...16:11:42,406 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>close()16:11:42,406 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>cleanup()16:11:42,406 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>Close SSH connection
|
我们的代码中,没有任何一句 显式的(declaratively) 调用 SSHConnection.close(),为什么该方法会被调用呢?下面我们进行测试。 现在我们把该SSHConnection.close()注解掉,把对应的接口方法ISSHConnection.close()也注解掉。 (1) 重新部署,步骤如下: * 关闭jboss * 部署ybxiang-ssh2-ra-api.jar到D:\java\jboss-5.1.0.GA\server\all\lib * 部署ybxiang-ssh2-ra-app.rar到D:\java\jboss-5.1.0.GA\server\all\deploy * 重新启动JBoss (2) 现在我们在运行EJBClient.java,JBoss Server日志如下:...19:09:32,156 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>SSHConnection constructor...19:09:32,156 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>getConnectionRequestInfo()19:09:32,156
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHConnection>initConnection():Creating a SSH
Connection with Public Key : null, HostName:192.168.1.10119:09:33,718 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>executeWithoutWait(mkdir ybxiangsshtest, /tmp)19:09:33,734 INFO [STDOUT] DEBUG: com.ybxiang.ssh2.ra.app.SSHConnection>executing command cd /tmp && mkdir ybxiangsshtest19:09:33,750 INFO [CachedConnectionManager] Could not find a close method on alleged connection objects. Please close your own connections.原来是JBoss Server主动寻找SSHConnection是否存在叫做close()的方法: * 如果没有找到,则打印出上面红色消息 * 如果找到了,则调用对应SSHConnection instance的close()方法。然后打印出对应的STACKTRACE(前面已经展示过)。 (3)运行 JMXBrowser 结果如下:...19:29:16,531 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>SSHConnection constructor...19:29:16,531 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>getConnectionRequestInfo()19:29:16,531
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHConnection>initConnection():Creating a SSH
Connection with Public Key : null, HostName:192.168.1.10119:29:16,828
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnection>executeWithoutWait(mkdir
ybxiangsshJMXtest, /tmp)19:29:16,843 INFO [STDOUT] DEBUG: com.ybxiang.ssh2.ra.app.SSHConnection>executing command cd /tmp && mkdir ybxiangsshJMXtest 我们发现,通过JMX MBean 运行的时候,得到的SSHConnection,JBoss是不会主动帮助关闭的!(4) 关于从ConnectionFactory获取的Connection(这里为SSHConnection)的close()方法的总结:- 必须设置一个方法,用于关闭真实的对Resource的连接【这里为ch.ethz.ssh2.Connection】。
- 通过EJBClient调用EJB,再从ConnectionFactory获取Connection(这里为SSHConnection)这种情况下,使用完毕该Connection后,
(a) 如果想要让JBoss自动帮助关闭它【JBOSS在EJB的方法(通常是一个transaction)执行完毕后执行关闭动作,这是合理的】,那么必须让该Connection的接口及其实现带有一个叫做close()的方法; (b) 如果想要自己写代码关闭从ConnectionFactory获取Connection(这里为SSHConnection),那么该关闭方法的名字可以随意。
- 通过JMX调
用MBean,再从ConnectionFactory获取Connection(这里为SSHConnection)这种情况下,使用完毕该
Connection后,JBoss永远 不会 帮助关闭该connection,本人猜测原因为JBoss无法判定该MBean的某方法
是否在代表了一个完整的transaction,如果该方法只是transaction的一部分,这时候JBoss帮助执行了该Connection(这
里为SSHConnection)的close()方法,那会造成不良后果。
(5) 本人建议: 为了保证从ConnectionFactory获取的Connection被回收,必须将它显式的(declarative)关闭。这样代码也便于移植到其它j2ee容器中。上面的STACKTRACE就是对用户的一种警告!执行该Connection的关闭动作时: (a) 可以 关闭 对资源的真正的连接(这里为ch.ethz.ssh2.Connection)
(b) 可以 把 对资源的真正的连接(这里为ch.ethz.ssh2.Connection) 放回 connection
pool中,并非真正的关闭之。下一次调用的时候,再分配出去。
|
|
|
7.4 测试:不使用叫做close()的方法来关闭,而是用testMethod4Close()执行: 7.4.1 测试: 不释放底层ch.ethz.ssh2.Connection连接。仅仅执行sshManagedConnection.cleanup();(1) 我们为ISSHConnection新增一个接口方法: public void testMethod4Close(); (2) 然后在SSHConnection中实现它: public void testMethod4Close(){ try{ sshManagedConnection.cleanup(); }catch(Exception e){
log.error("{hashCode("+this.hashCode()+")} > testMethod4Close()
Exception: "+e); } } (3) 在SSH2Executor / SSHService中,调用它: public void executeWithoutWait(SSHConnectionRequestInfo info,String command,String directory){ ISSHConnection connection = null; try { InitialContext ctx = new InitialContext();
Object ref =
ctx.lookup(ISSHConnectionFactory.JNDI_NAME);//"java:/AmsSSHAdapter" ISSHConnectionFactory cf = (ISSHConnectionFactory) ref; connection = cf.createConnection(info); connection.executeWithoutWait(command,directory); } catch (Exception e) { log.error("Failed during JNDI access", e); }finally{ try{ connection.testMethod4Close();
//connection.close();//JBoss will close it automatically.//TODO: restore
this line after test is finished. }catch(Exception e){ log.error("Failed during Close SSHConnection", e); } } } (4) 关闭JBOss (5) 重新部署一切改动过代码的模块: ybxiang-ssh2-ra-api.jar ybxiang-ssh2-ra-app ybxiang-ssh2-ejb-app
ybxiang-ssh2-jmx-app
(6) 重新启动JBoss。
|
下面是运行JMXBrowser 5次的结果: 23:05:20,875
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null) 23:05:25,875
ERROR [STDERR] ERROR: com.ybxiang.ssh2.jmx.SSHService> Failed during
JNDI accessjavax.resource.ResourceException: Unable to get managed
connection for AmsSSHAdapter23:05:25,890 ERROR [STDERR] ERROR:
com.ybxiang.ssh2.jmx.SSHService>Failed during Close
SSHConnectionjava.lang.NullPointerException 该日志表明:还是没有回收SSHManagedConnection! 原
因:利用SSHManagedConnection获取的SSHConnection instance因为没有释放
ch.ethz.ssh2.Connection,所以JBoss
server无法销毁该instance。这样SSHManagedConnection 就无法被放回连接池。 下面测试close真正的底层connection。
|
下面是运行JMXBrowser 5次的结果: 23:05:20,875
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=192.168.1.101;userName=root;keyFilePath=null;keyFilePassword=null) 23:05:25,875
ERROR [STDERR] ERROR: com.ybxiang.ssh2.jmx.SSHService>Failed during
JNDI accessjavax.resource.ResourceException: Unable to get managed
connection for AmsSSHAdapter 23:05:25,890 ERROR [STDERR] ERROR:
com.ybxiang.ssh2.jmx.SSHService>Failed during Close
SSHConnectionjava.lang.NullPointerException 还是没有回收SSHManagedConnection! TODO:测试close真正的底层connection。
|
7.4.2 测试关闭底层的ch.ethz.ssh2.Connection(1) 修改 SSHConnection.testMethod4Close()方法如下: public void testMethod4Close(){ try{
log.info("{hashCode("+this.hashCode()+")} > "+"Close SSH
connection"); if (ethz_ssh2_connection != null) { ethz_ssh2_connection.close(); ethz_ssh2_connection = null; } //sshManagedConnection.cleanup(); }catch(Exception e){
log.error("{hashCode("+this.hashCode()+")} > testMethod4Close()
Exception: "+e); } } (2) 重新部署 ybxiang-ssh2-ra-app.rar【如果不生效,那么完整的部署一遍所有的模块】
|
(3) 运行JMXBrowser 5次,第5次日志:09:01:52,577
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>createConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) 09:01:57,611
ERROR [STDERR] ERROR: com.ybxiang.ssh2.jmx.SSHService>Failed during
JNDI accessjavax.resource.ResourceException: Unable to get managed
connection for AmsSSHAdapter 09:01:57,611 ERROR [STDERR] ERROR:
com.ybxiang.ssh2.jmx.SSHService>Failed during Close SSHConnection
java.lang.NullPointerException 这表明,SSHManagedConnection还是没有被回收。
|
7.4.3 测试关闭底层的ch.ethz.ssh2.Connection并调用SSHManagedConnection.cleanup()(1) SSHConnection.testMethod4Close()改成如下: public void testMethod4Close(){ try{
log.info("{hashCode("+this.hashCode()+")} > "+"Close SSH
connection"); if (ethz_ssh2_connection != null) { ethz_ssh2_connection.close(); ethz_ssh2_connection = null; } sshManagedConnection.cleanup(); }catch(Exception e){
log.error("{hashCode("+this.hashCode()+")} > testMethod4Close()
Exception: "+e); } } (2)重新部署 ybxiang-ssh2-ra-app.rar
|
(3) 运行JMXBrowser 5次 结果还是无法回收 SSHManagedConnection。
|
7.4.4 测试 不关闭底层的ch.ethz.ssh2.Connection,只调用SSHManagedConnection.closeEventListener(SSHConnection)(1) SSHConnection.testMethod4Close()修改如下 public void testMethod4Close(){ log.info("{hashCode("+this.hashCode()+")} > "+"testMethod4Close()"); try{ log.info("sshManagedConnection.closeEventListener(this);");
sshManagedConnection.closeEventListener(this);
}catch(Exception e){
log.error("{hashCode("+this.hashCode()+")} > testMethod4Close()
Exception: "+e); } }(2) 重新部署 ybxiang-ssh2-ra-app.rar
|
第一次日志: ...INFO...SSHConnectionFactory>createConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnectionFactory>createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(18922657)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(18922657)} > addConnectionEventListener... ...INFO...SSHManagedConnection>{hashCode(18922657)}
>
getConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnectionFactory>createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHConnection>{hashCode(14222114)} > SSHConnection constructor... ...INFO...SSHManagedConnection>{hashCode(10563793)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(18922657)} > getConnectionRequestInfo() ...INFO...SSHManagedConnection>{hashCode(10563793)} > addConnectionEventListener.... ...DEBUG...SSHConnection>initConnection():Creating a SSH Connection with Public Key : null, HostName:135.251.246.180 ...INFO...SSHManagedConnectionFactory>createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(5063592)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(5063592)} > addConnectionEventListener... ...INFO...SSHConnection>{hashCode(14222114)} > executeWithoutWait(mkdir ybxiangsshJMXtest, /home/ems00) ...DEBUG...SSHConnection>executing command cd /home/ems00 && mkdir ybxiangsshJMXtest ...INFO...SSHConnection>{hashCode(14222114)} > testMethod4Close() ...INFO...SSHConnection>sshManagedConnection.closeEventListener(this); ...INFO...SSHManagedConnection>{hashCode(18922657)} > cleanup()(a) 构造了3个SSHManagedConnection,hashcode分别为: 18922657 10563793 5063592 (b) 用SSHManagedConnection(18922657)构造了 SSHConnection(14222114) (c) 新构造的SSHConnection在SSHManagedConnection中清理掉 该SSHConnection对应的ConnectionEventListener之后,被SSHManagedConnection.cleanup()被JBoss自动调用以回收该SSHManagedConnection到连接池!
|
第2次日志: ...INFO...SSHConnectionFactory>createConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnectionFactory>matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@120bca1].null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(18922657)} > getConnectionRequestInfo() ...INFO...SSHManagedConnection>{hashCode(18922657)}
>
getConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHConnection>{hashCode(16092196)} > SSHConnection constructor... ...INFO...SSHManagedConnection>{hashCode(18922657)} > getConnectionRequestInfo() ...DEBUG...SSHConnection>initConnection():Creating a SSH Connection with Public Key : null, HostName:135.251.246.180 ...INFO...SSHConnection>{hashCode(16092196)} > executeWithoutWait(mkdir ybxiangsshJMXtest, /home/ems00) ...DEBUG...SSHConnection>executing command cd /home/ems00 && mkdir ybxiangsshJMXtest ...INFO...SSHConnection>{hashCode(16092196)} > testMethod4Close() ...INFO...SSHConnection>sshManagedConnection.closeEventListener(this); ...INFO...SSHManagedConnection>{hashCode(18922657)} > cleanup()(a) SSHConnectionFactory 找出 匹配的 SSHManagedConnection(18922657),可以看出,还是第一次执行的那个SSHManagedConnection! (b) SSHManagedConnection(18922657)构造出新的SSHConnection(16092196) (c) 新构造的SSHConnection在SSHManagedConnection中清理掉 该SSHConnection对应的ConnectionEventListener之后,被SSHManagedConnection.cleanup()被JBoss自动调用以回收该SSHManagedConnection到连接池!
|
第3次日志: ...INFO...SSHConnectionFactory>createConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnectionFactory>matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@120bca1].null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHManagedConnection>{hashCode(18922657)} > getConnectionRequestInfo() ...INFO...SSHManagedConnection>{hashCode(18922657)}
>
getConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null) ...INFO...SSHConnection>{hashCode(2621958)} > SSHConnection constructor... ...INFO...SSHManagedConnection>{hashCode(18922657)} > getConnectionRequestInfo() ...DEBUG...SSHConnection>initConnection():Creating a SSH Connection with Public Key : null, HostName:135.251.246.180 ...INFO...SSHConnection>{hashCode(2621958)} > executeWithoutWait(mkdir ybxiangsshJMXtest, /home/ems00) ...DEBUG...SSHConnection>executing command cd /home/ems00 && mkdir ybxiangsshJMXtest ...INFO...SSHConnection>{hashCode(2621958)} > testMethod4Close() ...INFO...SSHConnection>sshManagedConnection.closeEventListener(this); ...INFO...SSHManagedConnection>{hashCode(18922657)} > cleanup()(a) SSHConnectionFactory 找出 匹配的 SSHManagedConnection(18922657),可以看出,还是第一次执行的那个SSHManagedConnection! (b) SSHManagedConnection(18922657)构造出新的SSHConnection(2621958) (c) 新构造的SSHConnection在SSHManagedConnection中清理掉 该SSHConnection对应的ConnectionEventListener之后,被SSHManagedConnection.cleanup()被JBoss自动调用以回收该SSHManagedConnection到连接池!
|
第4,5,6...次日志: (a) SSHConnectionFactory 找出 匹配的 SSHManagedConnection(18922657),可以看出,还是第一次执行的那个SSHManagedConnection! (b) SSHManagedConnection(18922657)构造出新的SSHConnection(...)
(c) 新构造的SSHConnection在SSHManagedConnection中清理掉 该SSHConnection对应的ConnectionEventListener之后,被SSHManagedConnection.cleanup()被JBoss自动调用以回收该SSHManagedConnection到连接池!可以发现:SSHManagedConnection(18922657)的确被回收到了连接池!!!
|
|
请到本文最后,看看“总结”,我们将根据该总结,对我们的程序进行改进:参见接下来的 第8节 内容。
|
|
|
|
|
8. 改进8.1 ISSHConnection修改的方法:
(a) executeWithoutWait(...) 方法等价于异步执行,不会立刻返回结果。它会返回一个String类型的SESSION_ID,便于用于根据它查询当前工作状态。
(b) isDone(String sessionID) 传入参数改成String,用户应该传递SESSION ID以查询当前状态。
新增方法:
public SSHCommandResult getResult(String sessionID); 如果该SESSION ID的工作已经结束,那么返回执行结果。
public boolean closeSession(String sessionID);//中断该session。
package com.ybxiang.ssh2.ra.api;public interface ISSHConnection{ /** * Session will be closed finally. */ public SSHCommandResult execute(String command, String directory,long timeout); /** * Session will be closed finally. ISSHProcessOutputHandler will get the result. */ public void execute(ISSHProcessOutputHandler handler, String command, String directory); /** * Session will NOT be closed, so return sessionID for caller to close it later. * return SESSION ID */ public String executeWithoutWait(String command, String directory); public boolean isDone(String sessionID); public SSHCommandResult getResult(String sessionID); public void closeSession(String sessionID); /**
* Physicall connection(ch.ethz.ssh2.Connection) will NOT be closed
because executeWithoutWait(...) may be using it.
* this method will be called by JBoss EJB container automatically,
however you should call it declaratively for good portability. */ public void close();}
|
8.2 SSHConnection.java所有方法直接调用 sshManagedConnection 对应的方法。 public class SSHConnection implements ISSHConnection{ public static final Logger log = Logger.getLogger(SSHConnection.class.getName()); private SSHManagedConnection sshManagedConnection;
public SSHConnection(SSHManagedConnection
sshManagedConnection,SSHConnectionRequestInfo info)throws
ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"SSHConnection constructor..."); this.sshManagedConnection = sshManagedConnection; } /** * Session will be closed finally. */ public SSHCommandResult execute(String command, String directory,long timeout){
log.info("{hashCode("+this.hashCode()+")} >
"+"execute("+command+","+directory+","+timeout+")"); return sshManagedConnection.execute(command, directory, timeout); } ...}
|
8.3 SSHPhysicalConnectionOperator.java该class利用ch.ethz.ssh2.Connection实现对SSH Server真正的底层的物理连接。用它作为SSHManagedConnection的父类!package com.ybxiang.ssh2.ra.app;import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.HashMap;import javax.resource.ResourceException;import ch.ethz.ssh2.ChannelCondition;import ch.ethz.ssh2.Session;import ch.ethz.ssh2.StreamGobbler;import com.ybxiang.ssh2.ra.api.ISSHProcessOutputHandler;import com.ybxiang.ssh2.ra.api.Logger;import com.ybxiang.ssh2.ra.api.SSHCommandResult;import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;public abstract class SSHPhysicalConnectionOperator { public static final Logger log = Logger.getLogger(SSHPhysicalConnectionOperator.class.getName()); public static final long TIMEOUT_WAITFOR_RESULT = 10000;//10 seconds private static final String CONNECTION_NOT_INITIALIZED_ERROR = "SSH connection not initalized"; private static final String FINAL_CLOSE_ERROR = "Close in final block threw exception"; private SSHConnectionRequestInfo info; private ch.ethz.ssh2.Connection ethz_ssh2_connection; private HashMap<String,Session> sessions = new HashMap<String,Session>(); public SSHPhysicalConnectionOperator(SSHConnectionRequestInfo info) throws ResourceException{
log.info("{hashCode("+this.hashCode()+")} >
"+"SSHPhysicalConnectionOperator() constructor..."); try { this.info = info; initConnection(); } catch (Exception e) { log.error("{hashCode("+this.hashCode()+")} > "+e); throw new ResourceException(e); } } /******************************[private helper methods ]******************************/ private void initConnection()throws IOException{
log.debug("{hashCode("+this.hashCode()+")}
> "+"initConnection():Creating a SSH Connection with Public Key : " +
info.keyFilePath + ", HostName:" + info.hostName); ethz_ssh2_connection = new ch.ethz.ssh2.Connection(info.hostName); ethz_ssh2_connection.connect(); // if(info.keyFilePath!=null){
log.debug("{hashCode("+this.hashCode()+")} > "+"Authenticating SSH
Connection with Public Key : " + info.keyFilePath);
if (ethz_ssh2_connection.authenticateWithPublicKey(info.userName, new
File(info.keyFilePath), info.keyFilePassword) == false){
throw new IOException("Authentication
failed.");
}
}else{
ethz_ssh2_connection.authenticateWithPassword(info.userName,info.password); } } private ch.ethz.ssh2.Connection getEthzSsh2Connection()throws IOException{ if(ethz_ssh2_connection==null){ initConnection(); } // return ethz_ssh2_connection; } private Session spawn(String command, String directory) throws IOException { String newCommand = command; if(directory !=null ){ newCommand = "cd "+directory+" && "+command; } // Session sess = null; if (getEthzSsh2Connection() != null) {
sess =
getEthzSsh2Connection().openSession();
sessions.put(getSessionID(sess),sess);//managed connection
log.debug("{hashCode("+this.hashCode()+")} > "+"executing command " +
newCommand); sess.execCommand(newCommand); } else {
log.error("{hashCode("+this.hashCode()+")} >
"+CONNECTION_NOT_INITIALIZED_ERROR); throw new IOException(CONNECTION_NOT_INITIALIZED_ERROR); } return sess; }
|
/******************************[public final methods: should NOT be overridden]******************************/ /** * Session will be closed finally. */ public final SSHCommandResult execute(String command, String directory,long timeout) {
log.info("{hashCode("+this.hashCode()+")} >
"+"execute("+command+", "+directory+","+timeout+")"); try{ return getSessionResults(spawn(command,directory),timeout); }catch(Exception e){ log.error("{hashCode("+this.hashCode()+")} > "+e); return null; } } /** * Session will be closed finally. */ public final void execute(ISSHProcessOutputHandler handler, String command, String directory) {
log.info("{hashCode("+this.hashCode()+")} >
"+"execute(ISSHProcessOutputHandler handler, String command, String
directory)"); try{ Session sess = spawn(command,directory); getSessionResults(sess, handler); }catch(Exception e){ log.error("{hashCode("+this.hashCode()+")} > "+e); } } /** * Session will NOT be closed, so return sessionID for caller to close it later. */ public final String executeWithoutWait(String command, String directory) {
log.info("{hashCode("+this.hashCode()+")} >
"+"executeWithoutWait("+command+", "+directory+")"); try{ Session s = spawn(command,directory); return getSessionID(s); }catch(Exception e){ log.error("{hashCode("+this.hashCode()+")} > "+e); return null; } } public final boolean isDone(String sessionID){ Session s = sessions.get(sessionID); return s.getExitStatus()!=null; } public final SSHCommandResult getResult(String sessionID){ try{ Session s = sessions.get(sessionID);
return
getSessionResults(s,TIMEOUT_WAITFOR_RESULT);
}catch(Exception e){ log.error("{hashCode("+this.hashCode()+")} > "+e); return null; } } public final void closeSession(String sessionID){ try{ Session s = sessions.get(sessionID); s.close(); }catch(Exception e){ log.error("{hashCode("+this.hashCode()+")} > "+e); } } public final void close(){ log.info("{hashCode("+this.hashCode()+")} > "+"Close SSH connection"); try{ if (getEthzSsh2Connection() != null) { getEthzSsh2Connection().close(); this.ethz_ssh2_connection = null;
}
}catch(Exception e){
log.error("{hashCode("+this.hashCode()+")} > "+"Close SSH connection
Exception:"+e); } }
|
/******************************[static helper methods ]******************************/
public static String getSessionID(Session s){ return String.valueOf(s.hashCode()); } /** * @param outputHandler implemented by the caller */
public static void getSessionResults(Session sess,
ISSHProcessOutputHandler outputHandler) throws IOException
{ try {
outputHandler.processOutput(sess.getStdout(), sess.getStderr());
sess.waitForCondition(ChannelCondition.EXIT_STATUS,
TIMEOUT_WAITFOR_RESULT); int status = sess.getExitStatus();
log.debug("{session.hashCode("+sess+")} >"+"status is " + status); } finally { if (sess != null) { try { sess.close(); } catch (Exception ignore) {
log.error("{session.hashCode("+sess+")} >"+FINAL_CLOSE_ERROR); } } } }
|
/** * Read stdout and error stream from session by yourself. * TODO: how to return result before timeout??? */
public static SSHCommandResult getSessionResults(Session sess,long
timeout) throws IOException { SSHCommandResult sshCmdRes = new SSHCommandResult("", -1); try { boolean testingTimeout = false; if(testingTimeout){
sess.waitForCondition(ChannelCondition.EXIT_STATUS, timeout); int status = sess.getExitStatus();
log.debug("{session.hashCode("+sess+")} >"+"status is " +
status);
if(status==ChannelCondition.STDOUT_DATA||status==ChannelCondition.STDERR_DATA||status==ChannelCondition.TIMEOUT
){ return null; }else{
//Now, it is NOT timeout, Let's read result. } } // StringBuffer sbStdout = new StringBuffer(); //1.read stdout
InputStream stdout = new ch.ethz.ssh2.StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); while (true) { String line = br.readLine(); if (line == null) { break; } sbStdout.append(line).append("\n"); }
log.debug("{session.hashCode("+sess+")} >"+"output " +
sbStdout.toString()); //2.read error stream
InputStream errorStream = new StreamGobbler(sess.getStderr());
BufferedReader errorBR = new BufferedReader(new
InputStreamReader(errorStream)); StringBuffer errorSB = new StringBuffer(); while (true) { String line = errorBR.readLine(); if (line == null) { break; } errorSB.append(line).append("\n"); }
log.debug("{session.hashCode("+sess+")} >"+"Error " +
errorSB.toString()); //wait 10 seconds for status is set correctly by the session. sess.waitForCondition(ChannelCondition.EXIT_STATUS, 10000); int status = sess.getExitStatus();
log.debug("{session.hashCode("+sess+")} >"+"status is " + status); //now return. sshCmdRes.status=status; sshCmdRes.result = sbStdout.toString(); sshCmdRes.error = errorSB.toString(); } finally { if (sess != null) { try { sess.close(); } catch (Exception ignore) {
log.error("{session.hashCode("+sess+")} >"+FINAL_CLOSE_ERROR); } } } return sshCmdRes; } }
|
8.4 SSHManagedConnection.java package com.ybxiang.ssh2.ra.app;import java.io.PrintWriter;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import javax.resource.NotSupportedException;import javax.resource.ResourceException;import javax.resource.spi.ConnectionEvent;import javax.resource.spi.ConnectionEventListener;import javax.resource.spi.ConnectionRequestInfo;import javax.resource.spi.LocalTransaction;import javax.resource.spi.ManagedConnection;import javax.resource.spi.ManagedConnectionMetaData;import javax.security.auth.Subject;import com.ybxiang.ssh2.ra.api.Logger;import com.ybxiang.ssh2.ra.api.SSHConnectionRequestInfo;public class SSHManagedConnection extends SSHPhysicalConnectionOperator implements ManagedConnection { public static final Logger log = Logger.getLogger(SSHManagedConnection.class.getName()); private static final String TRANSACTIONS_NOT_SUPPORTED_ERROR = "Transactions not supported";
/*****************************[fields used by JCA]*****************************/ private final SSHConnectionRequestInfo info; private PrintWriter m_out; private List<ConnectionEventListener> listeners = new LinkedList<ConnectionEventListener>();
/*****************************[methods used by JCA]*****************************/ public SSHManagedConnection(SSHConnectionRequestInfo info) throws ResourceException{ super(info); // log.info("{hashCode("+this.hashCode()+")} > "+"SSHManagedConnection("+info+")"); this.info = info; }
public Object getConnection(Subject arg0, ConnectionRequestInfo arg1) throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getConnection("+arg0+","+arg1+")"); return new SSHConnection(this,info); }
public void destroy() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"destroy()"); super.close(); }
public void cleanup() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"cleanup()"); }
public void associateConnection(Object arg0) throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"associateConnection("+arg0+")"); }
public void addConnectionEventListener(ConnectionEventListener arg0) { log.info("{hashCode("+this.hashCode()+")} > "+"addConnectionEventListener("+arg0+")"); listeners.add(arg0); }
public void removeConnectionEventListener(ConnectionEventListener arg0) {
log.info("{hashCode("+this.hashCode()+")} >
"+"removeConnectionEventListener("+arg0+")"); listeners.remove(arg0); }
public javax.transaction.xa.XAResource getXAResource() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getXAResource()"); throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR); }
public LocalTransaction getLocalTransaction() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getLocalTransaction()"); throw new NotSupportedException(TRANSACTIONS_NOT_SUPPORTED_ERROR); }
public ManagedConnectionMetaData getMetaData() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getMetaData()"); return new SSHManagedConnectionMetaData(); }
public PrintWriter getLogWriter() throws ResourceException { log.info("{hashCode("+this.hashCode()+")} > "+"getLogWriter()"); return this.m_out; }
public void setLogWriter(PrintWriter arg0) throws ResourceException {
log.info("{hashCode("+this.hashCode()+")} >
"+"setLogWriter(java.io.PrintWriter "+arg0+")"); this.m_out = arg0; }
|
/*****************************[methods used by other classes]*****************************/ //this method is called by SSHManagedConnectionFactory public SSHConnectionRequestInfo getConnectionRequestInfo() { log.info("{hashCode("+this.hashCode()+")} > "+"getConnectionRequestInfo()"); return this.info; } //called by SSHConnection to close related event listeners public void closeSSHConnectionEventListener(SSHConnection sshConnection){ ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED); event.setConnectionHandle(sshConnection); // Iterator<ConnectionEventListener> list = listeners.iterator(); while (list.hasNext()) { ConnectionEventListener listener = (ConnectionEventListener) list.next(); listener.connectionClosed(event); } } }
|
|
|
8.5 JMXBrowser.java我们新增1个方法,我们打算对不同的 SSH Server访问,看看SSHManagedConnectionFactory.matchManagedConnections 如何处理! public class JMXBrowser { public static final String RMIAdaptor_JNDI_NAME = "jmx/invoker/RMIAdaptor"; // public static final String JNDIViewMBean_ObjectName = "jboss:service=JNDIView"; public static final String SSHServiceMBean_ObjectName = "com.ybxiang.ssh2:service=SSHService"; public static void main(String[] args) throws Exception { //demoJNDIViewMBean(); //executeSSH2CommandAtHome(); // //executeSSH2CommandAtCompany_ems00(); executeSSH2CommandAtCompany_ems02(); } /************************[test methods]**************************/ public static void demoJNDIViewMBean() throws Exception{ printMBeanInfo(JNDIViewMBean_ObjectName); ////// RMIAdaptor server = getJBossRMIAdaptor(); ObjectName objName = new ObjectName(JNDIViewMBean_ObjectName); // Invoke the list(boolean) operation String[] sig = { "boolean" }; Object[] opArgs = { Boolean.TRUE }; Object result = server.invoke(objName, "list", opArgs, sig); //
System.out.println("JNDIView.list(true) output:\n" +
result); } public static void executeSSH2CommandAtHome()throws Exception{ printMBeanInfo(SSHServiceMBean_ObjectName); //
//Invoke public void
executeWithoutWait(SSHConnectionRequestInfo info, String command,String
directory); RMIAdaptor server = getJBossRMIAdaptor(); String[] sig = { SSHConnectionRequestInfo.class.getName(), "java.lang.String", "java.lang.String" }; Object[] opArgs = {
new
SSHConnectionRequestInfo("192.168.1.101","root","ybxiang"), "mkdir ybxiangsshJMXtest", "/tmp" }; Object result = server.invoke( new ObjectName(SSHServiceMBean_ObjectName), "executeWithoutWait", opArgs, sig); } public static void executeSSH2CommandAtCompany_ems00()throws Exception{ printMBeanInfo(SSHServiceMBean_ObjectName); //
//Invoke public void
executeWithoutWait(SSHConnectionRequestInfo info, String command,String
directory); RMIAdaptor server = getJBossRMIAdaptor(); String[] sig = { SSHConnectionRequestInfo.class.getName(), "java.lang.String", "java.lang.String" }; Object[] opArgs = {
new
SSHConnectionRequestInfo("135.251.246.180","ems00","emsems"), "mkdir ybxiangsshJMXtestems00", "/home/ems00" }; Object result = server.invoke( new ObjectName(SSHServiceMBean_ObjectName), "executeWithoutWait", opArgs, sig); } public static void executeSSH2CommandAtCompany_ems02()throws Exception{ printMBeanInfo(SSHServiceMBean_ObjectName); //
//Invoke public void
executeWithoutWait(SSHConnectionRequestInfo info, String command,String
directory); RMIAdaptor server = getJBossRMIAdaptor(); String[] sig = { SSHConnectionRequestInfo.class.getName(), "java.lang.String", "java.lang.String" }; Object[] opArgs = {
new
SSHConnectionRequestInfo("135.251.246.180","ems02","emsems"), "mkdir ybxiangsshJMXtestems02", "/home/ems02" }; Object result = server.invoke( new ObjectName(SSHServiceMBean_ObjectName), "executeWithoutWait", opArgs, sig); }
|
/************************[static helper methods]**************************/ public static InitialContext getJBossInitialContext() throws Exception{ Properties properties = new Properties(); properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces"); properties.put("java.naming.provider.url","localhost:1099");
return new
InitialContext(properties);
} public static RMIAdaptor getJBossRMIAdaptor()throws Exception{ InitialContext ic = getJBossInitialContext(); return (RMIAdaptor) ic.lookup(RMIAdaptor_JNDI_NAME); } }
|
8.6 EJBClient.java我们新增1个方法,我们打算对不同的 SSH Server访问,看看SSHManagedConnectionFactory.matchManagedConnections 如何处理! public class EJBClient { public static void main(String args[]) throws Exception { Context context = getInitialContext(); ISSH2Executor executor = (ISSH2Executor)context.lookup(ISSH2Executor.JNDI_NAME); //executeAtHome(executor); // executeAtCompany_ems00(executor); executeAtCompany_ems02(executor); } public static InitialContext getInitialContext() throws Exception{ Properties properties = new Properties(); properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces"); properties.put("java.naming.provider.url","localhost:1099");
return new
InitialContext(properties);
} public static void executeAtHome(ISSH2Executor executor)throws Exception{
SSHConnectionRequestInfo info = new
SSHConnectionRequestInfo("192.168.1.101","root","ybxiang"); executor.executeWithoutWait(info, "mkdir ybxiangsshtest", "/tmp"); } public static void executeAtCompany_ems00(ISSH2Executor executor)throws Exception{
SSHConnectionRequestInfo info = new
SSHConnectionRequestInfo("135.251.246.180","ems00","emsems");
executor.executeWithoutWait(info, "mkdir ybxiangsshtest", "/home/ems00"); } public static void executeAtCompany_ems02(ISSH2Executor executor)throws Exception{
SSHConnectionRequestInfo info = new
SSHConnectionRequestInfo("135.251.246.180","ems02","emsems");
executor.executeWithoutWait(info, "mkdir ybxiangsshtest", "/home/ems02"); } }
|
|
|
|
|
9 测试 准备工作:
- 关闭JBoss
- 重新把所有API[ybxiang-ssh2-ra-api.jar, ybxiang-ssh2-ejb-api.jar]部署到 D:\java\jboss-5.1.0.GA\server\all\lib
- 部署所有app[ybxiang-ssh2-ra-app.rar,ybxiang-ssh2-ds.xml,ybxiang-ssh2-
jmx-app.sar,ybxiang-ssh2-ejb-app.jar]到D:\java\jboss-5.1.0.GA\server\all
\deploy
- 重新启动JBoss
我们看见相关日志: 【这是JBoss部署ybxiang-ssh2-ra-app.rar打印的日志】 INFO: com.ybxiang.ssh2.ra.app.SSHResourceAdapter>start() > You should initialize something here if necessary.
【这是JBoss部署ybxiang-ssh2-ds.xml打印的日志】INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
> setLogWriter(org.jboss.logging.util.LoggerPluginWriter@2cc581)INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
createConnectionFactory(org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy@15ab2e9)INFO: com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(12421357)} > SSHConnectionFactory constructor...INFO:
[ConnectionFactoryBindingService] Bound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' to JNDI
name 'java:AmsSSHAdapter'该SSHConnectionFactory被绑定到 java:AmsSSHAdapter
|
9.1 第一次运行JMXBrowser9.1.1 其中main方法修改如下: public static void main(String[] args) throws Exception { executeSSH2CommandAtCompany_ems00(); //executeSSH2CommandAtCompany_ems02(); }
|
9.1.2 JBoss Server日志如下:[xiang:]由于客户端的调用,连接工厂首次被调用创建连接:INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(12421357)}
>
createConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)[xiang:] 由于连接池内没有任何SSHManagedConnection,所以初始化<min-pool-size>个(这里为3个)。 [xiang:] 注意:construct-No.i >>>表示构造第 i 个SSHManagedConnection ####################构造第 1 个SSHManagedConnection(14051333)construct-No.1
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.1
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(14051333)}
> SSHPhysicalConnectionOperator() constructor...construct-No.1
>>> DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(14051333)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180construct-No.1
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.1
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@168997e[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@d66805 handles=0
lastUse=1309846793990 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa])
|
####################构造第 2 个SSHManagedConnection(25591043) [xiang:] 可以看见,在构造第1个 个SSHManagedConnection(14051333)之后,它立刻被调用以创建SSHConnection,参见“cmd.ems00>>>”标识的日志。 [xiang:] 下面构造第 2 个SSHManagedConnection(25591043)的日志中,混造了 执行命令时的日志,参见“cmd.ems00>>>”标识的日志。 [xiang:] 期间还清理了 第一个 SSHManagedConnection(25591043),参见“cleanup-No.1”标识的日志cmd.ems00>>>
[STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)}
>
getConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.2
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.2
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(25591043)}
> SSHPhysicalConnectionOperator() constructor...construct-No.2
>>> DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(25591043)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180cmd.ems00>>> INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(4551109)} > SSHConnection constructor...cmd.ems00>>>
INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(4551109)} >
executeWithoutWait(mkdir ybxiangsshJMXtestems00,/home/ems00)cmd.ems00>>>
INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(14051333)}
> executeWithoutWait(mkdir ybxiangsshJMXtestems00, /home/ems00)cmd.ems00>>>
DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(14051333)}
> executing command cd /home/ems00 && mkdir
ybxiangsshJMXtestems00cmd.ems00>>> INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(4551109)} > close()cleanup-No.1 >>> INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)} > cleanup()construct-No.2
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(25591043)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.2
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(25591043)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@1de81ff[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1867d03 handles=0
lastUse=1309846794271 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa])
|
####################构造第 3 个SSHManagedConnection(32936290)construct-No.3
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.3
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(32936290)}
> SSHPhysicalConnectionOperator() constructor...construct-No.3
>>> DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(32936290)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180construct-No.3
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(32936290)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems00;keyFilePath=null;keyFilePassword=null)construct-No.3
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(32936290)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@db8258[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1f69162 handles=0
lastUse=1309846794490 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa])
|
9.2 第2次运行JMXBrowser注意,我们这次 打算连接到其它 SSH Server(帐号:ems02)。9.2.1 其中main方法修改如下: public static void main(String[] args) throws Exception { //executeSSH2CommandAtCompany_ems00(); executeSSH2CommandAtCompany_ems02(); }
|
9.2.2 JBoss Server日志如下: 客户端要求创建连接:INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(12421357)}
>
createConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) ##### Matching.32936290 >>> JBoss发现32936290不匹配【我们假设,连接帐号信息 不相等就不匹配】,直接销毁了该连接。INFO
[STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@1f69162],null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(32936290)} > getConnectionRequestInfo()ERROR
[STDERR] WARN:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
> return no matched ManagedConnection (null)WARN
[JBossManagedConnectionPool] Destroying connection that could not be
successfully matched:
org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@db8258[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1f69162 handles=0
lastUse=1309846794490 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa]INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(32936290)} > destroy()INFO
[STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(32936290)}
> Close SSH connection##### Matching.25591043 >>> JBoss发现25591043不匹配【我们假设,连接帐号信息 不相等就不匹配】,直接销毁了该连接。[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@1867d03],null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(25591043)} > getConnectionRequestInfo()[STDERR]
WARN:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
> return no matched ManagedConnection (null)[JBossManagedConnectionPool]
Destroying connection that could not be successfully matched:
org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@1de81ff[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1867d03 handles=0
lastUse=1309846794271 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa][STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(25591043)} > destroy()[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(25591043)} > Close SSH connection##### Matching.14051333 >>> JBoss发现14051333不匹配【我们假设,连接帐号信息 不相等就不匹配】,直接销毁了该连接。[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@d66805],null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)} > getConnectionRequestInfo()[STDERR]
WARN:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
> return no matched ManagedConnection (null)[JBossManagedConnectionPool]
Destroying connection that could not be successfully matched:
org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@168997e[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@d66805 handles=0
lastUse=1309846794005 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa][STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(14051333)} > destroy()[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(14051333)} > Close SSH connection
|
现在连接池里面一个 SSHManagedConnection都没有了。创建新的连接:28137824construct-No.4
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)construct-No.4
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> SSHPhysicalConnectionOperator() constructor...construct-No.4
>>> DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180construct-No.4
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)construct-No.4
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@c83a0d[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@1ad5960 handles=0
lastUse=1309846813629 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@355c70
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@147f8aa])SSHManagedConnection创建SSHConnection,执行business methods,完毕之后,被回收!cmd.ems02
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)}
>
getConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)cmd.ems02 >>> INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(22765881)} > SSHConnection constructor...cmd.ems02
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(22765881)} >
executeWithoutWait(mkdir ybxiangsshJMXtestems02,/home/ems02)cmd.ems02
>>> INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> executeWithoutWait(mkdir ybxiangsshJMXtestems02, /home/ems02)cmd.ems02
>>> DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> executing command cd /home/ems02 && mkdir
ybxiangsshJMXtestems02cmd.ems02 >>> INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(22765881)} > close()cmd.ems02 >>> INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)} > cleanup()
|
关于上面直接销毁 不匹配的ManagedConnection的原因,我们小小总结一下:第一次运行JMXBrowser时创建的3个SSHManagedConnection都不符合!全部关闭!这种做法在下面的场合非常有用: - 某资源的帐号密码被修改了(登陆名没有变化),如果旧的SSHManagedConnection不被销毁,那么JBoss的连接池内可能就会堆积很多没有用的SSHManagedConnection。
时间长了以后,如果无用的SSHManagedConnection个数达到了<max-pool-size>,这个ResourceAdapter就彻底没用了!必须重新启动。 - 同一个资源,由于时间长了,密码忘记了,需要重新建立帐号。和(a)情况相同。
- 如果帐号信息由client端提供(资源 的帐号/密码 多变的情况下,比如定期的密码修改),那么数据源文件 xxx-ds.xml 中最好不要包含帐号信息。就像这个SSH Resource Adapter一样。
- 如
果帐号信息基本不会修改,比如电信机房里面的数据库帐号,那么我们就把帐号信息通过 数据源文件 xxx-ds.xml
进行配置。可以用<config-property name="xxx"
type="xxx">xxx</config-property>配置
配置数据库的datasource时,同一个DB,有多个帐号,不同的帐号要对应不同的xxx-ds.xml文件!
|
|
|
9.3 第3次运行JMXBrowser9.3.1 这次,我们依旧执行executeSSH2CommandAtCompany_ems02();public class JMXBrowser { public static void main(String[] args) throws Exception { //executeSSH2CommandAtCompany_ems00(); executeSSH2CommandAtCompany_ems02(); } ...}
|
9.3.2 JBoss server日志:##### Matching.28137824 >>> 匹配成功,直接使用上面创建好的 28137824 连接 [STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(12421357)}
>
createConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)}
>
matchManagedConnections([com.ybxiang.ssh2.ra.app.SSHManagedConnection@1ad5960],null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)} > getConnectionRequestInfo()[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(19226043)} > return found SSHManagedConnection with hashCode(28137824)最后,资源被回收:[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)}
>
getConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(399759)} > SSHConnection constructor...[STDOUT]
INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(399759)} >
executeWithoutWait(mkdir ybxiangsshJMXtestems02,/home/ems02)[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> executeWithoutWait(mkdir ybxiangsshJMXtestems02, /home/ems02)[STDOUT]
DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(28137824)}
> executing command cd /home/ems02 && mkdir
ybxiangsshJMXtestems02[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnection>{hashCode(399759)} > close()[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(28137824)} > cleanup()
|
|
9.3.3 长时间超时销毁115:06:03,165 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(11557094)} > destroy() 15:06:03,165
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(11557094)}
> Close SSH connection 销毁215:06:03,165 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(8884544)} > destroy() 15:06:03,165
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(8884544)}
> Close SSH connection 销毁315:06:03,165 INFO [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(29242398)} > destroy() 15:06:03,165
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(29242398)}
> Close SSH connection 构造115:06:03,196
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(13714606)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:03,196
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(4788456)}
> SSHPhysicalConnectionOperator() constructor... 15:06:03,196
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(4788456)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180 15:06:03,446 INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(4788456)} >
SSHManagedConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:03,446
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(4788456)} >
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@10276a4[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@4910e8 handles=0
lastUse=1309849563446 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@272321
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@1737cd8]) 构造215:06:03,446
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(13714606)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:03,446
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(12268168)}
> SSHPhysicalConnectionOperator() constructor... 15:06:03,446
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(12268168)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180 15:06:03,774 INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(12268168)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:03,774
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(12268168)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@8938a8[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@bb3288 handles=0
lastUse=1309849563774 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@272321
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@1737cd8]) 构造315:06:03,774
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(13714606)}
>
createManagedConnection(null,hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:03,774
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(15119471)}
> SSHPhysicalConnectionOperator() constructor... 15:06:03,774
INFO [STDOUT] DEBUG:
com.ybxiang.ssh2.ra.app.SSHPhysicalConnectionOperator>{hashCode(15119471)}
> initConnection():Creating a SSH Connection with Public Key : null,
HostName:135.251.246.180 15:06:04,118 INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15119471)}
>
SSHManagedConnection(hostName=135.251.246.180;userName=ems02;keyFilePath=null;keyFilePassword=null) 15:06:04,118
INFO [STDOUT] INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnection>{hashCode(15119471)}
>
addConnectionEventListener(org.jboss.resource.connectionmanager.NoTxConnectionManager$NoTxConnectionEventListener@123ba32[state=NORMAL
mc=com.ybxiang.ssh2.ra.app.SSHManagedConnection@e6b46f handles=0
lastUse=1309849564118 permit=false trackByTx=false
mcp=org.jboss.resource.connectionmanager.JBossManagedConnectionPool$OnePool@272321
context=org.jboss.resource.connectionmanager.InternalManagedConnectionPool@1737cd8])
|
|
|
|
|
|
10. 通过ybxiang-ssh2-ds.xml向SSHManagedConnectionFactory传递参数【可以是各种帐号,size】
注意, xxx-ds.xml 是JBoss自定义的规范:"http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd" 不像ra.xml一样,是标准的:http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd
|
10.1 ybxiang-ssh2-ds.xml
修改如下
<!DOCTYPE connection-factories PUBLIC
"-//JBoss//DTD JBOSS JCA Config 1.5//EN"
"http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
<connection-factories>
<no-tx-connection-factory>
<jndi-name>AmsSSHAdapter</jndi-name>
<rar-name>ybxiang-ssh2-ra-app.rar</rar-name>
<connection-definition>com.ybxiang.ssh2.ra.api.ISSHConnectionFactory</connection-definition>
<config-property name="UserName" type="java.lang.String">XiangYingBing</config-property>
<config-property name="FirstName"
type="java.lang.String">xiang</config-property>
<config-property name="LastName"
type="java.lang.String">yingbing</config-property>
<min-pool-size>3</min-pool-size>
<max-pool-size>4</max-pool-size>
<blocking-timeout-millis>5000</blocking-timeout-millis>
<idle-timeout-minutes>10</idle-timeout-minutes>
<!-- <application-managed-security/> -->
</no-tx-connection-factory>
</connection-factories>
|
10.2 SSHManagedConnectionFactory.java
在这个class中加入下面的代码:
//parameters can ge passed into ManagedConnectionFactory by ybxiang-ssh2-ds.xml
private String user;
private String firstName; private String lastName;
public void setUserName(String userName){
log.info("{hashCode("+this.hashCode()+")} > "+"userName:"+userName);
this.user = userName;
}
public void setFirstName(String firstName){ log.info("{hashCode("+this.hashCode()+")} > "+"firstName:"+firstName); this.firstName = firstName; } public void setLastName(String lastName){ log.info("{hashCode("+this.hashCode()+")} > "+"lastName:"+lastName); this.lastName = lastName; }注意,只要setter方法中,set后面的名字和xml中的名字匹配就可以了!
|
10.3 重新部署ybxiang-ssh2-ra-app.rar和ybxiang-ssh2-ds.xml日志: [ConnectionFactoryBindingService]
Unbound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' from
JNDI name 'java:AmsSSHAdapter'[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(14100708)} > userName:XiangYingBing [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(14100708)} > firstName:xiang [STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(14100708)} > lastName:yingbing[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(14100708)}
> setLogWriter(org.jboss.logging.util.LoggerPluginWriter@c116a8)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(14100708)} > createConnectionFactory(...)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(22219402)} > SSHConnectionFactory constructor...[ConnectionFactoryBindingService]
Bound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' to JNDI
name 'java:AmsSSHAdapter'
|
10.4 还可以通过ra.xml传递参数到ManagedConnectionFactory里面!如下: (a) ra.xml <?xml version="1.0" encoding="UTF-8"?><connector version="1.5" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"> <display-name>SSH2 Adapter</display-name> <vendor-name>Xiang YingBing</vendor-name> <eis-type>SSH2 System</eis-type> <resourceadapter-version>1.0</resourceadapter-version> <license> <description>LGPL</description> <license-required>false</license-required> </license> <resourceadapter>
<resourceadapter-class>com.ybxiang.ssh2.ra.app.SSHResourceAdapter</resourceadapter-class> <outbound-resourceadapter> <connection-definition>
<managedconnectionfactory-class>com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory</managedconnectionfactory-class> <config-property>
<config-property-name>ParameterPassedByResourceAdapterXML</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>this is a parameter
passed by ra.xml</config-property-value> </config-property>...(b) SSHManagedConnectionFactorypublic class SSHManagedConnectionFactory implements ManagedConnectionFactory {.... //parameters can ge passed into ManagedConnectionFactory by ra.xml private String parameterPassedByResourceAdapterXML; public void setParameterPassedByResourceAdapterXML(String value){
log.info("{hashCode("+this.hashCode()+")} >
"+"parameterPassedByResourceAdapterXML:"+value); parameterPassedByResourceAdapterXML = value; }(c)重新部署后的日志:[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)} > parameterPassedByResourceAdapterXML:this is a parameter passed by ra.xml[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)} > userName:XiangYingBing[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)} > firstName:xiang[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)} > lastName:yingbing[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)}
> setLogWriter(org.jboss.logging.util.LoggerPluginWriter@6714db)[STDOUT]
INFO:
com.ybxiang.ssh2.ra.app.SSHManagedConnectionFactory>{hashCode(26890590)}
>
createConnectionFactory(org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy@1eb9cc2)[STDOUT] INFO: com.ybxiang.ssh2.ra.app.SSHConnectionFactory>{hashCode(32730874)} > SSHConnectionFactory constructor...[ConnectionFactoryBindingService]
Bound ConnectionManager
'jboss.jca:service=ConnectionFactoryBinding,name=AmsSSHAdapter' to JNDI
name 'java:AmsSSHAdapter'
|
我们完全可以把帐号信息通过 ra.xml(标准)和xxx-ds.xml(jboss定义dtd) 传递到ManagedConnectionFactory里面!!!这样客户端就不用传递帐号信息了!跟配置数据源一样。
|
|
|
|
11. 总结(1)
business连接(这里为SSHConnection)在被使用完毕之后,应该清理它在对应的ManagedConnection中,和它自己相关的
ConnectionEventListener。比如,SSHConnection调用
SSHManagedConnection.closeEventListener(this),关闭的时候,发送Event:
public void closeEventListener(SSHConnection sshConnection){
ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED);
event.setConnectionHandle(sshConnection);
//
Iterator<ConnectionEventListener> list = listeners.iterator();
while (list.hasNext()) {
ConnectionEventListener listener = (ConnectionEventListener) list.next();
listener.connectionClosed(event);
}
}
(2) JBoss收到Event之后,检测相关SSHManagedConnection中是否还有和这个business连接(这里为SSHConnection)相关的ConnectionEventListener:
- 如果没有,那么JBoss销毁该SSHConnection instance,并执行SSHManagedConnection.cleanup(),最后把该SSHManagedConnection放回连接池。
- 如果还有,那么JBoss就无法销毁该SSHConnection instance,无法把该SSHManagedConnection放回连接池。该SSHManagedConnection就永远被占用着!
(3)
因为business连接(这里为SSHConnection)
在使用完毕后,需要被销毁,所以对底层的资源的真正的连接(这里为ch.ethz.ssh2.Connection)不能在business连接(这里为
SSHConnection) 中定义!必须放到SSHManagedConnection中! (4)
在SSHManagedConnection中,只有在JBoss停止的时候,才关闭对底层的资源的真正的连接(这里为
ch.ethz.ssh2.Connection),所以关闭动作应该放在 SSHManagedConnection.destroy()中执行!
|
|