Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Sunday, 20 December 2009

Exception hell

All Java programmers have certainly encountered their fare share of excessively long, incomprehensible or just plain stupid stacktraces, but this one got me stumped when I saw it:

08:34:55,989 ERROR [jsp:165] java.lang.ClassCastException: com.icesoft.faces.context.ElementController cannot be cast to com.icesoft.faces.context.ElementController
at com.icesoft.faces.context.ElementController.from(ElementController.java:22)
at com.icesoft.faces.context.DOMResponseWriter.enhanceBody(DOMResponseWriter.java:294)
at com.icesoft.faces.context.DOMResponseWriter.enhanceAndFixDocument(DOMResponseWriter.java:239)
at com.icesoft.faces.context.DOMResponseWriter.endDocument(DOMResponseWriter.java:144)
at com.icesoft.faces.facelets.D2DFaceletViewHandler.renderResponse(D2DFaceletViewHandler.java:283)
at com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:161)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:107)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:268)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:137)
at com.icesoft.faces.webapp.http.core.JsfLifecycleExecutor.apply(JsfLifecycleExecutor.java:18)
at com.icesoft.faces.webapp.http.core.PageServer$1.respond(PageServer.java:25)
at com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:161)
at com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36)
at com.icesoft.faces.webapp.http.core.PageServer.service(PageServer.java:30)
at com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:56)
at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer$Matcher.serviceOnMatch(PathDispatcherServer.java:50)
at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:19)
at com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19)
at com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:29)
at com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:106)
Unless my eyesight has really gone, this exception is saying it can't cast ElementController to ElementController? Same name, same package, as per usual it's just a big bag of fail again. Why can't I just get a normal comprehensible exception and stacktrace for once?

This one is bad, but there is one that is much worse, the dreaded NoClassDefFoundError, but that one deserves its own post somewhere after new year.

Tuesday, 8 September 2009

Java profiling on OSX

Not so long ago I needed to profile a small application to check why a simple WebDAV listing call using Slide took 20 seconds. It turned out to be a network IO problem caused by a blocking readline call on the response stream. I usually tend to use JProfiler for finding out these kind of things, because it is very good at what it does. But because it is a paying application and my company doesn't provide me with a license, I have to keep my eyes open for alternatives (you can't keep working with trial licenses and Mailinator addresses aren't allowed when registering).

So when the Eclipse Test & Performance Tools Platform Project, TPTP in short, appeared on my radar thanks to DZone I decided to try it out. Since I'm using Eclipse as my primary Java IDE this profiling plugin seemed a perfect fit, but little did I know. In Eclipse I opened Help > Install New Software... and added the http://eclipse.org/tptp/updates/ URL as a new software site to download TPTP. After downloading, agreeing to some licenses and an Eclipse restart I was ready to use my newly acquired profiler, or ... maybe not.

I was getting all kinds of different errors, but mostly NullPointerExceptions and some Incompatible Platform messages. After some looking around it was StackOverflow to the rescue: even though TPTP is already at version 4.3 there still isn't a TPTP Agent Controller for OSX. You've gotta be kidding me! How is it possible that they leave such a large group of Java developers, the ones that use OSX, out in the cold. It gets even better, you can't even open the TPTP 4.3 release notes page in Safari without getting a Javascript pop with the message: Sorry but this page isn't currently viewable in Safari. WTF!

So my little excursion away from JProfiler came to a screeching halt and I had to return to my tried and trusted JProfiler once again. One day I'll have to convince the big cheeses to get me a license.

Update 9 september 2009: it looks like I'm not the only one complaining: Green's Opinion

Tuesday, 11 August 2009

Accessing WebDAV from Java on OSX

I'm currently working on an extension for an existing project. The project consists of a Canon MEAP application that enables users of multifunctionals to scan documents in a quick and simple way to a SMB share or to an email address. The extension that I have to build involves adding a third transfer method, WebDAV, so that scanned documents can be sent to our Atlassian Confluence wiki.

Since the Canon MEAP platform is Java based, I started looking a Java WebDAV libraries. I found 2 good ones: Slide and Jackrabbit. The Slide project has been retired due to lack of active maintenance. This leaves us with Jackrabbit, a JCR (JSR 170) implementation, that also contains a nice WebDAV implementation that is based on Commons HttpClient.

