You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by Apache Wiki <wi...@apache.org> on 2005/05/07 09:52:10 UTC

[Directory Wiki] Update of "MinaTutorial" by TrustinLee

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Directory Wiki" for change notification.

The following page has been changed by TrustinLee:
http://wiki.apache.org/directory/MinaTutorial

The comment on the change is:
Added tutorial draft

New page:
= MINA Tutorial: A Date with MINA =

This tutorial is intended for active user participation.  Please feel free to improve this crude tutorial.

== Table Of Contents ==

[[TableOfContents]]

== Overview ==

It’s an era of World Wide Web.  Countless web application frameworks were born to improve development productivity by order of magnitude.  In spite of this dominance of WWW, we know there are a lot of protocols that HTTP cannot replace, and even HTTP is just one of them.  We still need to build clients and servers that implements appropriate protocols.

=== What is MINA? ===

Have you ever implemented any protocols in Java, or in any other languages?  As you experienced, programming network applications is not so easy even for professional developers.  It is due to a few significant problems:

  * There is no appropriate network application framework designed for developer productivity.
    * You lose any chance to create your application in limited time.
  * Network I/O code, message encoder/decoder, and business logic is often coupled to each other.
    * You lose maintainability and reusability.
  * Network applications are difficult to unit-test
    * You lose agility.

MINA is a network application framework to resolve all the issues above not sacrificing its performance or scalability.

== I/O Layer: Programming Echo Server ==

MINA consists of two layers; I/O layer and protocol layer.  We first implement an echo server using only I/O layer because protocol layer is usually built on top of I/O layer.

TODO: I/O Layer diagram here

The above diagram shows interaction between clients and I/O layer.  IoAcceptor performs all low-level I/O, translates them to abstract I/O events, and forwards the translated events with associated IoSession to IoHandler.

=== IoSession ===

TODO: IoSession class diagram here

An IoSession represents an I/O connection between remote peer and your application.  With IoSession, you can write messages to the remote peer, access session configurations, and store custom attributes associated with the connection.

=== IoHandler ===

TODO: IoHandler class diagram here

  * sessionCreated: Invoked when a new I/O connection is established.  This method is invoked before any I/O operation is executed so that any socket parameters or session attributes can be set first.
  * sessionOpened: Invoked after sessionCreated is invoked.
  * sessionClosed: Invoked when I/O connection is closed.
  * sessionIdle: Invoked when there is no transmission of data between remote peer and user application.
  * exceptionCaught: Invoked when any exceptions are thrown from IoAcceptor or your IoHandler.
  * dataRead: Invoked when data is read from remote peer.
  * dataWritten: Invoked when your write request is written out to remote peer.

We’ll see how to implement IoHandler for echo protocol in the next section.

=== Implementing IoHandler and Startup Code ===

You usually extend IoHandlerAdapter to implement handler methods you have interest in:

{{{
package org.apache.mina.examples.echoserver;

import org.apache.mina.common.*;
import org.apache.mina.io.*;

public class EchoProtocolHandler extends IoHandlerAdapter
{
    public void sessionCreated( IoSession session )
    {
        SessionConfig cfg = session.getConfig();
        if( cfg instanceof SocketSessionConfig )
        {
            SocketSessionConfig scfg = ( SocketSessionConfig ) cfg ) ;
scfg.setSessionReceiveBufferSize( 2048 );
        }
    }

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

    public void dataRead( IoSession session, ByteBuffer rb )
    {
        // Write the received data back to remote peer
        ByteBuffer wb = ByteBuffer.allocate( rb.remaining() );
        wb.put( rb );
        wb.flip();
        session.write( wb, null );
    }
}
}}}

You’ve just implemented echo protocol with MINA.  Now you need to bind your handler to server port:

{{{
package org.apache.mina.examples.echoserver;

import org.apache.mina.common.*;
import org.apache.mina.io.*;
import org.apache.mina.io.filter.*;
import org.apache.mina.registry.*;

public class Main
{
    /** Choose your favorite port number. */
    private static final int PORT = 8080;
    

    public static void main( String[] args ) throws Exception
    {
        ServiceRegistry registry = new SimpleServiceRegistry();
        
// Bind
        Service service = new Service( "echo",
TransportType.SOCKET, PORT );
        registry.bind( service, new EchoProtocolHandler() );

        System.out.println( "Listening on port " + PORT );
    }
}
}}}

=== Adding IoFilters ===

IoFilter provides the most powerful way to extend MINA.  It intercepts all I/O events and pre- or post-processes them.  You can simply think it is similar to Servlet filters.  IoFilters can be used for many purposes such as:

  * Event logging
  * Performance profiling
  * Data transformation (e.g. SSL support)
  * Firewall, ...

TODO: I/O Layer diagram with filters here

