Custom Java ClassLoaders- Don't Do It!
I've been working with Java for about 8 years or so
and about once per year I come across someone who tries to write a custom ClassLoader. Here's my rule: If you aren't an app server, don't write a new ClassLoader implementation.
Normally the attempt is made for a very good reason, there's no "hot reloading" of Class definitions in Java by default. It sounds really easy to add some checks to a ClassLoader to see if a .class file's time stamp has changed or to add a flush system. I would love for this to exist. I would use it in a heart beat. Jakarta, BEA, JBoss, IBM and Oracle should add this functionality. But there's a reason why there is no project in Jakarta commons
: ClassLoader hierarchies can be very complex.
Here's a recent scenario. I use OAS and WebSphere a lot to deploy and test my apps. I use JAAS for authentication. This normally works fine because OAS and WAS allow for you to change the ClassLoader hierarchy to check the current loader before the parent. So when I use JAAS within my ear, the LoginModule classes can be stored in the ear, instead of at the app server or system ClassLoader level. This is different than the default behavior that Sun suggest, but is highly useful. As without this function, I couldn't use JAAS to authenticate (I can't put my classes in the app or system classpath for reasons I'll explain some other day).
I'm using an embedded service engine, that I won't name but is pretty cool, and it builds it's own Threads and ClassLoaders. But it does it like Sun says you should, not how OAS and WAS do it. So this means that when I try to use classes that live in the app or system classpath (like OAS' and WAS' JAAS frameworks- implicitly called by LoginContext.login), I get a bunch of NoClasDefFoundErrors
. And there's really no work around than to drop my entire class library in the app or system classpath, which I can't do. So this app that I have to embed and use is sucking a bit because it can't call out classes stored in the very ear that is running the app. The effort was good-hearted, but it caused me extra work to hack around it.
So my plea is this: Don't mess with ClassLoaders, you can't do it. If you are a genius and make the perfect ClassLoader, start a project in commons so the world can benefit and I don't have to muck around in near-genius code that doesn't quite make it.
Host Header can be tricky on Oracle Application Server (Apache)
I end up creating a bunch of j2ee apps that run on Oracle Application Server (OAS). When writing servlets/jsps it is frequently useful to get the URL or server name where the app is running. According to the java docs for HttpServletRequest
, there are a couple of useful messages to get this info. I usually stick to getServerName for just the host name or getRequestURL for the full url (getRequestURI will have this info in a GET request). Both of these methods get their info from the HTTP Host header.
The trickiness comes with Apache, because no matter what the browser sends in the Host header, it replaces the host portion with the configured serverName. So if you pass:
but if Apache has "foo" in the httpd.conf, Apache will change the header to have
The way this came to my attention is when a customer reported some of our site wasn't working. The url being used by the component was "http://serverName:8888/whateverUrlIs.do?foo=blargh" even though if you looked at the browser, the address is "http://serverName.fullhost.fulldomain.com:8888/whateverUrlIs.do?foo=blargh". This was a bit of pain as nowhere in our code were we shortening the host name. It ended up that OAS was installed with just the host name rather than the full host name.
OAS doesn't let you change the server name through a nice gui, but it is easy enough to edit the httpd.conf file through the advanced pane or directly in the file system.
So I wonder: why does OAS/Apache change the passed HTTP headers? This makes debugging a real pain. So now, one of my first debugging steps is running the app in jboss, oc4j or websphere to make sure the app server isn't doing something weird to the request. I had similar headaches with WebSphere on AIX/zOS not liking the Content-Type header with my SOAP requests.
Character sets in HTTP headers
Recently I was working with some web service products. We run the engine on WebSphere and OAS on Solaris, AIX and zOS so I was trying to get it embedded in each of our deployments. WebSphere on AIX was giving some curious responses to our SOAP requests. It was reporting that the SOAP request was empty. On the client, the request looked fine, but once it got to the SOAP servlet, there request was empty. On OAS, there were no errors and the same request came through properly.
I set up OC4J
to debug (since it's lightweight and easy to set up. I like it better than tomcat for j2ee dev and debugging.) It was throwing java.nio.charset.IllegalCharsetNameExceptions but the content-type header that was being sent was: Content-type: text/xml; charset="UTF-8"
Another architect found out what the problem was. It seems like the combination of WebSphere and IBM's JRE for AIX didn't like the quotes in the http header's charset. But the Sun JRE with WebSphere doesn't mind. Strange. So when we changed the header to: Content-type: text/xml; charset=UTF-8
, the request came through properly.
According to W3C's RFC2616 for HTTP 1.1
there are no quotes around the charset attribute. Even though there are quotes in other W3C examples (like Example 9 in theW3C SOAP Primer
So the moral of the story is that when you send SOAP requests over HTTP don't use quotes around the charset value of the around the Content-type header. Some app servers and JREs are flexible, but then again, some aren't.