3.3 - Acceptor

In order to build a server, you need to select an implementation of the IoAcceptor interface.

IoAcceptor

Basically, this interface is named because of the accept() method, responsible for the creation of new connection between a client and the server. The server accepts incoming connection request.

At some point, we could have named this interface ‘Server’.

As we may deal with more than one kind of transport (TCP/UDP/…), we have more than one implementation for this interface. It would be very unlikely that you need to implement a new one.

We have many of those implementing classes

  • NioSocketAcceptor : the non-blocking Socket transport IoAcceptor
  • NioDatagramAcceptor : the non-blocking UDP transport IoAcceptor
  • AprSocketAcceptor : the blocking Socket transport IoAcceptor, based on APR
  • VmPipeSocketAcceptor : the in-VM IoAcceptor

Just pick the one that fit your need.

Here is the class diagram for the IoAcceptor interfaces and classes :

Creation

You first have to select the type of IoAcceptor you want to instantiate. This is a choice you will made early in the process, as it all boils down to which network protocol you will use. Let’s see with an example how it works :

public TcpServer() throws IOException {
    // Create a TCP acceptor
    IoAcceptor acceptor = new NioSocketAcceptor();

    // Associate the acceptor to an IoHandler instance (your application)
    acceptor.setHandler(this);

    // Bind : this will start the server...
    acceptor.bind(new InetSocketAddress(PORT));

    System.out.println("Server started...");
}

That’s it ! You have created a TCP server. If you want to start an UDP server, simply replace the first line of code :

...
// Create an UDP acceptor
IoAcceptor acceptor = new NioDatagramAcceptor();
...

Disposal

The service can be stopped by calling the dispose() method. The service will be stopped only when all the pending sessions have been processed :

// Stop the service, waiting for the pending sessions to be inactive
acceptor.dispose();

You can also wait for every thread being executed to be properly completed by passing a boolean parameter to this method :

// Stop the service, waiting for the processing session to be properly completed
acceptor.dispose( true );

Status

You can get the IoService status by calling one of the following methods :

  • isActive() : true if the service can accept incoming requests
  • isDisposing() : true if the dispose() method has been called. It does not tell if the service is actually stopped (some sessions might be processed)
  • isDisposed() : true if the dispose(boolean) method has been called, and the executing threads have been completed.

Managing the IoHandler

You can add or get the associated IoHandler when the service has been instantiated. You just have to call the setHandler(IoHandler) or getHandler() methods.

Managing the Filters chain

if you want to manage the filters chain, you will have to call the getFilterChain() method. Here is an example :

// Add a logger filter
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
chain.addLast("logger", new LoggingFilter());

You can also create the chain before and set it into the service :

// Add a logger filter
DefaultIoFilterChainBuilder chain = new DefaultIoFilterChainBuilder();
chain.addLast("logger", new LoggingFilter());

// And inject the created chain builder in the service
acceptor.setFilterChainBuilder(chain);