How to make a class available to Spring within Tomcat? - java

I'm working with an application which has a modular architecture - each module is contained in a WAR file running on top of Tomcat. One of the modules allows users to extend its functionality with a request Interceptor interface, which is #Autowired into the class by Spring.
I'm working on a custom Interceptor and would like to make it available to Spring for autowiring within the module. Until now I've been building a custom version of the module's WAR which contains my interceptor, but I do not feel that this is a clean approach because the idea was to make the application easily extensible, and building my own fork for this reason seems to almost eliminate the benefits of the Interceptor interface.
I know one possibility is to crack the WAR open (it's just a ZIP archive) and drop a custom JAR in there, but that doesn't feel right either. Perhaps there is a way of adding custom JARs using Maven? Is there an industry-standard way of doing this?

I think I have at least a partial answer, everyone is welcome to provide a better one.
There is a helpful documentation page about class loading in Tomcat. It describes where classes are loaded from, snippets which are most interesting to a casual reader are reproduced below:
unpacked classes and resources in $CATALINA_BASE/lib
JAR files in $CATALINA_BASE/lib
unpacked classes and resources in $CATALINA_HOME/lib
JAR files in $CATALINA_HOME/lib
WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes directory of your web application, plus classes and resources in JAR files under the /WEB-INF/lib directory of your web application, are made visible to this web application, but not to other ones.

Related

What is correct about packaging a Java EE application

I am reading Beginning Java EE 6 with GlassFish 3 and I am confused about what is correct about packaging a Java EE application.
EJBs Lite can be pacakaged directly in a war or in a jar file. If you need to use the full EJB specification (e.g., remote interface, JMS, asynchrounous calls...) you have to packaged it inot a jar, not a war.
What does this mean? If I deploy an application packaged as a WAR in Glassfish, doesn't it give me all the Java EE services? If so what am I missing.
I understand that 3.1 introduced a new profile EJB Lite which is intended to be a subset of the full specification was targeted to implementors which doesn't want to implement everything, and that you from 3.1 can package EJBs in the WAR and use the services specified by the EJB Lite spec. But if you deploy a WAR in a full spec container it should give you everything as it would if you had created a JAR? Isn't a WAR just another name for a JAR? The distinction can't be on how it is packaged but what it actually supports?
Could somebody clarify.
The motivation of putting EJB logic beans in JAR files comes from a separation between business logic and view logic. At this time, as far as I am aware, there is no need to package all the EJBs into JAR and then combine this JAR with a WAR into EAR.
But... since EJBs are supposed to concentrate only on business logic, it makes sense to package them in a separate archive. WAR on the other hand is an archive of all things related to showing the GUI to the user, so JSPs, Facelets, images, CSS files and JavaScript libraries. WAR files can have a set of Classes in a WEB-INF\classes folder, as well as their own libraries in WEB-INF\lib. WAR file does not have to be a file, anyway. WAR file can become an exploded WAR, basically a directory with the same structure as it was in the archive.
A key aspect of that comes to class loader isolation in the class loader hierarchy. The WAR module has access to resources in EJB archive (JAR) and EJB module can reference and access resources (libraries) in the EAR file itself. The other direction, specifically an access to WAR resources from EJB module, is prohibited. And it is that way by design, as it prevents the developers - working under pressure - to mix those concerns and create a spaghetti code. Business Logic should be separated from View Logic, as it can and should be reused by Java SE clients, different Web Module clients, JAX-RS or within SOA based solution. If the business logic had any dependencies among JSFs or Servlets, using them in Java SE desktop solution would be impossible.
So, having a structure of EJB archive, which consists of many JAR and WAR files may not be necessary, but it is a best practice and one should be careful and concious about violating that rule.

How to run one JSF WAR file in second JSF project?

I am working on project in JSF, using Tomcat 7. The application will have two parts - the presentation and the administration, main part is about the administration. What I want to do is to create something like a web library.
To have this more clear, I'll try to show structure of the project:
The main application project (let's call it admin) that is builed into WAR file.
Second project using the first one (let's call it presentation).
Presentation is using the admin WAR file.
both projects are typical JSFs - admin has pages, beans, etc.
In NetBeans, I have no problem with adding WAR file as a library, but, there are two things. The first: are all ManagedBeans in admin initialized together with presentation run, so I can use them in presentation? The second: how do I access pages from presentation that are located in admin?
Maybe I am wrong about this idea and I should use different way how to achieve this - so just tell me please.
Also, I probably will not be able to deploy two war files and run them - most of the hostings where the application will run allow deploying of one WAR file only.
Make it a common JAR instead of WAR, so that you can include it in both WARs. This way you can share managed beans and templates between both WARs. The Facelets resources can just be placed in /META-INF/resources of the JAR. The JSF artifacts like managed beans will be auto-discovered if you provide a /META-INF/faces-config.xml file.
See also:
Structure for multiple JSF projects with shared code

Why prefer /WEB-INF/lib to /META-INF/MANIFEST.MF for webapps?

I wonder why Java webapps specifications imposed a specific directory for dependencies: /WEB-INF/lib.
Indeed, why don't use classic /META-INF/MANIFEST.MF file?
Someone will tell that webapps are so more secure because libs are physically integrated in WAR file.
But, if we think so, we could wonder :
Why for a simple Java application (simple JAR), there's no special directory for dependencies? It could be also more secure because no risk to have a wrong classpath (modified improperly for instance) in manifest file.
Other will tell that webapp is designed to be portable, so benefit of /WEB-INF/lib is to not worry about links dependencies.
I'm curious to know your opinions on the subject.
A jar is a standard library. For normal utility jars its probably better to keep them separate. If a library has a dependency on a different library and you need that dependent library more then once you would waste space, memory and maybe incorporte problems to due different library versions.
The web application however is an application bundle. You have to make sure that everythings works so you add the required libraries.
Because the WEB-INF/lib makes for a very easy, self contained package of libraries and simplifies the entire deploy for the most common use cases.
/WEB-INF/web.xml
/WEB-INF/lib/utils.jar
/WEB-INF/classes/com/example/Servlet.class
/page.jsp
That's a full boat WAR right there, and with Servlet 3.0, the web.xml is basically empty. Simple layout, trivial to create, and a stand alone artifact to work with in the end.

How does a web server/container treat a POJO in respect to other classes like EJB's and Entities?

I'm trying to use plain old java objects(POJO)'s and regular class files where needed and only use EJBs when I need the functionality that they add such as asynchronous calls, pooling, etc. I'm wondering how the server treats this behavior once the project is deployed on a server. Since it is not managed by the container does a new instance have to be created for every stateless session bean pooled that might call one of it's methods? How do things like static methods or state affect this model.
Edit:
1) I can clarify more. The point of Java EE is that you annotate a POJO with #stateless etc so that a container can manage it. You don't have to declare a new instance of a stateless bean you just inject and can make calls to it's type.
2) Most Java EE tutorials and books never mention non annotated classes as a part of your business logic. It's never brought up. This seems strange to me if you can use them in Java EE projects for your business logic and it can get deployed on a server. If you don't need pooling or asynchronous access--the things that a container helps manager through an EJB then you can use theses regular POJO's in your Java EE project.
3) that leads me to my question which is how do I incorporate properly into a project? Do I put them in the EJB project that's connected to an EAR or should they go in the EAR? or Dynamic web project. There is almost no mention or instruction on proper use of regular objects like this. When it gets compiled into a WAR for deployment are there any issues you run into on the server? Isn't it expecting properly annotated EJBs, servlets or JSP?
The don't affect it at all. Classes are classes, objects are objects. They're no managed, they're not interfered with, nothing happens to them. They're not special is any way.
Static singletons are static singletons, Java is java.
All you need to be aware of is the classloader layout of your container, and how it relates to your deployed applications and resources. (Classes in one app can't see classes in another app, for example.) Most of the time it's not really important. Sometimes, it is, as things get more complicated.
But for the most part, it's just Java.
Addenda:
A better way to look at this is to simply group your classes up in to blocks of locality.
Let's take a simple web app that uses EJBs.
The web app is deployed in a WAR artifact, and the EJBs can be deployed separately, as individual EJBs in the container, or, more likely, in an EAR. When you package your application in an EAR, you will likely bundle the WAR within the EAR as well. So, in the end the EAR contains your WAR, and your EJBs.
Now during development, in this case, you're going to have classes that have are in one of three categories.
Classes that are relevant solely to the EJBs (for example the Session Beans).
Classes that are relevant solely to the WARs (such as a Servlet class).
Classes that are relevant to both (a database entity perhaps).
So, a simple way to package them is in three jar files. A jar file for your WAR (in fact, this is the WAR, with the classes in WEB-INF/classes), a jar file for your EJBs, and a jar file for the 3rd type, we'll call that a library.
In terms of build dependency, the WAR build depends on the lib, and the EJB build depends on the lib. But neither the WAR nor EJB depend on each other, as they don't share anything directly, only indirectly through the 3rd library jar. The lib jar is stand alone, since it doesn't have any dependency on either the WAR or EJBs. Note, your EJB Session Bean interface classes will go in to the library jar (since both tiers rely upon them).
In your ear, you simply bundle the lib jar, the WAR, and the EJB jar along with a META-INF dir and an application.xml file. The WAR has its own structure, with the WEB-INF and all, the EJB jar has its META-INF and ejb-jar.xml. But of note is the that lib.jar is NOT in the WEB-INF/lib directory, it's in the EAR bundle and thus shared by both the EJBs and the WAR using class loader chicanery that the container is responsible for.
This is important to note. For example, if you have, say, a simple static Singleton in your lib jar, then BOTH the WAR and EJBs will share that Singleton, since they're all part of the same class loader. To use that Singleton, it's just normal Java. Nothing special there.
If the EJB and WAR were deployed separately, they would EACH need there own copy of the lib.jar, and in the case of the Singleton, they would NOT share it, since each module would have it's own class loader.
So, barring some real burning need otherwise, it's easier to bundle everything in to an EAR and treat both the EJB tier and WAR tier as a single, integrated application.
Addenda 2:
People don't much talk about using classes in Java EE development because there's nothing to talk about, they just use them, like in any Java program. You're over thinking this here.
The 3 jar idiom: war, ejb, lib is one I've used over the years because it separates the 3 concerns, and limits dependencies. Client -> lib -> EJB. It also simplifies the build, since clients typically need just the lib jar and java. In the Netbeans IDE, this is trivial to manage. With minor work, it's straightforward in other IDEs or even in ant/maven. It's not a huge burden, but keeps the 3 parts relatively clean.
Dependency and Jar management is the nightmare of any large Java project, and even more so with EJB when you're dealing with the different deployable artifacts. Anything that can help mitigate that is a win, in my book, and truth is, a clean, stand alone lib jar helps a lot, especially of you need to integrate and use that lib with other code. For example, if you later write an external GUI client using Remote EJBs, or even web services, the lib jar is the only dependency that client has. The benefits of this jar far outweigh the minor pain it takes to set up this kind of library.
In the end the lib jar is just a jar like any other jar you'd want to use in your application (like logging or any other popular 3rd party jars).

If I put EJB's in an EAR file, should I put the entity classes in there, a seperate jar, or the web app?

If I put EJB's in there on EAR file should I put the entity classes in there, a seperate jar, or the web app?
Thanks.
I don't think they should go in the web app, because I believe that class loader fires after the EJB class loader. If I'm correct, your EJB will fail because it can't find what it needs.
As for the JAR versus EJB, that would be determined by your requirements for sharing entity classes. Put them in the EJB if they're only needed by one EJB; put them in a separate JAR if they're shared.

Categories

Resources