Oct 31, 2012

JSF 1.2 w/ Facelets on Websphere 6.1: Compiler Initialization Error

I believe this issue isn't specifically related to WebSphere but either way I wanted to list my technology stack for those Googling:
  
WebSphere Portal 6.1 on  
WebSphere Application Server 7.0  
JSF 1.2_15 
Facelets 1.1.14 
Spring Web Flow 2.1.3
Spring 3.1.2  
I had a nice demo working fine on my local Windows machine, but when I went to deploy to our test environment I ran into this error:
Compiler Initialization Error
java.util.zip.ZipException: error in opening zip file
 at java.util.zip.ZipFile.open(Native Method)
 at java.util.zip.ZipFile.<init>(ZipFile.java:137)
 at java.util.jar.JarFile.<init>(JarFile.java:149)
 at java.util.jar.JarFile.<init>(JarFile.java:86)
 at com.sun.facelets.util.Classpath.getAlternativeJarFile(Classpath.java:204)
 at com.sun.facelets.util.Classpath.search(Classpath.java:74)
 at com.sun.facelets.compiler.TagLibraryConfig.loadImplicit(TagLibraryConfig.java:428)
Without getting into the details of the hours I spent debugging, I found out that the system was actually running out of file handles. Now this could be because the differing system is Linux vs Windows or it could be because the Classpath contained many more shared libraries that needed scanning to look for *.taglib.xml files in the META-INF directories. I downloaded the source and found the source of the problem here:
 public static URL[] search(ClassLoader cl, String prefix, String suffix) throws IOException {
  Enumeration[] e = new Enumeration[] {
    cl.getResources(prefix),
    cl.getResources(prefix + "MANIFEST.MF")
   };
  Set all = new LinkedHashSet();
  URL url;
  URLConnection conn;
  JarFile jarFile;
  for (int i = 0, s = e.length; i < s; ++i) {
   while (e[i].hasMoreElements()) {
    url = (URL) e[i].nextElement();
    conn = url.openConnection();
    conn.setUseCaches(false);
    conn.setDefaultUseCaches(false);
    if (conn instanceof JarURLConnection) {
     jarFile = ((JarURLConnection) conn).getJarFile();
    } else {
     jarFile = getAlternativeJarFile(url);
    }
    if (jarFile != null) {
     searchJar(cl, all, jarFile, prefix, suffix);
    } else {
     boolean searchDone = searchDir(all, new File(URLDecoder.decode(url.getFile(), "UTF-8")), suffix);
     if (!searchDone)
     {
      searchFromURL(all, prefix, suffix, url);
     }
    }
   }
  }
  URL[] urlArray = (URL[]) all.toArray(new URL[all.size()]);
  return urlArray;
 }
The error looks like it originates in the getAlternativeJarFile method but that is just because it gets called soooo many times during this for/while loop. The simple fix is to release the jarFile immediately after it has been used like so:
...
if (jarFile != null) {
  searchJar(cl, all, jarFile, prefix, suffix);
  jarFile.close();
  jarFile = null;
} else {
...
}
...
I made the change, deployed to my test server again and everything worked perfect. Now for a long term solution? I'm not sure what I'm going to do. I have read that I can possibly increase the number of allowable open file handles (see here) which may be ok since this only happens on startup and will release them all after it finishes. Problem is the admins of this box are stingy and I doubt they'll want to change this in production too.... hmmmm.....

Oct 19, 2012

Eclipse m2e Nexus Index

I recently got in a fight with Eclipse Juno and the m2e plugin. Read entire post or skip to end read summary of what I learned.

The pom.xml editor's dependency tab would show "0 results" no matter what I typed in when I tried to add a dependency.

I had ran into this before so thinking I was smart I immediately went to Window -> Preferences -> Maven to check the "Automatically download indexes on startup" checkbox only to find that it was already checked. Normally I would just check this, restart eclipse and everything would be fine.

A quick Google pointed me to a view that I had never used before just because I hadn't needed too. I went to Window -> Show View... -> Maven -> Maven Repositories. This view shows your repositories as they are configured in your settings.xml and allows you to Update or Rebuild Indexes for them.

I tried the Update and Rebuild commands only to find that my error log kept repeating the same message "Unable to update index for nexus: http://.....". This was showing up in the Error Log view and also in my .metadata/.log file with no other details.

More Google-ing pointed me to a ton of proxy issues; however, they were older posts. I spent forever turning on/off proxy settings in Window -> Preferences... -> General -> Network Connections trying every variation possible that I found even though I think the issues the posts were referring too had long since been solved.

I found out that it's possible for your index to get corrupt somehow in Eclipse. To fix this you are supposed to delete .metadata/.plugins/org.eclipse.m2e.core/nexus directory while Eclipse is not running and then when Eclipse starts, m2e will rebuild it. This didn't help me either. I kept getting the same "Unable to update index" messages.

While digging around in the Eclipse sub-directories I saw a org.eclipse.m2e.logback.config directory. Looking in there I saw that not only does it log to the Eclipse .metadata/.log but also to another file (0.log in the same directory in my case). Looking in there I finally figured out the actual cause of the error "401 unauthorized". Finally, I was on to something.

I tried entering the URL that m2e was attempting to access into my browser and everything worked fine. Again, I started thinking proxy issues like maybe my browser was doing something different than m2e. To figure out exactly what it was doing I used Wireshark to sniff the packets and saw that m2e was sending a HTTP GET request with BASIC authentication set. The response was a 401 unathorized from a Tomcat server stating I needed HTTP authentication.

I turned to my settings.xml to find that my <servers> were defined with encrypted passwords which I did not have the master password set up for (see Maven documentation for more information). I don't need those passwords since I don't deploy anyways so I removed them... no luck. Sniffing the packets still showed that BASIC auth was being sent. So I also removed the usernames from the <servers> and voila! My indexes started updating.

I don't remember this happening in the past so something must have changed with m2e. I'm too lazy to look through the codebase and compare (and I don't know what the old version was I used to use) so I can only speculate that m2e used to not try sending authentication if only usernames were specified without passwords in the <servers> section of settings.xml.

So my problem was finally fixed and along the way I learned a few things about m2e.

  1. There is a handy Maven Repositories view
  2. It stores indexes in org.eclipse.m2e.core/nexus
  3. It logs more details in org.eclipse.m2e.logback.config
  4. It will use HTTP BASIC authentication for repositories that have an username AND/OR a password defined in the <servers> section of settings.xml