package org.jboss.fresh.events.impl;
import org.jboss.fresh.events.Event;
import org.jboss.fresh.events.net.EventNetConnector;
import org.jboss.fresh.events.net.ConnectorException;
import org.jboss.fresh.events.net.TakenOverException;
import org.jboss.fresh.shell.ProcessInfo;
import org.jboss.fresh.shell.ejb.RemoteShell;
import org.jboss.fresh.shell.ejb.RemoteShellHome;
import org.jboss.fresh.shell.NoSuchProcessException;
import org.jboss.fresh.shell.ShellObjectReader;
import org.jboss.fresh.shell.ShellObjectWriter;
import org.jboss.fresh.persist.RandomKeyPKGenerator;
import org.jboss.fresh.util.ThrowableProxy;
import javax.naming.InitialContext;
import java.io.IOException;
import java.util.Properties;
import java.util.Map;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.List;
import java.util.LinkedList;
import org.apache.log4j.Logger;
public class RemoteShellEventNetConnector implements EventNetConnector {
private static final Logger log = Logger.getLogger(RemoteShellEventNetConnector.class);
private RandomKeyPKGenerator pkgen;
private Map props;
private RemoteShell shellin;
private RemoteShell shellout;
private ShellObjectReader shin;
private ShellObjectWriter shout;
private Properties shellprops;
private ProcessInfo pinf;
private String host;
private String app;
private String agentid;
private String componentName;
private int evid = 1;
private String conid;
private int reinitCount = 0;
private boolean reset = false;
private long lastReinit = -1;
Thread sndT;
public RemoteShellEventNetConnector(Map props, String host, String app, String agentid) {
log.debug("New RemoteShellEventNetConnector created ... ");
this.props = props;
this.host = host;
this.app = app;
this.agentid = agentid;
pkgen = new RandomKeyPKGenerator("11,31", null);
pkgen.reseed(host + app + System.currentTimeMillis());
try {
conid = (String) pkgen.newKey();
componentName = "RemoteShellEventNetConnector(" + conid + ")";
} catch(Exception ex) {
throw new RuntimeException("Failed to initialize component id", ex);
}
//log.info("Initializing remote shell ...");
_init();
//log.info("Shell established: " + pinf);
try {
shellprops = shellout.getEnvProperties();
log.debug("shell properties: " + props);
} catch(Exception ex) {
log.error("Failed to get shell properties !!!", ex);
}
}
public int getPingTime() {
String tos = shellprops.getProperty("PROCESS_TIMEOUT");
// log.info("getPingTime : " + tos);
try {
if((tos!=null)&&(!"".equals(tos))) {
return Integer.parseInt(tos);
}
} catch(Exception ex) {
log.debug("Failed to parse PROCESS_TIMEOUT shell environment variable '" + tos + "' into integer!");
}
return 30000;
}
public void reinit() {
log.info("reinit()");
_init();
}
private void _init() {
synchronized(this) {
lastReinit = 0;
notify();
}
try {
RemoteShellHome home = null;
outerloop:
while (true) {
for (int i = 0; i< 2 && home == null; i++) {
try {
InitialContext ctx = new InitialContext(new Hashtable(props));
home = (RemoteShellHome) ctx.lookup("ShellSession");
log.debug("ctx.lookup(\"ShellSession\"): " + home);
shellin = home.create();
log.debug("home.create(): " + shellin);
shellout = home.create(shellin.getSessionID());
log.debug("home.create(sessionID): " + shellout);
try {
// now we run the executable
// and save process info
if(app!=null) shellin.executeAsObject("project " + app);
reinitCount++;
log.info("reinitCount: " + reinitCount + " calling exe: " + "org.jboss.fresh.shell.commands.EventNetAgentExe -ex -h " + host + (app == null ? "" : " -a " + app) + " -i " + agentid + " -c " + conid + (reinitCount != 1 ? " -k" : ""));
pinf = shellin.execute("org.jboss.fresh.shell.commands.EventNetAgentExe -ex -h " + host + (app == null ? "" : " -a " + app) + " -i " + agentid + " -c " + conid + (reinitCount != 1 ? " -k" : ""));
shin = new ShellObjectReader(shellin, pinf.procid);
shin.setBufferSize(500);
shout = new ShellObjectWriter(shellout, pinf.procid);
shout.setBufferSize(500);
//} catch(org.jboss.fresh.shell.ShellIOException ex) {
// Throwable th = ex.getCause();
// if(th instanceof TakenOverException) {
// log.error("Someone did takeover on us:", ex);
// throw (TakenOverException) th;
// }
} catch(Exception ex) {
log.error("Failed to run netagent!", ex);
log.info("Going to sleep for 20 seconds....");
Thread.sleep(20000);
}
break outerloop;
} catch (InterruptedException ex) {
throw new RuntimeException("Interrupted", ex);
//} catch(TakenOverException ex) {
// throw new RuntimeException("Someone did takeover on us:", ex);
} catch (Exception ex) {
log.error("Could not establish connection... ", ex);
} finally {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
throw new RuntimeException("Interrupted", ex);
}
}
}
home = null;
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
throw new RuntimeException("Interrupted", ex);
}
}
} finally {
synchronized(this) {
lastReinit = System.currentTimeMillis();
notify();
}
}
}
public void ping() throws ConnectorException {
log.info("ping()");
try {
sndT = Thread.currentThread();
Event ev = new Event(host, app, componentName, agentid, "ENet", "Ignore", null);
if(reset) {
reset = false;
throw new ConnectorException("Reset forced");
}
synchronized(shellout) {
ev.setID(String.valueOf(evid++));
//shellout.write(pinf.procid, ev);
shout.writeObject(ev);
shout.flush();
}
if(reset) {
reset = false;
throw new ConnectorException("Reset forced");
}
} catch(Exception ex) {
//log.error("Exception while pinging remote process: ", ex);
throw new ConnectorException("Exception while pinging remote process: ", ex);
}
}
public void sendBuffer(List ls, int timeout) throws ConnectorException {
//StringBuffer sb = new StringBuffer();
//java.util.Iterator it = ls.iterator();
//while(it.hasNext()) {
// sb.append(it.next()).append("\n\r");
//}
//sb.append("\n\r]\n\r");
//log.info("Sending buffer: \n\r[\n\r" + sb);
if(!(ls instanceof LinkedList)) ls = new LinkedList(ls);
try {
sndT = Thread.currentThread();
if(reset) {
reset = false;
throw new ConnectorException("Reset forced");
}
synchronized(shellout) {
//shellout.writeBuffer(pinf.procid, (LinkedList) ls);
Iterator it = ls.iterator();
while(it.hasNext()) {
shout.writeObject(it.next());
}
shout.flush();
}
if(reset) {
reset = false;
throw new ConnectorException("Reset forced");
}
} catch(org.jboss.fresh.shell.ShellIOException ex) {
log.debug("CATCH ShellIOException ");
Throwable th = ex.getCause();
if(th instanceof org.jboss.fresh.io.ApplicationIOException) {
log.debug("CATCH ApplicationIOException ");
th = th.getCause();
if(th instanceof org.jboss.fresh.events.net.TakenOverException) {
log.debug("CATCH TakenOverException ");
throw (TakenOverException) th;
}
} else if(th instanceof ThrowableProxy) {
log.debug("CATCH ThrowableProxy ");
String cname = ((ThrowableProxy) th).getClassName();
if("org.jboss.fresh.io.ApplicationIOException".equals(cname)) {
log.debug("CATCH LC ApplicationIOException ");
th = th.getCause();
if(th instanceof ThrowableProxy) {
log.debug("CATCH ThrowableProxy ");
cname = ((ThrowableProxy) th).getClassName();
if("org.jboss.fresh.events.net.TakenOverException".equals(cname)) {
log.debug("CATCH LC TakenOverException ");
throw new TakenOverException(th.getMessage());
}
}
}
}
throw new ConnectorException("Exception while reading from remote process: (" + this + ", procid: " + shin.getProcID() + ")", ex);
} catch(Exception ex) {
//log.error("Exception while writing to remote process: (" + this + ", procid: " + shout.getProcID() + ")", ex);
throw new ConnectorException("Exception while writing to remote process: (" + this + ", procid: " + shout.getProcID() + ")", ex);
} finally {
sndT = null;
}
//log.info(" done sending.");
}
public List receiveBuffer(int timeout) throws ConnectorException {
//log.info("Receiving buffer...");
LinkedList ls = null;
try {
//List ls = shellin.readBuffer(pinf.procid, 1000);
ls = new LinkedList();
ls.add(shin.readObject());
int len = shin.available();
for(int i=0; i<len; i++) {
ls.add(shin.readObject());
}
//StringBuffer sb = new StringBuffer();
//java.util.Iterator it = ls.iterator();
//while(it.hasNext()) {
// sb.append(it.next()).append("\n\r");
//}
//sb.append("\n\r]\n\r");
//log.info(" received: \n\r[\n\r" + sb);
return ls;
} catch(org.jboss.fresh.shell.ShellIOException ex) {
log.debug("CATCH ShellIOException ");
Throwable th = ex.getCause();
if(th instanceof org.jboss.fresh.io.ApplicationIOException) {
log.debug("CATCH ApplicationIOException ");
th = th.getCause();
if(th instanceof org.jboss.fresh.events.net.TakenOverException) {
log.debug("CATCH TakenOverException ");
throw (TakenOverException) th;
}
} else if(th instanceof NoSuchProcessException) {
throw new TakenOverException(th.getMessage());
} else if(th instanceof ThrowableProxy) {
log.debug("CATCH ThrowableProxy ");
String cname = ((ThrowableProxy) th).getClassName();
if("org.jboss.fresh.io.ApplicationIOException".equals(cname)) {
log.debug("CATCH LC ApplicationIOException ");
th = th.getCause();
if(th instanceof ThrowableProxy) {
log.debug("CATCH ThrowableProxy ");
cname = ((ThrowableProxy) th).getClassName();
if("org.jboss.fresh.events.net.TakenOverException".equals(cname)) {
log.debug("CATCH LC TakenOverException ");
throw new TakenOverException(th.getMessage());
} else if("org.jboss.fresh.shell.UninitializedEnvironmentException".equals(cname)) {
throw new ConnectorException(new org.jboss.fresh.shell.UninitializedEnvironmentException(th.getMessage()));
}
}
}
}
log.debug("THROW ConnectorException ");
throw new ConnectorException("Exception while reading from remote process: (" + this + ", procid: " + shin.getProcID() + ") read buffer: " + ls, ex);
} catch(IOException ex) {
Throwable th = ex.getCause();
if(th instanceof NoSuchProcessException)
throw new TakenOverException(th.getMessage());
else
throw new ConnectorException("Exception while reading from remote process: (" + this + ", procid: " + shin.getProcID() + ") read buffer: " + ls, ex);
} catch(Exception ex) {
//log.error("Exception while reading from remote process: (" + this + ", procid: " + shin.getProcID() + ") read buffer: " + ls, ex);
throw new ConnectorException("Exception while reading from remote process: (" + this + ", procid: " + shin.getProcID() + ") ", ex);
}
}
public void reset() {
// cause all methods where there's currently something waiting to throw ConnectorException
log.info("reset()");
reset = true;
long linit = lastReinit;
Thread tmp = sndT;
if(tmp != null) tmp.interrupt();
try {
synchronized(this) {
if(lastReinit == -1 || lastReinit==linit) wait(30000);
}
synchronized(this) {
if(lastReinit == 0) wait();
}
} catch(InterruptedException ex) {
throw new RuntimeException("Interrupted");
}
log.debug("reset() done");
// then wait for reset to be entered - but not more than 30 seconds
// wait for reset to finish (indefinately)
}
}