Sunday, May 18, 2014

Island(s) in the (Non-blocking I/O) Stream
As a great aficionado of Ernest Hemingway and, you guessed it, Dolly Parton I thought that the title will fit the post about non-blocking I/O servers based on Java. While poking around on the Internet doing research for this article, I realized that Apache MINA is not the only one in the category of non-blocking I/O servers written in Java. There's are also Netty and Grizzly. So, only in this installment of this blog, you get triple amount of servers for the for the price of one. No coupons needed.

Java
Besides being an exotic island, it's also a name of a programing language. In good old times there were hardly any pictures in text books, so children had no problem remembering names like Fortran, COBOL, or even better, C. C++ is also an easy one: “C” doubleplusgood. Post 1984 generations, however, started naming programing languages after snakes, islands and gems, to mention a few.
Java is interpreted language, therefore it is slow. This is common knowledge, still, regardless of the fact, it is still widely and wildly used. Even more, it enjoys almost cult status which it attained early in it's life, of a posh “modern, object-oriented programming language”. Programmers are only human, at least most of them are, and word “modern” followed by “object-oriented” is enough to create huge following. To be fair, Java is the first decent programing language that was truly portable. As in development and as in deployment. With single VM (run-time interpreter) from single company. All this makes me want to use it more, than I hit the obstacle because it is slow, which takes me back to square one.
There's more. If you decide to start a Java project you have a number of choices to make. For GUI you can use AWT, Swing or SWT. If you are planning web application you can use JavaFX, JSP or JavaServer Faces. If you are using JSP you can opt for Java Servlets, in which case your choice of web servers narrows to just four: GlassFish, IBM WebSphere, Jetty and Apache Tomcat. And if you want to reuse some of your code, there are always JavaBeansreusable software components for Java” which are by no means to be confused with Enterprise JavaBeansa managed, server-side component architecture for modular construction of enterprise applications” (whatever this means). Well, um, this is kinda complicated, don't you think? Me, I like to keep things simple. This approach does wonders for my blood pressure level. I'm not trying to say abundance of choice is bad thing per se, but there is a number of theories which prove that more choices can prove arduous to make the right decisions. Sometimes Java community looks to me very much like Rebel Alliance which tries to keep things as complicated as possible in order to prevent the evil Galactic Empire from finding out how Java really works. The downside is that only Jedi programmers can understand it. The rest of us are left clueless most of the time.
To add insult to injury, JDK has forked recently and, in addition to official Oracle (Sun) version, there is also OpenJDK. This all very fine, but the problem is that some IDEs like Eclipse and NetBeans would not work with OpenJDK. No explanation given. Just like that.

Apache MINA
Apache foundation maintains a museum of unfinished and/or abandoned projects. In addition they apparently suffer from NIH (Not Invented Here) psychology. When you peek at their site this proud statement stands out:

The ASF is made up of over 100 top level projects that cover a wide range of technologies. Chances are if you are looking for a rewarding experience in Open Source, you are going to find it here.

I mean, not even Microsoft has “more than 100 top level projects”. Just imagine what it would look like if they had to develop Windows, Office and another 99 projects. Things are bad enough even as they are. I am no fan of Microsoft, but if they can't do it - no one can. Unless you are prepared to treat some of your 100+ children as step children. And no one wants to run into one of Apache's stepchildren in the course of planing his/hers new project.
Back to MINA. When you first visit http://mina.apache.org/ you notice that you are on Apache MINA Project page, and that MINA is a sub-project of Apache MINA Project (?!) along with a few other (one of which is “currently dormant”). When you click on the menu option MINA, only then you are transferred to MINA homepage. Anyone else confused, except me?
My next step was to see the documentation. And I found it rather strange. Some parts are well written. On the other hand, chapters are missing, links are missing and there are a lot of presentations and their quality is very uneven. Documentation as a whole is a hotchpotch and I found it very confusing. It's one of those sites where you have to bookmark an interesting page or risk never finding it again.

Netty
Actually, Netty is the result of trying to rebuild MINA from scratch and address the known problems, resulting in cleaner and more documented API. Documentation, although not so extensive as MINA's, but easier to navigate and easier to understand. The site is intuitive and usable.
To be fair I have to say that MINA has more out-of-the-box features. Unfortunately this makes it more complex and a bit slower than Netty. Some sources on the Internet say that Netty can be up to 10% faster than MINA. This, of course, is not a rule and depends a lot on what you do and how you do it. Having ready made features, on the other hand, can speed up your development.

