I have an Enterprise project (EAR) with one EJB and several web modules, these web modules have lots of classes in common, they are exactly the same for each project, so if I modify one of them I'll have to manually copy the code to the other projects as well. I don't want to put them in my EJB module because they use a lot of front-end related resources.
Is there a way to share these classes between the web projects?
Obs: They also use classes and resources from the EJB module.
Make another module with all commun classes and package it as a Jar. Then add the jar as a dependency to the other project.
Maven should be a good tool for this project.
There is no way to have shared classes outside of a .war which are capable of having web-specific resources injected.
I would refactor the common classes into a separate .jar. You could make them EJBs, or just regular classes. Either way, you won't be able to inject web-specific resources; the classes in .wars will have to pass such things as method parameters. In the case of EJBs, you can't directly pass non-serializable objects like HttpServletRequests; I don't know if that will create a significant impediment.
An EJB .jar can be placed anywhere in the .ear, but if you choose to make a non-EJB .jar, it can be placed in the lib directory of your .ear file. It's also a good place for EJB interfaces, if you aren't writing no-interface EJBs. From the Java EE specification's "Application Assembly and Deployment" chapter:
A .ear file may contain a directory that contains libraries packaged in JAR files. The library-directory element of the .ear file’s deployment descriptor contains the name of this directory. If a library-directory element isn’t specified, or if the .ear file does not contain a deployment descriptor, the directory named lib is used. An empty library-directory element may be used to specify that there is no library directory.
All files in this directory (but not subdirectories) with a .jar extension must be made available to all components packaged in the EAR file, including application clients. These libraries may reference other libraries, either bundled with the application or installed separately, using any of the techniques described herein.
Related
When I use Tomcat,
the common utilities are packaged as JARs in tomcat/lib
because every WAR has its own class loader,
and classes and libs under the WEB-INF/lib directoy of the WAR is not visible to other ones.
When I use Jboss,
the common utilities can packaged not only as JARs in jboss/lib but also as EJB JARs (invoked as services)
When I have some classes as common services, I can put them in JARs as well as EJB JARs.
I have no idea about the difference between JARs and EJB JARs from a usage perspective.
Can anyone guide me to the right path?
The difference is clear when you see the difference between the contents of a JAR vs a EJB JAR. Apart from the source files (compiled) and the manifest that a JAR file has, you'd also need the following (back in the pre-annotation days):
The XML deployment descriptor
The beans
The remote and home interfaces
Dependencies
This tells the container which are the EJBs and their home/remote interfaces so when a request asks for a bean, the container will know which one to invoke. Without these files, there is no way of you telling the containers (except annotations wherever applicable), that this the bean implementing an interface.
More information can be found at this url
I have a JAVA EE Project, containing both EJB and WAR projects inside of it.
I want to be able to access WAR project class from the EJB project class.
I have access the other way ( I can access ejb class from war).
Is that possibble? How can this be done?
Thank's In Advance.
I assume that you have got an EAR with two modules inside, WAR and EJB JAR. As both modules are independent, they shouldn't depend on each other. What you want to do is possible via MANIFEST.MF Class-Path entry in module META-INF folder, but I strongly discourage you to do so.
You can re-factor you application to following structure:
EAR/
ejb-app.jar
war-app.jar
lib/
common-libraries.jar
Just putyour common libraries to separate JAR (regular java project), and add it to ejb-app and war-app classpath.
Alternatively you can implement EJB's in WAR project as they are supported in WAR since Java EE6.
Is there a standard way (i.e. defined by some Java/J2EE/etc. spec) to provide a custom class loader to a Java Servlet Container which should be used to load a WAR file?
On a new project we are extending a large commercial Java software package (Foo) with web services which requires some flexibility of deployment (as separate services, etc). In particular, we want to avoid the necessity to include in each WAR file all of the Foo software dependency Jar files as they are numerous, large, and will be changing with patch/bugfix releases as we develop. Similarly, it is highly undesirable to have to copy all of the dependencies into each Servlet container's "lib" directory.
Ideally, I would like to tell the Java application server that these WAR files must be loaded using a custom class loader which I will provide which automatically includes the Foo software dependency Jars. Something like this (in Java-pseudocode):
public class MyWarFileClassLoader extends ClassLoader {
protected URLClassLoader urlcl;
public MyWarFileClassLoader(File warFile) {
File installDir = System.getEnv("FOO_HOME");
List<File> fooEntries = new File(installDir, "jars").listFiles("*.jar");
fooEntries.add(new File(installDir, "resources"));
fooEntries.add(warFile);
this.urlcl = new URLClassLoader(fooEntries);
}
public Class<?> findClass(String name) {
return this.urlcl.findClass(name);
}
}
If there is no standard way to do this, is there a straightforward way to achieve the same goal for several WAR files, regardless of the target Servlet Container?
[Edit]
To put it another way: is there a common pattern for allowing WAR files to manage their own dependencies at runtime instead of relying on the Servlet Container configuration? I could, of course, have the WAR file manifest include a Class-Path attribute but then the entries are still "hardcoded" at build time rather than detected automatically at runtime.
There is no standard way to enforce the use of a particular custom classloader in a Java EE application, to load classes from a predefined source. There is however the ability to bundle libraries within a Java EE application, so that multiple modules (including web-modules residing in WARs) can load and access classes in the bundled libraries.
The Java EE specification allows an Enterprise application deployment (a .ear file) to bundle libraries in a library deployment directory; by default this is the lib directory within a .ear file. These libraries may then be used by multiple web-modules (located in different .war files) within the root of the .ear file. The relevant part of the Java EE 6 specification is Section EE 8.2.1, where the following is stated:
A .ear file may contain a directory that contains libraries packaged in JAR files. The library-directory element of the .ear file’s deployment descriptor contains the name of this directory. If a library-directory element isn’t specified, or if the .ear file does not contain a deployment descriptor, the directory named lib is used. An empty library-directory element may be used to specify that there is no library directory.
All files in this directory (but not subdirectories) with a .jar extension must be made available to all components packaged in the EAR file, including application clients. These libraries may reference other libraries, either bundled with the application or installed separately, using any of the techniques described herein.
It is important to note that all Java EE compliant application servers (WebLogic/WebSphere/JBoss et al) will support deployment of EAR files with bundled libraries. However, there are servlet containers (like Tomcat and Jetty) which do not comply with the entire Java EE specification; such containers will not support deployment of EAR files.
In the event where the libraries are required to be accessed by multiple web modules in a servlet container (either due to the choice of the container or due to a preference for WAR files), you ought to rely on the servlet container support for shared libraries to deploy the WAR files without the libraries. The Java EE specification does not mandate any requirement in this area concerning the use of installed libraries. Some containers support shared libraries better than others, by supporting versioned shared libraries (where deployed applications may use only one version among several), while others (like Tomcat) do not.
I am trying to load some classes that are common to all the web applications of my ear in a java ee 5 application.
I tried to do this by putting the classes (not jar) in
a) directory called "lib"
b) also specifying in application.xml's
<module><java>lib/common.jar</java></module>
and was not successful by either option a or b
but when I jarred the classes into common.jar, I was able to load the classes by method b)
Do both these method need the classes to be jarred ?
what is the difference between providing the classes via the above 2 methods ? why does it seem like there are two ways to specify loading common classes ?
I'm not sure which application server is being referred to here, and the nature of the common.jar file. For now, I'll assume that the application server is any Java EE 5 container, and that the common.jar file is a utility jar (and not an EJB or similar module).
The Java EE 5 Platform Specification actually defines the manner in which library support is to be provided by containers:
A .ear file may contain a directory that contains libraries packaged in JAR files. The library-directory element of the .ear file’s deployment descriptor contains the name of this directory. If a library-directory element isn’t specified, or if the .ear file does not contain a deployment descriptor, the directory named lib is used. An empty library-directory element may be used to specify that there is no library directory.
All files in this directory (but not subdirectories) with a .jar extension must be made available to all components packaged in the EAR file, including application clients. These libraries may reference other libraries, either bundled with the application or installed separately, using any of the techniques described herein.
This does not mean that method B is incorrect, it is the one to be used for application servers like JBoss 4, that did not support the library-directory element in application.xml. I believe, Glassfish also supports the lib directory concept without a corresponding library-directory element.
Coming back to the question, placing classes alone in a directory in the EAR file appears to be supported only in WebLogic Server via the APP-INF\classes structure (needless to say, this is not a platform standard). Hence, it is recommended to jar the common classes and use the application server supported mechanism to make these common classes available to other modules in the application.
I have an ear which consists of 2 war files one containing junit classes and the other one containing actual application classes which are referenced by the junits.
Now when executing the junits i get a java.lang.NoClassDefFoundError
Is it due to the junit class files are located in different ear and hence not able to access the application class files that are located in another ear ?
OR
Whether this is due to the issue with deployment, Though i am able to run the application as well as some of the junits which are independent of application classes located in the other ear ?
According to the strict JavaEE visibility semantics, classes inside a WAR should not be visible to other components of the same EAR. JBoss relaxes this a fair bit, and tries to flatten out the classloading hierarchy to make it less irritating, but the WAR restriction still stands.
The solution I use is to put only web resources into the WAR, and to put the WAR's class files into a seperate JAR inside the EAR. That way, the webapp itself can find the classes, and so can your unit test webapp.
The correct way is to move the common classes into a dedicated JAR, and bundle that at the EAR level. So you will have a structure like this:
business-logic-jar
main-web-app-war
test-web-app-war
application-ear
You can bundle the JAR as well as any other libs you depend on in your EAR, and reference them using the manifest file of your WARs. In MANIFEST.MF it looks like:
Class-Path: business-logic-1.0.jar spring-2.5.5.jar ...
You can still bundle additional JARs inside each WAR's WEB-INF/lib folder, e.g. junit inside the test-web-app-war. If you are using Maven, read the skinny war page for a general approach.
JUnit classes don't belong in WAR or EAR files. They shouldn't be deployed.
You don't say which app server you're using, but if you use WebLogic you can put all your .class files into APP-INF/classes. They'll be visible at the EAR level then, so all WARs can see them.