Friday, 18 September 2015

Bundle_xyz.jar does not have a META-INF/MANIFEST.MF! Make sure, META-INF and MANIFEST.MF are the first 2 entries in your JAR!

I encountered this during deployment of an OSGI bundle on Karaf.
I needed to change some configuration files in the bundle JAR file, so instead of rebuilding it, I just unpacked it on the remote server, modified the configuration and then archived it using ZIP tool.
After all, that's what I thought a JAR file was, a ZIP file. I had followed the same process hundreds of times on my local setup and had never gotten the error. I thought something was wrong with the server. I thought the user with which I had deployed the JAR and the user with which server process was running were two different users, and since server process did not have the access to the JAR deployed by me, it couldn't read it and hence the error. A well formed possible explanation to make the sense of the things again and leave the burden to someone else.
After a lot of searching and reading I found what was wrong.

JAR file is not a simple ZIP file.

When creating a ZIP file any tool/program simply follows it's own guideline for which entries should be made first in the archive file. Most of the times it would be in alphabetic order where directories appear first.
However in a valid JAR file order of entries is not as loosely defined as in a ZIP file. In a valid JAR file following should be the first 2 entries:

  1. META-INF/
  2. META-INF/MANIFEST.MF
After these 2 entries rest of entries can be in any order.
Entries in a JAR file can be printed using following command :
jar -tf Test.jar

For example running above command on commons-lang-2.6.jar prints following output (I have included only top few lines)

META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/commons/
org/apache/commons/lang/
org/apache/commons/lang/builder/
org/apache/commons/lang/enum/
org/apache/commons/lang/enums/
org/apache/commons/lang/exception/
org/apache/commons/lang/math/
org/apache/commons/lang/mutable/
org/apache/commons/lang/reflect/
org/apache/commons/lang/text/
org/apache/commons/lang/time/
META-INF/LICENSE.txt
META-INF/NOTICE.txt

As you can see first two entries are META-INF/ and META-INF/MANIFEST.MF.

After getting this information, solution is obvious, just build the JAR using the build process that you are using and then deploy it on server.

This rule of first two fixed entries is ignored by many containers but we never know which one will enforce it. Safest way is to manipulate JAR file using the tools provided by the JDK.
The same rule seems to be true for WAR file also, but I have yet to encounter an application server which enforces it.

...till next time

No comments:

Post a Comment