Tuesday, April 26, 2005

JavaDoc library

Found this today while perusing the available eclipse plug-ins: http://www.javadoconline.com/. Google finds things every time, but this looks pretty convenient. Strangely enough :) there is an eclipse plug-in that will link to and search the site by clicking on a java element in your workspace.

Monday, April 25, 2005

m2 for Maven users

I have been working through trying to get m2 to work with my latest projects because I do want to use Maven and I think it might be simpler for others to pick up than Maven1. But there has been plenty of frustration and confusion along the way.

There is still no DTD or XSD for any of the config files, which drives me batty. But, at least this time, you'll get a somewhat helpful error message when you screw up. Something along the lines of 'we wanted to find a tag here, but we found this text instead'. In general, that's the only improvement I've seen in error messages. You still have to hunt and peck if it's anything else that's gone wrong.

There's this concept of 'scope' for dependencies. I'll admit it's a really good idea. I don't need junit files or my mock objects jar in my deployed war. But either I don't quite get it, or they don't work as they should. First of all, out of the four scopes, one of them is called 'build' and one is called 'compile'. I've yet to figure out what the difference is there. I guess it doesn't matter because I soon found out that if I set my dependency scope to 'build', none of my dependencies were included in the compile classpath. I had to set them all to compile for it to, well, compile. And even that was a trick. For every dependency it sees, it not only tries to fetch the artifact, but an associated .pom file. That's great if you've got a common thing that resides in the central repository. It's not so great for things like the JavaMail jar (which cannot be legally hosted on ibiblio). For that and a few others, I had to put together my own pom and put it in the appropriate repository directory. Yeesh!

They've changed the repository layout as well. I understand what they're trying to do, but I don't like it. I just end up having to navigate through a lot more directories. Instead of groupId/jars, the pattern is groupId/artifactId/version/. Like I said, I get it, but I don't like it yet.

They have made it easier for newbies to understand, "what do I type to create a jar", etc. Rather than needing to remember a plugin and/or goal name, you just need to know which "phase" of the project you want to execute. I believe there are five phases, and if you execute one, you execute all of it's predecessors. To name a few from memory, there's compile, test, and package. Just type 'm2 package' and your jar, war, whatever will be compiled, tested, and packaged into your desired archive format. You can also still access plugins and goals directly, but they have to be configured in your pom.xml. I haven't gone there yet, so I can't speak to how much pain that will be.

Other low impact, but noticeable changes:
- project.xml has been replaced with pom.xml
- I'm pretty sure it's impossible to set your 'home' to anything other than "user.home/.m2"
- no more build.properties, project.properties, etc. Instead, there is a settings.xml file that resides in user.home/.m2 directory. So far, mine looks something like this:

<settings>
<profiles>
<profile>
<active>true</active>
<localRepository>/develop/repository</localRepository>
</profile>
</profiles>
</settings>

That's all I have for now. I am using it for two very simple projects that only produce .jar files. For this type of project, the only real pain involved is getting all the files available in the repository.

I have a couple of web projects that are still using Ant. I'm sure the process there will not fit into the m2 "box". However, I noticed that they released tech preview 2 today, which can hook into Ant tasks. Maybe I'll have to see what that's about next.

Wednesday, April 06, 2005

mystery NullPointerException from Hibernate

So, I spent the entire weekend on what was expected to be a fairly simple application bug. See, there is this page that displays a list of summary information about Thingies. Each Thingie has several other associated objects such as Thing-a-ma-bobs, etc. If you went to the page and hit refresh in your browser several times, you would eventually get a NullPointerException (that went unhandled, by the way). Hit refresh again, the listing of Thingies would display. Hit refresh a few more times and you'd probably get the Exception again.

The thought was that Hibernate (or this application's implementation of Hibernate) had a leak somewhere or was just doing too much dang work to display this screen. The application owners wanted to reduce the amount of work for this page, likely by not loading all the associated objects (what the geeks like to call 'lazy-loading').

Well, I tried that. And the Exception still happened. With the need to understand what the real problem was so I could actually fix it, I spent plenty of time getting the code setup in my workspace. I mean a _L_O_T_ of time. Cyclic dependencies and duplicate classes abound. Ick. Multiple properties files with some correct database information and some INcorrect database information. Which was correct? Oh yeah, and did I mention I was grabbing the code from the WRONG directory for the first few hours? Oy! Just because you see the name of the app in a directory name does not mean that's the correct directory. Several hours later, it was ready. And then: I couldn't reproduce the problem. Double check-checked jar versions and all was identical. Okay, what's different? Well, the entire operating system for one. JVM versions were the same (though from different vendors). There was the fact that Eclipse debugging is a dog on my desktop, so it could just be a timing issue. My slow machine could be slowing it down just enough to appear like everything was okay.

So, with the code on my machine and the problem observable on the (ahem) Windows server with only FTP access, I set about adding logs here and there and manually uploading changed class files as needed. The fact that the FTP server dropped my connection after about 7 seconds of inactivity was an added "bonus". The added logs told me nothing I didn't already know. Tried running Tomcat in profiling mode on the server. The problem went away! That made me think it's gotta be a race condition buried somewhere. Profiling slowed things down enough that it no longer stepped on itself. Then I thought, "Well, let's prove or disprove that the code being called from this page is actually the problem". I created a load test to repeatedly call the module 50 times each on 5 different threads. Worked great on my machine. Worked great on the server. Why didn't I think of this earlier?!?

It can't be just that code, then. It's got to be a combination of things. I double-checked the application flow and there wasn't much else going on outside of the load-tested method.....just some basic Struts stuff. Now, this particular server is painfully out-of-date as far as Tomcat is concerned. Hmmmm....could be. I downloaded a close-to-latest version and "installed" it on the server. I began configuration, then realized that the port would be blocked and I wouldn't be able to run it. (Even if I had the rights, I'm no network admin.) What I didn't think of (and am kicking myself) was to shut down the other Tomcat instance and use it's port for the test. Anyway, I left 'upgrade Tomcat' as my last words in the effort to fix the problem. Know what? pssst....(that was it)

I guess the lesson here is that if you're using the "next big thing" persistence framework, everyone assumes you're using the nearly latest servlet engine. Otherwise, Google would've helped me out a long time ago. To all you other poor saps out there, I hope the magical 'G' will find this post and it will help you.