1

i got a couple of jars who contains images under /META-INF/resources/

I installed one Apache to balance all Tomcat-Servers.

Now i got a servlet3.0-application who offer those resources to the web.

I dont like tomcat to offer the images, i like apache to bring the images (because of performance).

Can they be extracted to an folder inside of tomcat/work without force tomcat to explode the .war-file?


Example

I got an image under

/opt/tomcat/webapps/MyApp.war!/WEB-INF/lib/LikeButton.jar!/META-INF/resources/like.png

ok, the tomcat serves the like.png to

http:// localhost:8080/MyApp/like.png

But he does not extract the like.png to an real directory!

Grim
  • 1,938
  • 10
  • 56
  • 123
  • It seems like it should work - have you tried it, or are you looking for warnings on why you shouldn't touch that directory? Any reason you can't make your own arbitrary image cache directory from inside your web app? – Brian Henry Nov 15 '12 at 13:01
  • I have tried it. Work folder does not contains the resouces. The image is indirectly a part of the webapp, i like too keep it as an indirectly resource! Beside of this: in some cases .war-archives will not be extracted. So the apache cant even find the images inside the webapplication. – Grim Nov 15 '12 at 13:21
  • I guess I might shy away from using the work folder, as I don't really know when tomcat would be overwriting the files there. But can you 1) grab the resources (on webapp startup) via classloader, or 2) get the contents of the jars via java.util.jar classes, dumping what you need completely outside of tomcat directory structure to be picked up by httpd? – Brian Henry Nov 15 '12 at 13:45

3 Answers3

2

Using Apache (or any other httpd server) over Tomcat just because of performance reasons will not give you any significant performance benefits. But it will add administrative overhead.

Anyway, if you insist you can extract these files yourself:

1) Find the real path of LikeButton.jar:

String relativeWebPath = "/WEB-INF/lib/LikeButton.jar";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File likeButtonJar = new File(absoluteDiskPath);

2) Unzip the files. You can use this tutorial, just add some conditionals against ZipEntry to only extract what you really need.

mindas
  • 26,463
  • 15
  • 97
  • 154
  • Your first link respects the JSR315 (3.6) "..., and in this case MUST return the unpacked location". But Tomcat doesnt. – Grim Dec 28 '12 at 10:57
  • I like to add administrative overhead because of handling the ssl-certificates. The balancer (proxy) of httpd2, integration of awstats and many more. – Grim Dec 28 '12 at 11:00
  • I am actually using this very API (`servletContext.getRealPath("/WEB-INF/...")`) and Tomcat returns me the right folder. What folder does Tomcat return for you? What is the Tomcat version you're using? – mindas Dec 28 '12 at 11:01
  • 7.0.x, different versions. Do you mean getRealPath("/like.png")? it only returns the "....jar!/..." in non-exploded environments! – Grim Dec 28 '12 at 11:16
  • 1
    Ah yes, you're right. In non-exploded environments `getRealPath` returns null for inner files (some app servers have a special flag to make this work but not Tomcat). But you can still try invoking `getRealPath("")` which will point you to the location of your `.war`. The difference then is that you will have to run two unzips: first extract `LikeButton.jar` and then images from it. – mindas Dec 28 '12 at 11:27
  • Ok, what about two different versions of LikeButton.jar? The app-load-order defines the congrete .png, to reproduce the load-order i need extra code+extra performance. If i get rid of getRealPath, i can get the png using Class.getResource() as an Stream like the DefaultServlet does. But there is do difference to the actual JSR315. You may say: you can inherit from DefaultServlet to write the resources to disk. Ok, but i realy dont like this imageine of hack ;D – Grim Dec 28 '12 at 11:31
  • http://stackoverflow.com/questions/8793891/tomcat-starting-webapps-in-a-specific-order – mindas Dec 28 '12 at 11:36
  • 8793891 is nothing to my question, different jars, not different wars. – Grim Dec 28 '12 at 11:40
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/21818/discussion-between-peter-rader-and-mindas) – Grim Dec 28 '12 at 11:41
2

The real question is why you are using Apache httpd in the first place.

I dont like tomcat to offer the images, i like apache to bring the images (because of performance).

