Showing posts with label AXIS2. Show all posts
Showing posts with label AXIS2. Show all posts

Sunday, May 29, 2011

HTTP Transport in axis2 : How to fix Timeout waiting for connection?

If you are fed up with navigating to different JIRA issue while trying to to understand why are you getting “Timeout waiting for connection” (every thing was fine till axis2 1.5 and you just upgraded to latest release say 1.5.4), you are at right place.

First lets understand when this happens:

for(int i=1; i<=3; i++){
ServiceClient sc = new ServiceClient();
----
OMElement response = client.sendReceive(payload);
response.build();
}

This will work perfectly fine in axis2 1.5 but will not work for axis 2 1.5.1 onwards. Particularly third call will fail due to timeout waiting for connection exception.

So what got changed and why we are getting the exception:

This is attributed to recent change in axis2 AbstractHttpSender#getHttpClient code. Which started caching the MultiThreadedHttpConnectonManager(MTHCM).

protected HttpClient getHttpClient(MessageContext msgContext) {

connManager = new MultiThreadedHttpConnectionManager();
configContext.setProperty(HTTPConstants.MULTITHREAD_HTTP_CONNECTION_MANAGER, connManager);
}

where connection manager being cached once created which was not the case prior to axis 2 1.5.1. Prior to 1.5.1 if caching is not enabled via axis2 option api every time new manager was getting created.