Grizzly
MINA and Netty are community driven open source projects designed and written by the same author. Trustin (Heuiseung) Lee. Therefore, they share a lot of ideas and functionality. Grizzly is entirely different beast, as the name suggests. It was created in 2004 under the GlasFish project. Initially it was built as HTTP web server, replacing Tomcat's Coyote Connector and Sun WebServer 6. This became known as Grizzly 1.0 and it used to be shipped as a replacement for Sun WebServer. This version became very popular in 2006. That same year Sun stared developing Grizzly 1.5. It was open sourced it in February 2007 and officially released during 2007 JavaOne conference. Having all this in mind, I find it rather curious that MINA and Netty are more popular than Grizzly.

Installation
Each of these frameworks is actually a collection of jar files. The only thing you have to do is to download them and place them on the folder of your choice. No installation whatsoever. And, if you happen to have Java VM already installed, you have everything you need to venture into Java technology based NIO development. Just plug and play.
Popular graphical tools such as Eclipse IDE, IntelliJ IDEA and NetBeans can be used for development. And it's no hassle. All you have to do is copy jar files you downloaded to whatever place your favorite IDE tells you to, and you're ready to go.

(Not So) Simple Samples
Now, if you expected to see samples in 10 or less lines of code like in the case of Python or Node.js, well you can forget about it. This is Java we are talking about. Imports and declarations can be longer than that. The simplest example I could find was, surprise surprise, for Apache MINA:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class MinaTimeServer
{
    private static final int PORT = 9123;
    public static void main( String[] args ) throws IOException
    {
        IoAcceptor acceptor = new NioSocketAcceptor();
        acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
        acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( 
    new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
        acceptor.setHandler( new TimeServerHandler() );
        acceptor.getSessionConfig().setReadBufferSize( 2048 );
        acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
        acceptor.bind( new InetSocketAddress(PORT) );
    }
}
That's not so much, what was the whining for? You need also the code for TimeServerHandler class:
import java.util.Date;

import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

public class TimeServerHandler extends IoHandlerAdapter
{
    @Override
    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
    {
        cause.printStackTrace();
    }
    @Override
    public void messageReceived( IoSession session, Object message ) throws Exception
    {
        String str = message.toString();
        if( str.trim().equalsIgnoreCase("quit") ) {
            session.close();
            return;
        }
        Date date = new Date();
        session.write( date.toString() );
        System.out.println("Message written...");
    }
    @Override
    public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
    {
        System.out.println( "IDLE " + session.getIdleCount( status ));
    }
}
If you really, really feel the urge to test this example then type the following at command prompt:
telnet 127.0.0.1 9123
and the server will greet you with “hello” followed by current date-time. A lot of functionality for such a small code. Right?


The smallest self-contained example is this one from Netty documentation:
package io.netty.example.discard;

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Discards any incoming data.
 */
public class DiscardServer {

    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to
  // gracefully shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
        new DiscardServer(port).run();
    }
}
One more example like this and this post would grow to 20 pages, so I'll stop right here. The morale is obvious. If the most basic servers take so many lines of code, how many lines of code are required for an application that really does something? It all translates to man-hours (um, person-hours to be politically correct) and that translates to cost.

Conclusion
One can but acknowledge the impact Java made and is still making on computer industry. Specially if you take Android into consideration. But (however), from the narrow perspective of wretched programmer, whose job is to create web application that is fast and easy to maintain, it's hard to see Java and frameworks based on it as God-given.
On the other hand, if anything, Java is platform independent. It'll soon be on a refrigerator near you and it will talk to your smart phone so you'll know what to buy on your way home. And, if you allow it, your telly is going to suggest your fridge which brands to buy. Still, I see Java more appropriate for client-server than for web applications. And all that is far from a thin client that can be written in JavaScript. Raise your hands all of you in favor of JavaScript. Thank you.
Here we reviewed an Apache project, a spin-off by the same author and a Oracle project. All very serious contestants. In essence, they are all pretty much alike. Some of them pack more ready-made features, and others make you sweat a little bit. On the Net you will find different opinions on which is better, faster or easier to work with. You'll favor one or the other based on what kind of programmer (person) you are and/or the type of the project you are planning. As usual.
If we were to judge the respective web sites of contestants, the points would go to Netty and Grizzly. They both have fairly similar front pages featuring block diagrams of their architecture. Both sites are clean and intuitive. The similarity stops here. Grizzly has much more elaborate presentation. The documentation is larger, more detailed, better organized and with more examples. Albeit a bit more complicated. Netty's site is simpler, the documentation is more basic, but much easier to understand for a newbie. Apache MINA's site? No comment.
Forced to choose I would most probably go with Grizzly. I am not usually in favor of corporate America's darlings, but in this case, I'd go the safe way. Mostly because of the team behind this project and possibility to get meaningful support.

P.S.
I almost forgot. There is yet another Apache Java NIO framework project. It is called Apache Deft. It's still in incubator. What? Where?