Table of Contents
This chapter describes how to package, deploy, and monitor JEUS web applications.
Web contexts are created when web applications are deployed to web engines. Web applications and web contexts can be considered as the same thing.
This section describes the content and structure of web contexts.
Web applications consist of static and dynamic contents that are required to run web-based services requested by clients.
Before being deployed to web engines, a web context must be packaged into a JAR file, a compressed file with the extension '.war'. The packaged file is called a WAR (Web ARchive) file. The following is the structure of a WAR file.
This directory is optional. If this directory is used, it contains the "MANIFEST.MF" file, a descriptor file defined in the JAR format.
This directory is required. It contains servlets, filters, listener classes, and libraries. The following components are in this directory.
File | Description |
---|---|
web.xml | Java EE web application deployment descriptor file. It contains meta-information about the web application. Starting from Servlet 3.0, web.xml is not a required file. Instead, servlets, filters, and listeners can be added using annotations and the registration API. |
jeus-web-dd.xml | JEUS web application deployment descriptor. Refer to "3.3.1. jeus-web-dd.xml Configurations" for more information. |
ejb-jar.xml jeus-ejb-dd.xml | EJBs that can be included in a WAR file according to the EJB 3.1 definitions of Java EE 6. EJBs can also can be defined as an annotation like servlets. For more information, refer to the EJB standards or "JEUS EJB Guide". |
classes\ | Contains servlet classes and utility classes in its subdirectories. It is organized into a standard Java package structure. |
lib\ | Contains the Java libraries that are required for web applications. The libraries are packaged into JAR files and stored in this path. The files are automatically added to the classpaths of all servlets. |
tlds\ | Contains custom tag library descriptors for JSP pages. |
Directories that contain contents such as JSP, HTML, and image files.
This section describes how to deploy web contexts. Deployment is the process that creates web contexts and prepares them to run on JEUS web engines.
Logically, web contexts exist on a virtual host. For more information about virtual hosts, refer to "Chapter 5. Virtual Hosts".
The web.xml and jeus-web-dd.xml files should only be created under the 'WEB-INF/' directory if necessary.
The following is an example of jeus-web-dd.xml. Refer to "13. jeus-web-dd.xml configuration" of "JEUS XML Reference" for information about items that have been omitted.
[Example 3.1] Web Context Configuration File: <<jeus-web-dd.xml>>
<jeus-web-dd xmlns="http://www.tmaxsoft.com/xml/ns/jeus" version="7.0"> <context-path>/examples</context-path> <enable-jsp>true</enable-jsp> <auto-reload> <enable-reload>true</enable-reload> <check-on-demand>true</check-on-demand> </auto-reload> <added-classpath> <class-path>/home/user1/libs/lib.jar</class-path> </added-classpath> <session-config> . . . </session-config> <async-config> <async-timeout-millis>600000</async-timeout-millis> <background-thread-pool> <min>0</min> <max>10</max> </background-thread-pool> <dispatch-thread-pool> <min>0</min> <max>10</max> </dispatch-thread-pool> </async-config> <properties> <property> <key>jeus.servlet.jsp.modern</key> <value>true</value> </property> </properties> </jeus-web-dd>
The following table describes the configuration tags.
Tag | Description |
---|---|
<context-path> | Context root path. This must begin with a "/". The path must be unique within the virtual host. In the URL "http://www.foo.com/examples/index.html", the context path is “/examples”. |
<enable-jsp> | If set to false, JSP will not be used. By default, JSP is supported. |
<user-log> | User logs that are created by web applications through the servlet context's log method. For more information, refer to Section 1.6.10, “Configuring User Logs”. |
<auto-reload> | Option to automatically reload servlet classes and custom tag classes when they are modified. Refer to "Chapter 9. Reloading Classes at Runtime". |
<added-classpath> | List of libraries that are referenced when a servlet program is compiled or executed. Can use directories. |
<allow-indexing> | Displays the list of URLs where the directory list is displayed upon client request. The directory list is displayed when the file requested by a client does not exist. Clicking on a file in the directory list will show the file contents. |
<deny-download> | Filter that defines resources that cannot be accessed or downloaded directly. These filters are file name extensions. Can use paths that include file names. File names and directories are specified as relative paths to the directory context document base. |
<aliasing> | Directory mapping for custom URL paths. This can be used to map a directory that is in a different location from the URL request path. |
<file-caching> | Determines the static contents that will be cached in the runtime memory to improve response times. Child configurations include the maximum size of cache memory in megabytes, the maximum size of static content in cache, and the path to the contents that will be cached. |
<jsp-engine> | Setting for JSP pages that are included in the web contexts. Refer to "4.4.2. Configuring jeus-web-dd.xml" for more information about <jsp-engine>. |
<session-config> | Sessions that are used in the context. This has a higher priority than the web engine configurations. For more information about configuring sessions, refer to "1.6.9. Sessions". |
<webinf-first> | Option for class loading priority. If this is set to 'true', classes in WEB-INF will be loaded first for this application. |
<attach-stacktrace-on-error> | Option to display the error details in the browser if an error occurs on the server. The message can be helpful in a development environment, but it is not recommend for use in a production environment. |
<keep-alive-error-response-codes> | Error code that will send a Keep-Alive response instead of a Connection: Close. It is applied when the error is sent by the web application itself, but not when the engine decides that the connection needs to be terminated internally. For example, it is applied when a servlet implements a response.sendError(500) but not applied when the engine sends the 500 error because an exception occured in the servlet. If multiple response codes need to be configured, separate them with a "," as in "404, 505". |
<encoding> | Encoding configuration for requests and responses. This is the same as the web engine configuration(domain.xml) but has a higher priority. For more information refer to "1.6.5. Encoding".
|
<cookie-policy> | Policy that is applied when reading cookies from an HTTP request header or adding new cookies to an HTTP response header according to the application request. For more information, refer to "1.6.8. Cookie Policy". |
<async-config> | Async processing that was added in Servlet 3.0. Child configurations such as async timeout, background thread pool, and dispatch thread pool can be configured. For more information, refer to the servlet standards. |
<web-security> | Configuration group of security policies that are limited to web applications including the policy configuration of address validation when using sendRedirect. |
<properties> | Properties that apply to the web application. These properties only apply to the application that they are configured for. |
The default value of <async-config><async-timeout-millis> is 30 seconds. If an error occurs because an operation performed by a background thread is taking too long, set this value in the jeus-web-dd.xml or adjust the timeout in the program code by using the javax.servlet.AsyncContext#setTimeout() method.
This guide does not cover web context redeployment.
For more information, refer to JEUS Applications & Deployment Guide. "2.2. Graceful Redeployment".
Shared libraries can be added to the 'JEUS_HOME/lib/shared' directory instead of the 'WEB-INF/lib' directory so that they can be shared by multiple applications. When modifying the libraries.xml file and redeploying the module, the updated libraries will be applied without restarting JEUS.
To add a shared library, add the <library> tag and configure the JAR files to share in the 'JEUS_HOME\lib\shared\libraries.xml' file as in the following example.
The specification version and the implementation class version can each be configured.
[Example 3.2] Adding Shared Library References: <<libraries.xml>>
<libraries xmlns="http://www.tmaxsoft.com/xml/ns/jeus"> <!-- DO NOT MODIFY JSF1.2 and JSTL1.2 libraries!!! --> <library> <library-name>jsf</library-name> <specification-version>1.2</specification-version> <implementation-version>1.2_06</implementation-version> <files dir="."> <include name="jsf-injection-provider.jar"/> </files> <files dir="jsf_ri_1.2"/> </library> <library> <library-name>jsf</library-name> <specification-version>2.0</specification-version> <implementation-version>2.0.0</implementation-version> <files dir="."> <include name="jsf-injection-provider.jar"/> <include name="jsf-weld-integration.jar"/> </files> <files dir="jsf_ri_2.0"/> </library> <library> <library-name>jstl</library-name> <specification-version>1.2</specification-version> <implementation-version>1.2</implementation-version> <files dir="jstl_1.2"/> </library> <!-- Add user libraries from here --> <library> <library-name>myLibrary</library-name> <specification-version>2.0</specification-version> <implementation-version>2.1</implementation-version> <files dir="."> <include name="commons-logging.jar"/> <include name="commons-util.jar"/> </files> <files dir="myLib-2.1"/> </library> </libraries>
To reference the configured shared libraries, set <library-ref> in jeus-web-dd.xml as in the following. If the version is not specified, the highest version of the library that is registered in libraries.xml will be referenced.
<library-ref> <library-name>myLibrary</library-name> <specification-version>2.0</specification-version> </library-ref>
In the libraries.xml file described in [Example 3.2], JSF and JSTL are added as shared libraries. Since the Java EE standard includes JSF and JSTL, they are provided in JEUS by default.
The libraries can be provided by JEUS, but this will only allow one each of JSF and JSTL implementation class to be used. Since JSF implementation class has multiple versions besides 2.0, including 1.2, Apache myfaces, and SUN RI, JEUS provides the JSF and JSTL as shared libraries so that multiple implementations can be used.
The implementation classes are classified by their locations and types as in the following.
JSF or JSTL implementation class in WEB-INF/lib.
Implementation classes in shared library. (This has a lower priority)
[Warning]
The following describes the changes have been made starting from JEUS 7 Fix#2.
Starting from this version, the Oracle JSF RI is not automatically added to the 'JEUS_HOME/lib/shared' directory. To use it, explicitly configure the <library-ref> setting in jeus-web-dd.xml.
Use the following declaration to use the libraries included in the 'JEUS_HOME/lib/shared' directory.
<library-ref> <library-name>jsf</library-name> </library-ref>
Also, JEUS has been modified to not automatically add the web listener included in Oracle JSF RI 2.x. It must be configured in the <listener> setting of web.xml.
<listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener>
To share the same JSF or JSTL libraries in multiple applications, manually configure the <library> setting in 'JEUS_HOME/lib/shared/libraries.xml' and that <library-ref> setting in jeus-web-dd.xml.
For JSF, the resources provided by WAS must be accessible from managed beans by using annotations such as @EJB and @Resource and WAS must be able to inject the resources that are specified by the annotations.
JEUS provides 'jsf-injection-provider.jar' as a shared library to support the injection of JEUS to JSF RI. The shared library exists in the following directory.
JEUS_HOME/lib/shared
The library is automatically included if web.xml contains the javax.faces.webapp.FacesServlet class.
A web context can be configured to resolve compatibility issues with previous versions JEUS or another WAS.
Prior to Servlet 2.4, many standards were not described properly. They were supplemented over the course of servlet 2.4 and 2.5 releases and this naturally resulted in restrictions being created in JEUS. To resolve these issues, JEUS started supporting non-standard operations. Due to such reasons, JEUS 4 web applications may not be compatible with JEUS 6.
JEUS must comply with servlet and JSP standards, and also ensure compatibility with the existing applications, but these requirements can cause conflicts. Usually when the javax.servlet standard API or internal operation is modified to comply with the standard, problems may arise if there are applications that were created based on the previous faulty operation. In this situation, the applications must be modified since compliance requirements have a higher precedence. Otherwise, the applications cannot run in other containers, and they may conflict with frameworks that comply with the servlet standards when the applications are upgraded.
If such issues are not identified in advance until the official start of the services, this may require the modification of JEUS operations instead of user applications. To resolve this, JEUS provides properties that can be configured for compatibility with previous versions.
For more information about compatibility of JSP engines and JEUS properties, refer to "4.4.3. Web Context Options for JSP Backward Compatibility" and JEUS Reference Book. "1.6.3.3. Properties for Compatibility".
Before Servlet 2.4, web applications were developed using servlets and JSPs directly, but a web framework is now being used. Starting from Java EE 5, JSF and JSTL libraries have been added to the standard web frameworks. Most web frameworks use Tomcat, a reference implementation class for servlet and JSP specifications, for development and testing. This may cause compatibility issues if the web frameworks support non-standard functions.
Compatibility can be configured selectively in jeus-web-dd.xml when there is a compatibility problem. For more information about configuring jeus-web-dd.xml, refer to JEUS Reference Book. "1.6. Web Engine Properties".
Separate configurations are required to use the following additional functions provided by JEUS.
Servlet Mapping for Static Resources
Registering mvc:default-servlet-handler in Spring 3.0 or later
Registering ProgressListener when Servlet 3.0 Multipart function is used.
The servlet standard specifies that the default servlet, which is provided by WAS, is used for a request that is neither a servlet nor JSP. The default servlet is called a ResourceServlet.
Map jeus.servlet.servlets.ResourceServlet to the <servlet-mapping> setting in web.xml as in the following.
[Example 3.3] Servlet Mapping for Static Resources: <<web.xml>>
<servlet-mapping> <servlet-name>jeus.servlet.servlets.ResourceServlet</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping>
From JEUS v7.0 Fix#2, the mvc:default-servlet-handler does not need to be registered in Spring 3.0 or later. Like Tomcat, JEUS default servlet is provided in the name of "default".
In JEUS v7.0 Fix#1, register it in web.xml as in the folllowing.
Since Spring calls ServletContext.getNamedDispatcher() with the name "default", JEUS ResourceServlet is used.
[Example 3.4] Registering ResourceServlet for Spring 3.0 mvc:default-servlet-handler in JEUS 7 Fix#1: <<web.xml>>
<servlet> <servlet-name>default</servlet-name> <servlet-class>jeus.servlet.servlets.ResourceServlet</servlet-class> </servlet>
Starting from Servlet 3.0, the multipart-config can be configured per servlet to assign the web container to process multipart/form-data of the POST request. A progressListener must be registered to trigger an event about the processing progress.
The jeus.servlet.engine.multipart.ProgressListener interface which is included in the jeus-servlet.jar file must be implemented. For information about the interface, refer to the Servlet API document.
Add the instance of the previous interface implementation class to the HttpServletRequest attribute using the same name as the interface, jeus.servlet.engine.multipart.ProgressListener. Note that this must be done before getPart(), getParts(), or getParameter() is called.
This section describes configuring web security for each application in jeus-web-dd.xml.
Applications can send the 302 Found response message by using the standard API javax.servlet.http.HttpServletResponse.sendRedirect(String location). In this case, the location parameter value will be converted to URL and set to the location header without checking the value. This allows users with malicious intent to use attacks like CRLF injection. To prevent this, applications can implement the jeus.servlet.security.RedirectStrategy interface and configure it in jeus-web-dd.xml.
The following is an example of configuring the jeus.servlet.security.RedirectStrategy interface.
[Example 3.5] Redirect Location Security Configuration Interface: <<RedirectStrategy>>
package jeus.servlet.security; import javax.servlet.http.HttpServletRequest; public interface RedirectStrategy { /** * Makes the redirect URL. * * @param location the target URL to redirect to, for example "/login" */ String makeRedirectURL(HttpServletRequest request, String location) throws IllegalArgumentException; }
This interface can be implemented as in the following.
[Example 3.6] Redirect Location Security Configuration Implementation Example: <<RejectCrlfRedirectStrategy>>
package jeus.servlet.security; import javax.servlet.http.HttpServletRequest; public class RejectCrlfRedirectStrategy implements RedirectStrategy { private Pattern CR_OR_LF = Pattern.compile("\\r|\\n"); @Override String String makeRedirectURL(HttpServletRequest request, String location) throws IllegalArgumentException { if (CR_OR_LF.matcher(location).find()) { throw new IllegalArgumentException("invalid characters (CR/LF) in redirect location"); } return makeAbsolute(location); } private String makeAbsolute(String location) { // make code for make absolute path } }
Jeus-web-dd.xml can be configured as in the following.
[Example 3.7] Redirect Location Security Configuration: <<jeus-web-dd.xml>>
... <web-security> <redirect-strategy-ref> jeus.servlet.security.RejectCrlfRedirectStrategy </redirect-strategy-ref> </web-security> ..
The <redirect-strategy-ref> setting is set to an implementation class of the jeus.servlet.security.RedirectStrategy interface. This class must be included in the web application class path.
The jeus.servlet.security.RejectCrlfRedirectStrategy class is a default RedirectStrategy provided. If a location that contains CR, LF, or CRLF character is sent to the sendRedirect API, an HTTP 500 error will occur.
In addition, the jeus.servlet.security.RemoveCrlfRedirectStrategy method that replaces CR, LF, or CRLF with an empty string is provided.
This section describes how to apply the security roles that are defined in web.xml to system users and groups. This mapping is described in jeus-web-dd.xml.
The following is a sample web.xml file.
[Example 3.8] Mapping Security Roles: <<web.xml>>
<web-app> <security-role> <role-name>manager</role-name> </security-role> <security-role> <role-name>developer</role-name> </security-role> <servlet> . . . </servlet> <security-constraint> <web-resource-collection> <web-resource-name> MyResource </web-resource-name> <url-pattern>/jsp/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>manager</role-name> </auth-constraint> </security-constraint> </web-app>
In the previous example, two security roles are declared in
bold. The third bolded element shows how the manager role is used in the
<security-constraint> tag.
The previous mapping can be defined in jeus-web-dd.xml as in the following.
[Example 3.9] Mapping Security Roles: <<jeus-web-dd.xml>>
<jeus-web-dd xmlns="http://www.tmaxsoft.com/xml/ns/jeus" version="7.0"> . . . <role-mapping> <role-permission> <principal>Peter</principal> <role>manager</role> </role-permission> <role-permission> <principal>Linda</principal> <role>developer</role> </role-permission> </role-mapping> . . . </jeus-web-dd>
When applications are deployed in a production environment, the manager and developer roles must be bound to a special user in the system.
This mapping is defined in the <context><role-mapping> setting. The <role-mapping> tag contains the <role-permission> tag which can be used to define the <principal-to-role> mapping.
The following child tags are also bound.
Tag | Description |
---|---|
<role>(1, required) | <role-name> value defined in web.xml. The <role-name> is "manager" in the previous example. |
<principal>(0 or more than 0) | User name linked to the <role-name> and managed by JEUS. For more information, refer to JEUS Security Guide. "3.3. Configuring Web Module Security". |
Two roles, "manager" and "developer", are mapped to "Peter" and "Linda", respectively.
Since the roles are mapped to the actual users, EJB references, resource references, and managed object references must also be mapped to the actual system resources.
The following is an example of symbolic reference mapping.
[Example 3.10] Mapping Symbolic References: <<web.xml>>
<web-app> . . . <ejb-ref> <ejb-ref-name>ejb/account</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <home>com.mycompany.AccountHome</home> <remote>com.mycompany.Account</remote> </ejb-ref> <resource-ref> <res-ref-name>jdbc/EmployeeAppDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref> <resource-env-ref> <resource-env-ref-name> jms/StockQueue </resource-env-ref-name> <resource-env-ref-type> javax.jms.Queue </resource-env-ref-type> </resource-env-ref> . . . </web-app>
To register the web application, all symbolic reference names used in the <ejb-ref>, <resource-ref>, <resource-env-ref> settings of web.xml must be mapped to the JNDI names of the corresponding resources. To map them, add the corresponding <ejb-ref>, <res-ref>, and <res-env-ref> tags in jeus-web-dd.xml.
The tags contain the following child tags.
The following example of jeus-web-dd.xml maps the JNDI names to the aforementioned three references.
[Example 3.11] Mapping Symbolic References: <<jeus-web-dd.xml>>
<jeus-web-dd xmlns="http://www.tmaxsoft.com/xml/ns/jeus" version="7.0"> . . . <ejb-ref> <jndi-info> <ref-name>ejb/account</ref-name> <export-name>AccountEJB</export-name> </jndi-info> </ejb-ref> <res-ref> <jndi-info> <ref-name>jdbc/EmployeeAppDB</ref-name> <export-name>EmployeeDB</export-name> </jndi-info> </res-ref> <res-env-ref> <jndi-info> <ref-name>jms/StockQueue</ref-name> <export-name>StockQueue</export-name> </jndi-info> </res-env-ref> . . . </jeus-web-dd>
Monitoring refers to checking information about web contexts. A list of web contexts that are deployed to the web engine and their current states can be checked in WebAdmin or the console tool.
Web contexts can be checked in WebAdmin using the following steps.
Click [Applications] from the left menu to go to the list of applications in the domain. Click an application ID with the'Application Type' of 'WAR'.
Click a web application ID to go to the web application information screen. The screen contains basic information such as the web application ID, path, type, target information, and options. For more information about the screen, refer to JEUS Applications & Deployment Guide. "4.3.10. Checking for Information about Applications".
Click a server from the 'Running Servers' list on the information screen to view the server details in a new tab.
The following describes each section.
The console tool can be used to monitor web contexts.
To display the web contexts that have been deployed, execute the application-info command as in the following. It displays all information about the web contexts. For more information about the application-info command, refer to JEUS Reference Book. "4.2.6.3. application-info".
application-info -type WAR
To display information about a specific web context, execute the command with the -id <application-id> option as in the following.
application-info -id <application-id>
Controlling a web context refers to changing the state of the web context to modify the service.
WebAdmin or the console tool can be used to reload, suspend, and resume web contexts.
If a deployed web context is changed or the context needs to be reset, the web context can be reloaded instead of being deleted and redeployed.
WebAdmin or the console tool can be used to reload web contexts.
Web contexts can be reloaded in WebAdmin using the following steps.
Click [Applications] to go to the list of applications. Click on an application ID from the application list. Click the desired server from the 'Running Servers' list.
A tab with the server name will be added. Click [reload] next to the web context to view the result.
The console tool can be used to reload web contexts.
Execute the reload-web-context command as in the following. For more information about the reload-web-context command, refer to JEUS Reference Book. "4.2.8.23. reload-web-context".
reload-web-context -ctx <context-name> seccessfully reloaded
To use thread pools provided by JEUS when web contexts are processing asynchronous requests, the relevant information needs to be configured in the <async-config> element of jeus-web-dd.xml. After configuring the <async-config> element, asynchronous thread pool information can be monitored.
The following is an example of configuring jeus-web-dd.xml.
[Example 3.12] <async-config> Configuration : <<jeus-web-dd.xml>>
... <async-config> <dispatch-thread-pool> <min>5</min> <max>20</max> </dispatch-thread-pool> <background-thread-pool> <min>5</min> <max>20</max> </background-thread-pool> <async-timeout-millis>120000</async-timeout-millis> </async-config> ...
The following describes each configuration tag.
Tag | Description |
---|---|
<dispatch-thread-pool> | Minimum and maximum thread pool sizes that are used when AsyncContext#dispatch is invoked. |
<background-thread-pool> | Minimum and the maximum thread pool sizes that are used when AsyncContext#start is invoked. |
<async-timeout-millis> | Standard time for when the web container processes timeout during an asynchronous task execution. This value is returned when an application calls AsyncContext#getTimeout without calling AsyncContext#setTimeout. (Default value: 30000, Unit: ms) |
The async thread pool information can be checked in WebAdmin.
The thread information of web contexts can be checked in WebAdmin using the following steps.
Click [Applications] from the left menu and click on a web application ID from the application list. Click on a server to check from the 'Running Servers' list.
After a tab with the target server name has been added, click [thread-info] of the desired web context to display the [thread-info] in a new tab.
Administrators can suspend a deployed web context that is running, and resume it later. Refer to "3.5.4. Resuming Web Contexts" for detailed information about resuming web contexts.
For information about suspending web contexts in WebAdmin refer to JEUS Applications & Deployment Guide. "4.3.7. Suspending Applications".
The console tool can be used to suspend web contexts.
Execute the suspend-web-component command as in the following. For more information about the suspend-web-component command, refer to JEUS Reference Book. "4.2.8.37. suspend-web-component".
suspend-web-component -ctx <context>
Suspended web contexts can be resumed.
WebAdmin and the console tool can be used to resume suspended web contexts.
For information about resuming suspended web contexts in WebAdmin, refer to JEUS Applications & Deployment Guide. "4.3.6. Starting Applications".
The console tool can be used to resume suspended web contexts.
Execute the resume-web-component command as in the following. For more information about the resume-web-component command, refer to JEUS Reference Book. "4.2.8.32. resume-web-component".
resume-web-component -ctx <context>
Consider the following when tuning web context configurations (jeus-web-dd.xml) for optimal performance.
Increase the user log size and refrain from using "stdout".
Disable the JSP engine when not in use.
Always disable the <enable-reload> and <check-on-demand> options. These options are intended for a development environment where classes are frequently modified.
If possible, use caching. Set as many static content directories in the caching tags as possible. Use a large value for the <max-idle-time> and <max-cache-memory> settings of the cache. They can be set to infinity.
This section describes what application developers must understand about asynchronous processing that has been added starting from servlet 3.0.
Application developers must directly handle the threads due to the nature of asynchronous processing programming, and this may trigger the following errors.
Creating too many threads
Sharing objects that are not supposed to be shared with other threads
Using the javax.servlet.RequestDispatcher class in asynchronous threads
Some of these errors cannot be detected during testing, but they may occur when too much load is incurred in the production environment. Note that the application developers, and not JEUS, are responsible for preventing these errors.
This section is written based on the servlet standard.(It is applicable to other products besides JEUS.)
Creating too many threads reduces the performance of the JVM or causes an OutOfMemoryError to occur. Following is an example of a faulty asynchronous processing programing that creates too many threads.
[Example 3.13] Example of Faulty Asynchronous Processing Program (1)
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/WrongAsyncServlet1", asyncSupported = true)
public class WrongAsyncServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
Thread thread = new Thread(new TestRunnable(asyncContext));
thread.start();
}
private class TestRunnable implements Runnable {
private final AsyncContext asyncContext;
public TestRunnable(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public void run() {
}
}
}
There can be more than thousands of concurrent asynchronous requests, which creates thousands of concurrent threads. This can greatly reduce the performance of the JVM or cause an "OutOfMemoryError: unable to create new native thread" to occur. Therefore, it is recommended to use the javax.servlet.AsyncContext#start(Runnable) method or a thread pool that can be directly managed.
AsyncContext asyncContext = req.startAsync(); asyncContext.start(new TestRunnable(asyncContext));
Sharing unsafe objects that are not supposed to be shared with other threads can reduce the performance, result in a deadlock, or violate data integrity.
The following is an example of a faulty asynchronous program that allows different threads to share unsage objects.
[Example 3.14] Example of Faulty Asynchronous Processing Program (2)
import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(urlPatterns = "/WrongAsyncServlet2", asyncSupported = true) public class WrongAsyncServlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)해 throws ServletException, IOException { AsyncContext asyncContext = req.startAsync(); asyncContext.start(new TestRunnable(asyncContext));밍 byte[] buffer = new byte[1024]; ServletInputStream inputStream = req.getInputStream(); inputStream.read(buffer); ServletOutputStream outputStream = resp.getOutputStream(); outputStream.write(buffer); } private class TestRunnable implements Runnable { private final AsyncContext asyncContext; public TestRunnable(AsyncContext asyncContext) { this.asyncContext = asyncContext; } @Override public void run() { byte[] buffer = new byte[1024]; try { ServletInputStream inputStream = asyncContext.getRequest().getInputStream(); inputStream.read(buffer); } catch (IOException e) { //log error return; } ServletOutputStream outputStream; try { outputStream = asyncContext.getResponse().getOutputStream(); outputStream.write(buffer); } catch (IOException e) { //log error return; } } } }
The previous example shows multiple threads sharing the ServletInputStream, Reader object, the ServletOutputStream that can be obtained from the Response object, or the Writer object. According to the servlet standard, JEUS does not take responsibility for security of such operations. If asynchronous processing, which is started in the filter or the servlet, is transferred to another thread, if possible, the thread must handle the operation instead of the filter or the servlet codes. This can help prevent programming errors caused by incorrect multi-thread programming knowledge, including performance reduction, deadlocks, and data integrity violation.
Use the javax.servlet.ServletRequest#isAsyncStarted() method to check whether asynchronous processing was started from the servlet or the filter which does not directly call the startAsync() method.
Using the javax.servlet.RequestDispatcher class from asynchronous threads can cause the program not to work in the intended way or an exception to occur.
The following is an example of a faulty asynchronous processing program that uses the javax.servlet.RequestDispatcher class from an asynchronous thread.
[Example 3.15] Example of Faulty Asynchronous Processing Program (3)
import javax.servlet.AsyncContext; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(urlPatterns = "/WrongAsyncServlet3", asyncSupported = true) public class WrongAsyncServlet3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { AsyncContext asyncContext = req.startAsync(); asyncContext.start(new TestRunnable(asyncContext)); } private class TestRunnable implements Runnable { private final AsyncContext asyncContext; public TestRunnable(AsyncContext asyncContext) { this.asyncContext = asyncContext; } @Override public void run() { // ...... do something RequestDispatcher requestDispatcher = asyncContext.getRequest().getRequestDispatcher("/views/report.jsp"); try { requestDispatcher.forward(asyncContext.getRequest(), asyncContext.getResponse()); } catch (ServletException e) { // log error } catch (IOException e) { // log error } } } }
The javax.servlet.AsyncContext class provides a way of dispatching from the asynchronous processing thread to another servlet or JSP.
asyncContext.dispatch("/views/report.jsp");
There are other precautions in addition to those for the servlet standard.
When java.util.concurrent.RejectedExecutionException occurs in the thread when AsyncContext.start(Runnable) is invoked.
AsyncContext.start represents a new task. A thread is needed to process the task, and a thread pool is used because there are limited thread resources. If there is no available thread in the thread pool that can process the new task, the task will be accumulated in the queue.
When tasks that require a long time to process cause delays in processing, other tasks are accumulated in the queue. Since the queue has a limited size(Maximum:4096), it may not be able to add a new task when it is full. This will cause java.util.concurrent.RejectedExecutionException to occur. Hence, application developers must consider this issue when programming asynchronous processing.
When the listener, which communicates with a Web server such as WebtoB and Apache, performs asynchronous processing.
A WebtoB or AJP13 listener uses a limited number of TCP connections. If multiple HTTP requests are delivered to WAS from the web server simultaneously, the service may hang. This method was designed for the original synchronous processing model. When the web application server receives an HTTP request from the web server, it transfers the ownership of the TCP connection to the servlet. It is assumed that the servlet will return the HTTP response immediately after processing and return the TCP connection.
But it cannot be assumed that the servlet will immediately return the HTTP response in asynchronous processing. If all the TCP connecctions with the web server are used for asynchronous processing, regular HTTP requests cannot be processed temporarily.
Consider the following solutions to address this problem.
Use reverse proxy through URL mapping for asynchronous requests. The reverse proxy targets an HTTP listener.
Using WebtoB 4.1.6 or later is recommended.
Specify sufficient number of TCP connections to the web server to avoid any asynchronous processing.