Our echo protocol handler doesn’t log any I/O events.  We could log them by adding a filter that logs them.  MINA, fortunately, provides IoLoggingFilter that provides that functionality.  Let’s add a logging filter to ServiceRegistry.

{{{
private static void addLogger( ServiceRegistry registry )
{
    IoAcceptor acceptor =
registry.getIoAcceptor( TransportType.SOCKET );
    acceptor.getFilterChain().addLast( "logger",
 new IoLoggingFilter() );
    System.out.println( "Logging ON" );
}
}}}

What about SSL?  MINA also provides an SSL filter that works in Java 5 or above.

{{{
private static void addSSLSupport( ServiceRegistry registry )
        throws Exception
{
    SSLFilter sslFilter =
        new SSLFilter( BogusSSLContextFactory.getInstance( true ) );
    IoAcceptor acceptor =
 registry.getIoAcceptor( TransportType.SOCKET );
    acceptor.getFilterChain().addLast( "sslFilter", sslFilter );
    System.out.println( "SSL ON" );
}
}}}

== Protocol Layer: Reversing the Echo ==

We learned how to use I/O layer via simplistic echo server example.  But have you ever imagined you implement complex protocols like LDAP?  It must be a nightmare because I/O layer doesn’t help you separate message codec and actual business logic such as accessing directory database.  Protocol layer is introduced to resolve this issue by transforming ByteBuffer events to POJO events which is higher-level:

TODO: Protocol Layer diagram here

You have to implement 5 interfaces: ProtocolHandler, ProtocolProvider, ProtocolCodecFactory, ProtocolEncoder, and ProtocolDecoder:

TODO: Class diagram here

Are they too many?  But please note that ProtocolCodecFactory, ProtocolEncoder, and ProtocolDecoder are fully reusable; Apache ASN1 project provides ASN.1 codec for MINA, and more common codecs like XML, Java object serialization, and simple text will be ready in the next release of MINA.  Once you implemented a flexible codec, you can reuse it for later uses.  Even if you don’t have any plan to reuse your codec, of course, MINA provides quite easy way to implement complex protocols. (Please refer to Advanced Topics)

In this chapter, we create a ‘reverse’ server that reverses all text lines it receives to demonstrate how to program in protocol layer.

=== ProtocolSession ===

TODO: Class diagram here

ProtocolSession is a counterpart of IoSession of I/O layer.  As you noticed from FIGURE X, you write messages as a POJO instead of a ByteBuffer.  ProtocolEncoder encodes message objects to ByteBuffers so that I/O layer can write them to sockets.

=== ProtocolHandler ===

TODO: Class diagram here

ProtocolHandler is a counterpart of IoHandler of I/O layer.  dataRead and dataWritten method are replaced with messageReceived and messageSent because ProtodolDecoder decodes ByteBuffers received from I/O layer into message objects.

=== ProtocolEncoder and ProtocolDecoder ===

TODO: Class diagram here

ProtocolEncoder and ProtocolDecoder have one method.  ProtocolEncoder encodes message objects to ByteBuffer, and ProtocolDecoder decodes ByteBuffers into message objects.  We’ll learn how to implement these interfaces below.

=== Implementing ProtocolHandler ===

Let’s implement ProtocolHandler first.  We extend ProtocolHandlerAdapter here, too, just like we did when we implement IoHandler:

{{{
package org.apache.mina.examples.reverser;

import org.apache.mina.protocol.*;

public class ReverseProtocolHandler extends ProtocolHandlerAdapter
{
    public void exceptionCaught( ProtocolSession session,
Throwable cause )
    {
        // Close connection when unexpected exception is caught.
        session.close();
    }

    public void messageReceived( ProtocolSession session,
Object message )
    {
        // Reverse reveiced string
        String str = message.toString();
        StringBuffer buf = new StringBuffer( str.length() );
        for( int i = str.length() - 1; i >= 0; i-- )
        {
            buf.append( str.charAt( i ) );
        }

        // and write it back.
        session.write( buf.toString() );
    }
}
}}}

=== Implementing ProtocolProvider and Setup Code ===

The only one interface left to implement reverse protocol is ProtocolProvider.  It is very simplistic:

{{{
package org.apache.mina.examples.reverser;

import org.apache.mina.protocol.*;

/**
 * {@link ProtocolProvider} implementation for reverser server protocol.
*/
public class ReverseProtocolProvider implements ProtocolProvider
{
    // Protocol handler is usually a singleton.
    private static ProtocolHandler HANDLER =
new ReverseProtocolHandler();

    // Codec factory is also usually a singleton.
    private static ProtocolCodecFactory CODEC_FACTORY =
new ProtocolCodecFactory()
    {
        public ProtocolEncoder newEncoder()
        {
            // Create a new encoder.
            return new TextLineEncoder();
        }

        public ProtocolDecoder newDecoder()
        {
            // Create a new decoder.
            return new TextLineDecoder();
        }
    };

    public ProtocolCodecFactory getCodecFactory()
    {
        return CODEC_FACTORY;
    }

    public ProtocolHandler getHandler()
    {
        return HANDLER;
    }
}
}}}

