mercredi 17 septembre 2014

Multi threaded UDP server with Netty on Linux

This article is only relevant when Netty is embedded in an application that is intended to run on a Linux distribution that supports native transport (e.g. CentOS >= 6.5).

Bootstrapping your UDP server is as simple as follows:

 Bootstrap bootstrap = new Bootstrap()  
      .group(new EpollEventLoopGroup(workerThreads))  
      .channel(EpollDatagramChannel.class)  
      .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)  
      .handler(channelInitializer);

 ChannelFuture future = bootstrap.bind(host, port).await();  
 if(!future.isSuccess())  
      throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", host, port), future.cause());  

However, no matter the value of workerThreads is, only one Channel will be created and therefore only one thread of the EventLoopGroup will be used. It is generally the right architecture when building a UDP server since UDP is connection- less. However, processing incoming datagrams may involve relatively long operations (e.g. accessing a database) and therefore you would like to take advantage of multi-threading in such case.

As of Netty 4.0.23.Final, there is no "Netty" way to do it, that would for example involve an ExecutorService to dispatch processing of incoming datagrams to multiple threads. You could for example add an inbound handler at the beginning of the pipeline that would be responsible of dispatching incoming datagrams but it may get you in some trouble depending on your pipeline.

A possible solution using native transport is to create multiple Channel that listen on the same port (note the enabled SO_REUSEPORT option when the Bootstrap is initialized).

 Bootstrap bootstrap = new Bootstrap()  
      .group(new EpollEventLoopGroup(workerThreads))  
      .channel(EpollDatagramChannel.class)  
      .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)  
      .option(EpollChannelOption.SO_REUSEPORT, true)  
      .handler(channelInitializer);

 ChannelFuture future;  
 for(int i = 0; i < workerThreads; ++i) {  
      future = bootstrap.bind(host, port).await();  
      if(!future.isSuccess())  
           throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", host, port), future.cause());  
 }  

It is also important to note that this solution works well for datagrams received from different remote transport addresses. The SO_REUSEPORT option is implemented by the kernel and will dispatch received datagrams to the created sockets based on the source transport address. Therefore, datagrams received from the same transport address will be dispatched to the same socket and therefore will be processed serially by the same Channel.

Initializing C3P0 pool at startup using Spring

As of C3P0 version 0.9.5-pre8, the pool manager will not be initialized until the first time getConnection() is called on the DataSource.

I wrote an application server that receives and processes commands. Processing the commands generally requires accessing a database, especially for the first received commands. The problem was the application server took time to process the first command because it was the first time the getConnection() method was called, and therefore the sending client triggered a timeout and removed the "unresponsive" application server from its list of available application servers. This is one use case where one would like to initialize as much as possible at application startup.

If you use Spring JdbcTemplate, one option is to force initialization of the exception translator as follows (note the second argument of the JdbcTemplate constructor):

@Repository("myRepository")  
public class MyRepositoryImpl implements MyRepository {
 
     private JdbcTemplate jdbcTemplate;

     @Autowired  
     public void setDataSource(DataSource dataSource) {  
          jdbcTemplate = new JdbcTemplate(dataSource, false);  
     }

}  

Initializing the exception translator requires accessing the database and therefore at some point will call the getConnection() method which will trigger pool manager initialization.

The main idea is just to call getConnection() at startup to trigger pool manager initialization. Therefore, as long as you can manage to get the getConnection() method called at startup, you are done.

If you don't use Spring but use Java 7, an empty try-with-resource block will be enough:

try(Connection conn = dataSource.getConnection()) {}

samedi 2 février 2013

JAXB/XJC: Select properties included in equals, hashcode and toString methods

When you generate source code from your WSDL/XSD using XJC, you may also want to generate equals, hashcode and/or toString methods. This is done by passing extra arguments to XJC. For example, when using the cxf-codegen-plugin with Maven, these arguments are passed as follows:


<plugin>
   <groupid>org.apache.cxf</groupid>
   <artifactid>cxf-codegen-plugin</artifactid>
   <version>${cxf.version}</version>
   <executions>
      <execution>
         <id>generate-sources</id>
         <phase>generate-sources</phase>
         <configuration>
            <wsdloptions>
               <wsdloption>
                  <wsdl>....</wsdl>
                  <extraargs>
                     <extraarg>-xjc-XhashCode</extraarg>
                     <extraarg>-xjc-Xequals</extraarg>
                     <extraarg>-xjc-XtoString</extraarg>
                  </extraargs>
              </wsdloption>
           </wsdloptions>
        </configuration>
        <goals>
           <goal>wsdl2java</goal>
        </goals>
     </execution>
  </executions>
  <dependencies>
     <dependency>
        <groupid>org.jvnet.jaxb2_commons</groupid>
        <artifactid>jaxb2-basics</artifactid>
        <version>${jaxb2.version}</version>
     </dependency>
  </dependencies>
