Skip navigation.
Arch2Arch Tab BEA.com

WebLogic Workshop Internals

by John Methot
06/30/2004

Table of Contents

What is BEA WebLogic Workshop?
BEA WebLogic Workshop Application Components
     Java Controls
     Java Web Services
     Page Flows
     Business Processes
An Example Component: A JWS File
     HelloWorld.jws
     JWS Structure
     Javadoc Annotations
Component Compilation
     Timing of Component Compilation
          Iterative Development Mode
          Exploded versus Archived Applications
          On-demand Compilation
     Component Compilation Products
          Transport Objects
          Dispatcher Objects
          Component Adapters
          Container Objects
     Cached Compilation Results
Application Directory Structure
     Split Source Model
     Code Generation Examples
          A Non-Conversational Web Service: HelloWorld.jws
          A Conversational Web Service: HelloWorldAsync.jws
Component Invocation
     Invocation Data Flow
     Message Transport
     Request Dispatch
          Synchronous vs. Asynchronous Dispatch
          Stateless vs. Stateful Methods
          Management of Conversational Instances
     Use of JMS
     Transactions
     User Code
     Method Responses
          Callbacks
Page Flows
     Struts Infrastructure
     Page Flow Compilation
     Page Flow Invocation
          Action Servlet
          Page Flow JSP Filter
          Page Flow Request Processor
          Using a Different Request Processor
     Page Flow Features
          Nesting
          Page Flow Scope
          Global.app
          Exception Handling
          Form Validation
          Struts Interoperability
          Struts Merge Capability
     Page Flow Portability
     Invoking Controls from a Page Flow: WlwProxy
          Page Flows, Nested Controls and Callbacks
Component Lifecycle
     Web Services (JWS) and Business Processes (JPD)
     Page Flows (JPF)
     Controls (JCS, JCX)
Application Customization
     jws-config.properties File
     wlw-config.xml File
     wlw-runtime-config.xml File
     wlw-manifest.xml
Summary

What is BEA WebLogic Workshop?


BEA WebLogic Workshop greatly simplifies the development and deployment of enterprise applications that leverage the power, scalability, and reliability of J2EE (Java 2 Enterprise Edition). Although knowledge of J2EE and the BEA WebLogic Workshop runtime is not required to build BEA WebLogic Workshop applications, those who architect enterprise applications or administer J2EE application servers often want to understand in some detail what BEA WebLogic Workshop is doing under the covers. This paper describes how BEA WebLogic Workshop uses the facilities of J2EE and the BEA WebLogic Platform to support and deploy applications.

BEA WebLogic Workshop consists of:
  • a visual development environment for creation of enterprise applications
  • a runtime infrastructure that supports application features; the runtime consists of J2EE components deployed on BEA WebLogic Server
  • java controls, which allow an application developer to encapsulate and/or access enterprise resources or business logic in a simple and consistent manner

The nature of the runtime infrastructure is the central topic of this paper.

BEA WebLogic Workshop Application Components


A BEA WebLogic Workshop application is composed of high-level components.
These components include:
  • Java controls, defined in JCS (Java Control Source) files or extended in JCX (Java Control Extension) files
  • Web services, defined in JWS (Java Web Service) files
  • Page flows, defined in JPF files
  • Business processes, defined in JPD files
  • JavaServer Pages (JSPs), some or all of which may be part of one or more page flows


Each of these components (except JSPs) is defined in a Java-language source file. In addition to the Java code that implements the logic of the component, each file contains custom Javadoc annotations that access runtime capabilities. The BEA WebLogic Workshop runtime consists of J2EE components that implement the infrastructure referenced by these annotations. A BEA WebLogic Workshop application is ultimately deployed as a pure J2EE application, but some portions of the application (the runtime) are provided transparently and are not directly visible to the application developer. This is intentional: the purpose of BEA WebLogic Workshop is to hide as much complexity as possible and allow developers to more productively build application logic, leaving detailed J2EE coding and architectural decisions to the framework layer.

Java Controls

A Java control is an object that encapsulates business logic or provides access to a resource. The control model allows a developer to access the business logic or resource in a consistent, straightforward manner as though it was a simple Java object.

BEA WebLogic Workshop includes built-in controls to simplify access to common resources such as databases, JMS (Java Message Service) queues, or EJBs (Enterprise JavaBeans). Developers may also implement custom Java controls to encapsulate any business logic or provide access to resources not covered by built-in controls.

Each control is implemented easily as a Java class, but controls are managed by the BEA WebLogic Workshop runtime like EJBs are managed by J2EE’s EJB container. The runtime provides automatic transactions, asynchrony, state management, and other services. A control can also define custom annotations and wizards that integrate seamlessly with the BEA WebLogic Workshop IDE.

A Java control is defined in a JCS (Java Control Source) file with the .jcs extension. Java controls can be extensible, meaning that the control can be customized via Javadoc annotations. Customized instances of an extensible control are defined in JCX (Java Control Extension) files with the .jcx extension.

A Java control may be used from a Web service, a page flow, a business process, or another Java control.

Java Web Services

A Web service is a software component whose functionality can be accessed by sending XML (Extensible Markup Language) messages over common Web protocols. Typically, but not always, these messages are in a specific XML dialect called SOAP (Simple Object Access Protocol). The messages usually represent requests for the Web service to perform some operation. When a server hosting Web services receives such a message, it delivers it to the entity that implements the Web service business logic. When the operation completes, the Web service typically responds to its client by sending an XML or SOAP response message.

Web services came about as a way to achieve distributed computing with a higher degree of interoperability than was possible with previous distributed computing architectures. Since Web services communicate exclusively via XML, the client and the Web service are not aware of the programming language or operating system on which the other is implemented. For example, SOAP and XML Schema provide a language- and OS-independent way to describe data types of arbitrary complexity.

The first generation of Web services is typically invoked over HTTP. However, the foundation of the Web services concept is messaging and the protocol over which the messages are transported is not limited.

A Web service is defined in a JWS (Java Web Service) file with the .jws extension. A JWS file contains a single Java class that defines one or more methods that may be exposed as web service operations. An operation is invoked when a request for the Web service’s URL is received and the request contains an appropriate XML or SOAP message identifying the operation to be performed and containing the data on which to operate. Javadoc annotations are used to configure attributes of the Web service and its operations.

A Web service may contain BEA WebLogic Workshop Java controls.

Page Flows

A page flow manages the presentation and flow of information among multiple Web pages, typically JSPs (JavaServer Pages). Like other Workshop resources, a page flow provides a single file where developers can build the business logic of a Web application. A page flow controls the user's path through the application and can access back-end resources consistently using Java controls. Page flows leverage the Struts framework, an open source facility from the Apache Jakarta Project (http://jakarta.apache.org/struts/) for their runtime infrastructure. While page flows are converted to pure Struts before execution, the page flow model improves on the Struts model by centralizing the management of information flow across the member pages.

A page flow is defined in a JPF (Java Page Flow) file with the .jpf extension. A JPF file contains a single Java class that defines one or more action methods. The actions are invoked, according to rules defined in the JPF file, in response to user interactions with individual pages. Javadoc annotations are used to configure attributes of the action methods.

A page flow may contain BEA WebLogic Workshop Java controls indirectly via the WlwProxy. The relationship between page flows and controls is described in the Page Flows section later in this paper.

Business Processes

BEA WebLogic Workshop, Platform Edition includes the BEA WebLogic Portal™ and BEA WebLogic Integration™ products. BEA WebLogic Integration provides the business process application component. A business process enables the integration of diverse applications and human participants, as well as the coordinated exchange of information between business partners and the enterprise. Business processes allow you to orchestrate the execution of business logic and the exchange of business documents among back-end systems, users and partners (systems and users) in a loosely coupled fashion.

