I have a group of static files (mainly the static files, including css and images, that make up the ExtJS JavaScript framework). This group of static files rarely changes and therefore I decided NOT to include them within the items in the web application's war file. (I.e. I didn't follow the approach recommended by this answer.)
Right now I serve all these static files under /extjs by having the following Context container defined in server.xml:
<Context docBase="/path/to/extjs-4.1.1" path="/extjs" />
That "works" so far; still if anyone is able to suggest a better approach please do.
However I can't find a way to add expires HTTP headers to files served by this context.
Any idea how to configure Tomcat7 in this respect?
It doesn't appear that Tomcat's default servlet (org.apache.catalina.servlets.DefaultServlet) has a way to do this.
The easiest thing to do would be to create a servlet filter that simply adds the HTTP headers you need to every request. Since the <context> defines a webapp, you can add a WEB-INF/web.xml file to /extjs and load your filter there. Since /extjs is a separate context, your 'real' application won't be affected.
Related
I have a simple web app that allows the user to upload and access files. When the user accesses an uploaded file, the server needs to support all of the header types such as Accept-Ranges so that partial-content responses can be made on large media files. The DefaultServlet (in Tomcat) handles everything well in its serveResource() method called by doGet(), so I would like to use the DefaultServlet for the uploaded files. This is easy enough in normal circumstances since it is the DEFAULT servlet, but unfortunately for my case, I am unable to find a way to use the default servlet.
In order to prevent the uploaded files from being deleted when the webapp is redeployed, I need to store them outside of the webapp directory.
These files should only be accessible to the user that uploaded them, so I created a javax.servlet.Filter to handle resource access authorization. I know that if I add a new context in server.xml for the external resource directory, they will be accessible, and the DefaultServlet will be used.
<Context docBase="/path/to/resources" path="/resource" />
But I do not want to do that because then I am required to invasively modify server.xml which is not recommended (for reasons), and when a context exists for the /resource path, my filter for that url-mapping will not be invoked. So I do not think creating a new context is a good solution.
The only other solution I can think of would be to create a servlet for all requests at '/resource/*' which extends DefaultServlet, and somehow override functionality that would instead get the requested file at its actual external location rather than returning 404 on the non-existent resource in the webapp.
However, I have not been able to find an easy way to convert the DefaultServlet into one that can fetch files external to the webapp directory. Maybe there is a way?
How would I go about handling this?
Not an answer
In order to prevent the uploaded files from being deleted when the
webapp is redeployed
It means you are re-deploying your stuffs wrong(in a very bad manner), probably using war files, or worse(worst) tomcat manager.
I know that if I add a new context in server.xml for the external
resource directory, they will be accessible, and the DefaultServlet
will be used.
You are right, but you are wrong about having another context, it's not necessary.
Solutions:
Dear Michael-O specified the easiest and probably best answer.
You may also implement something like DefaultServlet too, sometimes(not for your case) it's better to implement things from zer0 rather than configuring and maintaining many too much complex stuffs.
I have a large collection of different independent (stateless) web services written in Java and compiled as WAR files. I want to deploy them to a single web application server.
If the URIs handled by the services in each WAR file began with a prefix I could use as a web app name, then this would be easy. I could, for instance, have
SALES WAR FILE: contains code for the following:
GET http://example.com/sales/widgets
POST http://example.com/sales/widgets
GET http://example.com/sales/sky-hooks
MARKETING WAR FILE: contains code for the following:
GET http://example.com/marketing/widgets
PUT http://example.com/marketing/sky-hooks
...in which case I would simply deploy two WAR files under the names "sales" and "marketing". However, I am not that fortunate. Instead, the URI paths handled by the components overlap. Something like this:
SALES WAR FILE: contains code for the following:
GET http://example.com/widgets/sales
POST http://example.com/widgets/sales
GET http://example.com/sky-hooks/sales
MARKETING WAR FILE: contains code for the following:
GET http://example.com/widgets/marketing
PUT http://example.com/sky-hooks/marketing
My question is how (if at all) I can deploy these on a single web application server.
I am open to suggestions that require a significant amount of work. For instance, my best-so-far idea is to build services that expect a component-name prefix before the regular URI path, then pipe all incoming traffic through a different server that knows what component each URI pattern falls into and modifies the URI to add that prefix. The difficulty with this approach is that tools like Swagger that read my source code will have a mistaken idea of what the URIs look like.
Any ideas?
If you're willing to put apache in front of your web container, you can use apache's mod_proxy to forward request to the right place.
One way this could work, would be deploy the separate wars at separate prefixes as in your first case (sales and marketing) and then use ProxyPass to send the requests to the correct place:
ProxyPass /widget/sales http://example.com/sales/widget
ProxyPass /sky-hooks/sales http://example.com/sales/sky-hooks
ProxyPass /widget/marketing http://example.com/marketing/widget
ProxyPass /sky-hooks/marketing http://example.com/marketing/sky-hooks
Its probably a better idea to just refactor your routing though - it might be hard to maintain.
(EDIT: I originally suggested mod_rewrite, but I wanted to make my answer more specific, and it looks like this could be done purely with proxying)
If I understand your question correctly, one of the solutions would be (I am assuming Tomcat is used but this should apply to most of the modern servlet containers):
1) Deploy your sales and marketing wars with different prefixes. I.e., using your example, they should be able to serve the following urls:
GET http://example.com/sales/widgets/sales
POST http://example.com/sales/widgets/sales
GET http://example.com/sales/sky-hooks/sales
GET http://example.com/marketing/widgets/marketing
PUT http://example.com/marketing/sky-hooks/marketing
2) Use UrlRewriteFilter to craft lightweight web application that will be deployed to your servlet container root prefix (for Tomcat it is called ROOT.war) and will rewrite urls in incoming requests to point to relevant web application.
In other words, incoming request like:
/widgets/sales
will be transformed to:
/sales/widgets/sales
... and delivered to sales webapp.
Similarly, in response urls like:
/sales/widgets/sales
will be rewritten to:
/widgets/sales
3) Deploy this war to root of your servlet container.
This approach is somewhat similar to the one suggested by #nont but does not require apache as a frontend as the rewriting functionality will be handled by root web application (UrlRewriteFilter basically implements mod_rewrite functionality).
In other words you'll be able to deploy all your applications (including this rewrite application that is deployed to the root prefix) to single server alleviating need for extra intermediate proxy/rewrite servers.
First, Determine How the Deployments may be Configured
Are you sure the absolute URIs must overlap? The context root will prefix the path supported by each service, unless the absolute path has somehow been coded into the application itself. The first step is to enable direct access to each WAR file, either through unique context roots or application instances.
Option 1: Set the Context Root for each WAR File Explicitly
The context root for a war file is set at deploy time. For some servers, this can be set outside of the web application using an external deployment descriptor. For Tomcat, it may embedded within META-INF/context.xml. See http://tomcat.apache.org/tomcat-7.0-doc/config/context.html for more information.
Option 2: Separate the Context Root Instances using Multiple Containers
Alternatively, deploy each war file to a separate instance of a Java EE servlet container, each running on a different port. This will solve the deployment conflict in the case of a hard-coded absolute path.
Finally, Set up a Virtual Host and Proxy the Requests via Apache and mod_jk
Once the context roots instances have been made uniquely accessible by one of the previous methods, configure an instance of Apache to serve as a reverse-proxy. First, set up a virtual host to handle requests for the externally visible URI. Next, configure mod_jk to route the requests to the correct WAR file deployment. See http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html for more details.
Afterthoughts
The above solution approach is generic for this type of problem and will require some knowledge of Apache and Tomcat configuration, which were chosen as example reverse-proxy and Java EE servlet technologies for its implementation. Additional detail on the deployment constraints would help to determine an optimal solution. In general, identifying the hard constraints on what may be changed versus what may not be changed should guide you quickly to a solution.
The obvious slotuion is to rename the wars, or refactor so that the appropriate mappings are in the correct place.
Anything else is going to be a bit hacky, you can't change the war name, even to soemthing like below :
SALES WAR FILE: contains code for the following:
GET http://example.com/webapp1/widgets/sales
POST http://example.com/webapp1/widgets/sales
GET http://example.com/webapp1/sky-hooks/sales
MARKETING WAR FILE: contains code for the following:
GET http://example.com/webapp2/widgets/marketing
PUT http://example.com/webapp2/sky-hooks/marketing
You could also create another war for routing/filtering, that redirects everything appropriately - but that also relies on altering url somewhat.
This is a use case for Reverse Proxy. If your web server is Apache, as suggested by #nont proxy_mod can be used to create a reverse proxy.
I know that IBM Http Server (IHS) also allows this mod.
i want to tell my java servlet to ignore calls for static files, for example, if the file exists - just return the actual file without actually loading the servlet.
in my example i have a MyServlet in netbeans, and under the "web pages" directory i placed image.jpg.
next, i generated a .war file and placed it under tomcat/webapps
when i try to make a request to localhost:8080/MyServlet/image.jpg - the file is not loaded, the servlet is executed instead.
what i want is that if the file exists - it will return it, otherwise will run the servlet.
is there a quick way to implement it?
Mapping your servlet to / or /* is not the standard way for implementing servlets. In general you map global (controller) servlets to a path like /myServlet/*. Tomcat's default servlet is already available to serve your static content. It's configured in <tomcat>/conf/web.xml. Extract from inline documentation:
<!-- The default servlet for all web applications, that serves static -->
<!-- resources. It processes all requests that are not mapped to other -->
<!-- servlets with servlet mappings (defined either here or in your own -->
If you follow the above mentioned approach URLs in your application may look like this:
Static resource: http://myserver/myWAR/images/image.gif
Your servlet's URLs: http://myserver/myWAR/myServlet/* (* := wildcard)
Of course, more complex options like offloading static content to an external web server are available. You can override the standard configuration as well, but in most situations this is not necessary (at least in my experience).
Normally you'd handle this via your servlet mapping or by putting your static resources away from your servlet mapping.
Otherwise, if the request is mapping to your servlet, you either need to (a) check for the file in the servlet, and redirect to the real filename or stream back the image yourself, or (b) write a filter that knows enough about your webapp's structure to see if the request should be handled by your servlet, or the container.
If you described your usecase it'd be easier to be more helpful.
For static files you most likely need just to use http://localhost:8080/image.jpg (i.e. without the MyServlet part in the URL)
I've got a Spring Web MVC application (and also a BlazeDS application, though not as relevant) where files are dynamically generated based on certain client actions.
I'd like to just map a certain directory on the file system to Spring MVC (or the app server) url and let it serve the files in that directory (with streaming and standard last-modified header support). Ideally, the mapped directory would be configured via the spring config, since I already have support per-machine for setting that up.
So, how can I do this? The best I can find so far is to write a controller that reads the file manually and streams it byte-by-byte. However, that seems far less than ideal. Is support for something like this already baked into Spring MVC or the standard application server spec?
Thanks!
If your processing model supports it, why not cut the middleman of the filesystem out of the picture completely and just stream the files back through the response stream as they are generated? Take a look at the AbstractExcelView and AbstractPDFView classes of Spring MVC to see some examples of how this is done.
or the standard application server spec?
Yes, there is. As you didn't mention which one you're using, I'll give a Tomcat-targeted answer. All you basically need to do is to add a Context element for /path/to/your/resources in /conf/server.xml:
<Context docBase="/path/to/your/resources" path="/resources" />
This way they'll be accessible through http://example.com/resources/...
Ideal for this is using an lightweight proxying server in front of your appserver, like a nginx or lighthttpd. You can configure it for serving static content, without calling your app.
If directory and files so dynamic, you can prepare real path to file at your controller and give this filepath to the frontend server, using headers. For example for nginx it's a X-Accel-Redirect header. Read more about this (and follow links for other http servers) there
We want to share user validation configuration between a Java validation class (for sanity checking) and a Javascript-enabled form web interface (for usability). What's the best way to deploy this static file in our web application so that it is both available to the server-side code, and available via a URL accessed by the client?
So far I've thought of putting the file in the application root and pointing the validation class at it when it is used, and putting the file in the WEB-INF/classes directory and somehow configuring the container to serve it.
Has anyone else configured a web application like this? What did you end up doing?
Yeah. Put it in the WEB-INF/classes and have a servlet serve out the relevant portion of the validation configurations based on something like a form-id. Better yet, have the servlet transform the configuration into a JSON object and then you can simply include a script tag and start using it :)