If Apache httpd is providing some useful capability, then it's relevant to this question and you should state it. Otherwise, dump httpd altogether and use a properly-configured Tomcat (e.g. use the APR or NIO connectors).

Can they be extracted to an folder inside of tomcat/work without force tomcat to explode the .war-file?

$ unzip MyApp.war -j WEB-INF/lib/LikeButton.jar \
  && \
  unzip -d /var/www/htdocs/ LikeButton.jar '/META-INF/resources/*'

If you have many JAR files within your WAR, you'll have to repeat the above for each of those files.

Better yet, make it a part of your build process to build a static-content directory or ZIP file and then publish those files to the web server. Extracting them form the WAR post-hoc seems like the wrong approach.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • you are right, i should state it. But dont you know these endless discussions? my chief said "no" and this community sais "yes", what should i do? blame my chief and give the 200 points? blame you and accept a answer like "You cant!"? – Grim Dec 28 '12 at 11:05
  • hey i guess the likebutton would be deployed in different versions like LikeButton-1.0.0.jar and LikeButton-1.0.1.jar. If they contains different files i dont know what version will be load on app-start! – Grim Dec 28 '12 at 11:19
  • Anyway i dont think the resources will be load into RAM! So the server need to explode the war, explode the jar inside and serve the png, im pretty sure its more performance overhead than serve from work/folder. – Grim Dec 28 '12 at 11:23
  • 2
    Tomcat performs a lot of resource caching -- you might be surprised. Anyway, building a static content tarball during your build process is, IMO, the best option because you get to make decisions like which JAR's content takes precedence, etc. Only the developer knows that, not the deployer, so extracting from the WAR seems to be problematic. – Christopher Schultz Dec 28 '12 at 14:33
  • As for usefulness of Apache httpd, only you can tell that in your environment. I require reverse proxying which Tomcat does not provide so I do run httpd out front. If you don't need it, get rid of it and do load testing. I'm sure you'll find that Tomcat without httpd performs better than Tomcat with httpd. Again, just make sure you configure properly (use NIO or APR; if you need SSL, definitely use APR). – Christopher Schultz Dec 28 '12 at 14:34
1

There are a few options that I see:

  1. Change your servlet app to be configurable as to where the images shall be referenced from (as you talk about performance, this will also enable you to use any CDN (content delivery network) - delivering the images from a completely different host will be even better for performance). In addition to this you'll need to extract the images to some location available to httpd and configure your app to refer to the respective URL.

  2. Use caching on Apache to request the images once from tomcat, then from cache. This will enable you to flush the cache when you deploy an updated version with different images/resources and in general provide the easiest deployment as - once caching is set up properly - you'll only need to update your servlet app and not touch any static-files storage separately. The downside is that your app needs to provide correct cache-related http-headers, but this might also be counted as a positive aspect: it should do so anyway.

Disclaimer/comment about the performance requirement: in 95% of cases I see the performance argument to be made before any measurement. Most likely the application is fine performance-wise. And if it isn't, serving the images through Apache will probably not be the most effective way to improve performance. What you might do with these changes is, to improve your appserver's performance by 2%, but downgrade the system administration and -development performance by 10% due to improved configuration/deployment complexity.

Apologies if you're within the other 5% and that disclaimer does not apply to your situation, but many others will read this question and I feel it's quite an important aspect to mention.

Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • Sorry i cant accept this as the correct answer to the question itself. Indeed this solves the Problem to 100% and the reputaion is yours. At the end i think the correct answer to the concrete idea is: not implemented and wont be. – Grim Jan 02 '13 at 10:26
  • well, you could technically add something to the deployment process, but you'll have to do this on your own - e.g. customize tomcat or provide your own initialization code that is loaded on startup of your webapplication. I don't like this as it really adds to the complexity, dealing with custom deployment strategies hidden in the app or appserver. However, if you establish some process that does scripted deployment to tomcat, you might use this to your advantage and script not only the deployment to webapps, but also the unzipping of your resources to a location httpd can read. – Olaf Kock Jan 02 '13 at 11:16
  • guess so, i cant create a feature-request without a abstract problem. – Grim Jan 02 '13 at 11:31