Sun ONE Application Framework (JATO)

Deployment Guide

Table of Contents

Introduction

JATO Application Structure

Creating a WAR File

Accessing a JATO Application

Cross-Module Navigation

Configuring a JATO Application

Module Servlet Configuration

General Configuration

Module URL Configuration

ViewBean Display URL Configuration

SQLConnectionManager Configuration

Setting the SQLConnectionManager to use JNDI or the JDBC Driver Manager

Adding Datasource Mappings

If a Datasource Mapping Cannot be Found

Deploying a JATO Application

Interoperating with JATO Applications

Interoperating with JATO from an External Application

Interoperating with JATO from Within the Same Application

Introduction

JATO applications can be run in any Servlet 2.2/JSP 1.1-compliant J2EE container. This document covers the preparation of a JATO application for deployment in most J2EE containers, as well as deployment-time configuration of a JATO application. It assumes general familiarity with JATO as well as Web Application Archive (WAR) files, deployment descriptors, and your J2EE container's specific deployment method.

JATO Application Structure

JATO imposes a certain structure and design pattern for applications that makes creating a scalable and maintainable application easier for developers. JATO applications are comprised of one or more modules. Each module is a functional slice or logical grouping of the overall application, and contains module-specific classes such as ViewBeans and Models. Each module also contains a module servlet, which is directly accessible by clients of the application. At least one module is required in an application, but other modules are optional and may be added at any time. Each module is a sub-package of the base application package.

Each JATO application also defines what we call the application servlet, which is the base class from which each module servlet derives. Only the module servlets are accessed by clients of the application; the application servlet serves only as a common base class for the module servlets, providing the opportunity to consolidate common application-level event handling in a single class. Module servlets allow for module-only specialization of these events. Together, these servlets form the request handling infrastructure of each JATO application.

In general, a JATO application looks like the following:

/Base application package (may be multiple directories deep)
<Application servlet>
    <Other application classes/objects/files>
    /<module 1>
        <Module servlet>
        <Other module classes/objects/files>
    /<module 2>
        <Module servlet>
        <Other module classes/objects/files>
    ...
    /<module n>
        <Module servlet>
        <Other module classes/objects/files>

Each module is a self-contained sub-package of the overall application. Pages and objects in one module can interact with objects in other modules via cross-module navigation and/or simple class references. We cover cross-module navigation later in this document.

Creating a WAR File

JATO applications are packaged like any other J2EE web-tier application in a standard Web Application Archive (WAR) file. JATO applications have certain assumptions as to where certain files will be located within the WAR file. The following is the recommended layout for JATO war files:

/<base application package>
    /<module 1>
        <Module JSP files>
    /<module 2>
        <Module JSP files>
    ...
    /<module n>
        <Module JSP files>
/<other static resources>
/WEB-INF
    jato.tld (the JATO tag library descriptor)
    web.xml (the application deployment descriptor)
    /classes
        /<base application package>
            <Application servlet class>
            <Other application classes/objects/files>
            /<module package 1>
                <Module servlet>
                <Other module classes/objects/files>
            /<module package 2>
                <Module servlet>
                <Other module classes/objects/files>
            ...
            /<module package n>
                <Module servlet>
                <Other module classes/objects/files>
    /lib
        <JATO distribution jar file>
        <other application jar/zip files>

As you can see, there are two parallel directory hierarchies—one for JSP files, and one for module classes. We generally recommend that these two directory hierarchies remain in parallel, although strictly, they need not. Specifically, each ViewBean is configured with the URL of its JSP peer during development, and this URL is arbitrary. However, to avoid naming collisions between modules which may be developed by different groups, we recommend maintaining the parallel directory structure illustrated above.

Accessing a JATO Application

After packaging your JATO application into a WAR file, you will need to access the pages contained within it. JATO applications use a standard URL format of the following general form:

http://<host + container-specific path>/<servlet context name>/<module name>/<page name>

where:

For example, given the following:

the URL to access the Hello page would be the following:

http://<host + container-specific path>/HelloWorld/greeting/Hello

Note that the base application package name doesn't factor into the URL. Also note that the request page name must exist within the specified module. Trying to access a page outside of the requested module is illegal. (We cover more about this below in the discussion about cross-module navigation.)

Many J2EE containers do not impose container-specific paths for access to the servlet engine. For example, Caucho Resin or Apache Tomcat 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 may 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

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, JATO 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.

Configuring a JATO Application

In addition to packaging a JATO application, it must be configured before it can be deployed.

Module Servlet Configuration

General Configuration

The JATO 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:

jato:<class name>:<param name>

For example:

<context-param>
    <param-name>jato:fooapp.module1.Module1Servlet:foo</param-name>
    <param-value>bar</param-value>
</context-param>