A business process is defined in a JPD (Java Process Definition) file with the .jpd extension. A business process may contain BEA WebLogic Workshop Java controls.

An Example Component: A JWS File


A JWS (Java Web Service) is one example of a high-level application component a developer may build with BEA WebLogic Workshop. A JWS is defined in a file with the .jws extension. BEA WebLogic Workshop will expose each JWS file in an application as a Web service.

While this section uses a JWS file as an example to illustrate how the BEA WebLogic Workshop runtime works, the situation is analogous for JCS (Java Control) and JPD (Java Process Definition) files. Page flows (JPF files) are treated differently and are described later in this paper.

HelloWorld.jws

Below is the code for HelloWorld.jws, a sample web service provided in the SamplesApp sample application installed with the BEA WebLogic Platform:


/**
 * A very simple web service.
 *
 * @common:target-namespace namespace="http://workshop.bea.com/HelloWorld"
 */
public class HelloWorld implements com.bea.jws.WebService
{
    /**
     * @common:operation
     */
    public String Hello()
    {
        return "Hello, World!";
    }
}



JWS Structure

Each JWS file contains a single top-level class that implements a web service. While the file has the special .jws extension, it contains completely valid Java source code. The .jws extension is merely used to identify the file as a Web service. When a Web service is accessed via its URL, the .jws extension is used by the BEA WebLogic Workshop runtime to route the request to the correct subsystem.

A JWS file contains custom Javadoc annotations that indicate various configuration attributes of the web service that are supported by the BEA WebLogic Workshop runtime.

A JWS file may also reference BEA WebLogic Workshop Java controls. Java controls are encapsulated Java components represented by an interface that allow the Web service developer to access almost any resource or business logic as though it was a simple Java object. Java controls are described in more detail later in this paper. Javadoc Annotations

BEA WebLogic Workshop defines a collection of custom Javadoc tags that are used to annotate application files. The custom tags all begin with one of the following prefixes:
  • @common:<tagname> for tags that access generic runtime features


  • @jc:<tagname> for tags that access Java control-specific features


  • @jpd:<tagname> for tags that access JPD-specific features


  • @jpf:<tagname> for tags that access JPF-specific features


  • @jws:<tagname> for tags that access JWS-specific features

For example, two custom tags that directly affect the resources deployed to support a particular web service are:

@common:message-buffer enable="true": indicates that the method it annotates is buffered. Invocations of this method are buffered in a per-Web-application JMS queue for delivery to a JWS instance, making the Web service method asynchronous.

@jws:conversation phase="start | continue | finish": indicates that the method it annotates participates in a conversation. A conversation provides per-client persistence for Web service state, allowing Web service clients to participate in long-running operations even though the default web service protocol (HTTP) is stateless.

The use of Javadoc annotations to provide metadata about Java classes, functions, and fields is currently being standardized as part of the Java Community Process, as JSR 175 "A Metadata Facility for the Java Programming Language" (led by Sun Microsystems). Future versions of WebLogic Workshop will support the specification that eventually results from JSR 175.

BEA WebLogic Workshop introduced web service specific annotations in JWS files, which are being standardized as part of JSR 181 "Web Services Metadata for the Java Platform" (led by BEA Systems).

Component Compilation


Before a BEA WebLogic Workshop application component can be invoked, it must be compiled. Compilation can occur on-demand or a priori, depending on the component type and the environment.

In BEA WebLogic Workshop, the term compilation means more than just producing bytecode from the Java code in a component’s source file. Workshop compilation also includes analysis of the Javadoc annotations. Depending on the annotations found on a component, the BEA WebLogic Workshop runtime might configure existing runtime components, generate infrastructure code or both.

This section applies mainly to components that run in the EJB tier (JWSs, JCSs, and JPDs). Page flows (JPFs) run entirely in the Web tier and are covered in the Page Flows section later in this paper. Timing of Component Compilation

The timing of component compilation depends on two factors: whether the BEA WebLogic Workshop runtime is in iterative development mode or not; and whether the application is archived or exploded.

Iterative Development Mode
By default, the BEA WebLogic Workshop runtime runs in iterative development mode. This mode is controlled by the noiterativedev command line argument to the WebLogic Server start script (startWebLogic.xxx): the runtime runs in iterative development mode unless this argument is present.

Exploded versus Archived Applications
An application is archived if it is running from an EAR (Enterprise Application Archive) file. An application is exploded if it is running from a fully expanded directory tree. Typically while developing BEA WebLogic Workshop applications you run the application in exploded form. When you explicitly build the application into an EAR file (via the wlwBuild command) and deploy the EAR file to a server, the application is archived.

On-demand Compilation
In an exploded application running in iterative development mode, most application components are automatically compiled on demand. This includes all Web services, page flows and business processes. A Java control is compiled on demand if the control is implemented directly in a Web service or Web application project in the current application. If a control is implemented in a control project, the control project must be manually built to produce or update the control's JAR file.

In an archived application or an application not running in iterative development mode, no on-demand compilation is performed. The entire application must be compiled before deployment to the server. BEA WebLogic Workshop provides direct support for building applications that are deployable to a production server. This can be accomplished via "Build EAR" in the IDE or from the command line using the wlwBuild command. Both of these actions produce an EAR (Enterprise Application Archive) file.

Note: BEA WebLogic Server defines development and production modes, but BEA WebLogic Server's modes are independent of the BEA WebLogic Workshop runtime's iterative development mode.

Note: iterative development mode does not control the compilation of JSPs; if a JSP is requested and it does not exist in compiled form, the server will compile the JSP regardless of iterative development mode or application format (archived or exploded). wlwBuild pre-compiles JSPs, effectively disabling compilation at runtime because a compiled version of every JSP is already present in the deployed EAR file.


Component Compilation Products

When a component is compiled, a collection of artifacts is generated and/or configured for deployment. These artifacts make up two distinct pieces of a deployed WebLogic Workshop application: the Dispatcher and the Component Container. Figure 1 shows the organization of these artifacts and component invocation at a high level. Component invocation is explained in more detail later in this paper.

Note: a BEA WebLogic Workshop Component Container is distinctly different from a formal J2EE web or EJB container. A Component Container is merely a lightweight class that provides context and a consistent interface for WebLogic Workshop components. Component Containers are completely invisible to a typical WebLogic Workshop developer.


1

Figure 1: Invocation Dispatch Overview

Transport Objects
The transport objects in the Web tier provide protocol support for invocation of BEA WebLogic Workshop components from external clients. Transport objects receive invocation requests in a protocol-specific format and create generic Request objects that are passed to the Dispatcher.

In BEA WebLogic Platform 8.1, BEA WebLogic Workshop supports two transport protocols by which a client may invoke Web services: HTTP and JMS.

Web service invocations that arrive via HTTP are received by a servlet (com.bea.wlw.runtime.core.dispatcher.HttpServer). The Web application in which the Web services are deployed is configured to route all requests for URLs ending in .jws to this servlet. JWS URL routing, as well as any desired basic authentication security on specific Web service URLs, is specified in the standard J2EE Web application deployment descriptors (web.xml and weblogic.xml).

Web services invocations that arrive via the JMS protocol are directed to a specific configured JMS queue. By default, this queue has the JNDI name jws.queue. A Message Driven Bean named com.bea.wlw.runtime.jws.bean.JMSTransportBean is deployed to listen to this queue.

The Message Driven Bean used to receive JMS requests and the servlet used to receive HTTP requests are deployed to WebLogic Server automatically in any BEA WebLogic Workshop-enabled domain. These components are not involved in the compilation process, but are described here for completeness. Their role is described below in the Component Invocation section.

Dispatcher Objects