Reverse protocol is fully implemented now.  Setup code is very similar to that of echo server:

TODO: startup code here

=== Adding ProtocolFilters ===

ProtocolFilter is the counterpart of IoFilter from I/O layer:

TODO: Protocol Layer Diagram with filters here

Adding IoLoggingFilter logs low-level I/O events which is appropriate for debugging.  We could use ProtocolLoggingFilter instead to log higher-level events:

TODO: Code here

== Advanced Topics ==

We cover more advanced topics for serious MINA users here.

=== ByteBuffers ===

MINA doesn’t user NIO ByteBuffer class directly.  It uses custom ByteBuffer class that wraps NIO ByteBuffer to extend it.  Here are some differences:

  * MINA ByteBuffer is an abstract class that users can extend freely.
  * MINA manages and pools MINA ByteBuffers.  Users can control the point the buffers are released by providing acquire() and release() methods.
  * MINA ByteBuffer provides convenient methods like unsigned value getter and String getter and putter.

If you use MINA, you’ll never need to use NIO buffers directly because you can do most buffer manipulation tasks using MINA buffers only.

==== ByteBuffer pooling ====

MINA has a global ByteBuffer pool that is shared by all MINA applications in the same virtual machine.  Any allocated buffers are released after I/O operation or event handler method is performed or invoked.  So you can simply call ByteBuffer.allocate() to get a clean buffer from the pool and forget about returning it to the pool.  Please refer to ByteBuffer JavaDoc for more details.

=== Thread Model ===

MINA fulfills capability for various thread models via filter mechanism.  It runs in a single thread mode when no thread pool filters are added.  If you add one IoThreadPoolFilter to IoAcceptor, you get one leader-follower thread pool.  If you add one more ProtocolThreadPoolFilter, Your server will have two; one (IoThreadPoolFilter) for decoding message objects and the other (ProtocolThreadPoolFilter) for processing business logic.

SimpleServiceRegistry adds IoThreadPoolFilter and ProtocolThreadPoolFilter which is adequate for applications that requires high-scalability by default.  If you want to use your own thread model, please refer to SimpleServiceRegistry source code and initialize acceptors by yourself.  It is, of course, a trivial task.

TODO: Example code here

=== More Complex Protocols ===

‘Reverser’ example is still too simple comparing to other complex protocols.  There should be dozens of message types, and their codec is required to make the server work.  MINA provides utility classes to help you:

  * DemuxingProtocolHandler
  * DemuxingProtocolCodecFactory

Please refer to JavaDocs for more details.

=== In-VM Pipe Communication ===

You must have learned that protocol layer is built on top of I/O layer, but it is not really true.  Though we usually use protocol layer that wraps I/O layer, there is a special implementation of protocol layer called as ‘in-VM pipe communication.’

Let’s assume that you implemented SMTP server and spam filter server in MINA.  SMTP server will possibly communicate with spam filter server to detect spam messages or any clients which are listed in RBL.  If there two servers are in the same Java VM, I/O layer is not necessary; you can simply bypass encoding and decoding of message objects.  In-VM pipe communication enables you to use the same code without regarding whether spam filter server resides in the same VM or not.

Please refer to ‘Tennis’ example in the source distribution.

== How to Contribute ==

We want MINA to evolve actively reacting to user requests, and therefore we need your feedback as much as possible.  The Apache Directory team will strive to satisfy all possible use cases of MINA.  Please feel free to contact us.

=== How to Contact Us ===

  * Mailing list: dev@directory.apache.org (Please use ‘[mina]’ prefix)
  * Issue tracker: http://issues.apache.org/jira/browse/DIRMINA

=== How to Report Bugs ===

You can report any bugs found from MINA to our issue tracker page.  Please attach any test cases that can reproduce your issue if possible.

=== How Issues ===

Any patches and comments are welcome!  You can browse the list of unresolved issues in JIRA:

  * http://issues.apache.org/jira/browse/DIRMINA

Or, you could do some performance benchmark on MINA and tune it.

== Acknowledgements ==

MINA couldn’t exist without strong support of many contributors:

  * The Apache Directory team for letting me join the team
  * All users of Netty2 forum and dev@directory.apache.org for great feedbacks
  * Jan Andersson and his team for SSLFilter
  * Vel Pandian for enabling client mode for SSLFilter
  * Vinod Panicker for performance benchmark and active feedbacks