The specified class name may 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 may only contain a single asterisk, and will match any classes whose class name matches the string before and/or after the asterisk.

The specified 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 will be converted to the appropriate type for the setter method. If the type cannot be converted, an error message will be written to the servlet context indicating the exception.

The following module servlet parameters are currently available:

Parameter Name Type Description
moduleURL String The URL for the module servlet. See detailed description below.
debug boolean Enables or disables request parameter debug information sent to the servlet context log and the rendered HTML page. Note, some containers may not send this debug output in the client HTML stream.
showMessageBuffer boolean Enables or disables showing the application message buffer at the bottom of the rendered HTML page

Module URL Configuration

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 JATO application is rendered, the JATO tag library renders references to the current module's URL into the HTML output, so that submitted forms or clicked 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 JATO infrastructure. Additionally, in order 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. These restrictions are the following:

Given the above rules and assuming the following,

a basic JATO application would have the following deployment descriptor (including the taglib declaration):

<web-app>
    <context-param>
        <param-name>jato:fooapp.module1.*:moduleURL</param-name>
        <param-value>../module1</param-value>
    </context-param>

    <servlet>
        <servlet-name>Module1Servlet</servlet-name>
        <servlet-class>fooapp.module1.Module1Servlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Module1Servlet</servlet-name>
        <url-pattern>/module1/*</url-pattern>
    </servlet-mapping>

    <taglib>
        <taglib-uri>/WEB-INF/jato.tld</taglib-uri>
        <taglib-location>/WEB-INF/jato.tld</taglib-location>
    </taglib>
</web-app>

Adding a second module named Module2 to this application would result in the following:

<web-app>
    <context-param>
        <param-name>jato:fooapp.module1.*:moduleURL</param-name>
        <param-value>../module1</param-value>
    </context-param>

    <context-param>
        <param-name>jato:fooapp.module2.*:moduleURL</param-name>
        <param-value>../module2</param-value>
    </context-param>

    <servlet>
        <servlet-name>Module1Servlet</servlet-name>
        <servlet-class>fooapp.module1.Module1Servlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Module1Servlet</servlet-name>
        <url-pattern>/module1/*</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>Module2Servlet</servlet-name>
        <servlet-class>fooapp.module2.Module2Servlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Module2Servlet</servlet-name>
        <url-pattern>/module2/*</url-pattern>
    </servlet-mapping>

    <taglib>
        <taglib-uri>/WEB-INF/jato.tld</taglib-uri>
        <taglib-location>/WEB-INF/jato.tld</taglib-location>
    </taglib>
</web-app>

ViewBean Display URL Configuration

Each ViewBean in a JATO 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 may 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:

Parameter Name Type Description
defaultDisplayURL String The display URL for the specified ViewBean

This parameter is set using the naming convention established above for module servlet parameters (but note, 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>

NOTE: We do not generally recommend using this mechanism to override ViewBean display URLs, as it introduces some overhead. Instead, we recommend that the affected ViewBeans be recompiled with the appropriate display URL directly if possible.

SQLConnectionManager Configuration

Each JATO application will typically contain a class called SQLConnectionManagerImpl in its base application package. This class is an application-specific implementation of JATO's SQLConnectionManager interface, and an instance of this manager object will be available in a JATO 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 JATO objects. The basic usage of the SQLConnectionManager is that callers ask it for a JDBC Connection using what's 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 wish 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 wishes 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 may allow arbitrary names after the standard "jdbc/" prefix, where another container may 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 serious problem.

This is where JATO's SQLConnectionManager seeks to provide assistance. The SQLConnectionManager contains its own datasource mapping mechanism, which allows the JATO 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 JATO application to run in a container that doesn't support the JDBC 2.0 Standard Extension, albeit without the benefit of connection pooling.

Setting the SQLConnectionManager to use JNDI or the JDBC DriverManager

As we 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 a JATO 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; we recommend calling this method from the static initializer of your application-specific SQLConnectionManagerImpl class.

Calling the setUsingJNDI() method with a value of true will enable JNDI lookups of JATO datasource names. In this mode, all JATO 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 JATO datasource names map directly to JDBC URLs, and will attempt to obtain a JDBC Connection directly form the JDBC DriverManager.

WARNING: Unless you are using specially-written connection pooling JDBC drivers, disabling the use of JNDI results in the use of non-pooled database connections. This will cause the SQLConnectionManager to allocate a new connection whenever one is requested, and is an extremely expensive operation. This mode should absolutely not be used in a production deployment.

Adding Datasource Mappings

Either of the above modes assumes that a mapping exists for the provided JATO datasource name. These mappings are set by calling the SQLConnectionManagerBase.addDataSourceMapping(String, String) static method. This method is marked protected, and should generally be called from within the static initializer of the application-specific SQLConnectionManagerImpl class.

For example:

static
{
    setUsingJNDI(true);


    // Anyone asking for a connection under the JATO name "jdbc/MyDS"
    // would cause the SQLConnectionManager to do a JNDI lookup for 
    // a datasource under the name "jdbc/Foo/MyDS-Test"
    addDataSourceMapping("jdbc/MyDS","jdbc/Foo/MyDS-Test");
}

or

static
{
    setUsingJNDI(false);
 
    // Note, if we are not using JNDI, we will need to initialize our
    // JDBC drivers in the standard way
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Class.forName("oracle.jdbc.driver.OracleDriver");
// Anyone asking for a connection under the JATO name "jdbc/MyDS" // would cause the SQLConnectionManager to obtain a connection from // the JDBC DriverManager with the URL "jdbc:odbc:northwind" addDataSourceMapping("jdbc/MyDS","jdbc:odbc:northwind"); addDataSourceMapping("jdbc/HerDS","jdbc:oracle:thin:@10.0.0.1:1521:foo"); }

If a Datasource Mapping Cannot be Found

The SQLConnectionManager provides a fallback mechanism if a mapping can't be found for a given JATO datasource name. If a mapping can't be found, it assumes that the JATO datasource name is the JNDI datasource name/JDBC URL that should be used to obtain a connection. Therefore, if you choose JATO datasource names appropriately, you may not need to add a mapping.

Deploying a JATO Application

After configuring the application as described above, deploying a JATO application is no different than deploying any other WAR-based J2EE application. J2EE containers differ on the details of deploying such an application; we refer you to the deployment documentation for your container.

Some notes on deployment:

Interoperating with JATO Applications

Because JATO applications are just J2EE Web applications, other Web applications can interoperate with them. The techniques for interoperation with JATO depend on how the JATO application components will be accessed.

Interoperating with JATO from an External Application

By external application, we mean a completely separate application in a different servlet context, application server, web server, J2EE or non-J2EE container, etc.

For the most part, this type of interoperation is the same as it would be for any other web application—JATO applications are invokable through a standard HTTP URL. If you wish to pass parameters to a JATO application, you can simply append query parameters to the HTTP invocation and access these from within the invoked JATO component.

However, this type of invocation will result in a first-touch request, a request that doesn't invoke a request event handler. In most cases, this is fine. In some cases, though, you may wish to simulate a JATO button press or HREF click. If so, you will need to include at least one name-value pair as a query parameter or posted value.

Each request resulting from a JATO button or HREF includes a parameter that signals to JATO's request handling infrastructure that it should invoke a request event handler (a handle<child>Request() method). The name of this parameter is the fully-qualified name of the button or HREF. For example, a button name SubmitButton on PgFoo would generate a parameter like this:

PgFoo.SubmitButton=Submit

Therefore, to simulate this button press, you would send an HTTP request to the JATO application that looks something like this:

http://<host>/fooapp/module1/PageFoo?PageFoo.SubmitButton=Submit&...

This would result in the handleSubmitButtonRequest() method being invoked on PageFoo. Note that if you wish to populate any of the other fields on the same page, as most request event handler methods would expect, you need to append additional parameters to the query string or posted content.

If you wish to invoke a request event handler within a child TiledView of a page, you need to also include a row number in the parameter name:

PageFoo.FooTiledView[3].SubmitButton=Submit

This would invoke the request event handler in the TiledView named FooTiledView as if the button press had occurred on the fourth tile (tile numbers are zero-based).

Interoperating with JATO from Within the Same Application

In some cases, a single web application may contain both JATO and non-JATO J2EE components, such as non-JATO servlets and JSPs. The advantage of interoperating with JATO from within the same application is that the application components can share session and other objects via the request and servlet context attributes. This makes it much easier to move seamlessly between components.

In most situations, you can simply follow the same basic guidelines for interoperating with JATO from an external application. Note, however, that you will instead need to forward to or include the JATO component in the request using the standard javax.servlet.RequestDispatcher mechanism. When forwarding or including in this manner, you must be sure to request the standard JATO URL and not any of the JATO JSPs directly:

String target="/fooapp/module1/PageFoo?PageFoo.SubmitButton=Submit&...";
RequestDispatcher dispatcher=
   request.getServletContext().getRequestDispatcher(target);
dispatcher.forward(request,response);

This is currently our only recommended technique for interoperating with JATO within the same application, as it allows the JATO module servlet to establish a proper context for handling the request. We cannot recommend other techniques, such as attempting to instantiate and use a ViewBean directly, because they would require a significant amount of complex manipulation of the JATO infrastructure (which may change from one JATO version to another). In the future, based on user feedback, we may provide a simpler, API-based mechanism for this style of interoperation.