Dispatcher EJBs
A Dispatcher is constructed for each web application and is used by all components within the webapp module. The Dispatcher receives incoming invocation requests and routes them appropriately. The Dispatcher for a particular web application consists of one or two EJBs, depending on the runtime features the developer selected via Javadoc annotations in the components in the application. The Dispatcher may comprise the following EJBs:
  1. SyncDispatcherBean - Stateless Session Bean that receives all incoming method invocation requests. Routes synchronous requests directly to the adapter for the appropriate component container and asynchronous requests to the AsyncDispatcherBean (via a per-webapp JMS queue).


  2. AsyncDispatcherBean - Message Driven Bean that handles invocations of buffered component methods. This Dispatcher EJB is only deployed if the web application contains one or more components with buffered methods. Invoked indirectly by SyncDispatcherBean via messages placed in a per-webapp JMS queue. See Asynchronous Queues below.

The EJBs that compose the Dispatcher are generic and the same EJB classes are used for all WebLogic Workshop web applications (the WebLogic Workshop IDE project types "Web Application" and "Web Services" are J2EE web applications).

The Dispatcher EJBs are "private" and are not designed or intended for direct invocation by users. Only transport objects or other WebLogic Workshop components should invoke them.

Asynchronous Queues
If a component specifies the @common:message-buffer enable="true" annotation on one or more of its methods, a per-web application JMS queue is automatically configured to handle all requests to all asynchronous components in the component's web application. The queue is named using the project name. For example, the JMS queue configured to handle asynchronous requests to the WebServices/async/Buffer.jws sample JWS in the SamplesApp application is named WebServices.queue.AsyncDispatcher.

Component Adapters
Invocation of components by the Dispatcher is always accomplished via a generic invoke method, which decouples the Dispatcher from the implementation details of any given component. The WebLogic Workshop runtime automatically generates an adapter for each component that exposes the generic invoke method. When executed, an adapter's invoke method examines the dispatched request and determines the appropriate method to invoke on its component. The adapter provides fan-out from the single invoke entry point to the collection of methods in the component's public interface.

Container Objects
WebLogic Workshop uses a generic container model to wrap the user code found in JWS, JCS, JCX and JPD files. There is a top level Container class and subclasses JwsContainer, JcsContainer, JcxContainer and JpdContainer. These containers provide special functions like context services, control initialization and event routing, and container-specific pre/post-processing during request invocation. For example, the JwsContainer class implements the JwsContext interface that a developer can access from within a JWS.

Container EJBs
A Container is always encapsulated in a Container EJB. The Container EJB for a particular component exposes a business interface that mirrors the public interface of the component it contains. This enables per-method declarative security on components.

There are two types of Container EJB:
  1. SLSBContainerBean - Stateless Session Bean that handles stateless (non-conversational) component method invocations. Since no state is required, these invocations can be handled by any pooled instance of this Stateless Session Bean. May be invoked by SyncDispatcherBean for synchronous requests or by AsyncDispatcherBean for asynchronous requests.


  2. BMPContainerBean - Entity Bean that handles stateful (conversational) component method invocations. This EJB is only present if the web application contains one or more components with conversational methods. May be invoked by SyncDispatcherBean for synchronous requests or by AsyncDispatcherBean for asynchronous requests.


Note: in WebLogic Workshop 8.1 all controls are non-conversational but nested controls may participate in a conversation defined by a top-level container such as a JWS or JPD.


Stateless components are very common and they are treated as a special case at the container level. Instead of generating separate container EJBs for each flavor of stateless component, WebLogic Workshop defines the GenericStateless container EJB. GenericStateless is the EJB type used for most stateless components.

For each conversational (stateful) component, WebLogic Workshop generates a customized instance of the BMPContainerBean. The name of the generated bean is of the form <componentName>_<mangledPackageName>. The mangled package name is constructed by hashing the full package name of the component and is done to minimize component file system path length.

User Code
While a component container exposes a generic interface to the Dispatcher, each container directly contains an instance of the component's class defined in the source file. The code defined in a component's source file (e.g. JWS file) is ultimately executed directly by the container when a component method is invoked.

Cached Compilation Results


On a development server, the Dispatcher and Component Container EJBs are deployed to the server automatically when compilation of a web application completes successfully. The compilation results are also cached on a per-server basis for reuse.

Application Directory Structure


Figure 2 shows the application directory structure in which WebLogic Workshop applications are organized.

1

Figure 2: Application Directory Structure

Split Source Model


As of version 8.0, WebLogic Server supports a split source model in which the files that make up a web application may be stored under more than one root location. WebLogic Workshop uses this feature to separate user code from generated code. User code is always maintained in the application directory and all generated code is placed in a separate location. This facilitates management of the application in a configuration control system and enables simplified application cleanup.

The first time an application (or a project in an application) is built, WebLogic Workshop creates a .workshop subdirectory immediately below the application's root directory. The .workshop directory is the root directory for all generated code in the application. As each web application project (remember, a Web Services project is also a web application) is built, generated EJB code for that project is placed in a subdirectory of .workshop with the same name as the project's source directory. Web tier code for the project is placed in a subdirectory of .workshop/output with the same name as the project's source directory.

In an application that is exploded (not archived in an EAR file), WebLogic Server treats the multiple split source locations as a single logical web application directory.

When you build a WebLogic Workshop application using "Build EAR" in the IDE or the wlwBuild command, the split source directories are merged and a traditional J2EE EAR structure is produced. All classes that were generated into special split source directories are moved to the WEB-INF/lib directories in the resulting EAR file.

Code Generation Examples


The following sections describe the artifacts that are generated for specific web applications and components in the SampleApp sample application that is installed with WebLogic Platform 8.1. The artifacts described in these examples are typical of those generated and deployed for all WebLogic Workshop applications.

A Non-Conversational Web Service: HelloWorld.jws
The HelloWorld.jws sample web service is the simplest possible JWS: it is non-conversational (stateless) and uses no buffering or callbacks. If you "run" the SamplesApp/WebServices/HelloWorld.jws sample JWS, on-demand compilation will generate the following artifacts in SamplesApp/.workshop:



output/WebServices
    Contains class files for all non-JWS source files in the
    project, including JAVA, JCX and JCS files.

WebServices/classes/HelloWorld.class

    The class file from HelloWorld.jws.
    Class files for all JWSs in the project will be placed here.

WebServices/EJB/ProjectBeans/META-INF/ejb-jar.xml

  The deployment descriptor for the Dispatcher EJBs.
  The abbreviated contents are:
<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>SyncDispatcher</ejb-name>
            <home>com.bea.wlw.runtime.core.bean.SyncDispatcherHome</home>
            <remote>com.bea.wlw.runtime.core.bean.SyncDispatcher</remote>

            <ejb-class>
               com.bea.wlw.runtime.core.bean.SyncDispatcherBean
            </ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>


            <ejb-ref>
                <ejb-ref-name>WebServices.bean.SyncDispatcher</ejb-ref-name>
                <ejb-ref-type>Session</ejb-ref-type>
                <home>com.bea.wlw.runtime.core.bean.SyncDispatcherHome</home>
                …
            </ejb-ref>
            …
        </session>
    </enterprise-beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>SyncDispatcher</ejb-name>
                <method-name>*</method-name>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>



This deployment descriptor configures a single instance of the generic SyncDispatcherBean stateless session EJB to dispatch all incoming requests for the WebServices web application. The SyncDispatcherBean also participates in EJB-container-managed transactions.

WebServices/EJB/GenericStateless/com/bea/wlwgen/GenericStatelessSLSBCont*.class

The stateless session EJB, subclassed from SLSBContainerBean, that is the container for the HelloWorld.jws component. Generated classes include the adapter, the public interface and the implementation.

WebServices/EJB/GenericStateless/META-INF/ejb-jar.xml

The deployment descriptor for the Container EJBs. The abbreviated contents are:



