Memory leaks

Crazy Bob posted on ThreadLocal memory leaks.This type of memory leak really annoys me because I see it very often on Java EE servers and developers are not aware of it.The error is mostly annoying in development, testing environmentswhere the Java EE server is not restarted and the applicationsare just redeployed. Therefore, threads (of thread pools) are not recreated and hold references to old application classes.

My advice is CLEAN YOUR THREADLOCALs

Add a servlet filter, Web frameworkinterceptor or WS handler to set all ThreadLocal variables to null just beforereturning the response to the client. Lower level solutions should be preferred and turn out to be less risky. A dummy implementation (to give an idea) would be a servlet filter:

public class ContextCleanerFilter implements Filter {
private ContextCleaner ctxCleaner;
public void init(FilterConfig filterConfig) {
// CtxCleaner instantiated directly boooh !!!
ctxCleaner = new StaticContextCleaner();
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Reset ThreadLocals before processing the request
if (ctxCleaner != null) ctxCleaner.cleanAll();
chain.doFilter(request,response);
// Reset ThreadLocals after processing the request
if (ctxCleaner != null) ctxCleaner.cleanAll();
}
public void destroy() {
}
}

with a ContextCleaner Interface:

public interface ContextCleaner {
boolean cleanAll();
}

and a dummy implementation:

public class StaticContextCleaner implements ContextCleaner {
public boolean cleanAll() {
UserSession.setSessionData(null);
return true;
}
}

Where UserSession has static accessors to handle the ThreadLocal and is used by application code to store objects in a ThreadLocal instance:

public class UserSession {
private static ThreadLocal m_session= new ThreadLocal();
public static void setSessionData(SessionData sessionData){
m_session.set(sessionData);
}
public static SessionData getSessionData(){
return (SessionData)m_session.get();
}
}

The problem with this implementation is that it only works with classes that you controland are aware that they use ThreadLocal variables. Maybe with reflection it’s possible to accessthe current Thread’s Map which stores ThreadLocal objects and set them to null one by one. But it would be highly risky if your application server uses ThreadLocal for its own usage.

For further information on ThreadLocal memory leaks see this link

Axis through Apache HTTPD quick tips

Here are tips when using Axis Web services through Apache:

  • Gzip To enable gzip compression use the recommendations of the following blog entry. It consists in using Jakarta commons httpclient and configuring your Axis stub to set gzip compression on. On Apache 2.0.X, mod_deflate module can be used and it’s pretty straightforward to enable gzip compression for input and output streams.
    <Location /ws>;
    SetOutputFilter DEFLATE
    SetInputFilter DEFLATE
    </Location>

Gzip can be enabled by Mime-type but it didn’t seem to work for me… Enabling gzip compression is only advised when you have “large” messages (100 Kbytes). Benchmark it.

  • Preserve Host
    When the WSDL is generated via Axis servlet, the Host HTTP header is used to build the URL of WS endpoints in the WSDL. So if you are using mod_proxy to forward HTTP request to a servlet container don’t forget to add this instruction.
    ProxyPreserveHost On

Here’s a sample configuration (mod_proxy, mod_proxy_http must be enabled).

# Configure mod_proxy as a reverse proxy only
ProxyRequests Off
# To preserve HOST HTTP/1.1 header
ProxyPreserveHost On
ProxyPass http://j2eeserver:80/ws
ProxyPassReverse http://j2eeserver:80/ws
SetOutputFilter DEFLATE
SetInputFilter DEFLATE
  • Dealing with SOAP with attachments. mod_proxy can be used in front of any servlet container but when the Web containers are clustered it’s better to use the relative Apache module of these containers (mod_jk for Tomcat or mod_wl_20 for Weblogic). The problem is that some modules don’t handle well HTTP chuncked-encoding transfer type. Chunck-encoding is used by default by Jakarta commons httpclient library (see this RFC description of chunck-encoding). If you do SOAP with attachments with a Mime-Multipart HTTP request, the proxy alters the HTTP headers of the request and Axis doesn’t handle it well. The only solution for me has been to use the latest mod_proxy version.Here’s a sample request:
