Servlets: forwarding to a resource in a different webapp - java

I'm trying to construct a java web app along modular principles, with some common resources (JSPs, mainly) in one WAR, and some custom resources in another. This means JSPs scattered across different WARs.
Now JavaEE frowns upon this sort of shenanigans, and wants you to put everything in one place. My current workaround to this is to have an Eclipse-triggered Ant script which copies the content of one WAR into the other, but this is not a pleasant solution (it's fragile and too IDE-dependent).
Ideally, what I'd like to be able to do is for a servlet to forward to a JSP located in a different WAR to one in which it is itself deployed. This would allow greater freedom in how I assemble my WARs. However, the RequestDispatcher does not seem to support such things.
Another possibility is to use <c:import>, which does allow resources to be imported from a different WAR (with some caveats). This would probably allow me to have a "hook" JSP in one WAR, which then drags in the required JSP from another. This is a bit clunky, though, and the fact that <c:import> permits it shows that the underlying servlet API does also. But how do I access that functionality via the RequestDispatcher in a servlet?

You can, with the following steps:
obtain the foreign context using ServletContext.getContext(contextPath)
get the RequestDispatcher of the foreign ServletCotnext.
in META-INF/context.xml set crossContext="true" (perhaps tomcat-specific)

Related

How can I run GeoServer without the web frontend?

I am considering switching my applications existing WFS/WMS "SDK" to GeoServer. However my application has a few special requirements.
I must remain in control full of the applications entry point (main(...)).
I cannot introduce any additional interfaces (such as the GeoServer GUI).
Essentially my application just needs an SDK which exposes our data over an HTTP "/wfs" path. We need to avoid any other interfaces or code being added or exposed. This is unfortunately an unavoidable requirement. Also, until now I have little experience in the GeoServer source code as we have been using a different Toolset. I am of course combing through the source, but am having trouble finding the right classes to get started.
In our existing SDK, I am able to programmatically create a Jetty server with a WFS Servlet assigned to our desired path. One class is provided during the Servlet initialisation which handles communication between our code, and the Servlet.
In order to get a similar setup using GeoServer, I am assuming:
I must add org.geoserver.gs-wfs to my pom.xml dependencies
I must run my own Jetty server in my Main function, and programmatically add the WFS module somehow
I do not yet know:
How to initialise and add the gs-wfs module to my own programatically created Jetty server
How to get a shared instance of the Catalog to add / remove the configured data
With specific focus on points 1 and 2 above, how do I initialise an instance of "just" the GeoServer WFS endpoint?
The path you're taking is too complicated (besides, there is no WFS servlet to start with)... the GeoServer war is the packaging of a modular application, with a selection of modules of common usage included in it.
If you want to remove the GUI you simply go into the packaged war file, and remove any jar that starts with "gs-web". Since you want full control, you probably want to remove also the administrative REST interface, thus remove also all jars starting with "gs-rest". That should get you close to an application that can start, and can run.
I say "close" because this operation is not commonly attempted, and there might be some unintended cross-module dependency preventing it to work.
Another possibility is to check-out GeoServer, get into src/web/ap (or clone it) and edit the pom.xml file, removing all dependencies you don't want... rebuild and you'll get a minimized war file with only the necessary jars.
GeoServer is a lot more complex than just a pick and mix bag of jars. If you want to create a single jar WFS server you will need to start with a copy of the specification and probably an understanding of how GeoTools (the underlying library of GeoServer) works, and about a year or two of development time.
Or you could read the GeoServer manual and turn off the GeoServer GUI. Then all you need to do is master the REST API to load data into it.

How to cache objects on Tomcat across several WARs without putting the class-containing JAR into /lib/ext?

How can I cache server-wide (with cache scope spanning multiple WARs on this server) instances of classes from a JAR which is contained binary-identical in several WARs on a web container (server, e. g. Tomcat)?
<EDIT> I want to cache application data across WARs because the data is common to them. (It's a portal project, where it can be useful to share common data across different "views" implemented as different portlets deployed as different WARs, and using a Java object cache is much faster and more simple than using a central data-holding service.) </EDIT>
Is that possible at all? Or is it required to put such a JAR on a path accessed by a common parent classloader, like in /lib/ext ?
See: Java, Classpath, Classloading => Multiple Versions of the same jar/project
See: How does class loading work when the same class exists in different applications on the same server?
See: cast across classloader?
See: What is a serialVersionUID and why should I use it?
Yes, the best option is to put the classes in a class loader that is a parent of the two applications. If by lib/ext you mean JAVA_HOME/lib/ext, then I would not recommend that. Instead, you should put them in CATALINA_HOME/lib directory. See the Shared Library Files section of the documentation, which links to the Class Loader HOW-TO documentation.
You can add common classes (jars) to the shared.loader property in conf/catalina.properties. Those classes are available to all web apps but not tomcat itself.
If you implement a cache around a static singleton, then you would be able to access the objects from different web apps. I don't know if that is best practice however. For example it makes it hard to scale because it makes it impossible to load balance the apps onto many servers.
The answer seems to be "it depends".
If the JAR(s) (or classes) in question do not have dependencies conflicting with other components also deployed on the server, both proposed solutions (CATALINA_HOME/lib/ext/ and CATALINA_HOME/conf/catalina.properties :: shared.loader) should plainly work. Thus both are "correct answers" and I cannot see which one is "more correct" than the other.
However I missed a crucial detail when I first asked the question (but this does not invalidate it): In my case the JAR in question required Spring 4.2.9.RELEASE (and other dependencies), but other relevant WARs deployed on the same server contain and require Spring 3.0.7. (The objects to be cached do not depend on Spring, but the JAR was not designed with this problem in mind, and it also contains other related code depending on Spring which now would be very difficult to separate.)
Generally it should be possible to put into CATALINA_HOME/lib/ext/ what ever you want as long as all already deployed WARs contain everything they need: The "module first / parent last" class loading policy should prevent conflicts, even if (as in this example) Spring 4.2.9 is available to the parent classloader and Spring 3.0.7 is available to the WAR classloader. But it looks somewhat "unclean" and messy to me to mix-up things that way.
Therefore I decided to use the "to-be-cached" object's classloader hash code as the key in a map, in which the cached data are the values. Then all cached data is selected "by classloader" which automatically and transparently ensures assignment compatibility. If there is also another WAR deployed on the server which can change and thus invalidate the cached data, it can remove the whole map from the cache, forcing the "read-access" WARs to reload data on next access.
However this approach DOES NOT allow cross-WAR cacheing: Effectively every WAR will get its own private cache segment.
Another approach would be to deliberately transform all data to cache to/from e. g. JSON so as to get a "naturally global" data type like java.lang.String for the cached data. If chosen from the beginning of the project, to me this seems to be the cleanest way, but if there is already a complex (and generally working) implementation in place, this may cause some work to do.
Comments on this self-answer are welcome!

Share resources in Java web app

I have a Java web app. Over time it has evolved in to what should really be two apps. There are things like CSS and Javacript files though that both ill need. Is there a way to have them shared so I do not need to duplicate these files.
Here is some additonal info:
Java 1.7
Using JSF running in Glassfish 4
If you refactor to 2 web projects say Web1 & Web2, make one of them base Web say Web1 and have other Web2 reference Web1, so you dont have to duplicate and keep them separate as well.
But unless you have a strong reason to split out 2 web projects, its advisable to keep it one if you have shared resources since a lot of shared resources like DB connection objects, services could be commonly pooled and will require relatively lesser resources
Perhaps the best option is to have a third web application, even in another domain (e.g. the Google Hosted Libraries), containing static resources such as CSS, JS, images, etc.
This is very convenient when the site is a huge sets of pages and different sites in the organization. Thus, if you need change to another style sheet or image, just change in one place.

Relative views in view-states within a flow that is loaded from a jar-file

I have a question regarding Spring Web Flow with JSF: How can I teach Spring Web Flow to be able to load relative views like view="pages/view.xhtml" from a jar in the classpath of a tomcat webapp? After some research via google I think, that Web Flow does not support this constellation out of the box.
Maybe some context, to help understanding my question:
- Flows are registered in multiple FlowRegistries (I solved this problem by implementing a custom implementation, which finds all flowRegistries in the Spring Context)
- Flows can reside either as file resource outside the classpath or within a jar in the classpath, i.e. file ressource flows are located somewhere in WEB-INF/conf and they are at the same position within the jar files.
- Views in the flow definitions are adressed relatively to the flow-definition-file
Now you might ask the question why we have both constellations, where the flows can reside. At the moment we are trying to extract from a big bunch of a webapp modules that contain all functionality belonging to a certain domain. The approach is to bundle all artifacts relevant there within a single project that can be built as jar and added to the webapp then.
While it is no problem to load the Spring beans for each jar without knowing where our configuration files are located, the Web Flow causes some problems.
The first problem was, that the flowRegistry is a monolith that cannot be split without doing something before hand. This problem is solved by a custom flow registry.
But now I came to a second problem: Within view states we reference the pages relatively to the flow definition, like described in the documentation:
<view-state id="some-id" view="pages/somepage.xhtml"> ... </view-state>
Now, when I enter such a view state, web flow throws an exception, which tells me that this way is not supported:
A ContextResource is required to get relative view paths within this context;
the resource was ...
Googling around brought up this possible solution:
workaround for webflows in jars
But this workaround is not working as it has a problem with my multiple flow registries.
Another option might be to not put everything into the jar, but I am not sure if that is a better idea. Likely have everything that can be loaded from classpath in the jar and the rest as pure files in a defined structure.
Any ideas? Thank you very much for your efforts and hints.
I found a slight different solution by myself after several hours of trying and debugging my application on how to accomplish the goal of the question.
first thing to change was to advance from Tomcat 6 to Tomcat 7 because of a change in the servlet API spec, that enabled me to solve my problem with slight modifications
I switched from relative referencing in view states to absolute addressing
I changed the directory structure of my jar file to fit to the newer servlet API: all file resources needed for JSF or Spring Webflow needed to be placed in META-INF/resources (see Javadoc of ServletContext look for the method getResource, it specifies what I needed)
These three steps enabled me to completely pack webflows and their resources in jar-files.

EJB 3.1 application deployed as WAR-only: What about ejb-jar.xml?

I have a JavaEE6 application, consisting of Web stuff and EJBs and which is deployed as WAR-only (using EJB3.1). The build is based on Maven. I just read about a new possibility to order the module initialization in Java EE 6 here which i also need for my application. Also, i would like to have an option to define some EJB properties in XML.
Since the example is deployed as an EAR-project the order is defined in the application.xml. But in a WAR-deployed project, there is no application.xml. Now i wonder where i can define such informations? Or is it possible to use an application.xml somehow in a WAR-deployed-app?
EDIT:
Oops i didn't read the module-order-example right, in the first moment i thought it was about in which order the EJBs in my app are loaded. Of course i have only one module in my WAR-app, so ordering makes no sense.
Ok, but as i'm at it, one big question remains (also altered the question title to reflect the change): What about the ejb-jar.xml? Can i somehow define stuff about my EJBs in XML (as its useful for some settings, to avoid recompilation)?
In short, it is not possible with a WAR based deployment.
The module initialization feature of Java EE 6 is meant for initializing different modules of an application in a specific order. The moment you have a WAR based EJB application, you no longer have separate modules for your EJB and Web application. There is just one module - the web application module in a WAR based deployment.
Therefore, if you have to achieve the same feature as the module initialization order, offered in Java EE 6, you'll have to do either of the following:
Separate the EJB into a separate module, and use a EAR based deployment.
This is more or less trickery, as was done in Java EE 5, and you would want to be avoiding it. You might want to code in logic to ensure that the singleton EJBs have been created (assuming that this is due to the use of singletons in your application), before they're utilized in code.
Location of the ejb-jar.xml in a WAR file
The EJB 3.1 specification (in the chapter on Packaging) addresses the issue of the location of the ejb-jar.xml file when deployed in a WAR:
In a .war file, the deployment
descriptor is stored with the name
WEB-INF/ejb-jar.xml.
PS: I haven't tried this style of deployment yet. YMMV.
Side note on EJBs in .wars and ejb-jar.xml processing. As already noted the location is WEB-INF/ejb-jar.xml, but also note that is the only location checked even if there are ejbs jars inside WEB-INF/lib/ -- via standard rules any META-INF/ejb-jar.xml files there are ignored.
The Expert Group was rather split on that one, so if you have a preference it's not too late to send feedback to the EJB 3.1 expert group list for consideration in EJB.next.
My vote was to still allow individual jars to have META-INF/ejb-jar.xml files just as these jars can now have persistence.xmls, beans.xmls, web fragments etc. The larger issue for me was that it is at odds with the Embedded EJB Container API which supports an EAR-style classpath which allows several jars/modules each possibly containing a META-INF/ejb-jar.xml file. The result being if you do use the Embedded API to test a multi-jar ejb app that is composed into a single .war file, you are then faced with the task of merging any ejb-jar.xml data you have into a single ejb-jar.xml for the webapp. Sort of a pain for users.

Categories