(I mistakenly sent this to dev_at_glassfish.org first -- apologies if this comes through twice.)
Hi there,
I just solved something that's been blocking me for a couple of days, and I thought you guys might appreciate knowing about it. First, a reproduction case:
1. Build a deployment plan archive (per
http://docs.sun.com/app/docs/doc/820-7693/gijyb?l=en&a=view) with Maven. The following POM will do:
<project xmlns="
http://maven.apache.org/POM/4.0.0" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.glassfish</groupId>
<artifactId>deployment-plan</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
2. Note the contents of the deployment plan. In my case:
$ jar tf test-environment-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
account.war.sun-web.xml
root.war.sun-web.xml
sun-application.xml
META-INF/maven/
META-INF/maven/ca.grimoire/
META-INF/maven/ca.grimoire/test-environment/
META-INF/maven/ca.grimoire/test-environment/pom.xml
META-INF/maven/ca.grimoire/test-environment/pom.properties
3. Try to deploy an application with this deployment plan.
Under Glassfish 3.0.1, the deploy command fails with
$ bin/asadmin deploy \
--deploymentplan test-environment-1.0-SNAPSHOT.jar \
~/Development/grimoire/grimoire/target/grimoire-1.0-SNAPSHOT.ear
com.sun.enterprise.admin.cli.CommandException: remote failure: Exception while deploying the app : java.lang.NullPointerException
and in the logs, the following stack trace:
[#|2010-08-30T19:58:30.661-0400|SEVERE|glassfish3.0.1|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=21;_ThreadName=Thread-1;|Exception while deploying the app
java.lang.NullPointerException
at com.sun.enterprise.util.shared.ArchivistUtils.copyWithoutClose(ArchivistUtils.java:58)
at com.sun.enterprise.deployment.archivist.Archivist.copyJarElements(Archivist.java:1469)
at com.sun.enterprise.deployment.archivist.Archivist.copyInto(Archivist.java:1670)
I've reproduced the Archivist.copyJarElements here, with annotations:
protected void copyJarElements(ReadableArchive in, WritableArchive out, Vector ignoreList)
throws IOException {
/* entries is generated *by in* -oj */
Enumeration entries = in.entries();
/* ... */
if (entries != null) {
for (; entries.hasMoreElements();) {
String anEntry = (String) entries.nextElement();
if (ignoreList == null || !ignoreList.contains(anEntry)) {
InputStream is = in.getEntry(anEntry);
OutputStream os = out.putNextEntry(anEntry);
/* Oops! 'is' is null here, so copyWithoutClose NPEs out. -oj */
ArchivistUtils.copyWithoutClose(is, os);
is.close();
out.closeEntry();
}
}
}
}
Digging around a bit lead me to com.sun.enterprise.deployment.deploy.shared.DeploymentPlanArchive, the ReadableArchive implementation that handles deployment plans. The entries() and getEntry() methods contain some medium-hairy code designed to munge paths like foo.jar.sun-ejb.xml, and designed specifically to ignore META-INF/MANIFEST.MF. However, Maven's extra archive metadata confuses it in such a way that entries() includes Entry objects for pom.xml and pom.properties, but getEntry() will return null for those entries.
I think this is a bug, but I don't know what the right fix is. It's easy to work around, though: telling maven not to include Maven descriptors in the resulting JAR is simple:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
and, absent those two files (and their containing directories), asadmin deploy is quite happy.
Maybe getEntries() should ignore unexpected files in META-INF? I suspect something like this will happen if you sign your deployment plan, too.
-o