Friday, August 26, 2011

Daemons in Java

In Spanish the translation of daemon is "demonio" that means also devil, I know now why.
I will put the method to create one from zero, for any SO with J2SE 1.6. If you think that is easy, that could be done with tools like Java Service Wrapper, etc, etc, ok do it, you'll find that have to deal with other world of troubles.
Ok, the idea is, use a main to begin the program, and add a DaemonShutdownHook, what is that? This capture the shutdown signal (normal shutdown/kill) of the runnig JVM.
The main class will look like this
static public void main(String[] args)
{
Appender startupAppender = new ConsoleAppender(new SimpleLayout());
try
{
logger.addAppender(startupAppender);
// do sanity checks and startup actions
daemonize();
addDaemonShutdownHook();
}
catch (Throwable e)
{
logger.fatal("Startup failed.",e);
}
finally
{
logger.removeAppender(startupAppender);
}

while(!isShutdownRequested())
{
// wait for stimuli
// process stimulus
}

// do shutdown actions
//end thread shutdown hook
}
The methods used:

static public void shutdown()
{
shutdownRequested = true;
}

static protected void addDaemonShutdownHook()
{
Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { MainClass.shutdown(); }});
}

An issue I've found is, that the DaemonShutdownHook doesn't hold the app to finalize, you must not finalize the shutdown method till you end the main thread. Why? Because after the shutdown method the Signal continues with System.exit, that means that if you didn't end your tasks before that, you're going to leave lines without execution. My way to fix it was, waiting the main method to end, and then end the shutdown, avoiding the forced System.Exit of the JVM.

static public void shutdown()
{
shutdownRequested = true;
while (!MainClass.endFlag){//put some wait if u want}
}

static protected void addDaemonShutdownHook()
{
Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { MainClass.shutdown(); }});
}

static public void main(String[] args)
{
endFlag=false;
Appender startupAppender = new ConsoleAppender(new SimpleLayout());
try
{
logger.addAppender(startupAppender);
// do sanity checks and startup actions
daemonize();
addDaemonShutdownHook();
}
catch (Throwable e)
{
logger.fatal(“Startup failed.”,e);
}
finally
{
logger.removeAppender(startupAppender);
}

while(!isShutdownRequested())
{
// wait for stimuli
// process stimulus
}

// do shutdown actions
//end thread shutdown hook
endFlag=true;
}

I hope this helps
BR

Sources:
http://barelyenough.org/blog/2005/03/java-daemon/


Tuesday, November 24, 2009

Dancing Packets with Apache Mina

Thanks to some help of some colleague (Marcelo Marmol)Marcelo's Blog, I took my first experience with Apache Mina.
In shorts words this library helps with the transmission of packets, to develop server or client tools.
My first step it's to create a connection between a Tomcat Server and a Java Service (all the info I have). But the code is like this.


*****************CODE**************


import java.net.InetSocketAddress;
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.ats.example.ClientHandler;

public class ClientTcpIp {

public ClientTcpIp(){

}
//TODO ver diferente mensajes
public String SendMessage(String sMensaje){
String sRespuestaTcp;
IoSession session;
NioSocketConnector connector;
ClientHandler chEventoIO;

//WE CREATE THE CONNECTION (CLIENT SIDE, WITH 3 SECONDS OF TIMEOUT)
connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(30 * 1000L);
//THE HANDLER TO DO SOMETHING WITH THE EVENTS
chEventoIO = new ClientHandler();
chEventoIO.setMensaje("Hi my server, how are you?");
connector.setHandler(chEventoIO);
//THE CODING TO CONNECT WITH THE SERVER, IN THIS CASE STRING
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory()));
sRespuestaTcp=null;

//TRY TO CONNECT
for (;;) {
try {
//SETTING THE IP AND PORT (EXAMPLE TO LOCALHOST AND PORT 555)
ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1",5555));

//BECAUSE THIS IS SYNC, NO ASYNC WE MUST USE THIS
session.getConfig().setUseReadOperation(true);
ReadFuture read =session.read();
//AND WE WAIT THE MESSAGE FROM SERVER OR FIVE SECONDS
if (read.await(5000)){
//WE GET THE MESSAGE FROM THE SERVER
sRespuestaTcp=(String)read.getMessage();
// WE LEAVE THE FOR
break;
}
//IF FIVE SECONDS PASS WE CONNECT AGAIN
} catch (RuntimeIoException e) {
//System.err.println("Failed to connect.");
e.printStackTrace();
try {
// WE WAIT 5 TO TRY AGAIN
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//IF EVERYTHING IS OK, WE RETURN THE STRING
return sRespuestaTcp;
}
}


import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.logging.LoggingFilter;

public class ClientHandler extends IoHandlerAdapter {

private String sMensaje;

public ClientHandler(){
setMensaje("");
}
@Override
public void sessionOpened(IoSession session) throws Exception {
if (getMensaje()==""){
session.close(true).awaitUninterruptibly();
throw new Exception("YOU MUST DEFINE A MESSAGE");
}
session.write(getMensaje());
}

@Override
public void sessionClosed(IoSession session) {

}

@Override
public void messageReceived(IoSession session, Object message) {


}

@Override
public void messageSent(IoSession session, Object message) {

}

@Override
public void exceptionCaught(IoSession session, Throwable cause) {
session.close(true);
}

public void setMensaje(String sMensaje) {
this.sMensaje = sMensaje;
}

public String getMensaje() {
return sMensaje;
}
}


************END CODE *****************

Basically, we connect to the server in very simple and few lines with the all mighty and open source mina. This is a not working example, that why is very commented it's only to show how it works, if you want one, leave a comment.
BG

Sunday, November 2, 2008

The beginning

Hi everyone, this is my first step in the blog experience, I hope it'll be fine. My objective is to add experiencies in differents tecnologies, I'm working now in J2EE, but I also develop in .Net, so it will be interesting in some way, to compare both. Always adding some comments, solutions, ideas and why not doubts.
Hope you enjoy it.