After this I decided to do a small proof of concept to test the the 2 use cases that I needed for my extension: get a file listing and put a file on a WebDAV server. For this I needed a WebDAV capable server off course, normally I could have just used our actual wiki, but after a recent upgrade it seems that something had changed in the WebDAV integration and I couldn't access anything from the normal URL (later got to know that the new/current WebDAV URL of Confluence is https://myserver.com/confluence/plugins/servlet/confluence/default).

So I needed an alternative solution: setting up my own WebDAV server. After looking around a bit I found out that Jackrabbit also has a simple WebDAV enabled server included and does this via a WAR file that you can simply drop into a default Tomcat installation (I used jackrabbit-webapp-1.5.7.war). Another possibility would have been to configure the Apache server that is bundled with OSX to enable WebDAV, but since I've already got Jackrabbit and Tomcat is closer to my Java background I favored that approach.

Since I was already trying a lot of new stuff, I also decided to use that latest Tomcat version and download a 6.0.20 Core version. After doing this I unpacked the downloaded file into a directory, cd'ed to the bin directory of the Tomcat installation and ran ./catalina.sh start and encountered my first problems:
  • -bash: ./catalina.sh: Permission denied: solved by chmod +x catalina.sh
  • The BASEDIR environment variable is not defined correctly: again the cause seems to be some kind of permission problem and was solved by this post.
After this I dropped the download WAR, jackrabbit-webapp-1.5.7.war, into the webapps directory and watched the application deploy. If everything deployed correctly you should now be able to access the web interface at http://localhost:8080/jackrabbit-webapp-1.5.7. The home page displayed fine, but every other menu item I clicked threw errors. After a restart of Tomcat I traced the problem down to a missing JCR jar. This was solved by downloading one and placing it in the lib directory of Tomcat and restarting it. After this you'll need to go to the home page again and click the Create Content Repository button to initialize the WebDAV correctly. Once the initialization is done you'll be able to access your local WebDAV instance at http://localhost:8080/jackrabbit-webapp-1.5.7/repository/default/ (any username/password combination will work by default).

Now we have a working WebDAV server we can concentrate on creating a client that can do a listing of the WebDAV root directory and place a new file in it. Using a set of different sources I was able to put together the following code:


import java.io.FileInputStream;
import java.io.IOException;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.DavMethod;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;

public class WebdavTest {

public static void main(String[] args) throws IOException, DavException {
HostConfiguration hostConfig = new HostConfiguration();
hostConfig.setHost("127.0.0.1", 8080);
HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
Credentials creds = new UsernamePasswordCredentials("userId", "pw");
client.getState().setCredentials(AuthScope.ANY, creds);
client.setHostConfiguration(hostConfig);

PutMethod put = new PutMethod("http://127.0.0.1:8080/jackrabbit-webapp-1.5.7/repository/default/test.txt");
RequestEntity requestEntity = new InputStreamRequestEntity(new FileInputStream("/path/to/file/test.txt"));
put.setRequestEntity(requestEntity);
client.executeMethod(put);

DavMethod pFind = new PropFindMethod("http://127.0.0.1:8080/jackrabbit-webapp-1.5.7/repository/default", DavConstants.PROPFIND_ALL_PROP, DavConstants.DEPTH_1);
client.executeMethod(pFind);

MultiStatusResponse[] responses = pFind.getResponseBodyAsMultiStatus().getResponses();
System.out.println("Folders and files: ");
for (int i = 0; i < responses.length; i++) {
System.out.println(responses[i].getHref());
}
}
}

You'll need the following libraries to make the code compile and run: commons-codec, commons-httpclient, commons-logging, jackrabbit-jcr-commons, jackrabbit-webdav, slf4j-api and slf4j-nop.

Thursday, 6 August 2009

JMeter memory problems

Sometimes things that have never failed before do fail. Today this happened while using the tried, tested and trusted JMeter load testing tool. I've used JMeter a lot during the years and even though it is starting to show its age, it is hard to find something better to do the job.