<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>StatelessContainer</ejb-name>
            <local-home>com.bea.wlwgen.GenericStatelessSLSBContHome</local-home>
            <local>com.bea.wlwgen.GenericStatelessSLSBContIntf</local>

            <ejb-class>com.bea.wlwgen.GenericStatelessSLSBContImpl</ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>
            …
        </session>
    </enterprise-beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>StatelessContainer</ejb-name>
                <method-name>*</method-name>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>



The key element to note is the deployment of a stateless session EJB of type com.bea.wlwgen.GenericStatelessSLSBCont* named StatelessContainer. Also, a container transaction is configured for the StatelessContainer. WebLogic Workshop's implicit transaction management is described later in this paper.

A Conversational Web Service: HelloWorldAsync.jws
The HelloWorldAsync.jws sample web service is a simple conversational (stateful) JWS that uses callbacks but does not use message buffering. If you "run" the SamplesApp/WebServices/async/HelloWorldAsync.jws sample JWS, on-demand compilation will generate the following artifacts in SamplesApp/.workshop:

output/WebServices

Contains class files for all non-JWS source files in the project,
including JAVA, JCX and JCS files.

WebServices/classes/async/HelloWorldAsync.class

WebServices/classes/async/HelloWorldAsync$Callback.class

The class files from HelloWorldAsync.jws and its inner
interface named Callback.

WebServices/EJB/ProjectBeans/META-INF/ejb-jar.xml

The deployment descriptor for the Dispatcher EJBs. The abbreviated contents are:



<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>SyncDispatcher</ejb-name>
            <ejb-class>
               com.bea.wlw.runtime.core.bean.SyncDispatcherBean
            </ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>
                    …
        </session>

        <message-driven>
            <ejb-name>AsyncDispatcher</ejb-name>
            <ejb-class>
               com.bea.wlw.runtime.core.bean.AsyncDispatcherBean
            </ejb-class>
            <transaction-type>Container</transaction-type>
            …
        </message-driven>

        <message-driven>
            <ejb-name>AsyncErrorHandler</ejb-name>
            <ejb-class>
               com.bea.wlw.runtime.core.bean.AsyncErrorBean
            </ejb-class>
            <transaction-type>Container</transaction-type>
            …
        </message-driven>
    </enterprise-beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>SyncDispatcher</ejb-name>
                …
                <ejb-name>AsyncDispatcher</ejb-name>
                …
                <ejb-name>AsyncErrorHandler</ejb-name>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>



This deployment descriptor configures three EJBs: a single instance of the generic SyncDispatcherBean stateless session EJB to receive and dispatch all incoming requests for the WebServices web application; a single instance of the generic AsyncDispatcherBean to handle asynchronous invocation requests enqueued by the SyncDispatcherBean; and a single instance of the generic AsyncErrorBean to handle delivery errors that occur during asynchronous invocation dispatch. All of the Dispatcher EJBs participate in EJB-container-managed transactions.

WebServ…/EJB/HelloWorldAsync_cgcuba6/…/HelloWorldAsyncBMPCont*.class

The entity EJB, subclassed from BMPContainerBean, that is the Container EJB used for any stateful invocations of the HelloWorldAsync.jws component. Generated classes include the adapter, the public interface and the implementation.

The directory name HelloWorldAsync_cgcuba6 is formed by hashing the package name; this is done to minimize the length of file paths.

WebServ…/EJB/HelloWorldAsync_cgcuba6/…/HelloWorldAsyncSLSBCont*.class

The stateless session EJB, subclassed from SLSBContainerBean, that is the Container EJB used for any stateless invocations of the HelloWorld.jws component. Generated classes include the adapter, the public interface and the implementation. The directory name HelloWorldAsync_cgcuba6 is formed by hashing the package name; this is done to minimize the length of file paths.

WebServ…/EJB/HelloWorldAsync_cgcuba6/META-INF/ejb-jar.xml

The deployment descriptor for the Container EJBs. The abbreviated contents are:



<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>StatelessContainer</ejb-name>
            <local-home>com.bea.wlwgen.HelloWorldAsyncSLSBContHome</local-home>
            <local>com.bea.wlwgen.HelloWorldAsyncSLSBContIntf</local>

            <ejb-class>com.bea.wlwgen.HelloWorldAsyncSLSBContImpl</ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>
                   …
        </session>

        <entity>
            <ejb-name>PersistentContainer</ejb-name>
            <local-home>com.bea.wlwgen.HelloWorldAsyncBMPContHome</local-home>
            <local>com.bea.wlwgen.HelloWorldAsyncBMPContIntf</local>

            <ejb-class>com.bea.wlwgen.HelloWorldAsyncBMPContImpl</ejb-class>
            <persistence-type>Bean</persistence-type>
            <prim-key-class>java.lang.String</prim-key-class>
            <reentrant>False</reentrant>
        </entity>
    </enterprise-beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>StatelessContainer</ejb-name>
                …
                <ejb-name>PersistentContainer</ejb-name>
                <method-name>*</method-name>
            </method>
            <trans-attribute>Required</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>



The key elements to note are the deployment of a stateless session EJB of type com.bea.wlwgen.HelloWorldAsyncSLSBCont* named StatelessContainer and an entity EJB of type com.bea.wlwgen.HelloWorldAsyncBMPCont* named PersistentContainer. Also, a container transaction is configured for the container EJBs. WebLogic Workshop's implicit transaction management is described later in this paper.

Component Invocation


This section describes what occurs when an XML or SOAP message representing a web service or business process method invocation arrives at the server.

Note: as of WebLogic Workshop 8.1, only top-level components - JWSs and JPDs - may be invoked directly by external clients. Controls may only be invoked from within top-level components. In future releases of WebLogic Workshop, controls may be directly invocable by external clients.


This section applies mainly to components that run in the EJB tier (JWSs and JPDs). Page flows (JPFs) run entirely in the web tier; component invocation from JPFs is covered in the Page Flows section later in this paper.

Invocation Data Flow


Figure 3 illustrates the data flow for an invocation of a JWS method. The data flow is identical for JPD methods. Each part of the data flow is described in more detail below.

1

Figure 3: Invocation Dispatch Detail

Message Transport


The request arrives as either a JMS message or an HTTP request. The transport object receiving the request takes the following steps:
  • determine the destination component from the JMS message properties or the SOAP envelope
  • convert the incoming message or HTTP request into a WebLogic Workshop Request object
  • retrieve the cached compilation results and metadata (from annotations) for the target component (if current compilation results are not available when running in iterative development mode, top-level components - JWSs and JPDs - are recompiled automatically)
  • invoke the SyncDispatcherBean for the target web application, passing the Request object

Request Dispatch


Synchronous vs. Asynchronous Dispatch
The first EJB invoked is the SyncDispatcherBean (a stateless session bean). The SyncDispatcherBean determines whether the request represents invocation of a synchronous or asynchronous operation. Asynchronous operations are those annotated with the @jws:message-buffer enable="true" tag.

In the synchronous case, processing of the request continues as described in Stateless vs. Stateful Methods below.

In the asynchronous case, the Request object is serialized to the Async Queue to be serviced later. If the request arrived via HTTP, a void return value is returned to the client in the HTTP response. When the request is subsequently dequeued by the AsyncDispatcherBean, processing continues as described in Stateless vs. Stateful Methods below.

Stateless vs. Stateful Methods
The next step is to service the request. Either the SyncDispatcherBean (if the method being invoked is synchronous) or the AsyncDispatcherBean (upon Request dequeue, if the method being invoked is asynchronous) determines whether the method being invoked is stateless or stateful.

Stateless Methods
Methods annotated as @jws:conversation phase="none" or with no @jws:conversation annotation are stateless. Stateless methods are handled by the component-specific SLSBContainerBean (a stateless session bean).

Stateless methods, by definition, do not require access to any persistent component instance data, so the next available pooled instance of the appropriate SLSBContainerBean subclass for the target component is obtained and the target method is invoked on that instance.

