Make your static content (html, java script, Cascading Style Sheets (CSS) etc.) deployment on IBM WebSphere Application Server (WAS) shareable among different applications by taking advantage of the feature in IBM WAS's application deployment descriptor extension. This is specifically useful if several applications require access to a set of common static files. You can place these files in a directory (can be network file system) and configure each application so that the content deployed outside (external to Web Application Archive (WAR) is accessible to each application.
Usually, the best practice (for performance reason) is to deploy the static content in a front-end Web Server (Apache, IBM HTTP Server (IHS), nginx etc). In this case, we don't have to worry about the application deployment extension feature of WAS. However, if you don't have front-end Web Server but still want to deploy the static content separately (outside of a WAR directory) or have to deal with some unique requirements like the one I'm going to describe below, you can utilise the application deployment extension feature of WAS.
Here is what I am dealing with on one of the migration projects (migrating from front-end IHS to DataPower Gateway).
In the old environment, IHS served the static content, which was deployed under it's DocumentRoot directory. The WAS plug-in for IHS filtered the requests (URLs) and only passed requests for Servlet or JSP to back-end WAS.
Now, as part of the migration project, DataPower Gateway will act as a Proxy as well as load balancer. Even though, Datapower can cache the content and serve to end users, but there is no easy mechanism to deploy the static content there. So, it is decided that WAS is going to serve the static content along with Servlet and JSPs. However, the static content will be packaged and deployed separately.
In addition to that, during the transition period, users must be able to access the application the usual way (request passes through the front-end IHS) as well as the new way (request passes through the front-end Datapower Gateway). This means, IHS should continue to serve the static content for the traffic coming through it and only pass Servlet or JSP related request to back-end WAS.
Here is the requirements in point form:
- User traffic can pass through either one of the available two distinct routes as shown in the diagram below.
- For user requests that pass through front-end DataPower Gateway to WAS, both application and static content are served by WAS.
- For user requests that pass through IHS to WAS, static content is served by IHS and application is served by WAS.
- Static content is packaged and deployed separately.
|
The diagram shows user traffic coming though two different routes. Static contents deployed and served accordingly. |
In order to fulfil the above mentioned requirements, we need to deploy the static content as follows:
- Deploy static content under DocumentRoot directory of IHS and configure WAS plug-in for IHS so that IHS serves static content from within the DocumentRoot directory and only passes requests for dynamic content (like Servelt, JSP etc) to back-end WAS.
- Deploy static content outside of the WAR directory (can be network file system) that is accessible to WAS web container. This is achieved through proper configuration in application deployment descriptor extension file, namely ibm-web-ext.xmi or ibm-web-ext.xml files.
The main focus of this post is to explain how to do the 2nd option (i.e. configure the application deployment descriptor extension file) above. However, we'll also do a quick overview of the 1st option. And we'll do it using a real example. We'll use
DefaultApplication.ear, that ships with WAS and play with it.
First however, let's have quick overview of these extensions.
ibm-web-ext.xmi vs ibm-web-ext.xml
- ibm-web-ext.xmi: IBM extension for Java Enterprise Edition (EE) application deployment descriptor and compatible with pre-Java EE 5 application deployment
- ibm-web-ext.xml: IBM extension for Java EE application deployment descriptor and compatible with Java EE 5 or later application deployment
For more details on compatibility, refer to supported configurations paragraph from
https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/tweb_jspengine.html
extendedDocumentRoot, and
fileServingEnabled are two important properties in ibm-web-ext.xmi or ibm-web-ext.xml that need to be enabled and configured properly in order to support the file-serving (by Servlet) when an application requires access to files that exist outside of the application web application archive (WAR) directory.
Note: there are some other attributes related to extendedDocumentRoot, however, we are not going to discuss about them in this post. Refer to below URLs for details:
Now, it's time to go through a real example and understand the concept. As a working example, we take
DefaultApplication.ear application that ships with IBM WAS, update ibm-web-ext.xmi file accordingly and deploy its static content outside of the WAR directory. I'll also show an example of WAS plug-in for IHS.
DataPower Gateway configuration is out of scope for this blog post.
Note: WAS does not support the modification of deployment descriptor extension parameters through the Administrative Console or wsadmin scripting.
I've put together an Ant based scripting solution, that can update the file serving and extended document root properties in one or more WAR modules within one or more Enterprise Application Archive (EAR). I'll share the scripting solution as well.
Here are the steps to deploy static content outside of WAR
1.
Prepare EAR/WAR file and deploy static content.
Since,
DefaultApplication.ear is built as pre-JEE 5 compatible, we'll need to update the
ibm-web-ext.xmi that is located under WEB-INF directory of it's web module
DefaultWebApplication.war.
Here is look of
DefaultApplication.ear before the changes. As you can see
ibm-web-ext.xmi file located under
WEB-INF directory has attribute
fileServingEnabled="false".
As a part of our update, we'll remove the
index.html and
banner.gif from
DefaultWebApplication.war, update the
ibm-web-ext.xmi and deploy the EAR file and static content.
Here is how the updated
ibm-web-ext.xmi will look like after the changes:
As seen (highlighted above), fileServingEnabled is changed to "true" and fileServingAttribute "extendedDocumentRoot" has been added with value "/opt/ibm/static_contents" |
Once, the ibm-web-ext.xmi is updated, we remove the static content from WAR file and place them under the /opt/ibm/static_contents directory on the server where WAS web container will be able to access them. Recreate the EAR file and Deploy into WAS. Here is how the deployment of static content and EAR looks on server where WAS is running:
Listing of /opt/ibm/static_content:
Listing under Deployed DefaultApplication.ear.ear/DefaultWebApplication.war. As you see, static contents are not there.
Note: If you want to change the ibm-web-ext.xmi or ibm-web-ext.xml file of pre-deployed/running application manually for testing purpose, you need to do it in two locations:
- under <was-install-dir>/profiles/<profile-name>/installedApps/<cell-name>/<app-ear-dir>/<app-war-dir>/WEB-INF
- under <was-install-dir>/profiles/<profile-name>/config/cells/<cell-name>/applications/<app-ear-dir>/deployments/<app-dir>/<app-war-dir>/WEB-INF
Also, note that if it is network deployment environment, then as soon as you do synchronisation from master configuration repository, your manual changes will be overwritten.
2.
Test and Verify
Let's access our default application using the URL: http://<host>:<port>/index.html. As long as we can see the index page with the listing of Snoop, Hello and Hitcount servlets, it is safe to say that the static content is served from the directory defined by
extendedDocRoot property of
fileServingAttributes, because our repackaged and redeployed application does not contain any static content. However, there is another (more official) way to do validate it as well.
We can enable WAS WebContainer Trace to confirm where static content is served from. Here is the trace spec. Detail about the WebContainer trace can be found
here.
You can enable the run-time trace as follows:
Launch and access the WAS administrative console and navigate to:
- Troubleshooting > Logging and tracing > <server-name> Change log detail levels
- Select "Runtime" tab
- Replace the existing "*=info" with the above mentioned trace spec into "Select components and specify a log detail level. ..." text box
- Click "OK"
There is no need to restart the server. Once the trace is enabled, type the application URL (http://<host>:<port>/index.html) again on your browser and access it. As soon as the index page is rendedered on the browser, look the trace file for your WAS. You'll see something like below:
As you can see from the highlighted (in yellow) text above, WAS is able to match and route
/index.html to
/opt/ibm/static_contents/index.html
Serving Static Content From IHS
Since, it is a very general type of deployment, I'm not going to elaborate this topic in detail, but just highlight few things in the context of our requirements above.
As per the requirement above, users whose application traffic passes through IHS, the static content is served by IHS.
Below are the steps:
1) Copy/Deploy static content under directory defined by DocumentRoot in httpd.conf.
Listing of /opt/ibm/HTTPServer/htdocs:
Now, we need to make sure that the WAS plug-in for IHS filters the request correctly so that static content is served directly from IHS.
Fragment of (original) generated plugin-cfg.xml, which passes every request to back-end WAS.
Here is a fragment of modified plugin-cfg.xml, which filters the request. It enforces IHS to serve the content not explicitly listed in given UriGroup.
2.
Test and Verify
Now, let's access our application. This time, we'll use IHS's host and port. IHS in this case is listening on port 80. So, I access it using http://<host>/index.html
Since, I've enabled the trace in my plugin-cfg.xml file, I can see that the index.html and banner.gif is served from IHS itself. See below:
As you can see from the highlighted text above it has failed to match the URI
/index.html and
/banner.gif as expected. However, the browser is able to render the page, means the content is served by IHS.
Above, I explained the concept of extended document root and how to use it in certain scenarios. As I mentioned above, you need to update the IBM extension file for application deployment descriptor to utilise the extended document root feature, however, WAS does not support the modification of deployment descriptor extension parameters through the Administrative Console or wsadmin scripting, so you have to do it manually. It is OK to manually update, if it is just a one or two web modules, what if you have 10 or hundreds of web modules? I have put together
Ant based script just to do that. You can get everything that is required to run the script from GitLab project here:
https://gitlab.com/pppoudel/public_shared/tree/master/extdocroot
You can run the script either using
extDocRootUpdater.sh (Unix) or
extDocRootUpdater.cmd (Windows). Included
README.txt explains some property values that you need to update as per your environment. Here is the content of the
README.txt
Hope, you found this blog post useful while deciding how to manage and deploy static content for your WAS based application serving platform.