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 JavaBeans
“reusable software components for
Java” which are by no means to be
confused with Enterprise
JavaBeans “a 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?
Comments
Post a Comment