Stateful Methods
Methods annotated as @jws:conversation phase="start", "continue" or "finish" are stateful. Stateful methods are handled by the component-specific subclass of BMPContainerBean (an entity bean).

Stateful methods, by definition, require access to the persisted state of a particular component instance. Persistent component instances are represented in WebLogic Workshop as conversations. When a method marked @jws:conversation phase="start" is invoked, a new entity bean instance is created to represent a new conversation instance. The conversation ID provided by the client is used as the primary key for the entity bean. The data of the entity bean is the persisted state of the component's instance (the serialized instance of the JWS, JPD or JCS class).

Subsequent invocations of continue or finish methods operate on the instance of the entity bean obtained using the conversation ID. When a continue or finish method request arrives, the conversation ID is used to reload the conversation state into an entity bean instance and then the target method is invoked on the instance.

Control Invocation
Controls always exist within the context of a top-level container such as a JWS or JPD. Invocations of control methods are always direct invocations of a method of the JCS's class. Specifically, controls do not reside within separate EJBs; every control instance ultimately exists within a top-level container.

Management of Conversational Instances
The WebLogic Workshop runtime uses a database to persist the conversation state represented by the BMPContainerBean entity beans. A separate table is created for each conversational component, with a row in the table for each active conversational instance of the component. The JDBC data source used by the WebLogic Workshop runtime to maintain conversation state is configurable by the domain administrator. It is specified by the ConversationDataSource property in the jws-config.properties file located in the domain directory. The database table created to persist the state of a particular component is named using the project, package and class name of the JWS. For example, the table created to persist conversation state for the sample JWS WebServices/async/Buffer.jws sample web service in the SamplesApp application is named JWS_WEBSERVICES_ASYNC_BUFFER.

The conversational state of a component is persisted by serializing the component container instance (which contains an instance of the class defined in the JWS, JCS or JPD file). A component developer can influence the size of a conversational instance by controlling the size of the member data of the component class. A component developer can also make judicious use of Java's transient access modifier to prevent serialization of particular component class members.

Since conversational instances represent consumed resources, it is important to manage conversations efficiently. Component developers can promote efficient use of conversations in the following ways:
  • Use conversational shapes that are obvious to potential clients. Use clear method and callback names that indicate start and end phases of component usage.
  • Design components with efficient default conversational behavior. For example, if a callback to the client logically finishes a conversation, annotate the callback so that it finishes the conversation instead of expecting the caller to invoke a subsequent finish method.
  • Use the available conversation lifetime facilities exposed by the @jws:conversation-lifetime annotation. You can set both the maximum idle time a conversation can experience before terminating as well as the absolute lifespan of a conversation. These parameters are also available programmatically from within a JWS.
  • Document the expected usage of the component. Explicitly instruct developers to use conversation finish methods if necessary.

Use of JMS


The WebLogic Workshop runtime uses JMS (Java Message Service) to facilitate several runtime features. Three examples are Timer controls, conversation lifetime and asynchronous request handling. The runtime uses JMS messages with the DeliveryTime attribute as a timer service. Depending on the number and type of components deployed and the features they use, the runtime's use of JMS may consume significant resources. One of the areas you can tune performance of WebLogic Workshop is the configuration of the JMS persistent store. You can configure a JMS server to page its persistent store, which will decrease memory consumption under high load at the potential cost of increased time for retrieval of persisted data.