Lately the only thing that made JMeter fail was when an OutOfMemoryError occurred. This was always easily solved by adjusting the heap memory size settings (-Xms and -Xmx) and sometimes even the Permanent Generation size settings (-XX:PermSize and -XX:MaxPermSize) to appropriate values. But today we did this to no avail. While we were only running a load test for 40 threads with 10 loops each, it would still crash and burn even with 2 gigabytes of heap memory.

So we were thinking that maybe the listeners were to blame, so we disabled the Graph Results listener and even the View Results Tree listener, but still kept getting OutOfMemoryError occurrences. So now we were kind of stuck, or maybe not... . I remembered that JMeter can also be run remotely and without a GUI. Could this maybe help? It sure can't hurt to try. So we fired up JMeter in non-GUI mode and what do you think, no more OutOfMemoryError occurrences as far as the eye can see (the jmeter.log file in the bin directory that is).

So now we only had to re-enable the listener, configure them to write their data to some files (so that we could view them in JMeter after the non-GUI tests were done) and run JMeter using the following command: ./jmeter -n -t /path/to/loadtest.jmx

Monday, 3 August 2009

JAX-WS and Maven2

Another day in Maven hell! I still don't get how something as simple as trying to get the JAX-WS tool wsgen to work can be this difficult.

My goal was to create a set of webservices starting from Java code and to then generate the necessary WSDL and XSD files. The first part, creating a domain model, annotating it with JAXB and then generating an XSD was simple enough. The second step kept me busy for the remaining 75% of the day.

I just added a new dependeny to my pom.xml and annotated my service with @WebService. But after triggering a recompile I got an error, the WebService annotation couldn't be found. Checked the pom.xml again, but it contained the correct dependency. So what was going wrong. Afer trying out some suggestions made in various blogs and forum posts, the problem remained. I even got to a point in which the code compiled, but when I executed the wsgen goal it would fail with the message: java.lang.NoClassDefFoundError: javax/jws/WebService. What? How can this be? By this time I was cursing away at Maven again: how can this bloody thing, that is supposed to make my life easier, always fuck up in the most incomprehensible way possible?

Then a little speck of light in the distance: it seems that the JAX-WS libraries are spread over a maven1 and a maven2 repository and that there are problems with some versions and references to other libraries that JAX-WS uses. The solution to all this:
  • empty out your local repository
  • add the java.net maven1 and maven2 repositories to your pom.xml
  • add a dependency to JSR-181 to the wsgen plugin
After doing all this I was able to compile, build and generate everything I wanted (it only took way too much time).

The pom.xml I used:


xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
EDRL
Preprocessor
0.0.1-SNAPSHOT



com.sun.tools.jxc.maven2
maven-jaxb-schemagen-plugin
1.1


process-sources

${project.build.directory}/schemas

be/test/*.java

${basedir}/src/main/java
true


generate





org.codehaus.mojo
jaxws-maven-plugin
1.12



wsgen

generate-sources

be.test.service.TestService
true
true
true






javax.jws
jsr181-api
1.0-MR1







maven-repository.dev.java.net
Java.net Repository for Maven 1
http://download.java.net/maven/1/
legacy


maven2-repository.dev.java.net
Java.net Maven 2 Repository
http://download.java.net/maven/2




maven2-repository.dev.java.net
Java.net Maven 2 Repository
http://download.java.net/maven/2




javax.xml
jaxb-impl
2.1


javax.xml.bind
jaxb-api
2.2


com.sun.xml.ws
jaxws-rt
2.1.3


javax.jws
jsr181-api
1.0-MR1



1.5
1.5




Sunday, 2 August 2009

Better validation messages in JSF

This week a collegue of mine wanted to enhance the form validation messages in a JSF application, but he was having problems getting a nice fieldname into the message. The default behavior of JSF is to display something like: j_id_id19: Validation Error: Value is required. This is Ok for a programmer, but an end-user gets kinda confused. There are several solutions for this problem:
  • Overwrite the default JSF messages in Messages.properties to not include the field name, but this will make the problem even worse.
  • Write a custom renderer for the messages, but this is about the same as amputating a leg when you've hit your toe against the bed.
  • Or we could just write a correct HTML form element that has, and this is the important bit, a label attribute, as this is what JSF will use in its default validation message. When this isn't present it will default to the id and when this id auto generated, as it usually is, will show something like j_id_id19.
So my collegue's problem was easily solved by adding label attributes to the fields of his form.