thenaglecode thenaglecode - 4 months ago 44
Java Question

Hello World Ear: NoModuleFileException: A file does not exist for module element having uri: core-api.jar

I have what is a simple EAR file configured like so:

app.ear
|-- lib/...
|-- META-INF/application.xml
|-- core.jar
| |-- test/MyServiceImpl.class
| `-- META-INF/MANIFEST.MF // Class-Path: core-api.jar
|-- core-api.jar
| `-- test/MyService.class
`-- web.war
`-- META-INF/MANIFEST.MF // Class-Path: core.jar core-api.jar


The application.xml is as follows:

<?xml version="1.0"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" id="app 1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
<application-name>MyApp</application-name>
<display-name>My App</display-name>
<module id="mod 1">
<java>core-api.jar</java>
</module>
<module id="mod 2">
<java>core.jar</java>
</module>
<module id="mod 3">
<web>
<web-uri>web.war</web-uri>
<context-root>/</context-root>
</web>
</module>
<library-directory>lib</library-directory>
</application>


When i attempt to deploy the application to the server, I get the following exception:

[*] 00000088 SystemErr R Caused by: org.eclipse.jst.j2ee.commonarchivecore.internal.exception.NoModuleFileException: A file does not exist for module element having uri: core-api.jar
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.ModuleRefImpl.checkType(ModuleRefImpl.java:591)
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.ModuleRefImpl.initModuleFileFromEAR(ModuleRefImpl.java:167)
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.ModuleRefImpl.getModuleFile(ModuleRefImpl.java:120)
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.EARFileImpl.getModuleFile(EARFileImpl.java:165)
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.EARFileImpl.getDeploymentDescriptor(EARFileImpl.java:817)
[*] 00000088 SystemErr R at org.eclipse.jst.j2ee.commonarchivecore.internal.impl.ModuleRefImpl.getDeploymentDescriptor(ModuleRefImpl.java:230)
[*] 00000088 SystemErr R ... 49 more


I am using Websphere Test Environment v8.5.5.0

UPDATE: I suspected maybe the compression algorithm used to zip the ear file may be to blame and it seems as though I was right; unzipping and rezipping the ear file using 7zip caused the deployment to work without errors.

I am using gradle as a build tool which provides it's own mechanism for zipping archives. I have tried setting the
entryCompression
mode to
ZipEntryCompression.STORED
without success.

This leads me to a new question:


  1. How can i control the assembly/compression of the ear file to conform with what Websphere expects?

    and

  2. What method does gradle use to compress the ear?



UPDATE 2: Looking at the gradle source code, I can see the Zip implementation uses ant's
org.apache.tools.zip.ZipOutputStream
(1.9.3). has anyone had difficulty with this process before?


UPDATE 3: It seems as if I've been chasing a red herring. I have inspected the file that supposedly deployed correctly and saw that the ear contained an extra folder level above the root of the ear (that is
app.ear!app/<root>
).

assuming that compression algorithms have nothing to do with it, does anyone have any ideas?

UPDATE 4: Ok, I'm really close, I managed to get the deployment working after inspecting some sample ear files and testing various theories. I did these things and it worked (see Update 5).


  • Instead of java modules in the application.xml i have ejb modules

  • I included a basic META-INF/ejb-jar.xml file in the core.jar (even though the spec says you don't need them) as websphere apparently does not like it when it's missing

  • I removed the core-api.jar module from the application.xml



So i now have the following application.xml:

<?xml version="1.0"?>
<application ...>
<application-name>MyApp</application-name>
<display-name>My App</display-name>
<module id="mod 1">
<ejb>core.jar</ejb>
</module>
<module id="mod 2">
<web>
<web-uri>web.war</web-uri>
<context-root>/</context-root>
</web>
</module>
<library-directory>lib</library-directory>
</application>


One last question: how can i 'deploy' an artifact to an ear project without adding it to the application xml? alternatively, how can i customize the application.xml after the deployments have been resolved?

UPDATE 5: Apologies for the fluctuating state of my question.

Although the application successfully deployed, it did not start up, giving me an error saying that my ejb jars had no ejbs. I have since decided, following the advice I have received and also an answer below, that my spring-based jars are classed as "utility" jars and should live in the lib folder.

I am expecting to use these jars in EJBs in the future and so wish to keep them in the lib folder instead of directly in the war.

this is my final application.xml:

<?xml version="1.0"?>
<application ...>
<application-name>MyApp</application-name>
<display-name>My App</display-name>
<module>
<web>
<web-uri>web.war</web-uri>
<context-root>/</context-root>
</web>
</module>
<library-directory>lib</library-directory>
</application>


Thank you for your time and patience.

Answer

Well I can see by your application.xml header that you're using JavaEE 6 packaging and you also mentioned you're using WebSphere 8.5.5 so follow some ear packaging information.

You do not need the application.xml at all if you're using annotated EJB 3.x and then follow the standard packaging convention:

app.ear
|-- lib/$UTILITY_JARS_HERE
|-- EJB.jars
|-- web.war

Notice that this is the default packaging for Java EE 6 structures and following this all utility jars that you place inside the lib directory will be available to both the EJBs and WARs you have there so you should use this directory only if your utility jars are required by both EJBs and web applications. If your utility jar is used only by your web application than you should package them inside the standard WEB-INF/lib folder in you war package only.

Now if you're using EJBs 2.x together with your packaging than you'll need to have the application.xml and declare your ejbs and war, you should keep the recommended approach of leaving the utilities jars inside the lib folder and the ones required only by the web layer inside the lib folder of the war package.

If for any reason you want to keep your utilities jars at the root level or the ear you can use the approach of declaring them at the Manifest for the EAR but than you DON'T and can't declare them again in the manifest for the war package. All declared jars on the ear manifest will be automatically visible by the classloader of the war file and EJBs.

The javaEE 6 specifiction Chapter 8 "Application Assembly and Deployment" has the complete explanation on this subject. You can download the document here.