Skip to content

Webtop customizations and a java.lang.NoClassDefFoundError

So, a few weeks back, I was working with a webtop customization (webtop is a web interface to Documentum). We were getting a weird error whenever we tried to access it. When I showed details, I saw this message:

com/documentum/web/formext/action/IActionPrecondition

After closing this window, press the Refresh or Reload button on your browser to continue.

Hide Details

Stack Trace:

java.lang.NoClassDefFoundError: com/documentum/web/formext/action/IActionPrecondition at java.lang.ClassLoader.defineClass(Ljava.lang.String;[BIILjava.security.ProtectionDomain;)Ljava.lang.Class;(Unknown Source)
at java.security.SecureClassLoader.defineClass(Ljava.lang.String;[BIILjava.security.CodeSource;)Ljava.lang.Class;(SecureClassLoader.java:123)
...

We spent the better part of the day debugging it. The IActionPrecondition class was in the WEB-INF/classes directory of the webtop web app. It looked just the same as it had before (no recent modifications). When we commented out the Precondition, we didn’t see this error, but still couldn’t use the customization. It happened on Unix and on Windows.

We were msytified, and ended up having to go back to a system that worked, then move forward very slowly until the system didn’t work, then focus on those changes (all hail CVS).

What we found suprised the heck out of me. Basically, we have a jar file of all the TBOs and documentum utilities that we have to put in the system classpath, because it needs to be loaded when the dfc.jar is loaded. (These are the words of the documentum experts I was working with.) The webtop custom classes were inadvertantly included in this jar file, and were loaded by the system classloader. But some of these classes depended on classes in the webtop web apps classes directly, loaded by that descendant classloader. Hence, the custom classes were couldn’t find their super classes and were invalid. Once we moved the custom webtop classes out of the TBO jar files, everything was good as gold.

I once worked with a colleague who said, rather than calling her a senior software developer, she sometimes felt she should be called a senior classpath debugger. Indeed.

Lesson learned: copying bytes from an OutputStream to an InputStream in Weblogic 8

A few weeks back, I posted about calling one servlet from another, passing a multipart/form-data for submission. I ended up using an HttpURLConnection and POSTing to the second servlet. My target platform was Weblogic 8 on Solaris 8, but I was developing on Windows Server 2003; both had Weblogic running on a Java 1.4 platform.

I set both the doOutput and doInput properties of the connection to true, so I can first post the needed data and then read the response, which I can parse and pass on to the user. Here’s the setup:

    URL url = new URL("http://localhost/myws/myservlet");
    URLConnection con = url.openConnection();
    HttpURLConnection conn = (HttpURLConnection)con;
    conn.setDoOutput(true);
    conn.setDoInput(true);
    conn.setRequestProperty("Content-Type", request.getHeader("Content-Type"));
    conn.setRequestProperty("Cookie", request.getHeader("Cookie"));
    BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
    BufferedOutputStream bos = new BufferedOutputStream(conn.getOutputStream());

I set the Cookie property so that the user does not have to reauthenticate to the second servlet.

However, when I was reading from the first servlet’s InputStream and writing to the second servlet’s OutputStream, I encountered some issues. The below code ran perfectly fine in the development environment, but in the production environment, the file being transferred was corrupted. The corruption happened in a number of ways, actually. At first, the file was about twice the size. Then, after fiddling a bit and moving the bis.close() and bos.close() closer to the write/read, I was able to get the file to be smaller than the posted file. However, it was a zip file and was still corrupt.)

    byte[] data = new byte[1024];
    int res = bis.read(data);
    while (res != -1) {
        bos.write(data);
        res = bis.read(data);
    }
    bos.flush();
    // other stuff, like getting response code
    bis.close();
    bos.close();

You can see that I’m double buffering the InputStream here, first with the BufferedInputStream, and then with my byte array, data[]. That’s apparently unnecessary; I don’t know where I got the idea. It actually leads to loss of data on the Solaris box.

Luckily, the Java Cookbook (and for that matter, the I/O section of the Java Tutorial) suggested code similar to this:

    int res;
    while ((res = bis.read()) != -1) {
        bos.write(res);
    }
    bis.close();
    bos.close();

This code works on both Windows and Solaris. I’m a bit mystified as to why the first byte transfer method worked on Windows but not Solaris, and I thought I’d post this so that any other folks struggling with the same problem don’t endure the debugging that I did.

Singing the praises of vmware

In the past few months, I’ve become a huge fan of vmware, the Workstation in particular. If you’re not familiar with this program, it provides a virtual machine in which you can host an operating system. If you’re developing on Windows, but targeting linux, you can run an emulated machine and deploy your software to it.

The biggest, benefit, however, occurs when starting a project. I remember at a company I worked at a few years ago, I was often one of the first people on a project. Since our technology stack often changed to meet the clients’ needs, I usually had to learn how to install and troubleshoot a new piece of server software (ATG Dynamo, BEA Weblogic, Expresso, etc). After spending a fair amount of time making sure I knew how to install and deploy the new platform, I then wrote up terse yet complete (hopefully) installation documents for the future members of the team as the project rolled into development. Of course, that was not the end of it; there were slight differences in environment and user capability which meant that I was a resource for the rest of the team regarding platform configuration.

These factors made me a strong proponent of server based development, where you buy a high powered box and everyone develops (via CVS, samba or some other network protocol) and deploys (via a virtual server for each developer) to that box. Of course, setting it up is a hassle, but once it’s done, adding new team members is not too much of a hassle. Compare this with setting up a windows box to do java development, and some of the complications that can ensue due to the differing environments.

But vmware changes the equation. Now, I, or someone like me, can create a development platform from scratch that includes everything from the operating system up. Combined with portable hard drives, which have become absurdly cheap (many gig for a few hundred bucks) you can distribute the platform to a new team member in less than hour. He or she can customize it, but if they ruin the image, it’s easy enough to give the developer another copy. No weird operating system problems and no complicated dev server setup. This software saves hours and hours of development time and lets developers focus on code and not configuration. In addition, you can actually do development on an OS with a panoply of tools (Windows) and at the same time test deployment to a serious server OS (a UNIX of some kind).

However, there are still some issues to be aware of. That lack of knowledge often means that regular programmers can’t help debug complicated deployment issues. Perhaps you believe that they shouldn’t need to, but siloing the knowledge in a few people can lead to issues. If they leave, knowledge is lost, and other team members have no place to start when troubleshooting problems. This is, of course, an issue with or without vmware, but with vmware regular developers really don’t even think about the install process; with an install document, they may not fully understand what they’re doing, but probably have a bit more knowledge regarding deployment issues.

One also needs to be more vigilant than ever about keeping everything in version control; if the vmware platforms diverge, you’re back to troubleshooting different machines. Ideally, everyone should mount a local directory as a network drive in vmware and use their own favorite development tools (Eclipse, netbeans, vi, even [shudder] emacs) on the host. Then each team member can deploy on the image and rest assured that, other than the code or configuration under development, they have the exact same deployment environment as everyone else.

In addition, vmware is a hog. This is to be expected, since it has an entire operating system to support, but I’ve found that for any real development, 1 gig of RAM is the absolute minimum. And if you have more than one image running at the same time, 1 gig is not enough. A fast processor is needed as well.

Still, for getting development off to a galloping start, vmware is a fantastic piece of software. Even with the downsides, it’s worth a look.