I need to perform pre- and post-processing of all incomming requests to a web server. The functionality is both url-level access restriction and language translation but also other special cases that need to be handled globaly.
Typically this can be achieved with servlet filters but when the number of web applications grow it becomes desirable not to bundle the filters with every application since all applications need to be rebuilt and re-deployed when making a change to a filter.
Instead I would like to install the filters globally on the server and I have found two possible solutions of which I'm not satisfied with any of them.
On Tomcat it is possible to deploy server-wide filters in the "lib" directory and configure the server web.xml to map them to incoming requests. The problem I see is that any filter dependencies also need to be deployed globally in the lib directory. From what I understand this can cause hard to solve dependency conflicts with installed applications. (Does Tomcat load the same library file into memory twice if they are in two web apps?)
Deploying the filters in a simple web application that mainly acts as a proxy would at least bundle the filters with their corresponding dependencies. This application can then be deployed on the server and take all incoming requests before forwarding them to the target application using the crossContext config parameter. (RequestDispatcher forward between Tomcat instances) However, this requires fiddling with the urls such that all links point to the "proxy".
Neither of these solutions seem to be satisfactory. They are both platform dependent since they rely on Tomcat. They also both seem to have possible problems and require special handling of dependencies.
What is the best practise when using server wide functionality?
This is my untested thought (so not a best practice) - which is a variation of option 2 in your list.
You can use Sitemesh (which is actually meant for decorating your multiple web apps with a common header/footer - but in this case dont use the header/footer).
Host the Sitemesh as a separate web app with crossContext = true.
Sitemesh will be invoked as a Filter for each web app, so the URLs that the end user sees will not change at all. But you will have to define the decortaor.xml for each web app.
You can write your actual Filter processor and chain it after the Sitemesh Filter. All requests will go to the Sitemesh app first - then to your Filter - then to the individual servlet within the web app.
Related
I have two different APIs. They each have their own .war file and are both running on the same tomcat instance.
Strangely, I am able to reach one API with requests like this: https://(ip-address):443/(path1)
but the other responds only to this: http://(ip-address):8090/(path2)
Also complicating things is that, when I deploy the second war to a certain other tomcat instance on another server, it will respond to https 443 requests.
Any idea how this is possible?
This is strange, because at different times either the war or tomcat works as intended (by using https), so it is unclear whether to blame the war or tomcat.
Applications can declare they need confidential connections (HTTPS). Look at the WEB-INF/web.xml inside.
So one of the applications might use both because there is no constraint defined, the other may just respond to https as the container is responsible to ensure secured communication. I'd be more surprised to hear that one of the applications responds to http only.
From https://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Introduction:
One or more such Connectors can be configured as part of a single Service, each forwarding to the associated Engine to perform request processing and create the response.
Check in your server.xml whether you have several services with http and https connectors that are mapping to different engines, and whether the applications are deployed distributed on these different engines. That could explain one application responding to http only, while the other is responding to https only.
I'm working on a web application which is in the form of some war files for the JSF2 front end, some jar files for services, and some shared jars to call the services from the front end, eg
webLayer.war -> serviceUtilities.jar -> service.jar
My problem is that when I try to call a service from the front end using my service utilities (which use reflection to call a service class in a separate jar) I get a class not found exception.
I have worked around the problem by changing the scope of the dependencies in my web project pom.xml from provided to compile, but this is not ideal because I have to build all the relevant projects and then build them into my web layer as libraries.
What I want is to have my web layer wars and service layer jars completely separate so that if I change my service I only need to compile that project. But obviously I still want to be able to access the jars from my war.
Can this be done, and if so how?
Thanks in advance
I believe you are trying to achieve total decoupling between your projets but in an unorthodox way.
First of all, using provided, means that while the library is present at compile time, it will not be added to your deployable (the war in this case) because it is assumed to be present in the platform where you deploy. Think of a similar case when using the servlet api but you do not need it as an explicit dependency at runtime because your servlet container provides it. It does not give you decoupling but a way to prevent dependency duplication. So in your case, the web application and serviceUtilities.jar do not know anything about your service.jar at runtime, while they do at compile time.
It is very difficult to be able to access the jars directly as you say (even using reflection - it is still a binary dependency), while keeping the projects' lifecycle independent.
I think the best way to get total decoupling between layers is to use Rest + Json for communication. You may even be able to deploy your layers in separate nodes. As long as the services contract does not change (the rest urls in this case) you are safe to even switch between different implementations or expose multiple front ends
Your serviceUtilities in the web side will then be replaced by code that uses some rest client library and your service layer will also use some rest service provider to listen to your rest urls. Which technology you use depends on your preference and technology stack. Jersey is the reference implementation for JAX-RS, while you can also easily use spring controllers in the provider side.
I am a bit of a GlassFish beginner, so please forgive my ingnorance on the subject.
Basically we are serving a game website, and to make the client downloadable by our web app we copy it into a directory within domain1. The problem with this is that when redeploying the web app the client downloadable is lost and we have to copy it across again.
I'd like to be able to store the client downloadable in some external location and have GlassFish provide access to it.
I could just hardcode the link into the web app, but then we would lose portability so that's the reason for having GlassFish handle it.
I could also put the client downloadable into our database but that seems like poor use of a database and could also result in poor database performance.
The third option I have found is to add a custom resource mapping from some name to the file location, and then provide a method in one of my beans to retrieve the file location. This seems like a lot of work just to have an external resource, I feel like there must be an easier way.
So what should I do?
With GlassFish you can define an alternate document root to serve files from outside the war. From the documentation:
Alternate Document Roots
An alternate document root (docroot)
allows a web application to serve
requests for certain resources from
outside its own docroot, based on
whether those requests match one (or
more) of the URI patterns of the web
application's alternate docroots.
To specify an alternate docroot for a
web application or a virtual server,
use the alternatedocroot_n property,
where n is a positive integer that
allows specification of more than one.
This property can be a subelement of a
sun-web-app element in the
sun-web.xml file or a virtual server
property. For more information about
these elements, see sun-web-app in
Oracle GlassFish Server 3.0.1
Application Deployment Guide.
So you could configure something like this:
<property name="alternatedocroot_1" value="from=/ext/* dir=/path/to/ext"/>
Refer to the documentation for full details.
The link to your downloadables needn't be in the same application as the game servlets, right?
One solution would be to create a new "pseudo" application containing only a web.xml and your static file content. You would of course not deploy it in war form (well, only if you really want to) but just copy the files into the unpacked directory when you want to change content. I use a setup like this to serve a bunch of files from a Web app server I run.
At work, in an "enterprise" kind of environment, we do things differently. We have an Apache HTTPD server working as the front end. It forwards to the app server for stuff that needs to be done in Java, but any static content, as well as cookie management, SSL, load balancing and other "web server-y" stuff is done by HTTPD. This yields a bit of a performance advantage with heavily loaded sites and lots of big but static files. It also lets us split the work among different physical boxes, which again can help with performance.
I am working on a project where we'd like to pull content from one of our legacy applications, BUT, we'd like to avoid showing the "waiting for www.somehostname.com/someproduct/..." to the user.
We can easily add another domain that points to the same server, but we still have the problem of the someproduct context root in the url. Simply changing the context root is not an option since there are hundreds of hard coded bits in the legacy app that refer to the existing context root.
What I'd like to do is be able to send a request to a different context root (Say /foo/bar.do), and have it actually go to /someproduct/bar.do, (but without a redirect, so the browser still shows /foo/bar.do).
I've found a few URL rewriting options that do something similar, but so far they seem to all be restricted to catching/forwarding requests only to/from the same context root.
Is there any project out there that handles this type of thing? We are using weblogic 10.3 (on legacy app it is weblogic 8). Ideally we could host this as part of the new app, but if we had to, we could also add something to the old app.
Or, is there some completely different solution that would work better that we haven't though of?
Update: I should mention that we already originally suggested using apace with mod_rewrite or something similar, but management/hosting are giving the thumbs down to this solution. :/
Update 2 More information:
The places where the user is able to see the old url / context root have to do with pages/workflows that are loaded from the old app into an iframe in the new app.
So there is really nothing special about the communication between the two apps that client could see, it's plain old HTTPS handled by the browser.
I think you should be able to do this using a fairly simple custom servlet.
At a high level, you'd:
Map the servlet to a mapping like /foo/*
In the servlet's implementation, simply take the request's pathInfo, and use that to make a request to the legacy site (using HttpUrlConnection or the Apache Commons equivalent).
Pipe the response to the client (some processing may be necessary to handle the headers).
Why not front weblogic with Apache.
This is a very standard setup and will bring lots of other advantages also. URL rewriting in apache is extremely well supported and the documentation is excellent.
Don't be put off by the setup it's fairly simple and you can run apache on the same box if necessary.
Using Restlet would allow you to do this. The Redirector object can be used. See here and here for example.
If you instead serve out a JSP page you can use the tag to do the request server side.
Then the user will not even know that the resource was external.
http://java.sun.com/products/jsp/syntax/1.2/syntaxref1214.html
a bit more context for the API the client is working against would help here to give a solution that could work. Are you trying to provide a complete new API totally different from the legacy Java EE app? What artifact is serving the API (Servlet, EJB, REST service)?
If you have the API provided by a different enterprise application then I suppose you simply use a Pojo class to work as a gateway to the legacy app wich of cause can then be reachable via another context root than the new service app. This solution would assume you know all legacy API methods and can map them to the calls for the new API.
For a generic solution where you don't have to worry about what methods are called. I am curious if the proxy approach could really work. Would the user credentials also be served correctly to the legacy system by URL re-writing? Would you have to switch to a different user for the legacy calls instead of using the origin caller? Is that possible with URL re-writing. Not sure if that could work in a secure context.
Maybe you can provide a bit more information here.
What options do you have to communicate between the WARs in an EAR?
We have several WARs providing different webservices deployed within one EAR. For their tasks they need to communicate with the other WARs. Of course they could communicate using webservices. What other, perhaps more efficient, options are there?
EDIT: The reason for the communication is that the modules use some shared functionality, and we want to locate this functionality in only one place, since it requires a significant amount of resources. Also, this requires synchronous communication.
First, you should be clear about what is that you are sharing. You should differentiate between the service and a library.
Library lets you share the common functionality, this is what you achieve when you use log4j library for example. In that case, you setup log4j in each project that is using it.
On the other hand, you could have the centralized logging service that has its own logging configuration and lets you manage this in a single place. In this case, you need to share the service.
You can share the library by placing the jar inside each war or inside the ear.
You can share the service by being the service client. So, your web services can use another service. In that case, one web service is a client of another, achieving service composition (a common pattern in enterprise development)
If both service client and service itself reside inside the same ear, than you might avoid some overhead by calling the service “directly”, for example using the Spring’s parent context feature:
http://springtips.blogspot.com/2007/06/using-shared-parent-application-context.html
but I would advise against flattening the service because you will loose different benefits that having service in the first place provides like governance, manageability etc.
Since your edit seems to imply that the communications are not actually required between WARS, but both need to access the same shared resources. The simplest solution would be to put the jars for this resource in the EAR and add the dependency for those jars to both web projects so they are using the shared resource.
If there is stateful code in both web projects that need to be updated, then your only option is to make a call to the servlet for the web project (assuming the stateful code is contained within the web project).
Just remember that the shared resource must be threadsafe.
Similar question here.
Why not put the common classes into a JAR and work with them directly? Or slightly more heavy weight make the common classes session beans?
Two things come to mind
There's JMS for sending signals.
EJB could record shared information.
A lib jar in the EAR's lib directory.
If you just need shared methods, 3 is what you want. But your edit points tells me you've got shared functionality that operates on shared data. For example, you've got user records that both WARs access and update. If so, you want an EJB.