</plugin>


By default, the generated methods use all the properties in the generated classes. Often, only a part of the properties compose the business key, and uniqueness should be determined based only on these properties. This concerns the equals and hashcode methods. For the toString method, one may want part of the properties to be displayed by the method.

In order to select the properties to be used by these methods, custom bindings have to be set. These bindings may be provided directly in the XML schema or externally using a separate file.

Here, I will show how this can be done using a separate file but the same applies when the first way is used.

First, the bindings file must be created. There is no required extension for this file but since it consists of an XML document, the .xml extension is appropriated. Assume we have the following complex type declared in the XML schema:


<xs:schema targetnamespace="target-namespace" xmlns:tns="target-namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:complextype name="PersonType">
      <xs:sequence>
         <xs:element name="idNumber" type="xs:string"/>
         <xs:element name="lastName" type="xs:string"/>
         <xs:element name="firstName" type="xs:string"/>
      </xs:sequence>
   </xs:complextype>
</xs:schema>

In the generated class PersonType, we only want the idNumber property to be used by the equals and hashcode methods. Assume we also want only the lastName and firstName properties to be displayed by the toString method. Therefore, we need to specify this as bindings as follows:


<jxb:bindings node="/xs:schema" schemalocation="XmlSchema.xsd" version="2.1" xmlns:equals="http://jaxb2-commons.dev.java.net/basic/equals" xmlns:hashcode="http://jaxb2-commons.dev.java.net/basic/hashCode" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:tostring="http://jaxb2-commons.dev.java.net/basic/toString" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <jxb:bindings node="//xs:complexType[@name='PersonType']/xs:sequence/xs:element[@name='idNumber']">
           <tostring:ignored/>
        </jxb:bindings>
   
        <jxb:bindings multiple="true" node="//xs:complexType[@name='PersonType']/xs:sequence/xs:element[position()&gt;1]">
           <equals:ignored/>
           <hashcode:ignored/>
        </jxb:bindings>
</jxb:bindings>

The path of the XML entity on which the custom JAXB binding applies is indicated in the node attribute as an XPath expression. Note that these paths are relative to the node identified by the XPath expression in the node attribute present in the top <jxb:bindings> element (here it is /xs:schema). 

It is also important to note that the order of definition of the elements in the complex type is important since the position() method is used to select all the elements but the first one (i.e. idNumber).

Also, when the XPath expression present in the node attribute targets more than one node, the multiple attribute must be set to true.

Configuring TLS on the client with CXF

When your web service is secured using TLS (this is generally done at the web container level, e.g. Tomcat), your client has to be configured to work properly.

Here, I briefly describe how to configure a CXF client to work with TLS.

When TLS is used, the server must be authenticated by the client. Optionnaly, the client may also be authenticated by the server.

This configuration is done through the HTTPConduit instance associated with your client. The HTTPConduit is obtained as follows:

Client client = ClientProxy.getClient(proxy);

HTTPConduit httpConduit = (HTTPConduit) client.getConduit();

Then, you need to create a TLSClientParameters instance that will wrap the TLS configuration. There are two ways to provision the TLSClientParameters with TLS configuration:
  • using an SSLSocketFactory instance
  • or, by provisioning the TLS configuration using the multiple properties of the TLSClientParameters instance

Here, I will describe the second way.

First, for the client to authenticate the server, instances of TrustManager should be provided. One possibility is to use a TrustManagerFactory initialized using a truststore. A truststore is a container for the security data (e.g. a file that contains certificates of trusted entities). In Java, it is represented by an instance of the KeyStore class. Assume you have a truststore that contains the trusted certificate of the server, you can initialize a TrustManagerFactory as follows:

// A specific algorithm may be provided or the default algorithm may 

// be obtained using TrustManagerFactory.getDefaultAlgorithm() 

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);

trustManagerFactory.init(truststore);

When your TrustManagerFactory is initialized, you can obtain the TrustManager instances as follows:

TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

Then, you provision your TLSClientParameters instance as follows:
TLSClientParameters tlsClientParams = new TLSClientParameters();

tlsClientParams.setTrustManagers(trustManagers);

Finally, you provision the HTTPConduit with the TLSClientParameters:
httpConduit.setTlsClientParameters(tlsClientParams);

If you are using mutual authentication (i.e. the client is also authenticated by the server), the client authentication part must also be configured. For this purpose, a class "symmetric" to TrustManager is used: KeyManager. As for TrustManager instances, a KeyManagerFactory is initialized using a keystore, also represented by a KeyStore instance.

// A specific algorithm may be provided or the default algorithm may 

// be obtained using KeyManagerFactory.getDefaultAlgorithm() 

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);

keyManagerFactory.init(keystore, password); // The password is required since sensible data is accessed

As for TrustManager, KeyManager instances are obtained and provisioned to the TLSClientParameters instances:

KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

tlsClientParams.setKeyManagers(keyManagers);