To learn more about tuning JMS performance, please see JMS: Tuning (http://edocs.bea.com/wls/docs81/ConsoleHelp/jms_tuning.html) on the BEA e-docs web site.

Transactions


WebLogic Workshop automatically wraps each component method invocation in an implicit transaction. Transactions begin at the points indicated by the T symbol in Figure 3. These points include invocation of the Dispatcher by either the HTTP Servlet or the JMS transport MDB, as well as invocation of the AsyncDispatcherBean bean upon dequeue of a request from the Async Queue. Note that in the case of invocation of an asynchronous method, the original transaction that begins when the SyncDispatcherBean is invoked completes almost immediately, after the request is placed in the Async Queue. Another transaction, covering the actual invocation of the component method, begins when the asynchronous request is dequeued from the Async Queue and actually dispatched to the component's container.

If any uncaught exception occurs during the invocation of the component method, the encapsulating transaction is rolled back. The WebLogic Workshop documentation describes the behavior and scope of WebLogic Workshop's default transactions in detail.

User Code


The code the developer provides in a JWS, JCS, or JPD file is ultimately executed directly. As was described earlier in this paper, the Javadoc annotations in each JWS, JCS or JPD file are used to determine the number, type and configuration of EJBs that are deployed to support the component.

The original XML or SOAP message that constitutes the method invocation request is carried through the Dispatcher. The last phase of method invocation is conversion of the XML or SOAP message into the Java parameters of the JWS's or JPD's method. This is referred to as XML mapping, and is accomplished by the Container object that wraps each component.

Method Responses


In the case of synchronous method invocations, the return value of the component method is translated into an XML or SOAP response via XML mapping. The response is returned through the Dispatcher to the appropriate Transport object. If the request arrived via HTTP, the response is packaged as an HTTP response and returned by the servlet as the response to the originating HTTP request. In the case of requests that arrive via JMS, no direct response is necessary (or possible).

Callbacks
If a client can receive callbacks, it must supply a callback location (a URL) when it starts a conversation. The container object initializes a callback proxy that sends all callbacks the component invokes by directly opening a socket and transmitting the callback message.

Page Flows


WebLogic Workshop provides page flows as a model for developing web applications. A page flow is a component that controls navigation and data flow across a set of related web pages. Page flows are based on the Struts web application framework that is part of the Apache Jakarta project (http://jakarta.apache.org/struts/).

Why use Page Flows Instead of Struts?

A page flow is a Struts web application, but page flows provide many benefits over Struts. Specific benefits include:

1. Ease-of-use. Struts development requires managing and keeping in sync multiple files for each Action, form bean, and Struts configuration file. Even in the presence of tools that help edit these files, developers are exposed to all the underlying plumbing, objects, and configuration. Page flows provide a dramatically simpler, single-file programming model that allows developers to focus on the code they care about, see a graphical representation of the overall application flow, and easily navigate between pages, Actions, and form beans.

In addition, WebLogic Workshop provides visual tag libraries and a number of wizards to automate common page flow tasks. Page flows also provide key programming model benefits like thread-safety, so developers are isolated from some of the complexities of web development models like Struts and servlets.

2. Nesting. Struts provides a great framework for smaller applications, but has trouble scaling to larger applications. Every page and action is referenced from a single configuration file, and the managability of applications and projects quickly decreases. With the nested page flow feature, developers can easily create "mini-flows" and link them together, helping support larger team development projects over large applications. Nested page flows automatically manage session state as a user moves between them, minimizing demand for system resources.

3. State management. Page flows make state management easy -- you can put data in session state simply by using a variable in your page flow, and you can easily pass data (as JavaBeans) to individual pages. Data stored in page flows is automatically freed as a user leaves the page flow for efficient use of session data.

4. Rich databinding support. While page flows manage the overall flow of pages and actions, WebLogic Workshop's data binding tags and wizards make it extremely easy to create rich, dynamic pages on top of data from anywhere: a database, a web service, an EJB, or a custom application. Simply by dragging and dropping you can bind to data, including repeating data, lists, trees, tables, etc.

5. Access to controls. Page flows have access to WebLogic Workshop Java controls, a simple programming model abstraction for accessing enterprise resources and packaging business logic. Controls give developers access to the powerful features of the J2EE platform (security, transactions, asynchrony) in a simple, graphical environment with methods, events and properties.

6. Easy integration with Portal. Have a page flow? You also have a portlet! Page flow applications can be turned into portlets via a simple wizard in WebLogic Workshop.

7. Strong typing. Struts treats all data as a String, making it hard to work with rich form data. Struts allows developers much easier access to strongly typed data, making it a lot easier to work with form information.

8. More powerful exception handling. With page flows, you can handle exceptions by pointing to local actions in your page flow, and handle not-logged-in errors globally across a set of page flows. This makes it much easier to manage errors and centralized login processes for your entire application.

9. Fast iterative development experience. With Workshop and page flows, developers don't need to go through the tedious edit, build, deploy, test cycle. Simply make a change and hit run. You see the results of your code change immediately.

10. Built on Struts. While page flows provide a number of advantages on top of plain-vanilla Struts, page flows are fully based on Struts, and in fact with BEA’s portability kit can run on any Struts container. This means that you have full access to the underlying power of Struts at any time -- you don't make any compromises by using page flows.

These and other benefits of page flows are described in detail later in this paper.

Struts Infrastructure


The Struts framework is based on the Model-View-Controller (MVC) pattern. Struts is designed to allow a developer to choose the appropriate technology for the model and view portions, but in reality J2EE components are used for each of the parts: the views are typically implemented as JSPs (JavaServer Pages); the controller is typically a Java servlet; and the model typically comprises one or more EJBs (Enterprise JavaBeans).

The Struts framework provides multiple extensibility points where developers can augment or replace the default Struts behavior. WebLogic Workshop uses the standard Struts extensibility points to provide the simplified model of page flows.

Figure 4 illustrates the control flow of a Struts application. The figure is annotated with the extensibility points WebLogic Workshop uses and what functionality it provides at each point. See Page Flow Invocation, below, for an explanation of the control flow shown in the figure.

1

Figure 4: Struts control flow with page flow behavior

The deployed artifacts that enable a Struts application are:
  • An ActionServlet: a special servlet to which all action URIs in a Struts application are directed. The servlet uses mappings that associate specific URI patterns with Struts modules to direct incoming requests to the appropriate module.

    The Struts framework allows substitution of a custom action servlet; WebLogic Workshop provides a custom action servlet named DynamicSubappActionServlet.

    Note: in the WebLogic Platform 8.1 SP2 release, the action servlet was renamed to PageFlowActionServlet.


  • A RequestProcessor: an object associated with each Struts module that shepherds a request through multiple phases including user role verification, action lookup, form data management, action dispatch and request forwarding. The Struts framework allows substitution of a custom request processor; WebLogic Workshop provides a custom request processor named PageFlowRequestProcessor.
  • A Struts-specific JSP tag library that provides predefined tags for accessing JavaBeans, binding forms to form data, embedding navigation logic in pages, etc.

    WebLogic Workshop provides JSP tag libraries that are analogous to those defined by Struts. The Workshop tags provide powerful and flexible data binding capabilities to automatically transfer data between pages and underlying application components such as Java controls.


  • Struts configuration files and action mapping files. These are XML files that describe the Struts modules in the application and the mapping of actions to action classes.

    When a JPF file is compiled, WebLogic Workshop generates the Struts configuration files based on annotations in the JPF file. A WebLogic Workshop developer need never manipulate Struts configuration files directly (although WebLogic Workshop provides a "Struts Merge" capability that a developer may use to access Struts capabilities that are not natively supported by Page Flows).

Page Flow Compilation


If the WebLogic Workshop runtime is running in iterative development mode, JPF files are compiled on demand. When a JPF file is compiled, it produces a class file for the class defined in the JPF file plus an XML configuration file for the Struts module associated with the JPF. Each JPF file produces exactly one Struts module.

The class file is placed {application directory}/.workshop/output/{webapp directory}/WEB-INF/classes.. This is the "split source" location for generated code; see the section on Application Directory Structure earlier in this paper for an explanation of split source.

The generated Struts module configuration file for a page flow is named

WEB-INF/jpf-struts-config-<module-path>.xml.

So the configuration file for a web application with the URI /a/b/something.jpf would be

WEB-INF/jpf-struts-config-a-b.xml.

When you build an application using "Build EAR" in the IDE or the wlwBuild command, the JPF class file and Struts configuration files are included in the application's EAR file.

Note: starting with the WebLogic Platform 8.1 SP2 release, page flow-generated Struts configuration files are stored in the

WEB-INF/.pageflow-struts-generated/

directory instead of in the WEB-INF directory.

Page Flow Invocation


The following sections describe the processing performed on an incoming request to a page flow (or a JSP in a page flow).

Note: in a pure Struts application, only the actions may be addressed directly (URLs ending in .do). In a page flow, both the page flow itself (URL ending in .jpf) and JSPs within the page flow (URLs ending in .jsp) may be accessed directly by a user.


Action Servlet
A page flow uses the normal web.xml file to map incoming requests directed at specific URIs (or URI patterns) to servlets. URIs that end in .do or .jpf are mapped to the PageFlowActionServlet. The URI-to-servlet mapping is set up by default by WebLogic Workshop for all page flow web applications; a page flow developer need never edit the web.xml file directly to manage mappings.

Once an incoming request arrives at the PageFlowActionServlet, the servlet performs the following actions:

1. If the WebLogic Workshop runtime is running in iterative development mode, the runtime will compile any source files that have changed since the last invocation. Files that are checked for compilation include the JPF file, all JCS or JCX files in the same project, all external form beans (form beans declared outside the JPF file but in the project), and all source files stored in or below the project's WEB-INF/src directory.

2. If any compilation errors occur in the requested page flow or dependent files, they are formatted and returned to the browser as the HTTP response to the request.

3. The action servlet next looks for a registered Struts module to which the request's URI is mapped. If one is found, the request is dispatched to the request processor associated with that Struts module. The module that is found may be a page flow Struts module that was registered dynamically in Step 4 during a previous request.

4. If there is no registered Struts module associated with the request's URI, see if an appropriate Struts module can be registered dynamically. If the URI ends with .jpf, it is dynamically mapped to the Struts module associated with that page flow. If a matching page flow-generated Struts module configuration file (see Page Flow Compilation, above) is found, it will be registered and used in Step 3 for future requests. If no mapping is successfully found, the request is handled like a normal (non-page flow, non-Struts) request.

5. Each Struts module is associated with a request processor class that is identified in the module's configuration file. If the request's URI was resolved to a Struts module, processing of the request is delegated to the module's request processor. For page flow-generated Struts modules, the request processor is always PageFlowRequestProcessor.

A Struts developer could conceivably configure a page flow application to use a custom action servlet. However, the developer would then have to explicitly register the page flow-generated Struts module in web.xml for each page flow. The developer would also have to manually ensure that all of the page flow's code was compiled since the custom action servlet could not trigger the WebLogic Workshop runtime to do so.

Page Flow JSP Filter
By default, a WebLogic Workshop web application is configured to intercept JSP requests with PageFlowJspFilter (a servlet filter mapped to *.jsp). On an incoming request for a JSP, this filter performs the following actions:

1. If the WebLogic Workshop runtime is running in iterative development mode, the runtime will compile any source files that have changed since the last invocation. Files that are checked for compilation include the JPF file, all JCS or JCX files in the same project, all external form beans (form beans declared outside the JPF file but in the project), and all source files stored in or below the project's WEB-INF/src directory.

2. If any compilation errors occur in classes referenced from the JSP, they are formatted and returned to the browser as the HTTP response to the request.

3. If the directory path for the JSP corresponds to a registered Struts module (or a Struts module dynamically registered on-the-fly as in step #4 above), that module is selected in the request. Thus the JSP tags in the page will operate against the proper context.

4. If there is a page flow in the JSP's directory, ensure that it is instantiated, that it is set as the current page flow, and that its context state is set so that methods like getRequest(), getResponse(), getSession(), etc. can be called directly or indirectly through data binding in the JSP tags.

Page Flow Request Processor
The Struts framework defines the request processor interface to allow the framework to be extended at various points in the processing of a request. WebLogic Workshop utilizes these extensibility points by providing a custom request processor implementation named PageFlowRequestProcessor. The default Struts request processing behavior is extended by overriding helper methods named processXxx.

The following sections describe the individual extensibility points of the Struts request processor that are overridden by PageFlowRequestProcessor. For each extensibility point the default Struts functionality is described as well as the additional work performed by PageFlowRequestProcessor.

processMapping
Each request must resolve to an action. In this step, the request processor examines the action mappings defined in the Struts configuration to find an action associated with the request's URI.

Struts behavior is to return an error to the browser if no action is mapped to the request's URI.

If the page flow request processor does not find a suitable action mapping in the current module, it will check the special Global.app module. If Global.app also does not contain a suitable mapping, the request processor throws an ActionNotFoundException that can be caught in Global.app or the target page flow. The exception handler can format a readable response to be returned to the user. If successful, processMapping returns an ActionMapping that encapsulates information about the action.

processRoles
The web application may be configured to require that the user be authenticated as a member of a specific security role in order to execute specific actions. processRoles determines whether the calling user is in a suitable role.

Struts behavior is to return an error to the browser if the user cannot be authenticated as belonging to the required role. The page flow request processor merely sets a flag in the request indicating that role authentication failed and should cause an error later in the process. See processActionPerform below.

processActionForm
The request processor determines whether the target action has an associated form bean and whether the form bean should be scoped to the request or to the session. The request processor then attempts to access the form bean in the request or session state. If it is not found, a new form bean is created and stored in the appropriate state.

As of WebLogic Platform 8.1 SP2 release, page flows may specify form beans as page flow-scoped. Page flow lifetime is typically longer than a single request and shorter than an entire session (one session might involve multiple page flows). If the target action specifies a page flow-scoped form, the referenced page flow member variable is accessed (and initialized to a new instance of the form bean if necessary). Note that in this situation, processActionCreate is called early in order to get the current page flow, and its result is cached for later use.

processPopulate
The request processor attempts to map the request's input data to the form bean identified in the processActionForm step.

Struts performs the data mapping "blindly" and silently. If fields in the posted data match properties of the form bean, the appropriate form bean property is populated. But if data is missing from the request or data exists in the request but has no counterpart in the form bean, Struts does nothing with that data or property.

Page flows provide a powerful, flexible, verifiable and optionally typed data binding capability. To learn more about data binding in Page Flows, see
http://e-docs.bea.com/workshop/docs81/doc/en/workshop/guide/netui/guide/conDatabindingXScript.html.

processActionCreate
The request processor next finds the appropriate Action object.

Struts instantiates an object using the class specified in the action mapping and returns that Action.

The base class of each page flow is PageFlowController.

PageFlowController is derived from the Struts Action class, so the page flow request processor instantiates the appropriate page flow object (if necessary), caches it in the session and returns it as the Action.

A page flow may also optionally implement lifecycle methods that will be invoked at appropriate times. These methods are onCreate, beforeAction, afterAction and onDestroy. When the page flow is instantiated, its onCreate method is invoked.

processActionPerform
The request processor invokes the Action's execute method, expecting an ActionForward object to be returned.

WebLogic Workshop does not override the processActionPerform method directly. The base FlowController class provides an execute method that is invoked by processActionPerform. The execute method than determines the actual page flow (or Global.app) method to invoke.

Note: FlowController's execute method is synchronized on the page flow instance, so a page flow developer can always be assured that anything she does within a page flow method is thread-safe.


PageFlowController's execute method performs several steps around the invocation of the page flow method:
  1. The controller sets up context that will be available to the method. The request, response, session and action mapping objects are all stored in the page flow object. This allows page flow methods to have smaller signatures that are appropriate for the specific method semantics.
  2. The controller calls the page flow's beforeAction lifecycle method.
  3. If the page flow is annotated with @jpf:controller login-required="true" or the page flow method is annotated with @jpf:action login-required="true" and the user is not logged in (request.getUserPrincipal()==null), the request processor throws a NotLoggedInException. If the page flow is annotated with @jpf:controller roles-allowed or the page flow method is annotated with @jpf:action roles-allowed and the user is not in one of the specified roles, the request processor throws an UnfulfilledRoleException.
  4. Next the execute method invokes the target page flow action method, expecting a Forward object to be returned.

    In Struts, the request processor invokes the action's execute method and expects an ActionForward to be returned; the developer must resolve forwards manually by calling findForward(name) on the passed-in ActionMapping.

    In a page flow, the developer returns new Forward(name) where name refers to a @jpf:forward annotation on the method. Page flow forwards can have special attributes such as return-to="page" and return-to="action" (meaning "previous page" and "previous action") or can specify that the forward should do a browser redirect. The developer can attach additional data to a Forward, including an ActionForm as in Struts or other input data to which tags on the destination page can data bind. Finally, unlike Struts a page flow Forward can specify an absolute URI instead of just a forward name.
  5. The controller calls the page flow's afterAction lifecycle method.
  6. The controller returns an ActionForward object to the request processor.

processForwardConfig
The request processor acts on the ActionForward returned by the action, which may be a page forward or a redirect.

Page flows can also handle the case of a forward to an absolute URI (a URL).

Using a Different Request Processor
A Struts developer could conceivably configure a page flow application to use a different request processor, but page flows and their associated JSPs (using page flow JSP tags) will not function properly unless the alternate request processor derives from PageFlowRequestProcessor and delegates to it where appropriate.

Struts includes a page-templating feature called "tiles". Use of tiles requires a special request processor, making it incompatible with page flows in the same directory. Since each directory in a web application typically constitutes a separate Struts module with a potentially different request processor, page flow and tiles modules can coexist as long as they are in different directories. Tiles modules can forward to page flow modules and vice versa.

Page Flow Features


The following sections describe features that page flows provide, beyond the pure Struts framework.

Nesting
A page flow can be annotated with the @jpf:controller nested="true" annotation, making it nestable. A nested page flow acts somewhat like a page within the nesting page flow. When control returns to an originating page flow (when the nested page flow raises an action on its originating page flow by returning a @jpf:forward with the return-action attribute), the state of the original page flow is automatically restored.

If the nested page flow forwards or redirects outside of itself without raising an action on the original page flow, the nesting "stack" is discarded.

Page Flow Scope
Page flows provide an intermediate scope between the brief lifetime of a request and the potentially long lifetime of a session. A user may visit multiple page flows within the span of a single session, but as the user leaves each (non-nested) page flow the page flow's resources are released.

Global.app
WebLogic Workshop provides a file named Global.app that is defined in every page flow web application in the WEB-INF/src/global directory. Global app provides a session-scoped data storage location and fallback action methods and exception handlers. A Global.app instance is created and stored in the session before any PageFlowController is called in a web application. The Global.app instance is guaranteed to exist as long as the session.

If an action is not implemented in a target JPF, the request processor checks to see if the action is implemented in Global.app. If it is, the Global.app action method will be invoked. Global.app can therefore be used to provide backup actions across multiple pages in a web application.

If an exception is thrown during processing of a request and the exception is not caught in the current JPF, the exception is passed to Global.app. Global.app can therefore be used to provide common error handling across multiple pages in a web application. For example, Global.app can provide features such as login that are automatically called from all pages in the page flow when a NotLoggedInException is thrown.

Note that Global.app is not a page flow, and can never "own" pages or become the current page flow.

Exception Handling
When an exception occurs, Struts can forward to a path or invoke a handler class. In addition to these targets, a page flow or Global.app can invoke a handler method when the exception occurs.

Form Validation
Struts provides input data validation and can forward to a path if validation fails. Page flows can perform similar forwarding, and can also specify the target as "previous page" or "previous action" without specifying the explicit path.

Struts also provides a declarative validator plugin capability. Page flows do not have this capability as of the WebLogic Platform 8.1 GA release. However, the Struts Merge facility, described below, can be used to provide this capability.

Struts Interoperability
Page flows and Struts pages can coexists in the same web application using the PageFlowActionServlet. A developer could replace PageFlowActionServlet, but would then have to manually register the mappings for any page flow-generated Struts modules.

Page flow and Struts pages can share form bean classes and instances. Page flows store form data using the same attribute names as Struts. The page flow FormData class extends the Struts ActionForm class and page flow action methods can accept ActionForm objects as arguments.

Struts Merge Capability
Using the @jpf:controller struts-merge annotation in a JPF file, you can direct WebLogic Workshop to include pure Struts artifacts in a page flow web application. Using this capability, you can reuse existing Struts actions or add capabilities such as the Struts Validator plugin. You can also use the Struts merge capability to cause page flow actions to use session-scoped form beans instead of the default request scope.

Page Flow Portability


While at runtime page flows are Struts applications, they require compiler and runtime components (such as the PageFlowActionServlet and the PageFlowRequestProcessor) in order to run. In the WebLogic Platform 8.1 GA release these compiler and runtime components are not readily separable from the platform. In the 8.1 SP2 release, BEA provides these components in a standalone package that may be deployed to any Struts-capable platform. This makes page flows portable to any Struts platform.

Invoking Controls from a Page Flow: WlwProxy


Java controls can only be invoked from a WebLogic Workshop top-level container. The only two types of top-level container directly exposed in WebLogic Workshop are web services (JWSs) and business processes (JPDs). However, Java controls can be invoked from JSPs and page flows due to the presence of a top-level container that is not exposed directly: WlwProxy.

When a JSP or JPF is initialized, a WlwProxy object is automatically created for each control referenced in the JSP or JPF. For a JSP, the lifetime of the WlwProxy object is the same as the HTTP session. However, the state of the control is not maintained across requests in the same session. For controls referenced from a JPF, the WlwProxy (and therefore the control) lifetime is the same as the lifetime of the JPF and the state of the control is maintained for the lifetime of the JPF.

Page Flows, Nested Controls and Callbacks
Consider the case illustrated below, where a page flow invokes a chain of controls, one or more of which attempt to invoke callbacks on their "parent". In this case, control JCS B is attempting to invoke a callback on JCS A:

1

Prior to the WebLogic Platform 8.1 SP2 release, controls invoked from a JPF could not be conversational. Thus, none of the controls in the chain could receive callbacks from controls they referenced. If the situation depicted above occurred, delivery of the callback would fail and an error message would be logged.

As of the 8.1 SP2 release, the WebLogic Workshop runtime analyzes the control chains associated with each instance of WlwProxy and performs the necessary work to support conversations when callbacks are present in the control chain.

Note, however, that callbacks cannot be delivered to the WlwProxy object, and therefore cannot be delivered back to the JPF. Note also that this conversational behavior is not available for controls referenced from JSPs; it is only available for JPFs. Finally, note that controls cannot be made explicitly conversational: you cannot apply the @jws:conversation annotation to a control method. The 8.1 SP2 enhancements merely allow a control to function conversationally within conversations defined by the control's top-level container.

Component Lifecycle


The lifecycle of each component type and its supporting infrastructure is described in the following sections.

Web Services (JWS) and Business Processes (JPD)


JWSs and JPDs are the only components that are explicitly conversational, and the lifetime of a JWS or JPD instance is exactly the lifetime of its conversation. When a new conversation is begun a new entity bean (a component-specific subclass of BMPContainerBean) is created. When the conversation ends, the entity bean is released.

Non-conversational JWSs effectively have conversations that last exactly one method invocation. This is also true for invocations of non-conversational methods on conversational JWSs. When a non-conversational method is invoked a new stateless session bean (a component-specific subclass of SLSBContainerBean) is "created", although creation of such beans typically only entails allocation from a pool. When the method invocation completes, the session bean instance is released.

Page Flows (JPF)


The lifetime of a JPF depends on the actions taken in the page flow. In general, a page flow is instantiated when it is first requested (either the JPF or one of its JSPs/actions) and is released when the user exits the page flow. The user exists the page flow if there is a request for another page flow (or a JSP/action in another page flow). The current page flow is also released when the HTTP session expires.

The special Global.app object is instantiated the first time any page flow in the a web application is requested and then lives as long as the HTTP session.

Page flows and Global.app can override lifecycle methods that get called on creation (onCreate) and release (onDestroy).

Controls (JCS, JCX)


Controls cannot be directly invoked by external clients; they can only be invoked from a JWS, JPD or JPF. The lifetime of a control is directly tied to the lifetime of the control's client.

Controls are created and initialized using lazy instantiation; a control (JCS) instance is not actually instantiated until the first time a control client invokes one of the control's methods. Once instantiated, the control instance exists until the control client is released. When a control client terminates, all of the controls referenced by that client are released.

Controls may be nested. Consider the case where Top.jws references FirstControl.jcs, which in turn references SecondControl.jcs. FirstControl.jcs will not be instantiated until Top.jws invokes one of FirstControl.jcs's methods. SecondControl.jcs, in turn, will not be instantiated until FirstControl.jcs invokes one of SecondControl.jcs's method. When Top.jws is released (at the end of its conversation), FirstControl.jcs and SecondControl.jcs will also be released.

Application Customization


Since many resources differ between development and production servers, WebLogic Workshop provides configuration files that allow customization of application properties during development and at deployment.

jws-config.properties File


The jws-config.properties file defines resources used by the WebLogic Workshop runtime, such as the data source used to persist conversational state and the JMS server used to buffer asynchronous service requests.

You can find documentation for the jws-config.properties file at:
http://edocs.bea.com/workshop/docs81/doc/en/workshop/reference/configfiles/con_jws-config_properties_ConfigurationFile.html

wlw-config.xml File


The META-INF directory of each WebLogic Workshop application may contain a wlw-config.xml file that configures various aspects of the application on both a development server and production server. When you build the application into an EAR file for deployment, the values in the wlw-config.xml file override the application's default values. This is useful for overriding such things as the endpoint URI of web services that will ultimately be reached through a cluster or firewall.

You can find documentation for the wlw-config.xml file at:
http://edocs.bea.com/workshop/docs81/doc/en/workshop/reference/configfiles/con_wlw-config_xml_ConfigurationFile.html

The values in the wlw-config.xml file are in turn overridden by values specified in the wlw-runtime-config.xml file.

wlw-runtime-config.xml File


While the settings in the wlw-config.xml file are used during development and production, the settings in the wlw-runtime-config.xml file are used only when the application is built for production. You build an EAR file using "Build EAR" in the IDE or by using the wlwBuild command.

You can find documentation for the wlw-runtime-config.xml file at:
http://edocs.bea.com/workshop/docs81/doc/en/workshop/reference/configfiles/con_wlw-runtime-config_xml_ConfigurationFile.html

wlw-manifest.xml


When you deploy a WebLogic Workshop application to a production server, you must configure the resources referenced by the application. These resources might include database tables, JMS queues, security roles, etc. When you build an application into an EAR file, WebLogic Workshop generates a manifest describing the resources referenced by the application. You can use the manifest as a guide when configuring the necessary application resources.

You can find documentation for the wlw-manifest.xml file here.

Summary


WebLogic Workshop substantially lowers the barrier to entry for developers who wish to deploy enterprise-class applications on the J2EE platform. It is intentionally designed to hide as many details of J2EE as possible from the developer. However, as this paper demonstrates this is accomplished using the standard facilities provided by the J2EE platform.

Article Tools

Email E-mail
Print Print
Blog Blog

Related Products

Check out the products mentioned in this article:

Related Technologies

Bookmark Article

del.icio.us del.icio.us
Digg Digg
DZone DZone
Furl Furl
Reddit Reddit