C H A P T E R 4 |
Deploy an Application |
This Sun ONE Application Framework Deploy an Application chapter covers the preparation of a Sun ONE Application Framework application for deployment in most J2EE containers, as well as deployment-time configuration of a Sun ONE Application Framework application.
It assumes general familiarity with Sun ONE Application Framework, as well as Web Application Archive (WAR) files, deployment descriptors, and your J2EE container's specific deployment method.
Note - Sun ONE Application Framework applications can be run in any Servlet 2.2/JSP 1.1-compliant (J2EE 1.2) Web container. |
In addition to packaging a Sun ONE Application Framework application, it must be configured before it can be deployed.
If you are using the Sun ONE Application Framework IDE toolset, all of the following configuration is automatically managed for you.
This section is intended to provide information to developers who want to create Sun ONE Application Framework applications or objects by hand, or for developers who want to understand the details of how the framework operates.
The Sun ONE Application Framework servlet infrastructure established by ApplicationServletBase includes the ability to configure arbitrary properties on each module servlet using reflection. Parameters are specified in the application deployment descriptor (web.xml) as either context or servlet init parameters using a special name format:
<context-param> <param-name>jato:fooapp.main.MainModuleServlet:foo</param-name> <param-value>bar</param-value> </context-param> |
The specified class name might contain an asterisk wild card character to allow parameters to be set on more than one object:
<context-param> <param-name>jato:fooapp.*:foo</param-name> <param-value>bar</param-value> </context-param> |
Each parameter might only contain a single asterisk, and will match any classes whose class name matches the string before and/or after the asterisk.
The class name expression might also be omitted if the parameter should apply to all module servlets:
<context-param> <param-name>jato:enabledLogLevels</param-name> <param-value>ALL</param-value> </context-param> |
To have a parameter set on it, the module servlet class must have a setter method that conforms to the JavaBeans method naming convention. For example, a parameter named foo would cause the servlet to call a method called setFoo() to set the parameter value. The value is converted to the appropriate type for the setter method. If the type cannot be converted, an error message is written to the servlet context indicating the exception.
The following table shows the module servlet parameters that are currently available.
Each module servlet has an associated module URL. This URL is a standard servlet URL path mapping, and must be configured in the application's deployment descriptor (or equivalent). When each page in a Sun ONE Application Framework application is rendered, the Sun ONE Application Framework tag library renders references to the current module's URL into the HTML output, so that submitted forms or activated links return to the module and ViewBean that rendered the original output. Therefore, the module URL for each module must be configured in a standard way that makes it accessible to the Sun ONE Application Framework infrastructure. Additionally, to allow cross-module navigation within the application, the module URLs of each module servlet must be available to each of the other module servlets. Therefore, the module URL is the only module servlet parameter that must be configured before the application can be run.
The moduleURL parameter is configured like other module servlet parameters, but has some additional restrictions, as follows:
Because the moduleURL parameter is used also by the ViewBeans in each module, each of which share the same package name, the moduleURL parameter must be named as follows:
Whereas other module servlet parameters can be configured as either context parameters or servlet init parameters, the moduleURL parameter must be configured as a context parameter (see below for an example). The reason for this restriction is that the moduleURL parameters for each module servlet must be available to all other module servlets.
The URLs rendered into a Sun ONE Application Framework page are relative URLs. Because of the standard Sun ONE Application Framework URL format, which specifies the page name at the end of the URL path, the moduleURL must be configured as follows:
<context-param> <param-name>jato:[app package].[module package].*:moduleURL</param-name> <param-value>../[module package]</param-value> </context-param> |
Similarly, the module servlet URL must be mapped to the following URL:
<servlet-mapping> <servlet-name>[servlet name]</servlet-name> <url-pattern>/[module package]/*</url-pattern> </servlet-mapping> |
Technically, the URL path of the module need not be named after the module package--it could be any arbitrary name. Although this is what is recommended for simplicity, the main constraint is that the URL path used in the moduleURL parameter be the same as that used in the servlet mapping URL pattern.
Given the above rules and assuming the following,
a basic application would have the following deployment descriptor:
Adding a second module named Module2 to this application would result in the following:
Each ViewBean in a Sun ONE Application Framework application has a peer JSP, and the URL of this JSP is referred to as the display URL of the ViewBean. Each ViewBean has a default display URL it expects to use, and this URL is available/settable via the ViewBean.getDefaultDisplayURL() and ViewBean.setDefaultDisplayURL(String) methods. Developers are normally expected to set the default display URL in a ViewBean's constructor.
However, in some cases, it might be useful or necessary to override the default display URL of a ViewBean at application deployment time. In this case, the deployer can set a context parameter in the deployment descriptor that will set the a ViewBean's default display URL at runtime:
This parameter is set using the naming convention established above for module servlet parameters (however, it is not a module servlet parameter):
<context-param> <param-name>jato:fooapp.module1.FooViewBean:defaultDisplayURL</param-name> <param-value>/fooapp/module1/Foo-Alternate.jsp</param-value> </context-param> |
The Sun ONE Application Framework contains a manager object called SQLConnectionManager. An instance of this object will be available to an application from the RequestContext on any given request. The purpose of this class is to make the task of obtaining a JDBC Connection object easier for developers and the built-in Sun ONE Application Framework objects.
The basic usage of the SQLConnectionManager is that callers ask it for a JDBC Connection using what is called a datasource name. This datasource name is an arbitrary, logical name for a pre-configured database connection. This class also standardizes this task regardless of the technique used to obtain the connection. Finally, the class provides a level of indirection that can be useful when switching between development, test, and deployment environments.
In standard Java applications, JDBC Connections are normally obtained via a call to the java.sql.DriverManager. Callers provide a JDBC URL specific to the database they want to use, and the DriverManager matches an available JDBC driver with the specified URL, obtains a database connection from the driver, and returns it to the caller. The caller then uses the connection as long as it wants before closing it.
In Web applications, the use of the DriverManager is highly inefficient because it requires a new database connection to be opened and initialized for each application request that requires database access. However, the JDBC 2.0 Standard Extension (the javax.sql package) defines a standard J2EE mechanism for database connection pooling. This allows connections to be reused over multiple requests, and avoids the inefficiency of repeatedly opening connections to the database.
The JDBC 2.0 Standard Extension provides a JNDI mechanism through which Web application developers can obtain a pooled JDBC Connection object. This mechanism consists of allocating a JNDI context and asking it for a datasource by name. This name, also called a datasource name, is of a standard form which begins with "jdbc/". The idea is that instead of embedding JDBC URLs directly in an application, the application deployer pre-configures a JDBC datasource with all the necessary information--host, protocol, username, password, etc.--and makes it available under a logical datasource name that begins with the prefix "jdbc/". Application developers only reference this logical datasource name, which they assume will be mapped appropriately in whatever container the application is deployed.
Unfortunately, not all containers provide this datasource mechanism, and/or they impose certain limitations on the datasource name. For example, one container might allow arbitrary names after the standard "jdbc/" prefix, where another container might require the addition of the application context name after the prefix. This might not be a problem with an application developed and deployed in the same container; however, it's fairly common for an application to be developed and deployed under different containers, making this situation a potential problem.
This is where the SQLConnectionManager seeks to provide assistance. SQLConnectionManager contains its own datasource mapping mechanism, which allows the developer to use truly arbitrary datasource names in their application, yet still allow these names to be operational within any given container. Additionally, the SQLConnectionManager allows mapping of datasource names to either JNDI datasource names or plain JDBC URLs. This feature allows a Sun ONE Application Framework application to run in a container that does not support the JDBC 2.0 Standard Extension, albeit without the benefit of connection pooling.
In your application, you can obtain a JDBC connection from SQLConnectionManager directly using its getConnection() or obtainConnection() methods. The static obtainConnection() method is used to obtain connections outside of the scope of a request, such as during application initialization. You can also bypass SQLConnectionManager and go directly to a JNDI lookup (or to DriverManager) if you want, but the Sun ONE Application Framework classes that use JDBC, such as QueryModelBase, will always use SQLConnectionManager to obtain database connections.
As mentioned above, the SQLConnectionManager allows either use of plain JDBC URLs (via the JDBC DriverManager) or JNDI datasource names when obtaining a JDBC Connection using an arbitrary datasource name. These two modes are mutually exclusive, and the current mode is selected by calling the SQLConnectionManagerBase.setUsingJNDI(Boolean) static method. This method need only be called once; call this method from the static initializer of your application servlet class.
Calling the setUsingJNDI() method with a value of true will enable JNDI lookups of datasource names. In this mode, all datasource names are assumed to map to JNDI datasource names of the general form "jdbc/...". If the setUsingJNDI() method is called with a value of false, the SQLConnectionManager will assume that datasource names map directly to JDBC URLs, and will attempt to obtain a JDBC Connection directly form the JDBC DriverManager.
Under no circumstances should you use the DriverManager to obtain JDBC connections in a production application! Such usage causes a new database connection to be opened for every use of the connection, and will cause enormous performance and scalability problems with your application. Make sure you use SQLConnectionManager's JNDI lookup mechanism along with a database connection pool in your container when you finally deploy your applications into production.
Either of the above modes assumes that a mapping exists for the provided datasource name. These mappings are set by calling the SQLConnectionManagerBase.addDataSourceMapping(String, String) static method. This method should generally be called from within the static initializer of the application servlet class.
The SQLConnectionManager provides a fallback mechanism if a mapping cannot be found for a given datasource name. If a mapping cannot be found, it assumes that the datasource name is the JNDI datasource name/JDBC URL that should be used to obtain a connection. Therefore, the default mechanism is to use the literal datasource name passed to the SQLConnectionManager. This means that unless the developer adds mappings, the use of SQLConnectionManager is completely transparent.
Packaging of Sun ONE Application Framework applications follows the standard J2EE guidelines for Web Application aRchive files. If you've developed your application by following this guide's recommendations, you need do nothing more than use a JAR or Zip tool to archive your application directory structure into a WAR file. The WEB-INF directory and its peer directories and files should be at the root of the archive. The name of the WAR file is arbitrary, though it needs to have a .war file extension.
After configuring the application as described above, deploying a Sun ONE Application Framework application is no different than deploying any other WAR-based J2EE Web application. J2EE containers differ on the details of deploying such an application; refer to your container's deployment documentation for specifics. However, in many cases, you simply need to copy the WAR file to the container's /webapps directory.
Some additional notes on deployment:
After deploying your Sun ONE Application Framework application, it is available to be accessed by HTTP clients. Sun ONE Application Framework applications use a standard URL format of the following general form:
http://<host + container-specific path>/<servlet context name>/<module name>/<page name>
For example, given the following:
the URL to access the Hello page would be the following:
http://<host + container-specific path>/HelloWorld/greeting/Hello
The base application package name does not factor into the URL. Additionally, the requested page name must exist within the specified module. Trying to access a page outside of the requested module is illegal. For more information, see Cross-Module Navigation.
Many J2EE containers do not impose container-specific paths for access to the servlet engine. For example, Sun ONE Application Server, Apache Tomcat, or Caucho Resin would use the following URL:
http://<host>/HelloWorld/greeting/Hello
However, because some J2EE containers use a multi-tiered architecture with a conventional Web server for external access, the URL might require additional path information. For example, the example URL in iPlanet Application Server 6.x would be this:
http://<host>/NASApp/HelloWorld/greeting/Hello
Cross-module navigation refers to handling a request in one module but responding with a page from another module. This scenario normally arises when moving from one logically related area of the application to another.
For the most part, the Sun ONE Application Framework runtime manages this switch automatically for you, but it is important to understand the basic mechanics. The crucial task in moving across modules is in making sure that the page ultimately rendered to the client contains references back to the module in which that page is contained. Otherwise, a request for a page in a different module would be sent back to the server, causing a security exception. Once a request crosses module boundaries, the target module's servlet will be the next servlet to handle a request from the user. For example, if a user request triggered an event in PageOne of module1, and this event forwarded the request to PageTwo in module2, module2's module servlet would be the servlet to handle the next and all subsequent user requests (until another request crossed another module boundary).
There is one subtlety of which developers should be aware when crossing module boundaries within their applications. Normally, developers use the ViewBeanManager available from the RequestContext to obtain ViewBean references. The ViewBeanManager allows developers to provide a short name for the ViewBean they want to retrieve via the getLocalViewBean() method. However, this method must prepend a package name to the provided name to derive a class name. This package name is always the package name of the module servlet which handled the request. Therefore, it is not possible to obtain a ViewBean from another module using this method; only ViewBeans within the current module are available through this shortcut method. To obtain a reference to a ViewBean in another module, use one of the other ViewBeanManager methods that expects a class or fully-qualified class name.
Copyright © 2003, Sun Microsystems, Inc. All rights reserved.