POST /ws/Call HTTP/1.1
Content-Type: multipart/related; type="text/xml"; start=""; boundary="----=_Part_1_29493424.1136228652812"
SOAPAction: ""
User-Agent: Axis/1.3
Host: localhost:81
Transfer-Encoding: chunked
542
------=_Part_1_29493424.1136228652812
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id:
me31
------=_Part_1_29493424.1136228652812
Content-Type: text/xml
Content-Transfer-Encoding: binary
Content-Id:
------=_Part_1_29493424.1136228652812--

And here are the altered HTTP headers (behind the Weblogic mod_wl_20 proxy). The Content-length header is missing. The request is not chuncked encoded anymore and it makes Axis unable to find the Mime part of the SOAP-Enveloppe and the Mime part of the attachment.

POST /ws/Call HTTP/1.1
Host: localhost:8081
Content-Type: multipart/related; type="text/xml"; start=""; boundary="----=_Part_1_810652.1136228287250"
SOAPAction: ""
User-Agent: Axis/1.3
Max-Forwards: 10
X-Forwarded-For: 192.168.0.1
X-Forwarded-Host: localhost:81
X-Forwarded-Server: gateway

About Weblogic module for Apache

I wish BEA could opensource their proxy module for Apache. In front of a Weblogic cluster it’s the only module for Apache that can be used because the module keeps a list of alive members of the cluster (by connecting to one of the cluster members). The list of the cluster members is returned to the mod_weblogic module in an encoded form. See the X-Weblogic-Cluster-List header below.

X-WebLogic-Cluster-Hash: 4VGHN1gZDEo+SVsK2yjMU+4La3w
X-Powered-By: Servlet/2.4 JSP/2.0
X-WebLogic-Cluster-List: 1468479224!-1407317905!7002!-1|648190806!-1407317905!7003!-1

I haven’t figured out what the X-Weblogic-Cluster-Hash is and how it’s generated (=> a decompilation of Weblogic classes) should do it but in the X-Weblogic-Cluster-List you can see the inversed IP addresses and port of the cluster members in numerical format. Here ‘s a class to retrieve the IP address from the inversed numerical format.
Try: GetIP 1407317905

public class GetIP {
public static void main(String[] args) throws Exception {
long a= Long.parseLong(args[0]) ;
long b = ~a;
StringBuffer ip=new StringBuffer();
for (int i=1;i<=4;i++) {
long c=b>>(8*(4-i));
c = c & 255;
ip.append(Long.toString(i==4?c+1:c));
ip.append(".");
}
System.out.println(ip.substring(0,ip.length()-1));
}
}

Is Ruby ready for enterprise ?

I have been attracted by the horns and whistles of Ruby (and Rails) and recently I decided to jump on the bandwagon.

I had to code a script that polls SNMP agents. Since there’s a decent ruby SNMP library on the net, I decided to code it in Ruby and also because it’s easy to create a Windows executable with ruby2exe.rb ruby script.

But here’s why I have been disappointed by some aspects of “ruby the platform” during this coding session:

  • Ruby doesn’t support Unicode strings yet. Try to do: a=\’café\’b=a[0,3] and you’ll get an error (not the proper character). A character is today encoded in a single byte. Well there are some workarounds explained here but no perfect solutions until the support of multilinguism in the language itself.
  • No XML validation. The REXML library included in Ruby distribution does not support validation of an XML document on a XML schema. Some third-party libraries like libxml seem to support it but they are partially coded in C
  • The ruby interactive interpreter does not support French keyboard on Windows and i can’t type the [ character.

If I appreciate the language syntax, I don’t understand how can some bloggers encourage Java coders to move to Ruby and Rails. ruby “the platform” doesn’t seem really mature.