One thing to note is, axis2 1.5.4 creates new HttpClient object for each call unless its explicitly cached by using “CACHED_HTTP_CLIENT” option.
The reason behind caching MTHCM is to improve performance(http://hc.apache.org/httpclient-legacy/performance.html).

Http Connection manager serves as connection factory and manage connection pool. They come in different flavors. MTHCM is thread safe flavor of connection manager which allows multiple connection to run concurrently in thread safe way.

MTHCM manage http connection pool and make sure new connection is not created every time new call is made(Establishing a new connection is quite time consuming, it involves multiple packet exchange between client and server http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html : Connection persistence).



So idea behind recent change in axis2 is to use connection pool facility of MTHCM to avoid new http connection every time you call webservice. While earlier for every webservice call new MTHCM instance was getting created and thus new connection pool and new connection(unless you are using caching MTHCM facility exposed by option api of axis2, now axis2 made caching MTHCM default behaviour ).

But then using single MTHCM comes with couple of constraints which leads to connection time out problem.

By default MTCH create only max 2 connection per host and 20 nos of total http connections (http://hc.apache.org/httpclient-legacy/threading.html) in the pool. And once you are done using these connection you need to return it to pool by releasing the connection (if you have already consumed two connection to talk to a host, request for third connection for the same host will wait and eventually throw timeout waiting for connection if no connection is available in the pool at the end of timeout period). Releasing the connection has to be done at the application level after reading the response stream since there is no way Apache client can determine if response has been read.

So if we are using axis2 1.5.1 onwards we need to release the connection to the pool since we can not have more than one MTHCM resulting only two available connection per host(default no of connections can be increased using options provided by MTHCM [http://hc.apache.org/httpclient-legacy/threading.html]).

Lets rewrite the sample pseudo with the suggested approach to fix the issue.

for(int i=1; i<=3; i++){
try{
ServiceClient sc = new ServiceClient();
----
OMElement response = client.sendReceive(payload);
response.build();
}finally{
sc.transportCleanup();
}
}

Transport cleanup interns calls releaseConnection() which releases the connection back to the pool.

Please note cleanup works only if HTTP response status code is one of following 200, 202, 400, 500.

Coming Soon: Other ways (using option api though one mentioned in the current blog is best way) to fix timeout issue, and some related discussion about axis2 and transport cleanup

Sunday, November 21, 2010

Enabling SSL for AXIS2 service and client

We often encounter the satuation where requirement is to consume webservice exposed on https. In this article we will investigate how to consume webservice exposed over https using axis2. First lets see how to enable SSL for AXIS2 services:

Enabling SSL on server side for AXIS2 in tomcat:

You really don't need to do much enable SSL for services deplyed in AXIS2. Just follow how to enable SSL in tamcat.Add following in Server.xml of tamcat.

<Connector
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="test.jks" keystorePass="test123"
clientAuth="false" sslProtocol="TLS"/>


Use axis2 1.5.3 in which axis2.xml has https transportReceiver enabled by default, listening on 8443 port so you don't need any configuration change in axis2.xml.
<transportReceiver name="https"
class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8443</parameter>
</transportReceiver>

Prior to this version of axis2 was using org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener as transportReceive which was having issues and not generating https endpoint correctly.

SSL on client side:

Axis2 uses http commons to transfer SOAP message over http. Apache http common uses JSSE(java secure socket extension) library for SSL.
JSSE is integrated with JDK since version 1.4.

Ideally if we just provide end point URL starting with https, SSL connection will be started and we don’t need any additional configuration. Creation of secure connection will be taken care by JSSE. But then trust store and keystore used by the JSSE would be default keystores shipped with JDK.

In the practical/production scenarios user should have capability to choose his truststore/keystore.
user may decide to trust a self signed certificate and keep it his local truststore or different applications may use different keystore/truststore.
Above can be achieved by two ways:
Approach 1:
We can set truststore, password etc in system properties. This will be picked by JSSE in SSL handshake.
Ex.
System.setProperty("javax.net.ssl.trustStore","Your truststore path");
System.setProperty("javax.net.ssl.trustStorePassword","your trust store password");
This approach will not be appropriate for tooling since it sets keystore on JVM level. We should have flexibility where we could attach different keystore/truststore for different axis2 clint running in same JVM.

Approach 2:
Apache commons provide facility which allows us to customize the SSL socket factory responsible for creation of secure socket. By customization I mean ability to use user truststore/keystore in SSL handshake. To achieve it we need to extend SecureProtocolSocketFactory interface. In our custom socket factory implementation user refer its Keystore/Truststore against default keystores.
Apache commons provide a reference implementation class named AuthSSLProtocolSocketFactory for this purpose.

This class takes Truststore/Keystore as argument to constructor which will be referred later while initiating SSLContext. SSLContext is used to create SSL Socket Factory.
In your axis2 client code you need to add following:
Protocol authhttps = new Protocol ("https", new AuthSSLProtocolSocketFactory (new url("keystore URL"), "pwd", newURL("truststore URL"), "pwd"), 443);
Protocol.registerProtocol("https", authhttps);

And you are all set to consume secure webservice.

Saturday, October 16, 2010

Dealing with low disk space problem caused by AXIS2 temp files

Recently I came across interesting scenario where axis2 modules jars file were getting created on every execution of axis2 client code. This was resulting in low disk space since temp directory was flooded with temp jars created by axis2. We can't avoid creation of these jars in temp dir since these are modules jars used by axis2 class loader to load modules class needed to engage axis2 modules. What we can difinitely do is reusing the generated jar files created on first use and deleted these temp file on JVM shut down.

Lets first see how to reuse the temp file generated.

As we know ConfigurationContext object created every time client tries to invoke the service or every time we create ServiceClient instance. To avoid this situation we need to cache ConfigurationContext class once created. We need to modify AXIS2 1.4 ServiceClient code as follows(Highlighted):

ServiceClient#configureServiceClient

if (configContext == null) {
if (ListenerManager.defaultConfigurationContext == null) {
configContext = ConfigurationContextFactory.
createConfigurationContextFromFileSystem(null, null);
ListenerManager.defaultConfigurationContext = configContext;
createConfigCtx = true;
} else {
configContext = ListenerManager.defaultConfigurationContext;
}
}

Now lets try to delete the single set of temp file on JVM shutdown.
AXIS2 engine does the write thing while creating these temp file. it also calls java.io.File#deleteOnExit which tells the JVM to delete these file on exit.
But unfortunately AXIS2 class loader will be referring these files so these could not be deleted by JVM(which is un resolved bug in JVM). To deal with it once you are done with using serviceclient. you have to call ServiceClient#cleanup. Cleanup method looks into temp folder start with _axis2 and deletes all files which are not referred by axis2 which may be present from previous JVM session.
The temp file created in one JVM session will be deleted not on JVM exit but in the nest session of JVM. When you invoke ServiceClient#cleanUp().

AXIS2 1.5 onward the startegy for dealing with temp file is improved. Here responsibility to manage temp files are delegated to class named TempFileManager instead of using java.io.File#createTempFile directly.

This uses TempFileManager#createTempFile which along with temp folder to contain the jars creates another file named tempFolderName suffixed by .lck. On both of these java.io.File#deleteOnExit is called. JVM will not be able to delete the temp folder containing the temp jars but it will be able to delete the .lck file on shout down. Since these is no reference to .lck file. Now on next start up when TempFileManager class is loaded it has static block which will look for all axis2 temp folder for which corresponding .lck file is not present.

The advantage is if you are using AXIS2 1.5 you don't need to call ServiceClient#cleanup to clean these temp file. It will be cleaned up on TempFileManager class loading.

Friday, October 15, 2010

Engaging modules in AXIS2 on client side

Engaging modules at client side gets quite frustrating when you have written stand alone client on eclipse. There are no. of ways you can do that. The easiest one is to change module extensions form .mar to .jar so that you can add them to eclipse class path. You don't have to make any other changes and you can engage module at client side programatically.

suppose you want to engage addressing module, then following code will be sufficient provided you have addressing.jar file in your class path.

ServiceClient sc = new ServiceClient();
sc.engageModule("addressing");

Now lets remove addressing jar from class path and try running the same code. You will get infamous "Unable to engage module : addressing"!

So what if I don't want to change the extension of modules. We need to pass location of module file while creating configuration context as follows.

ConfigurationContext configContext =
ConfigurationContextFactory.createConfigurationContextFromFileSystem("E:/LAB/apache/axis2-1.3-bin/axis2-1.3/repository","E:/LAB/apache/axis2_repo/axis2.xml");
ServiceClient sc = new ServiceClient(configContext,null);
sc.engageModule("addressing");

Engaging modules can be set globally when you pass axis2.xml while creating configuartion context. You need to uncomment <module ref="addressing"/> in axis2.xml. Now sc.engageModule("addressing"); is not needed to engage addressing module. Moreover if you don't want addressing feature for every client request comment <module ref="addressing"/> in axis2.xml and engage module by calling ServiceClient#engageModule when needed.

There is another way to provide modules information at runtime by setting :Constants.AXIS2_REPO and Constants.AXIS2_CONF config properties.

System.setProperty(Constants.AXIS2_REPO, "C:/MyFolder/MySoftwareLab/tools/axis2-1.5.1-bin/axis2-1.5.1/repository");
System.setProperty(Constants.AXIS2_CONF, "your local axis2 path");

Above works because of following code of AXIS2 engine.

if (repoLocation == null) {
//checking wether user has set the system property
repoLocation = System.getProperty(Constants.AXIS2_REPO);
}

if (axis2xml == null) {
// If not, check for a system property setting
axis2xml = System.getProperty(Constants.AXIS2_CONF);