Fusion Middleware Documentation
Advanced Search


Developing Fusion Web Applications with Oracle Application Development Framework
Close Window

Table of Contents

Show All | Collapse

13 Implementing Business Services with Application Modules

This chapter describes how to create ADF application modules that encapsulate the data model of an Oracle ADF application derived from a JDBC data source. This chapter also describes how to combine business service methods with that data model to implement a complete business service.

This chapter includes the following sections:

13.1 About Application Modules

An application module is an ADF business component that encapsulates the business service methods and data model for a logical unit of work related to an end-user task.

In the early phases of application development, architects and designers often use UML use case techniques, as well as ADF task flows, to create a high-level description of the application's planned end-user functionalities. Each high-level, end-user use case identified during the design phase typically depends on:

  • The domain business objects involved. To answer the question, "What core business data is relevant to the use case?"

  • The user-oriented view of business data required. To answer the questions, "What subset of columns, what filtered set of rows, sorted in what way, grouped in what way, is needed to support the use case?"

The identified domain objects involved in each use case help you identify the required entity objects from your business domain layer. The user-oriented view of the required business data helps to define the right SQL queries captured as view objects and to retrieve the data in the exact way needed by the end user. For best performance, this includes retrieving the minimum required details necessary to support the use case. In addition to leveraging view object queries and view criteria to shape the data, you've learned how to use view links to set up natural master-detail hierarchies in your data model to match exactly the kind of end-user experience you want to offer the user to accomplish the use case.

The application module is the "work unit" container that includes instances of the reusable view objects required for the use case in question. These view object instances are related through metadata to the underlying entity objects in your reusable business domain layer where the end-user use cases determine the information being presented or modified.

13.1.1 Application Module Use Cases and Examples

This chapter illustrates the following concepts illustrated in Figure 13-1, and more:

  • You expose instances of view objects in an application module to define its data model.

  • You write service methods to encapsulate task-level business logic.

  • You expose selected methods on the client interface for UI clients to call.

  • You expose selected methods on the service interface for programmatic use in application integration scenarios.

    Note that starting in release 12c, support for EJB Session Bean-enabled application modules in an ADF Business Components model project has been deprecated in Oracle JDeveloper. It is no longer possible to create or run EJB Session Bean-enabled application modules in JDeveloper. As an alternative for existing EJB Session Bean-enabled application modules, you may want to migrate application modules services to Web Service-enabled application modules, as described in Chapter 15, "Integrating Service-Enabled Application Modules." This approach is consistent with the best practice for exposing service methods using external services.

  • You use application module instances from a pool during a logical transaction that can span multiple web pages or views.

  • Your application module works with a Transaction object that acquires a database connection and coordinates saving or rolling back changes made to entity objects.

  • The related Session object provides runtime information about the current application user.

Figure 13-1 Application Module Is a Business Service Component Encapsulating a Unit of Work

Image of how application module encapsulates a unit of work

13.1.2 Additional Functionality for Application Modules

You may find it helpful to understand other Oracle ADF features before you start working with application modules. Following are links to other functionality that may be of interest.

13.2 Creating and Modifying an Application Module

In a large application, you typically create one application module to support each coarse-grained end-user task. In a smaller-sized application, you may decide that creating a single application module is adequate to handle the needs of the complete set of application functionality. Section 13.4, "Defining Nested Application Modules" provides additional guidance on this subject.

13.2.1 How to Create an Application Module

Any view object you create is a reusable component that can be used in the context of one or more application modules. Each view object performs the query it encapsulates in the context of that application module's transaction. The set of view object instances used by an application module defines its data model, in other words, the set of data that a client can display and manipulate through a user interface.

To add an application module to your existing ADF Business Components project, use the Create Application Module wizard, which is available in the New Gallery.

Before you begin:

It may be helpful to have an understanding of application modules. For more information, see Section 13.2, "Creating and Modifying an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired view objects, as described in Section 5.2.1, "How to Create an Entity-Based View Object," and Section 5.8.1, "How to Create an Expert Mode View Object."

To manually create an application module:

  1. In the Applications window, right-click the project in which you want to create the application module and choose New and Application Module.

  2. In the Create Application Module wizard, on the Name page, provide a package name and an application module name. Click Next.

    Note:

    In Fusion web applications, the reserved words data, bindings, security, and adfContext must not be used to name your application module. Also, avoid using the "_" (underscore) at the beginning of the name. For more information, see Section 13.2.5, "How to Edit an Existing Application Module."

  3. On the Data Model page, include instances of the view objects you have previously defined and edit the view object instance names to be exactly what you want clients to see in the Data Controls panel. Then click Next.

  4. On the Java page, you can optionally generate the Java files that allow you to programmatically customize the behavior of the application module or to expose methods on the application module's client interface that can be called by clients. To generate an XML-only application module component, leave the fields unselected and click Finish.

    Initially, you may want to generate only the application module XML definition component. After you complete the wizard, you can subsequently use the overview editor to generate the application module class files when you require programmatic access. For details about the programmatic use of the application module, see Section 13.7, "Customizing an Application Module with Service Methods."

For more step by step details, see Section 13.2.3.2, "Adding Master-Detail View Object Instances to an Application Module."

13.2.2 What Happens When You Create an Application Module

When you create an application module, JDeveloper creates the XML document file that represents its declarative settings and saves it in the directory that corresponds to the name of its package. For example, given an application module named BackOfficeAppModule in the summit.model package, the XML file created will be ./summit/model/BackOfficeAppModule.xml under the project's source path. This XML file contains the information needed at runtime to re-create the view object instances in the application module's data model.

If you are curious to view its contents, you can see the XML file for the application module by double-clicking the application module node in the Applications window to open the overview editor. In the editor window, click the Source tab to view the XML so that you can inspect it. The Structure window shows the structure of the XML file.

When you create business components, JDeveloper automatically creates a data control that contains all the functionality of the application module. Data controls are an ADF Model abstraction layer that provides supplemental metadata to describe the application module's operations and data collections (row sets of view object instances), including information about the attributes, methods, and types involved. Developers can then use the representation of the data control displayed in JDeveloper's Data Controls panel to create UI components that are automatically bound to the application module. At runtime, the ADF Model layer reads the metadata describing the data controls and bindings from appropriate XML files and implements the two-way connection between the user interface and the business service.

For example, the BackOfficeAppModule application module implements the business service layer of the SummitADF application workspace. Its data model contains numerous view object instances, including several master-detail hierarchies. The view layer of the core Summit ADF sample application consists of JSF pages whose UI components are bound to data from the view object instances in the BackOfficeAppModule's data model, and to built-in operations and service methods on its client interface. For details about how the Data Controls panel exposes the application module to UI developers, see Section 17.3, "Exposing Application Modules with ADF Data Controls."

13.2.3 How to Add a View Object Instance to an Application Module

You can add a view object instance to an application module as you create the application module with the Create Application Module wizard, or you can add it later to an already created application module.

For information about using the Create Application Module wizard, see Section 13.2.1, "How to Create an Application Module."

13.2.3.1 Adding a View Object Instance to an Existing Application Module

You can add a view object instance to an application module that you have already created. To add a view object instance to an existing application module, and optionally, customize the view object instance, use the Data Model page of the overview editor for the application module.

Before you begin:

It may be helpful to have an understanding of application modules. For more information, see Section 13.2, "Creating and Modifying an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired view objects, as described in Section 5.2.1, "How to Create an Entity-Based View Object," and Section 5.8.1, "How to Create an Expert Mode View Object."

To add a view object instance to an existing application module:

  1. In the Applications window, double-click the application module for which you want to define a new view instance.

  2. In the overview editor, click the Data Model navigation tab.

  3. On the Data Model Components page, expand the View Object Instances section and, in the Available View Objects list, select the view instance you want to add.

    The New View Instance field below the list shows the name that will be used to identify the next instance of that view object that you add to the data model.

  4. To change the name before adding it, enter a different name in the New View Instance field.

  5. With the desired view object selected, shuttle the view object to the Data Model list.

    Figure 13-2 shows the view object CountriesVO has been renamed to Countries before it was shuttled to the Data Model list.

    Figure 13-2 Data Model Displays Added View Object Instances

    View object instance in the data model

13.2.3.2 Adding Master-Detail View Object Instances to an Application Module

You can use the data model that the application module overview editor displays to create a hierarchy of view instances, based on existing view links that your project defines. If you have defined view links that establish more than one level of master-detail hierarchy, then you can proceed to create as many levels of master-detail view instances as your application supports.

Before you begin:

It may be helpful to have an understanding of application modules. For more information, see Section 13.2, "Creating and Modifying an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create hierarchical relationships between view objects, as described in Section 6.2, "Working with Multiple Tables in a Master-Detail Hierarchy."

To add master-detail view object instances to a data model:

  1. In the Applications window, double-click the application module for which you want to define a new master-detail view instances.

  2. In the overview editor, click the Data Model navigation tab.

  3. On the Data Model Components page, expand the View Object Instances section and, in the Available View Objects list, select the instance of the view object that you want to be the actively coordinating master.

    The master view object will appear with a plus sign in the list indicating the available view links for this view object. The view link must exist to define a master-detail hierarchy.

    Figure 13-3 shows CountriesVO selected and renamed Countries in the New View Instance field.

    Figure 13-3 Master View Object Selected

    Data Model page of Create Application Module wizard.
  4. Shuttle the selected master view object to the Data Model list.

    Figure 13-4 shows the newly created master view instance Countries in the Data Model list.

    Figure 13-4 Master View Instance Created

    Data Model page of Create Application Module wizard.
  5. In the Data Model list, leave the newly created master view instance selected so that it appears highlighted. This will be the target of the detail view instance you will add. Then locate and select the detail view object beneath the master view object in the Available View Objects list.

    Figure 13-5 shows the detail OrdersVO indented beneath master CustomerVO with the name OrdVO via OrdCustomerIdFkLink. The name identifies the view link OrdCustomerIdFkLink, which defines the master-detail hierarchy between CustomerVO and OrdVO. Notice also that the OrdVO will have the view instance name OrdersForCustomers when added to the data model.

    Figure 13-5 Detail View Object Selected

    Data Model page of Create Application Module wizard.
  6. To add the detail instance to the previously added master instance, shuttle the detail view object to the Data Model list below the selected master view instance.

    Figure 13-6 shows the newly created detail view instance OrdersForCustomers as a detail of the Customers in the data model.

    Figure 13-6 Master View Instance Created

    Data Model page of Create Application Module wizard.
  7. To add another level of hierarchy, repeat Step 3 through Step 6, but select the newly added detail in the Data Model list, then shuttle over the new detail, which itself has a master-detail relationship with the previously added detail instance.

    Figure 13-7 shows the Data Model list with instance Customers (renamed from CustomerVO) as the master of OrdersForCustomer (renamed from OrdVO via OrdCustomerIdFkLink), which is, in turn, a master for ItemsForOrder (renamed from ItemVo via ItemOrdIdFkLink).

    Figure 13-7 Master-Detail-Detail Hierarchy Created

    Image of Data Model page of Business Components browser

13.2.3.3 Customizing a View Object Instance that You Add to an Application Module

You can optionally customize the view object instance by using the Data Model Components page of the overview editor for the application module. For example, you might want to apply a filter to set the controlling attribute for a master-detail view object relationship.

Before you begin:

It may be helpful to have an understanding of application modules. For more information, see Section 13.2, "Creating and Modifying an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To customize a view object instance that you add to an existing application module:

  1. In the Applications window, double-click the application module for which you want to customize an existing view instance.

  2. In the overview editor, click the Data Model navigation tab.

  3. On the Data Model Components page, expand the View Object Instances section and, in the Data Model list, select the view object instance you want to customize and click the Edit button.

  4. In the Edit View Instance dialog, perform any of the following steps, and then click OK.

    • In the View Criteria group box, select one or more view criteria that you want to apply to the view object instance. The view criteria will be appended as a WHERE clause to the instance query. For details about defining view criteria, see Section 5.9, "Working with Named View Criteria."

    • In the View Criteria group box, for each view criteria that you add to the Selected list, you may define one or more view criteria as mandatory filters on the view instance. Select the Required checkbox for the currently selected view criteria when it should remain applied on the view instance at all times. Normally, when multiple view criteria are applied to a view instance, one will be the default view criteria and should remain applied at all times. Mandatory view criteria, will remain applied on the view criteria list even when the application programmatically applies view criteria (using applyViewCriteria() for example).

    • In the Bind Parameters Values group box, enter any values that you wish the instance to use when applying the defined view criteria. For more information about defining bind variables, see Section 5.10, "Working with Bind Variables."

    Figure 13-8 shows the Edit View Instance dialog opened for the SalesPeople view instance with the FilterByTitleIdVC selected. The bind variable TitleIdBind defines a default value of 2, which sets the value of the TitleId attribute, as the controlling attribute for the SalesPeople view instance. The controlling attribute, when set by the view criteria filter, provides a way to retrieve only the view rows for the matching ID.

    Figure 13-8 Customized View Object Instance Using a View Criteria FIlter

    Image of filter defined for a view object instance.

13.2.4 What Happens When You Add a View Object Instance to an Application Module

You add instances of view object components to define the data model of an application module. Figure 13-9 shows a JDeveloper business components diagram of a BackOfficeAppModule application module.

Figure 13-9 Application Module Containing Two Instances of a View Object Component

Application module with two VO instances

The sample application module contains two instances of the CustomerVO view object component, with member names of Customer and AnotherCustomer to distinguish them. At runtime, both instances share the same CustomerVO view object component definition—this ensures that they have the same attribute structure and view object behavior—however, each might be used independently to retrieve data about different users. For example, some of the runtime properties, like an additional filtering WHERE clause or the value of a bind variable, might be different on the two distinct instances.

Example 13-1 shows how the BackOfficeAppModule application module defines its member view object instances in its XML document file.

Example 13-1 Member View Object Instances Defined in XML

<AppModule
   Name="BackOfficeAppModule"
   ...>
   <ViewUsage
      Name="Customer"
      ViewObjectName="oracle.summit.model.appmodule.CustomerVO"/>
   <ViewUsage
      Name="AnotherCustomer"
      ViewObjectName="oracle.summit.model.appmodule.CustomerVO"/>
</AppModule>

13.2.5 How to Edit an Existing Application Module

After you've created a new application module, you can edit any of its settings by using the Edit Application Module dialog. To launch the editor, in the Applications window, right-click the application module node and choose Open, or double-click the application module. By visiting the different pages of the editor, you can adjust the data model to determine whether or not to reference nested application modules, specify Java generation settings, client interface methods, runtime instantiation behavior, and custom properties.

If you edit the name of your application module, choose a name that is not among the reserved words that Oracle Application Development Framework (Oracle ADF) defines. In particular, reserved words are not valid for a data control usage name which JDeveloper automatically assigns based on your application module's name. In Fusion web applications, these reserved words consist of data, bindings, security, and adfContext. For example, you should not name an application module data. If JDeveloper creates a data control usage with an ID that collides with a reserved word, your application may not reliably access your data control objects at runtime and may fail with a runtime ClassCastException.

Do not name the application module with an initial underscore (_) character to prevent a potential name collision with a wider list of reserved words that begin with the underscore.

Application module names that incorporate a reserved word into their name (or that change the case of the reserved word) will not conflict. For example, Product_Data, Product_data, or just Data are all valid application module names since the whole name does not match the reserved word data.

13.2.6 How to Change the Data Control Name Before You Begin Building Pages

By default, an application module will appear in the Data Controls panel as a data control named AppModuleNameDataControl. The user interface designer uses the Data Controls panel to bind data from the application module to the application's web pages. For example, if the application module is named SummitAppModule, the Data Controls panel will display the data control with the name SummitAppModuleDataControl. You can change the default data control name to make it shorter or to supply a more preferable name.

When the user interface designer works with the data control, they will see the data control name for your application module in the DataBindings.cpx file in the user interface project and in each data binding page definition XML file. In addition, you might refer to the data control name in code when needing to work programmatically with the application module service interface. For this reason, if you plan to change the name of your application module, do this change before you begin building your view layer.

For complete information about the application module data control, see Chapter 17, "Using ADF Model in a Fusion Web Application."

Note:

If you decide to change the application module's data control name after you have already referenced it in one or more pages, you will need to open the page definition files and DataBindings.cpx file where it is referenced and update the old name to the new name manually.

To change the application module data control name:

  1. In the Applications window, double-click the application module for which you want to edit the data control name.

  2. In the Properties window, expand the Other section, and enter your preferred data control name in the Data Control Name field.

13.2.7 What You May Need to Know About Application Module Granularity

A common question related to application modules is, "How big should my application module be?" In other words, "Should I build one big application module to contain the entire data model for my enterprise application, or many smaller application modules that allow me to compartmentalize the application according to functionality?" The answer depends on your situation.

In general, application modules should be as big as necessary to support the specific use case you have in mind for them to accomplish. They can be assembled from finer-grained application module components using a nesting feature, as described in Section 13.4, "Defining Nested Application Modules." Since a complex business application is not really a single use case, a complex business application implemented using Oracle ADF will typically not be just a single application module.

In actual practice, you may choose any granularity you wish to support the type of modularization you require. For example, the need to support disparate data sources or the need to configure separate tuning options are both legitimate cases for creating multiple application modules. Or, in a small application with one main use case and a "backend" supporting use case, you might create two application modules. However, for the sake of simplicity you can combine both use cases, rather than create a second application module that contains just a couple of view objects.

Other situations may dictate creating more than one root application module. For example, if you need to support more than one transaction per user session, you can create multiple application modules. Alternatively, you can work with data control scope and task flows to manage transactions, as described in Section 24.3, "Managing Transactions in Task Flows."

13.2.8 What You May Need to Know About View Object Components and View Object Instances

While designing an application module, you use instances of a view object component to define its data model. Just as the user interface may contain two instances of a Button component with member names of myButton and anotherButton to distinguish them, your application module contains two instances of the CustomerVO view object component, with member names of CustomerList and AnotherCustomerList to distinguish them.

13.3 Configuring Your Application Module Database Connection

When you initialize your data model project to use ADF Business Components, JDeveloper prompts you to supply database connection details. You must specify a database connection before you can run ADF Business Components wizards and work with the database's tables and views to create business components. After you specify the connection details, JDeveloper also creates a Java Database Connectivity (JDBC) data source that will be used as the default runtime connection for all application modules created in the current project. You can use the Edit Configuration dialog to change the JDBC data source definition for each application module individually. In cases where you do not want to use a data source, you also use the dialog to replace the connection type for individual application modules with a JDBC URL connection type.

You can use either the JDBC data source or the JDBC URL connection type to run the application module in any context where Java can run. Your application is not restricted to running inside a Java Enterprise Edition (Java EE) application server. For example, although the Oracle ADF Model Tester is a standalone Java tool and does not run within the context of a Java EE application server, you can use either connection type to test your business components in the Oracle ADF Model Tester. You can use the Edit Configuration dialog to select among both connection types for the existing application resource connections that appear in the Databases window.

JDeveloper configures the application module by default to use the data source connection type. A JDBC data source is a vendor-independent encapsulation of a database server connection. The JDBC data source offers advantages that the JDBC URL connection type does not. When you define a connection type based on a data source, you reconfigure the data source without changing the deployed application. The data source is also centrally defined at the application server level, whereas JDBC URL connections are not. In cases where a JDBC data source is not viable, at runtime, ADF Business Components will construct a default JDBC URL based on the data source connection information.

13.3.1 How to Use a JDBC Data Source Connection Type

The type of connection all default application module configurations use is a JDBC data source. You define a JDBC data source as part of your application server configuration information, and then the application module looks up the resource at runtime using a logical name. When you use the JDBC data source as the connection type, your application resource connection details may change, and you will not need to change the deployed application module configuration. For this reason the JDBC data source is the recommended choice for all application module configurations. Figure 13-10 shows how the default selection appears in the Edit Configuration dialog.

Figure 13-10 JDBC DataSource Connection Type Setting in Edit Configuration Dialog

Data source connection type in Configuration editor

Example 13-2 shows the <resource-ref> tags in the web.xml file of a Fusion web application. These define two logical data sources named jdbc/Summit_adfDS and jdbc/Summit_adfCoreDS. The Edit Configuration dialog references this logical connection name after the prefix java:comp/env in the JDBC Datasource Name field. For example, the JDBC data source name for the same Fusion web application would display the value java:comp/env/jdbc/summit_adfDS that you can select. Therefore the Datasource Name field is prepopulated with the JNDI name for all available application resources connection names.

Example 13-2 Logical Data Source Resource Names Defined in web.xml

<!-- In web.xml -->
  <resource-ref>
    <res-ref-name>jdbc/summit_adfDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
  <resource-ref>
    <res-ref-name>jdbc/summit_adfCoreDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

You can directly edit the Datasource Name field when you want to specify a connection name for a global data source that is required to run the application on a target standalone application server. When you deploy to Oracle WebLogic Server, by default, the application-specific data source is not packaged with the application and Oracle WebLogic Server is configured to find a global data source named jdbc/applicationConnectNameDS using the look up java:comp/env/jdbc/applicationConnectNameDS. Therefore, by following this naming convention, you enable a single data source connection name to work correctly when running the application in JDeveloper using an application-specific data source or when running on the deployed standalone server using a global data source.

Note:

When configuring the ADF application module to access a highly available database system, such as redundant databases or Oracle Real Application Clusters (Oracle RAC) as the backend, the data source must be container-defined. In this scenario, the application module will use a multi data source; however, from the standpoint of the application module configuration, the naming convention for the multi data source is the same as it is for an non-multi data source. This ensures that the correct data source will be used at runtime. For details about configuring multi data sources for high availability applications, see the High Availability Guide.

13.3.2 How to Use a JDBC URL Connection Type

The other type of connection type you can use for an application module configuration is a JDBC URL connection. It is based on the named connection definition set on the Business Components page of the Project Properties dialog for the project containing your application module. Figure 13-11 shows what this section would look like in a configuration using a JDBC URL connection.

Note:

If you are using a non-Oracle JDBC driver, make sure that you set the appropriate properties for the driver on the Properties page of the Edit Configuration dialog to avoid runtime exceptions.

Figure 13-11 JDBC URL Connection Type Setting in Edit Configuration Dialog

URL connection type in Configuration editor

Note:

See Section 50.1.1.2, "Database Connection Pools," and Section 50.2.9, "What You May Need to Know About Database Connection Pool Parameters" for more information on how database connection pools are used and how you can tune them.

13.3.3 What Happens When You Create an Application Module Database Connection

When you select connection type in the Edit Configuration dialog, JDeveloper updates the application module configuration file, bc4j.xcfg in the ./common subdirectory relative to the application module's XML document. The file defines configurations for all of the application modules in a single Java package. For example, if you look at the bc4j.xcfg file in the ./classes/oracle/summit/model/services/common directory of the core Summit ADF sample application's Model project, you will see the named configurations for its application module.

The configurations defined by the bc4j.xcfg file allow the Fusion web application to interact with specific, deployed application modules. In addition to the connection type for the application module, the bc4j.xcfg file contains metadata information about application module names and it contains the runtime parameters that are configured for the application module. The application resource database connection details for the named connection type are defined in the Connections node of the Applications window and saved in the application's connections.xml file.

Example 13-3 displays a sample bc4j.xcfg file from the core Summit ADF sample application. The configurations SummitAppModuleLocal and SummitAppModule both reference a data source (named Summit_adfDS) in the JDBCDataSource attribute. The JDBCDataSource attribute in each configuration specifies the JNDI name for the application resources connection name in the form of java:comp/env/jdbc/applicationConnectNameDS, where applicationConnectName is the name of the application resources database connection defined in JDeveloper (in this case, Summit_adf). This JNDI naming convention (with the application-specific name space java:comp/env/jdbc/ and DS appended to the application resources database connection name ) ensures that a deployed Fusion web application will run on Oracle WebLogic Server using the application's global data source and no changes will be required. The global data source is typically defined by the application server administrator using the Oracle WebLogic Server Administration Console.

Example 13-3 Application Module Database Configurations in the bc4j.xcfg File

<BC4JConfig version="11.1" xmlns="http://xmlns.oracle.com/bc4j/configuration">
   <AppModuleConfigBag ApplicationName="oracle.summit.model.services.SummitAppModule">
      <AppModuleConfig name="SummitAppModuleLocal"
                       DeployPlatform="LOCAL"
                       JDBCName="summit_adf"
                       jbo.project="oracle.summit.model.Model"
                       java.naming.factory.initial="oracle.jbo.common.JboInitialContextFactory"
                       ApplicationName="oracle.summit.model.services.SummitAppModule">
         <Database jbo.TypeMapEntries="Java"/>
         <Security AppModuleJndiName="oracle.summit.model.services.SummitAppModule"/>
         <Custom ns0:JDBCDataSource="java:comp/env/jdbc/summit_adfDS"
                                     xmlns:ns0="http://xmlns.oracle.com/bc4j/configuration"/>
      </AppModuleConfig>
      ...
   </AppModuleConfigBag>
</BC4JConfig>

13.3.4 How to Change Your Application Module's Runtime Configuration

In addition to creating the application module XML document, JDeveloper also adds a default configuration named appModuleNameLocal to the bc4j.xcfg file in the subdirectory named common, relative to the directory containing the application module XML document file. The bc4j.xcfg file does not appear in the Applications window. To view the bc4j.xcfg file in JDeveloper, open the Configuration page of the overview editor for the application module and click the link bc4j.xcfg. To view the default settings or to change the application module's runtime configuration settings, select a configuration in the overview editor and click the Edit button to open the Edit Configuration dialog shown in Figure 13-12.

Figure 13-12 bc4j.xcfg File Configurations Displayed by Edit Configuration Dialog

Edit Configuration dialog displays default configuration

Before you begin:

It may be helpful to have an understanding of application module database connections. For more information, see Section 13.3, "Configuring Your Application Module Database Connection."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To manage your application module's configuration:

  1. In the Applications window, double-click the application module for which you want to edit the configuration.

  2. In the overview editor, click the Configurations navigation tab.

  3. In the Configurations page, select the configuration you want to edit and click the Edit Selected Configuration Object button.

    The Configuration page may display these three default configurations:

    • appModuleNameLocal: One local configuration is automatically defined when you create the application module. Create a new local configuration, for example, when you want to change the runtime properties for the application module for testing purposes.

    • appModuleNameShared: The shared application module configuration is present only when a named instance of a shared application module has been defined in the Project Properties dialog for the data model project. A shared application module is one that groups view instances when you want to reuse lists of static data across the application. For example, you can define a shared application module to group view instances that access lookup data, such as a list of countries.

    • appModuleNameService (type SI for service interface): The service interface configuration is present only when the service interface (web service implementation wrapper) has been defined in the Service Interface page of the overview editor for the application module. An application module exposed as a web service allows your application module to participate in a composite application to provide data access and method calls to web service clients. The same application module can support interactive web user interfaces using ADF data controls and web service clients.

  4. In the Edit Configuration dialog, edit the desired runtime properties and click OK to save the changes for your configuration.

13.3.5 How to Change the Database Connection for Your Project

When you are developing applications, you may have a number of different users or schemas that you want to switch between. You can do this by changing the database connection properties of the project that contains the business components. The selection you make will automatically update the connection string for each configuration in your project's bc4j.xcfg file that specifies a JDBC URL type connection.

Before you begin:

It may be helpful to have an understanding of application module database connections. For more information, see Section 13.3, "Configuring Your Application Module Database Connection."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To change the connection used by your application module's configuration:

  1. In the Applications window, right-click the project that contains the application module and choose Project Properties.

  2. In the Project Properties dialog, select ADF Business Components and from the Connection dropdown list, choose the desired connection and then click the Edit icon.

  3. In the Edit Database Connection dialog, make the appropriate changes.

  4. Click OK.

13.4 Defining Nested Application Modules

Application modules support the ability to create software components that mimic the modularity of your use cases, for which your higher-level functions might reuse a "subfunction" that is common to several business work flows. You can implement this modularity by defining composite application modules that you assemble using instances of other application modules. This task is referred to as application module nesting. That is, an application module can contain (logically) one or more other application module instances, as well as view object instances. The outermost containing application module is referred to as the root application module.

Declarative support for defining nested application modules is available through the overview editor for the application module, as shown in Figure 13-14. The API for application modules also supports nesting of application modules at runtime.

When you nest an instance of one application module inside another, you aggregate not only the view object instances in its data model, but also any custom service methods it defines. This feature of "nesting," or reusing, an instance of one application module inside of another is an important design aspect of ADF Business Components for implementing larger-scale, real-world application systems.

Considering that an application module represents an end-user use case or work flow, you can build application modules that cater to the data required by some shared, modular use case, and then reuse those application modules inside of other more complicated application modules that are designed to support a more complex use case. For example, imagine that after creating the application modules BackOfficeAM and CustomerSelfServiceAM, you later need to build an application that uses both of these services as an integral part of a new composite service application module. Figure 13-13 illustrates what this composite service would look like in a JDeveloper business components diagram. Notice that an application module like SummitAppModule can contain a combination of view object instances and application module instances.

Figure 13-13 Application Module Instances Can Be Reused to Assemble Composite Services

Application module instance reuse

13.4.1 How to Define a Nested Application Module

To specify a composite root application module that nests an instance of an existing application module, use the overview editor for the application module. All of the nested component instances (contained by the application module instance) share the same transaction and entity object caches as the root application module that reuses an instance of them.

Tip:

If you leverage nested application modules in your application, be sure to read Section 17.3.1.4, "How Nested Application Modules Appear in the Data Controls Panel" to avoid common pitfalls when performing data binding involving them.

Before you begin:

It may be helpful to have an understanding of nested application modules. For more information, see Section 13.4, "Defining Nested Application Modules."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To define a nested application module:

  1. In the Applications window, double-click the root application module for which you want to define a nested application module.

  2. In overview editor, click the Data Model navigation tab.

  3. In the Data Model Components page, expand the Application Module Instances section and, in the Available list, select the application module that you want to add to the data model.

    The New App Module Instance field below the list shows the name that will be used to identify the nested application module that you add to the data model.

  4. To change the name before adding it, type a different name in the New App Module Instance field.

  5. With the desired application module selected, shuttle the application module to the Selected list.

    Figure 13-14 shows the application modules BackOfficeAM and CustomerSelfServiceAM have been shuttled to the Selected list.

    Figure 13-14 Data Model Displays Added Application Module Instances

    Application module instance in the data model

13.4.2 What You May Need to Know About Root Application Modules Versus Nested Application Module Usages

At runtime, your application works with a main — or what's known as a root — application module. Any application module can be used as a root application module; however, in practice the application modules that are used as root application modules are the ones that map to more complex end-user use cases, assuming you're not just building a straightforward CRUD application. When a root application module contains other nested application modules, they all participate in the root application module's transaction and share the same database connection and a single set of entity caches. This sharing is handled for you automatically by the root application module and its Transaction object.

Additionally, when you construct an application using an ADF bounded task flow, to declaratively manage the transactional boundaries, Oracle ADF will automatically nest application modules used by the task flow at runtime. For details about bounded task flows and transactions, see Section 24.3, "Managing Transactions in Task Flows."

13.5 Creating an Application Module Diagram for Your Business Service

As you develop the business service's data model, it is often convenient to be able to visualize it using a UML model. JDeveloper supports easily creating a diagram for your application module that other developers can use for reference.

You can perform a number of tasks directly on the diagram, such as editing the application module, controlling display options, filtering methods names, showing related objects and files, publishing the application, and launching the Oracle ADF Model Tester.

13.5.1 How to Create an Application Module Diagram

To create an application module diagram, use the Create Business Components Diagram dialog, which is available in the New Gallery.

Before you begin:

It may be helpful to have an understanding of the UML model diagram For more information, see Section 13.5, "Creating an Application Module Diagram for Your Business Service."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To create a diagram of your application module:

  1. In the Applications window, right-click the data model project in which you want to create the diagram and choose New and then Business Components Diagram.

  2. In the Create Business Components dialog, enter a diagram name and a package name in which the diagram will be created.

  3. Click OK to create the empty diagram and open the diagrammer.

  4. In the Applications window, select the desired application module and drop it onto the diagram surface.

  5. Inside the application module diagram, right-click the desired diagram node and choose Visual Properties and make the desired changes in the Edit Visual Properties dialog.

  6. In the diagram editor, click anywhere outside of the application module diagram to display the Properties window for the diagram editor and make these changes:

    • Set the layout style

    • Change the font

    • Turn off the grid

After you complete these steps, the diagram looks similar to the diagram shown in Figure 13-15.

Figure 13-15 Partial UML Diagram of Application Module

UML diagram for application module

13.5.2 What Happens When You Create an Application Module Diagram

When you create a business components diagram, JDeveloper creates a .adfbc_diagram file to represents the diagram in a subdirectory of the project's model path that matches the package name in which the diagram resides.

By default, the Applications window unifies the display of the project content's paths so that ADF components and Java files in the source path appear in the same package tree as the UML model artifacts in the project model path. You can use the Applications Window Options > Directory View toolbar option in the Applications window to switch between the unified directory view and a more distinct directory path view of the project content.

13.5.3 How to Use the Diagram to Edit the Application Module

The UML diagram of business components is not just a static picture that reflects the point in time when you dropped the application module onto the diagram. Rather, it is a UML-based rendering of the current component definitions, so it will always reflect the current state of affairs. The UML diagram is both a visualization aid and a visual navigation and editing tool.

You can bring up the overview editor for any application module in a diagram by choosing Properties from the context menu (or by double-clicking the application module).

You can also perform some application module editing tasks directly on the diagram, tasks such as renaming view object instances, dropping view object definitions from the Applications window onto the data model to create a new view object instance, and removing view object instances by pressing the Delete key.

Note:

Deleting components from the diagram only removes their visual representation on the diagram surface. The components and classes remain on the file system and in the Applications window.

13.5.4 How to Control Diagram Display Options

After you display the application module in the diagram, you can use the Edit Visual Properties dialog to control its display options. To display the dialog for the diagram, in the diagram, right-click the application module node and choose Visual Properties.

In the Display page, toggle properties like the following:

  • Show Package — to display the package name

  • Show Methods — to display service methods

  • Show Stereotype — to display the type of object (for example "<<application module>>")

  • Show Usages — to display all usages by other application modules in the current project

In the Methods page, consider changing the following settings depending on the amount of detail you want to provide in the diagram:

  • Show Visibility (public, private, etc.)

  • Show Return Type of Method

  • Show Static Methods

By default, all operations of the application module are fully displayed, as shown by the Edit Visual Properties dialog settings in Figure 13-16.

Figure 13-16 Edit Visual Properties Dialog with Default Diagram Editor Options

Visual Properties dialog with diagram node options

On the context menu of the diagram, you can also select to View As:

  • Compact — to show only the icon and the name

  • Symbolic — to show service operations

  • Expanded — to show operations and data model (default)

13.5.5 How to Filter Method Names Displayed in the Diagram

Initially, if you show the methods for the application module, the diagram displays all the methods. Any method it recognizes as an overridden framework method displays in the <<Framework>> operations category. The rest display in the <<Business>> methods category.

The Exclude Method Filters setting in the Methods page of the Edit Visual Properties dialog is a regular expression that you can use to filter out methods you don't want to display on the diagram. For example, by setting Exclude Method Filters to:

findLoggedInUser.*|retrieveOrder.*|get.*

you can filter out all of the following application module methods:

  • findLoggedInUserByEmail

  • retrieveOrderById

  • All the generated view object getter methods

13.5.6 How to Show Related Objects and Implementation Files in the Diagram

After selecting the application module on the diagram — or any set of individual view object instances in its data model — you can choose Show > Related Elements from the context menu to display related component definitions on the diagram. In a similar fashion, choosing Show > Implementation Files will include the files that implement the application module on the diagram. You can repeat these options on the additional diagram elements that appear until the diagram includes the level of detail you want to convey.

Figure 13-17 illustrates how the diagram displays the implementation files for an application module. You will see the related elements for the application module's implementation class (AppModuleImpl). The diagram also draws an additional dependency line between the application module and the implementation class. If you have cast the application module instance to a specific custom interface, the diagram will also show that.

Figure 13-17 Adding Detail to a Diagram Using Show Related Elements and Show Implementation Files

Image of UML diagram

13.5.7 How to Publish the Application Module Diagram

To publish the diagram to PNG, JPG, SVG, or compressed SVG format, choose Publish Diagram from the context menu on the diagram surface.

13.5.8 How to Test the Application Module from the Diagram

To launch the Oracle ADF Model Tester for an application module in the diagram, choose Run from the context menu.

13.6 Supporting Multipage Units of Work

While interacting with your Fusion web application, end users might:

  • Visit the same pages multiple times, expecting fast response times

  • Perform a logical unit of work that requires visiting many different pages to complete

  • Need to perform a partial "rollback" of a pending set of changes they've made but haven't saved yet.

  • Unwittingly be the victim of an application server failure in a server farm before saving pending changes

The application module pooling and state management features simplify implementing scalable, well-performing applications to address these requirements.

Note:

ADF bounded task flows can represent a transactional unit of work. You can specify options on the task flow to determine how to handle the transaction. For details about the declarative capabilities of ADF bounded task flows, see Section 24.3, "Managing Transactions in Task Flows."

13.6.1 How to Simulate State Management in the Oracle ADF Model Tester

To simulate what the state management functionality does, you can launch two instances of Oracle ADF Model Tester on an application module.

Before you begin:

It may be helpful to have an understanding of state management. For more information, see Section 13.6, "Supporting Multipage Units of Work."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To simulate transaction state passivation using the Oracle ADF Model Tester:

  1. Run the Oracle ADF Model Tester and double-click a view object instance to query its data.

  2. Make a note of the current values of several attributes for a few rows.

  3. Update those rows to have a different value for those attributes, but do not commit the changes.

  4. Choose File > Save Transaction State from the Oracle ADF Model Tester main menu.

    A Passivated Transaction State dialog appears, indicating a numerical transaction ID number. Make a note of this number.

  5. Exit the Oracle ADF Model Tester completely.

  6. Restart the Oracle ADF Model Tester and double-click the same view object instance to query its data.

  7. Notice that the data is not changed. The queried data from the data reflects the current state of the database without your changes.

  8. Choose File > Restore Transaction State from the Oracle ADF Model Tester main menu, and enter the transaction ID you noted in Step 4.

At this point, you'll see that your pending changes are reflected again in the rows you modified. If you commit the transaction now, your changes are permanently saved to the database.

13.6.2 What Happens at Runtime: How the Application Uses Application Module Pooling and State Management

Applications you build that leverage an application module as their business service take advantage of an automatic application module pooling feature. This facility manages a configurable set of application module instances that grows and shrinks as the end-user load on your application changes during the day. Due to the natural "think time" inherent in the end user's interaction with your application user interface, the number of application module instances in the pool can be smaller than the overall number of active users using the system.

As shown in Figure 13-18, as a given end user visits multiple pages in your application to accomplish a logical task, with each page request an application module instance in the pool is acquired automatically from the pool for the lifetime of that one request. At the end of the request, the instance is automatically returned to the pool for use by another user session. In order to protect the end user's work against application server failure, the application module supports the ability to freeze the set of pending changes in its entity caches to a persistent store by saving an XML snapshot describing the change set. For scalability reasons, this state snapshot is typically saved in a state management schema that is a different database schema than the one containing the application data.

Figure 13-18 Using Pooled Application Modules Throughout a Multipage, Logical Unit of Work

Image of using pooled application modules

The pooling algorithm affords a tunable optimization whereby a certain number of application module instances will attempt to stay "sticky" to the last user session that returned them to the pool. The optimization is not a guarantee, but when a user can benefit from the optimization, they continue to work with the same application module instance from the pool as long as system load allows. When load is too high, the pooling algorithm uses any available instance in the pool to service the user's request and the frozen snapshot of their logical unit of work is reconstituted from the persistent store to allow the new instance of the application module to continue where the last one left off. The end user continues to work in this way until they commit or roll back their changes.

Using these facilities, the application module delivers the productivity of a stateful paradigm that can easily handle multipage work flows, in an architecture that delivers the runtime performance near that of a completely stateless application. You will learn more about these application module features in Chapter 49, "Using State Management in a Fusion Web Application" and about how to tune them in Chapter 50, "Tuning Application Module Pools and Connection Pools."

13.7 Customizing an Application Module with Service Methods

An application module can expose its data model of view object instances to clients without requiring any custom Java code. This allows client code to use the ApplicationModule, ViewObject, RowSet, and Row interfaces in the oracle.jbo package to work directly with any view object in the data model. However, just because you can programmatically manipulate view objects any way you want to in client code doesn't mean that doing so is always a best practice.

Whenever the programmatic code that manipulates view objects is a logical aspect of implementing your complete business service functionality, you should encapsulate the details by writing a custom method in your application module's Java class. This includes code that:

  • Configures view object properties to query the correct data to display

  • Iterates over view object rows to return an aggregate calculation

  • Performs any kind of multistep procedural logic with one or more view objects

By centralizing these implementation details in your application module, you gain the following benefits:

  • You make the intent of your code more clear to clients.

  • You allow multiple client pages to easily call the same code if needed.

  • You simplify regression-testing of your complete business service functionality.

  • You keep the option open to improve your implementation without affecting clients.

  • You enable declarative invocation of logical business functionality in your pages.

13.7.1 How to Generate a Custom Class for an Application Module

To add a custom service method to your application module, you must first enable a custom Java class for it. If you have configured your IDE-level Business Components Java generation preferences to automatically generate an application module class, a custom class will be present. As Figure 13-19 shows, if you're not sure whether your application module has a custom Java class, open the overview editor for the application module node in the Applications window. The Java Classes page of the editor displays the complete list of classes generated for the application module in the project. If the file exists because someone created it already, then the Java Classes page will display a linked file name identified as the Application Module Class. To open an existing file in the source editor, click the corresponding file name link.

Figure 13-19 Application Module's Custom Java Class in Overview Editor

Application module class in overview editor

If no Java class exists in your project, you can generate one using the Java Classes page of the overview editor for the application module.

Before you begin:

It may be helpful to have an understanding of application module service methods. For more information, see Section 13.7, "Customizing an Application Module with Service Methods."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To generate a Java file for your application module class:

  1. In the Applications window, double-click the application module.

  2. In the overview editor, click the Java navigation tab and then click the Edit java options button.

  3. In the Select Java Options dialog, select Generate Application Module Class.

  4. Click OK.

    The new .java file will appear in the Java Classes page.

13.7.2 What Happens When You Generate a Custom Class for an Application Module

When you generate a custom class for an application module, JDeveloper creates the file in the same directory as the component's XML document file. The default name for its custom Java file will be AppModuleNameImpl.java.

The Java generation option choices you made for the application module persist on the Java Classes page on subsequent visits to the overview editor for the application module. Just as with the XML definition file, JDeveloper keeps the generated code in your custom Java classes up to date with any changes you make in the editor. If later you decide you do not require a custom Java file, from the Java Classes page open the Select Java Options dialog and deselect Generate Application Module Class to remove the custom Java file from the project.

13.7.3 What You May Need to Know About Default Code Generation

By default, the application module Java class will look similar to what you see in Example 13-4 when you've first enabled it. Of interest, it contains Getter methods for each view object instance in the data model.

Example 13-4 Default Application Module Generated Code

package oracle.summit.model.services;

import oracle.jbo.server.ApplicationModuleImpl;
// ---------------------------------------------------------------------
// ---    File generated by ADF Business Components Design Time.
// ---    Custom code may be added to this class.
// ---    Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class AppModuleImpl extends ApplicationModuleImpl {
  /** This is the default constructor (do not remove) */
  public AppModuleImpl() { }

  /** Container's getter for YourViewObjectInstance1 */
  public YourViewObjectImpl getYourViewObjectInstance1() {
    return (YourViewObjectImpl)findViewObject("YourViewObjectInstance1");
  }

  // ... Additional ViewObjectImpl getters for each view object instance

  // ... ViewLink getters for view link instances here
}

As shown in Figure 13-20, your application module class extends the base ADF ApplicationModuleImpl class to inherit all the default behavior before adding your custom code.

Figure 13-20 Your Custom Application Module Class Extends ApplicationModuleImpl

Image of application module class extending model

13.7.4 How to Add a Custom Service Method to an Application Module

To add a custom service method to an application module, simply navigate to the application module's custom class and enter the Java code for a new method into the application module's Java implementation class. Use the following guidelines to decide on the appropriate visibility for the method:

  • If you will use the method only inside this component's implementation as a helper method, make the method private.

  • If you want to allow eventual subclasses of your application module to be able to invoke or override the method, make it protected.

  • If you need clients to be able to invoke it, it must be public.

Note:

The application module examples in this chapter use strongly typed, custom entity object classes. For details about creating these entity classes, see Chapter 4, "Creating a Business Domain Layer Using Entity Objects."

Example 13-5 shows a private retrieveOrderById() helper method in the AppModuleImpl.java class for the AppModule application module. It uses the static getDefinitionObject() method of the OrdEOImpl entity object class to access its related entity definition, it uses the createPrimaryKey() method on the entity object class to create an appropriate Key object to look up the order, and then it uses the findByPrimaryKey() method on the entity definition to find the entity row in the entity cache. It returns an instance of the strongly typed OrdersImpl class, the custom Java class for the Orders entity object.

Example 13-5 Private Helper Method in Custom Application Module Class

// In summit.model.appmodule.service.AppModuleImpl class
/*
 * Helper method to return a Order by Id
 */
private OrdersImpl retrieveOrderById(long orderId) {
  EntityDefImpl orderDef = OrdersImpl.getDefinitionObject();
  Key orderKey = OrdersImpl.createPrimaryKey(new DBSequence(orderId));
  return (OrdersImpl)orderDef.findByPrimaryKey(getDBTransaction(), orderKey);
}

Example 13-6 shows a public findOrderAndCustomer() method that allows the caller to pass in an ID of an order to be created. It uses the getCustomer() method of the OrdersImpl entity object class to access its related entity definition.

Example 13-6 Public Method in Custom Application Module Class

/*
 * Create a new Customer and Return its new id
 */  
public String findOrderAndCustomer(long orderId) {
    OrdersImpl order = retrieveOrderById(orderId);
  if (order != null) {
        CustomerImpl cust = order.getCustomer();
    if (cust != null) {
      return "Customer: " + cust.getName() + ", Location: " + cust.getCity();
    }
    else {
      return "Unassigned";
    }
  }
  else {
    return null;
  }
}

13.7.5 How to Test the Custom Application Module Using a Static Main Method

When you are ready to test the methods of your custom application module, you can use JDeveloper to generate JUnit test cases. With JUnit, you can use any of the programmatic APIs available in the oracle.jbo package to work with the application module and invoke the custom methods. For details about using JUnit with ADF Business Components, see Section 42.11, "Regression Testing with JUnit."

As an alternative to JUnit test cases, a common technique to test your custom application module methods is to write a simple test case. For example, you could build the testing code into an object and include that code in a static main() method. Example 13-7 shows a sample main() method you could add to your custom application module class to test the sample methods you will write. You'll make use of a Configuration object (see Section 8.4.2, "How to Create a Command-Line Java Test Client") to instantiate and work with the application module for testing.

Note:

The fact that this Configuration object resides in the oracle.jbo.client package suggests that it is used for accessing an application module as an application client. Because a main() method is a kind of programmatic, command-line client, so this is an acceptable practice. Furthermore, even though you typically would not cast the return value of createRootApplicationModule() directly to an application module's implementation class, it is legal to do so in this one situation since despite being a client to the application module, the main() method's code resides right inside the application module implementation class itself.

A glance through the code in Example 13-7 shows that it exercises the methods created in the previous examples to:

  1. Retrieve the total for order 101.

  2. Retrieve the name of the customer for order 101.

  3. Set the status of order 101 to the value "Y".

Example 13-7 Sample Main Method to Test a Custom Application Module from the Inside

package oracle.summit.model.appmodule.service;

import oracle.jbo.ApplicationModule;
import oracle.jbo.JboException;
import oracle.jbo.client.Configuration;

public class TestAM {
    public TestAM() {
        super();
    }

    /*
     * Testing method
     */

    public static void main(String[] args) {
      String amDef = "oracle.summit.model.appmodule.service.AppModule";
      String config = "AppModuleLocal";
      ApplicationModule am =
                      Configuration.createRootApplicationModule(amDef,config);
        /* 
         * NOTE: This cast to use the AppModuleImpl class is OK since this
         *       code is inside a business tier file and not in a
         *       client class that is accessing the business tier from "outside".
         */
        AppModuleImpl service = (AppModuleImpl)am;

        String customerName = service.findOrderAndCustomer(101);
        System.out.println("Customer for Order # 101 = " + customerName);
        try {
           service.updateOrderStatus(101,"Y");
        }
        catch (JboException ex) {
           System.out.println("ERROR: "+ex.getMessage());
        }
      Configuration.releaseRootApplicationModule(am,true);
    }
}

Running the custom application module class calls the main() method in Example 13-7, and shows the following output:

anonymous
Customer for Order # 101 = Customer: Kam's Sporting Goods, Location: Hong Kong

Note:

For an explanation of how you can use the client application to invoke the custom service methods that you create in your custom application module, see Section 13.9, "Publishing Custom Service Methods to UI Clients."

13.7.6 What You May Need to Know About Programmatic Row Set Iteration

Any time your application logic accesses a row set to perform programmatic iteration, you should use a secondary row set iterator when working with view object instances in an application module's data model, or view link accessor row sets of these view object instances, since they may be bound to user interface components. To create a secondary iterator, use the createRowSetIterator() method on the row set you are working with. When you are done using it, call the closeRowSetIterator() method on the row set to remove the secondary iterator from memory. Example 13-8 shows a typical application module custom method that correctly uses a secondary row set iterator for programmatic iteration, because the CustomerView1 view object instance in its data model may be bound to a user interface (either now or at a later time).

Example 13-8 Using a Secondary Row Set Iterator in an Application Module Custom Method

// Custom method in an application module implementation class
public void doSomeCustomProcessing() {
    ViewObject vo = getCustomerView1();
    // create secondary row set iterator with system-assigned name
    RowSetIterator iter = vo.createRowSetIterator(null);
    while (iter.hasNext()) {
        Row r = iter.next();
        // Do something with the current row.
        Integer custId = (Integer)r.getAttribute("Id");
        String name  = (String)r.getAttribute("Name");
        System.out.println(custId + " " + name);
    }
    // close secondary row set iterator
    iter.closeRowSetIterator();
}

Note:

The same recommendation holds for custom code in a view object's implementation class that iterates its own default row set using that row set's default row set iterator.

There are two important reasons to follow this recommendation. Failing to do so can lead to confusion for the end user when the current row unexpectedly changes or it can introduce subtle business logic errors because the first or last row, or both rows get skipped.

  • Confusing the end user by changing the current row unexpectedly

    The iterator bindings determine what row the end-user sees as the current row in the row set. If your own programmatic logic iterates through the row set using the same default row set iterator that the iterator binding uses, you may inadvertently change the current row the user has selected, leaving the user confused.

  • Introducing subtle business logic errors by inadvertently skipping the first or last row

    Iterator bindings force their row set iterator to be on a valid row to guarantee that UI components display data when the row set is not empty. This has the side-effect of preventing your custom logic from navigating to the slot either before the first row or to the slot after the last row (when it is using the same row set iterator as an iterator binding). In concrete terms, this means that a typical while (iter.hasNext()) row set iteration loop will either be skipped or start by processing the second row instead of the first as shown in Example 13-9.

Example 13-9 Consequences of Using the Default Row Set Iterator

// Reset the default row set iterator (iter) to the slot before the first row
iter.reset();
// If an iterator binding is bound to the same default row set iterator,
// then it has already forced it to navigate to the first row here instead
// of being on the slot before the first row.
// 
// If the row set iterator has only one row, the following will then return false
while (iter.hasNext()) {
  // If the row set has more than one row, the first time through the loop
  // this call to next() will return the second row rather than the first
  // row as expected.
  Row curRow = iter.next();
  // Do something with current row
}

13.8 Customizing Application Module Message Strings

The ADF application module does not normally require a resource bundle of its own. However, if you do want to create a .properties file that can use to add your custom message strings, you use the resource bundle option on the Resource Bundle page of the Project Properties dialog and select the option One Bundle Per File. By default JDeveloper sets the option to One Bundle Per Project, which produces a single .properties file for the project.

The .properties file you create can reference attribute properties by their fully qualified package name and custom method exception messages. For example, you might define message keys and strings as follows:

test.Order.Orderno_LABEL=Order Number
INVALID=You have called the method foo in an invalid way.

If your resource bundle defines a message for a method exception message, the custom method should appear in the application module client interface, as described in Section 13.9.1, "How to Publish a Custom Method on the Application Module's Client Interface."

For example, if you defined a message for the method foo() to replace the exception message INVALID, your interface might define this method to invoke the message from the resource bundle as:

public void foo() {
    ResourceBundleDef r = getResourceBundleDef();
    throw new JboException(r,"INVALID",null);
}

Before you begin:

It may be helpful to have an understanding of how projects use resource bundles. For more information, see Section 13.8, "Customizing Application Module Message Strings."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete these tasks:

  1. Create the desired application module, as described in Section 13.2.1, "How to Create an Application Module."

  2. Set the project properties for the data model project to generate one bundle per file, as described in Section 4.7, "Working with Resource Bundles."

To generate the resource bundle for the application module:

  1. In the Applications window, double-click the application module for which you want to generate the resource bundle.

  2. In the overview editor, click the General navigation tab and enter any display name.

    Adding a display name for the application module will generate the .properties file with a message key for the display name.

  3. Save the file.

13.8.1 What Happens When You Add a Resource Bundle to an Application Module

When you generate a resource bundle for an application module, JDeveloper creates the .properties file in the same directory as the component's XML document file. The default name for its custom Java file will be AppModuleNameMsgBundle.properties.

Example 13-10 shows the ResourceBundle element in the application module XML document that references the .properties file.

Example 13-10 Application Module Metadata with Resource Bundle Declaration

<AppModule
  ...
  <ResourceBundle>
    <PropertiesBundle
      PropertiesFile=
         "oracle.summit.model.services.common.BackOfficeAppModuleMsgBundle"/>
  </ResourceBundle>
</AppModule>

13.9 Publishing Custom Service Methods to UI Clients

When you add a public custom method to your application module class, if you want your application's UI to be able to invoke it, you need to include the method on the application module's UI client interface.

13.9.1 How to Publish a Custom Method on the Application Module's Client Interface

To include a public method from your application module's custom Java class on the client interface, use the Java Classes page of the overview editor for the application module.

Before you begin:

It may be helpful to have an understanding of the purpose of the client interface. For more information, see Section 13.9, "Publishing Custom Service Methods to UI Clients."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To publish a custom method on the client interface:

  1. In the Applications window, double-click the application module for which you want to define the client interface.

  2. In the overview editor, click the Java navigation tab and in the Client Interface section, click the Edit application module client interface button.

  3. In the Edit Client Interface dialog, select one or more desired methods from the Available list and click the Add button to shuttle them into the Selected list.

  4. Click OK.

    The new methods will appear in the Client Interface section of the Java Classes page.

Figure 13-21 shows multiple public methods added to the client interface.

Figure 13-21 Public Methods Added to an Application Module's Client Interface

Image of Edit Client Interface dialog

13.9.2 What Happens When You Publish Custom Service Methods

When you publish custom service methods on the client interface, as shown in Figure 13-22, JDeveloper creates a Java interface with the same name as the application module in the common subpackage of the package in which your application module resides. For an application module named AppModule in the summit.model package, this interface will be named AppModule and reside in the summit.model.common package. The interface extends the base ApplicationModule interface in the oracle.jbo package, reflecting that a client can access all of the base functionality that your application module inherits from the ApplicationModuleImpl class.

Figure 13-22 Custom Client Interface Extends the Base ApplicationModule Interface

Image of interface extending application module interface

As shown in Example 13-11, the AppModule interface includes the method signatures of all of the methods you've selected to be on the client interface of your application module.

Example 13-11 Custom Client Interface Based on Methods Selected in the Client Interface Panel

package summit.model.appmodule.service.common;
import oracle.jbo.ApplicationModule;
// ---------------------------------------------------------------------
// ---    File generated by ADF Business Components Design Time.
// ---------------------------------------------------------------------
public interface AppModule extends ApplicationModule {
    String findOrderAndCustomer(long orderId);
    void updateOrderStatus(long orderId, String newStatus);
    String findOrderTotal (long orderId);
    long createCustomer(String name, String city, Integer countryId);
}

Note:

After adding new custom methods to the client interface, if your new custom methods do not appear to be available when you use JDeveloper's code insight context-sensitive statement completion, try recompiling the generated client interface. To do this, select the application module in the Applications window, select the source file for the interface of the same name in the Structure window, and choose Rebuild from the context menu. Consider this tip for new custom methods added to view objects and view rows as well.

13.9.3 How to Generate Client Interfaces for View Objects and View Rows

In addition to generating a client interface for your application module, it is also possible to generate strongly typed client interfaces for working with the other key client objects that you can customize. For example, you can add custom methods to the view object client interface and the view row client interface, respectively.

Before you begin:

It may be helpful to have an understanding of the purpose of the client interface. For more information, see Section 13.9, "Publishing Custom Service Methods to UI Clients."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired view object, as described in Section 5.2, "Populating View Object Rows from a Single Database Table."

To publish a custom method on the client interface for view objects:

  1. In the Applications window, double-click the view object for which you want to define the client interface.

  2. In the overview editor, click the Java navigation tab and in the Client Interface section, click the Edit java options button.

  3. In the Select Java Options dialog, click the Generate View Object Class and click the Generate View Row Class. Click OK.

  4. In the overview editor, expand the Client Interface section and then click the Edit view object client interface button.

  5. In the Edit Client Interface dialog, select one or more desired methods from the Available list and click the Add button to shuttle them into the Selected list.

  6. In the overview editor, expand the Client Row Interface section and then click the Edit view object client row interface button.

  7. In the Edit Client Interface dialog, select one or more desired methods from the Available list and click the Add button to shuttle them into the Selected list.

  8. Click OK.

    The new methods will appear in the Java Classes page.

For example, if for the CustomerView view object in the summit.model.views package you were to enable the generation of a custom view object Java class and add one or more custom methods to the view object client interface, JDeveloper would generate the CustomerViewImpl class and CustomerView interface, as shown in Figure 13-23. As with the application module custom interface, notice that it gets generated in the common subpackage.

Figure 13-23 Custom View Object Interface Extends the Base ViewObject Interface

Image of view object interface extending another interface

Likewise, if for the same view object you were to enable the generation of a custom view row Java class and add one or more custom methods to the view row client interface, JDeveloper would generate the CustomerViewRowImpl class and CustomerViewRow interface, as shown in Figure 13-24.

Figure 13-24 Custom View Row Interface Extends the Base Row Interface

image view row interface extending the Base Row Interface

13.9.4 How to Test Custom Service Methods Using the Oracle ADF Model Tester

You can test the methods of your custom application module in the Oracle ADF Model Tester after you have published them on the client interface, as described in Section 13.9, "Publishing Custom Service Methods to UI Clients."

Before you begin:

It may be helpful to have an understanding of the purpose of the client interface. For more information, see Section 13.9, "Publishing Custom Service Methods to UI Clients."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To test the service methods that you have published:

  1. In the Applications window, right-click the application module and choose Run.

    Alternatively, choose Debug when you want to run the application in the Oracle ADF Model Tester with debugging enabled. The debugger process panel opens in the Log window and the various debugger windows. When debugging using the Oracle ADF Model Tester, you can use these windows to view status message and exceptions, step in and out of source code, and manage breakpoints.

    For information about receiving diagnostic messages specific to ADF Business Component debugging, see Section 8.3.10, "How to Enable ADF Business Components Debug Diagnostics."

  2. To open the method testing panel for a method defined by a client interface, do one of the following:

    • In the data model tree, select the application module node and in the main menu choose View and then Operations when you want to execute a method you published for the application module client interface. You can also double-click the application module node to display the method testing panel.

    • In the data model tree, select the desired view object node and in the main menu choose View and then Operations when you want to execute a method you published on the client interface for a view object. You can also right-click the view object node and choose Operations.

  3. To open the method testing panel for a method defined by a client row interface for a view object row, expand the data model tree, right-click the desired view object node and choose Show Table. Then in the overview panel for the view instance, select the desired row, and in the main menu, choose View and then Operations.

    Do not select a master view instance in the data model tree since view row operations are not permitted on master view objects. Always select a detail view instance or a view instance that is not specified in a master-detail hierarchy, as shown in Figure 13-25.

    Tip:

    In the case of a detail view instance, you can open the master view instance to navigate to the detail with the desired row. The Oracle ADF Model Tester automatically synchronizes the data displayed in the open overview panel with the master view instance that you navigate to.

    Figure 13-25 Menu Selection for View Row Operations in the Oracle ADF Model Tester

    Image of tester View menu.
  4. In the method panel, select the desired service method from the dropdown list, enter values to pass as method parameters, and click Execute.

    Notice that the method testing panel displays the parameter names to help you identify where to enter the values to pass. This is particularly useful when the method signature defines multiple parameters of the same data type.

    You can view the return value (if any) and test result. The result displayed in the Oracle ADF Model Tester will indicate whether or not the method executed successfully.

13.9.5 What You May Need to Know About Method Signatures on the Client Interface

You can include any custom method in the client interface that obeys these implementation rules:

  • If the method has a non-void return type, the type must be serializable.

  • If the method accepts any parameters, all their types must be serializable.

  • If the method signature includes a throws clause, the exception must be an instance of JboException in the oracle.jbo package.

In other words, all the types in its method signature must implement the java.io.Serializable interface, and any checked exceptions must be JboException or its subclass. Your method can throw any unchecked exception — java.lang.RuntimeException or a subclass of it — without disqualifying the method from appearing on the application module's client interface.

Note that method signatures of type java.util.List are allowed as long as the implementing class for the interface is serializable. For example, java.util.ArrayList and java.util.LinkedList are both serializable implementing classes. The same requirement applies to element types within the collection. The ADF Business Components runtime will produce an error if you instantiate a class that implements the interface yet does not implement the java.io.Serializable interface.

Note:

If the method you've added to the application module class doesn't appear in the Available list, first verify that it doesn't violate any of the method implementation rules. If it seems like it should be a legal method, try recompiling the application module class before visiting the overview editor for the application module again.

13.9.6 What You May Need to Know About Passing Information from the Data Model

The private implementation of an application module custom method can easily refer to any view object instance in the data model using the generated accessor methods. By calling the getCurrentRow() method on any view object, it can access the same current row for any view object that the client user interface sees as the current row. As a result, while writing application module business service methods, you may not need to pass in parameters from the client. This is true if you would be passing in values only from the current rows of other view object instances in the same application module's data model.

For example, the custom application module method in Example 13-12 accepts no parameters. Internally, the createOrderItem() method calls getGlobals().getCurrentRow() to access the current row of the Globals view object instance. Then it uses the strongly typed accessor methods on the row to access the values of the Description and LineItemId attributes to set them as the values of corresponding attributes in a newly created OrderItem entity object row.

Example 13-12 Using View Object Accessor Methods to Access a Current Row

// In AppModuleImpl.java, createOrderItem() method
GlobalsRowImpl globalsRow = (GlobalsRowImpl)getGlobals().getCurrentRow();
newOrder.setDescription(globalsRow.getDescription());
newOrder.setLineItemId(globalsRow.getLineItemId());

13.10 Working Programmatically with an Application Module's Client Interface

After publishing methods on your application module's client interface, you can invoke those methods from a client.

13.10.1 How to Work Programmatically with an Application Module's Client Interface

To work programmatically with an application module's client interface, do the following:

  • Cast ApplicationModule to the more specific client interface.

  • Call any method on the interface.

Note:

For simplicity, this section focuses on working only with the custom application module interface; however, the same downcasting approach works on the client to use a ViewObject interface as a view object interface like Customers or a Row interface as a custom view row interface like CustomersRow.

Example 13-13 illustrates a TestClientEntity class that puts these two steps into practice. You could also use the main() method of this class to test application module methods, as described in Section 13.7.5, "How to Test the Custom Application Module Using a Static Main Method." Here you use it to call all of the same methods from the client using the AppModule client interface.

Note:

If you work with your application module using the default ApplicationModule interface in the oracle.jbo package, you won't have access to your custom methods. Make sure to cast the application module instance to your more specific custom interface like the AppModule interface in this example.

The basic logic of Example 13-13 follows these steps:

  1. Retrieve the total for order 1011.

  2. Retrieve the name of the customer for order 1011.

  3. Set the status of order 1011 to the value "Y".

  4. Create anew customer supplying a null customer name.

  5. Create a new customer with a customer name and display its newly assigned customer ID.

Example 13-13 Sample Main Method to Test a Custom Application Module from the Inside

package oracle.summit.model.appmodule.client;

import oracle.jbo.client.Configuration;
import oracle.jbo.*;
import oracle.jbo.domain.Number;
import oracle.jbo.domain.*;

import oracle.summit.model.appmodule.service.common.AppModule;

public class TestClientCustomInterface {
  public static void main(String[] args) {
      String amDef = "oracle.summit.model.appmodule.service.AppModule";
      String config = "AppModuleLocal";

      /*
       * This is the correct way to use application custom methods
       * from the client, by using the application module's automatically-
       * maintained custom service interface.
       */
      AppModule service =
               (AppModule)Configuration.createRootApplicationModule(amDef,config);
      String total = service.findOrderTotal(1011);
      System.out.println("Total for Order # 1011 = " + total);
      String custName = service.findOrderAndCustomer(1011);
      System.out.println("Customer for Order # 1011 = " + custName);
      try {
         service.updateOrderStatus(1011,"Y");
      }
      catch (JboException ex) {
         System.out.println("ERROR: "+ex.getMessage());
      }
      long id = 0;
      try {
         id = service.createCustomer(null, "Oakville", 14);
      }
      catch (JboException ex) {
         System.out.println("ERROR: "+ex.getMessage());
      }
      id = service.createCustomer("Oakville Curling Club", "Oakville", 14);
      System.out.println("New customer created successfully with id = " + id);
      Configuration.releaseRootApplicationModule(service,true);
  }
}

Running the custom application module class calls the main() method in Example 13-13, and shows the following output:

Total for Order # 1011 = 99.99
Customer for Order # 1011 = Customer: Zibbers, Location: Boston
ERROR: JBO-27014: You must provide a value for Name.
New customer created successfully with id = 133

Notice that the first attempt to call findOrderAndCustomer() with a null for the customer name raises an exception due to the built-in mandatory validation on the Name attribute of the Customer entity object.

13.10.2 What Happens at Runtime: How the Application Module's Client Interface is Accessed

Because the client layer accessing your application module will be located in the same tier of the Java EE architecture, the application module is deployed in what is known as local mode. In local mode, the client interface is implemented directly by your custom application module Java class. You access an application module in local mode whenever you access the application module in the web tier of a JavaServer Faces application.

13.10.3 How to Access an Application Module Client Interface in a Fusion Web Application

The Configuration class in the oracle.jbo.client package makes it very easy to get an instance of an application module for testing. This eases writing test client programs like the test client program described in Section 42.11, "Regression Testing with JUnit" as part of the JUnit regression testing fixture.

Best Practice:

For Fusion web applications you should always work though the binding layer to access the application module. While developers may be tempted to use the class createRootApplicationModule() and releaseApplicationModule() methods anywhere to access an application module, the best approach is to use the declarative features of the ADF Model layer.

When working with Fusion web applications using the ADF Model layer for data binding, JDeveloper configures a servlet filter in your user interface project called the ADFBindingFilter. It orchestrates the automatic acquisition and release of an appropriate application module instance based on declarative binding metadata, and ensures that the service is available to be looked up as a data control using a known action binding or iterator binding, specified by any page definition file in the user interface project. You may eventually want to read about the ADF binding container, data controls, page definition files, and bindings, as described in Chapter 17, "Using ADF Model in a Fusion Web Application." For now, it is enough to realize that you can access the application module's client interface from this DCBindingContainer by naming an ADF action binding or an ADF iterator binding. You can reference the binding context and call methods on the custom client interface in a JSF managed bean, as shown in Example 13-14 for an action binding and Example 13-15 for an iterator binding.

To access the custom interface of your application module using an action binding, follow these basic steps (as illustrated in Example 13-14):

  1. Access the ADF binding container.

  2. Find a named action binding. (Use the name of any available action binding in the page definition files of the user interface project.)

  3. Get the data control by name from the action binding.

  4. Access the application module data provider from the data control.

  5. Cast the application module to its client interface.

  6. Call any method on the client interface.

Example 13-14 Accessing the Application Module Client Interface in a JSF Backing Bean Using a Named Action Binding

package oracle.summit.model.viewobjects;

import oracle.summit.model.appmodule.service.common.SummitAppModule;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCDataControl;
import oracle.jbo.ApplicationModule;
import oracle.jbo.uicli.binding.JUCtrlActionBinding;
public class YourBackingBean {
  public String commandButton_action() {
    // Example using an action binding to get the data control
    public String commandButton_action() {
    // 1. Access the binding container
    DCBindingContainer bc = (DCBindingContainer)getBindings();
    // 2. Find a named action binding
    JUCtrlActionBinding action = 
                    (JUCtrlActionBinding)bc.findCtrlBinding("SomeActionBinding");
    // 3. Get the data control from the iterator binding (or method binding)
    DCDataControl dc  = action.getDataControl();
    // 4. Access the data control's application module data provider
    ApplicationModule am = (ApplicationModule)dc.getDataProvider();
    // 5. Cast the AM to call methods on the custom client interface
    SummitAppModule service = (SummitAppModule)am;
    // 6. Call a method on the client interface
    service.doSomethingInteresting();
    return "SomeNavigationRule";
  }
}

To access the custom interface of your application module using an iterator binding, follow these basic steps (as illustrated in Example 13-15):

  1. Access the ADF binding container.

  2. Find a named iterator binding. (Use the name of any iterator binding in the page definition files of the user interface project.)

  3. Get the data control by name from the iterator binding.

  4. Access the application module data provider from the data control.

  5. Cast the application module to its client interface.

  6. Call any method on the client interface.

Example 13-15 Accessing the Application Module Client Interface in a JSF Backing Bean Using a Named Iterator Binding

package oracle.summit.model.viewobjects;

import oracle.summit.model.appmodule.service.common.SummitAppModule;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCDataControl;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.jbo.ApplicationModule;
public class YourBackingBean {
  public String commandButton_action() {
    // Example using an iterator binding to get the data control
    public String commandButton_action() {
    // 1. Access the binding container
    DCBindingContainer bc = (DCBindingContainer)getBindings();
    // 2. Find a named iterator binding
    DCIteratorBinding iter = bc.findIteratorBinding("SomeIteratorBinding");
    // 3. Get the data control from the iterator binding
    DCDataControl dc  = iter.getDataControl();
    // 4. Access the data control's application module data provider
    ApplicationModule am = (ApplicationModule)dc.getDataProvider();
    // 5. Cast the AM to call methods on the custom client interface
    SummitAppModule service = (SummitAppModule)am;
    // 6. Call a method on the client interface
    service.doSomethingInteresting();
    return "SomeNavigationRule";
  }
}

These backing bean examples depend on the helper method shown in Example 13-16.

Example 13-16 Helper Method for Backing Bean Class

public BindingContainer getBindings() {
{
        return BindingContext.getCurrent().getCurrentBindingsEntry();
}

If you create the backing bean class by overriding a button that is declaratively bound to an ADF action, then JDeveloper will automatically generate this method in your class. Otherwise, you will need to add the helper method to your class yourself.

13.11 Overriding Built-in Framework Methods

The ApplicationModuleImpl base class provides a number of built-in methods that implement its functionality. While Appendix D, "Most Commonly Used ADF Business Components Methods" provides a quick reference to the most common code that you will typically write, use, and override in your custom application module classes, this section focuses on helping you understand the basic steps to override one of these built-in framework methods to augment the default behavior.

13.11.1 How to Override a Built-in Framework Method

To override a built-in framework method for an application module, use the Override Methods dialog, which you open for the application module Java class from the main menu.

Before you begin:

It may be helpful to have an understanding of the application module base class. For more information, see Section 13.11, "Overriding Built-in Framework Methods."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired application modules, as described in Section 13.2.1, "How to Create an Application Module."

To override an application module framework method:

  1. In the Applications window, double-click the application module for which you want to override framework methods.

  2. In the overview editor, click the Java navigation tab and then click the linked file name of the application module Java class that you want to customize.

    The class file opens in the source editor.

  3. In the main menu, choose Source and then Override Methods.

    If the Source menu is not displayed, be sure that the desired Java class file is open and that the source editor is visible.

  4. In the Override Methods dialog, scroll the list to locate the desired methods or type the first few letters of the method name to perform an incremental search.

  5. Select one or more methods.

    The Override Methods dialog allows you to select any number of methods to override simultaneously.

    For example, if you wanted to override the application module's prepareSession() method to augment the default functionality when a new user session begins working with an application module service component for the first time, you would select the checkbox next to the prepareSession(Session) method, as shown in Figure 13-26.

    Figure 13-26 Overriding a Built-in Framework Method

    Image of Override Methods dialog
  6. Click OK.

13.11.2 What Happens When You Override a Built-in Framework Method

When you dismiss the Override Methods dialog, you return to the source editor with the cursor focus on the overridden method, as shown in Figure 13-27. Notice that the method appears with a single line that calls super.prepareSession(). This is the syntax in Java for invoking the default behavior that the base class would have normally performed for this method. By adding code before or after this line in the custom application module class, you can augment the default behavior before or after the default functionality.

Figure 13-27 Source Editor Margin Gives Visual Feedback About Overridden Methods

Image of Code Editor margin

Also notice that when you override a method using the Override Methods dialog, the source editor inserts the JDK @Override annotation just before the overridden method. This causes the compiler to generate a compile-time error if the method in the application module class does not match the signature of any method in the superclass.

Be careful when you add method names to your class to override a method in the superclass; you must have the signature exactly the same as the base class method you want to override. Be sure to add the @Override annotation just before the method. This way, if your method does not match the signature of any method in the superclass, the compiler will generate a compile-time error. Also, when you write code for a method instead of calling the superclass implementation, you should have a thorough understanding of what built-in code you are suppressing or replacing.

13.11.3 How to Override prepareSession() to Set Up an Application Module for a New User Session

Since the prepareSession() method is invoked by the application module when it is used for the first time by a new user session, it's a useful method to override in your custom application module class to perform setup tasks that are specific to each new user that uses your application module. Example 13-17 illustrates an overridden prepareSession() method in the AppModuleImpl class that invokes a setApplicationInfo() helper method to specify database client information for the connected user.

Example 13-17 Initializing the Client Data to Use for Current User Session

public class AppModuleImpl extends SummitApplicationModuleImpl 
                           implements AppModule {
...

    @Override
    protected void prepareSession(Session session) {
        super.prepareSession(session);
        setApplicationInfo ("AppModuleImpl", "prepareSession");
        String username = this.getUserPrincipalName();
        System.out.println(username);
    }
    
    protected void setApplicationInfo(String clientInfo, String clientIdentifier){
        DBTransactionImpl dbti = (DBTransactionImpl)getDBTransaction();
        CallableStatement statement =
            dbti.createCallableStatement("BEGIN " 
          + "DBMS_APPLICATION_INFO.SET_CLIENT_INFO (client_info => :client_info);"
          + "DBMS_SESSION.SET_IDENTIFIER (:client_identifier);"
          + "END;", 0);
        try {
            statement.setString("client_info", clientInfo);
            statement.setString("client_identifier", clientIdentifier);
            statement.execute();
        } catch (SQLException sqlerr) {
            throw new JboException(sqlerr);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException closeerr) {
                throw new JboException(closeerr);
            }
        }
    }
}

13.12 Calling a Web Service from an Application Module

In a service-oriented architecture, your Oracle ADF application module may need to take advantage of functionality offered by a web service that is not based on an application module. A web service can be implemented in any programming language and can reside on any server on the network. Each web service identifies the methods in its API by describing them in a standard, language-neutral XML format. This XML document, whose syntax adheres to the Web Services Description Language (WSDL), enables JDeveloper to understand the names of the web service's methods, as well as the data types of the parameters they might expect and their eventual return value.

Note:

Application modules can also be exposed as web services so that they can be consumed across modules of the deployed Fusion web application. For details about reusing ADF Business Components using external services, see Chapter 15, "Integrating Service-Enabled Application Modules."

JDeveloper's built-in web services wizards make this an easy task. Create a web service proxy class using the wizard, then call the service using method calls you add to a local Java object.

13.12.1 How to Call an External Service Programmatically

To call a web service from an application module, you create a web service proxy class for the service you want to invoke. A web service proxy is a generated Java class that represents the web service inside your application. It encapsulates the service URL of the web service and handles the lower-level details of making the call.

To work with a web service, you need to know the URL that identifies its WSDL document. If you have received the WSDL document as an email attachment, for example, and saved it to your local hard drive, the URL could be similar to:

file:///D:/temp/SomeService.wsdl

Alternatively, the URL could be an HTTP-based URL like:

http://someserver.somecompany.com/SomeService/SomeService.wsdl

Some web services make their WSDL document available by using a special parameter to modify the service URL. For example, a web service that expects to receive requests at the HTTP address of http://someserver.somecompany.com/SomeService might publish the corresponding WSDL document using the same URL with an additional parameter on the end, like this:

http://someserver.somecompany.com/SomeService?WSDL

Since there is no established standard, you will just need to know what the correct URL to the WSDL document is. With the URL information, you can then create a web service proxy class to call the service.

ADF Business Components services have URLs to the service of the following formats:

  • On Integrated WebLogic Server, the URL has the format http://host:port/EJB-context-root/@WebService-name?WSDL, for example:

    http://localhost:8888/EJB-SummitService/SummitService?WSDL
    
  • On Oracle WebLogic Server, the URL has the format http://host:port/context-root/@WebService-name?WSDL, for example:

    http://localhost:8888/SummitService/SummitService?WSDL
    

The web service proxy class presents a set of Java methods that correspond to the web service's public API. By using the web service proxy class, you can call any method in the web service in the same way as you work with the methods of any other local Java class.

To call a web service from an application module using a proxy class, you perform the following tasks:

  1. Create a web service proxy class for the web service. To create a web service proxy class for a web service that you need to call, use the Create Web Service Client and Proxy wizard.

  2. Implement the methods in the proxy class to access the desired web services.

  3. Create an instance of the web service proxy class in your application module and invoke one or more methods on the web service proxy object.

13.12.1.1 Creating a Web Service Proxy Class to Programmatically Access the Service

To create a web service proxy class for a web service you need to call, use the Create Web Service Proxy wizard.

Before you begin:

It may be helpful to have an understanding of web services. For more information, see Section 13.12, "Calling a Web Service from an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To create a web service proxy class to programmatically access the service:

  1. In the Applications window, right-click the project in which you want to create the web service proxy and choose New and then Web Service Client and Proxy.

  2. In the Create Web Service Client and Proxy wizard, on the Select Web Service Description page, enter the URL for the WSDL of the service you want to call in your application, and then tab out of the field.

    When the wizard displays Next enabled, then JDeveloper has recognized and validated the WSDL document. If the Next button is not enabled, fix the problem after verifying the URL and repeat this step.

  3. Continue through the pages of the wizard to specify details about the web service proxy.

  4. Click Finish.

13.12.1.2 Calling the Web Service Proxy Template to Invoke the Service

After you create the web service proxy, you must implement the methods in the proxy class to access the desired web services.

Before you begin:

It may be helpful to have an understanding of web services. For more information, see Section 13.12, "Calling a Web Service from an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

You will need to complete this task:

Create the desired web service proxy class, as described in Section 13.12.1.1, "Creating a Web Service Proxy Class to Programmatically Access the Service."

To call the web service proxy template to invoke the service:

  1. Open the proxy client class, called port_nameClient.java, in the source editor, and locate the comment // Add your own code to call the desired methods, which is in the main method.

  2. Add the appropriate code to invoke the web service.

  3. Deploy the full set of client module classes that JDeveloper has generated, and reference this class in your application.

13.12.1.3 Calling a Web Service Method Using the Proxy Class in an Application Module

After you've generated the web service proxy class, you can use it inside a custom method of your application module, as shown in Example 13-18. The method creates an instance of the web service proxy class and calls the web service method from the web service proxy class for the result.

Example 13-18 Web Service Proxy Class Calls Web Service Method

// In YourModuleImpl.java
public void performSomeApplicationTask(String symbol) throws Exception {
  // application-specific code here
   :
  // Create an instance of the web service proxy class 
  StockQuoteServiceSoapHttpPortClient svc =
            new StockQuoteServiceSoapHttpPortClient();
  // Call a method on the web service proxy class and get the result
  QuoteInfo quote = svc.quoteForSymbol(symbol);
  float currentPrice = quote.getPrice();
  // more application-specific code here
}

13.12.2 What Happens When You Create the Web Service Proxy

JDeveloper generates the web service proxy class in the package you've indicated with a name that reflects the name of the web service port it discovered in the WSDL document. The web service port name might be a human-readable name like StockQuoteService, or could be a less-friendly name like StockQuoteServiceSoapHttpPort. The port name is decided by the developer that published the web service you are using. If the port name of the service were StockQuoteServiceSoapHttpPort, for example, JDeveloper would generate a web proxy class named StockQuoteServiceSoapHttpPortClient.

The web service proxy displays in the Applications window as a single, logical node called WebServiceNameProxy. For example, the node for the StockQuoteService web service would appear in the Applications window with the name StockQuoteServiceProxy. As part of generating the proxy class, in addition to the main web service proxy class that you use to invoke the server, JDeveloper generates a number of auxiliary classes and interfaces. You can see these files in the Applications window under the WebServiceNameProxy node. The generated files are used as part of the lower-level implementation of invoking the web service.

The only auxiliary generated classes you need to reference are those created to hold structured web service parameters or return types. For example, imagine that the StockQuoteService web service has a quoteForSymbol() method that accepts one String parameter and returns a floating-point value indicating the current price of the stock. If the designer of the web service chose to return a simple floating-point number, then the web service proxy class would have a corresponding method like this:

public float quoteForSymbol(String symbol)

If instead the designer of the web service thought it useful to return multiple pieces of information as the result, then the service's WSDL file would include a named structure definition describing the multiple elements it contains. For example, assume that the service returns both the symbol name and the current price as a result. To contain these two data elements, the WSDL file might define a structure named QuoteInfo with an element named symbol of string type and an element named price of floating-point type. In this situation, when JDeveloper generates the web service proxy class, the Java method signature would instead look like this:

public QuoteInfo quoteForSymbol(String symbol)

The QuoteInfo return type references one of the auxiliary classes that comprises the web service proxy implementation. It is a simple bean whose properties reflect the names and types of the structure defined in the WSDL document. In a similar way, if the web service accepts parameters whose values are structures or arrays of structures, then you will work with these structures in your Java code using the corresponding generated beans.

13.12.3 How to Create a New Web Service Connection

After developing a web service proxy, you can generate additional connections for the proxy that you can use in testing and deployment situations. For example, you might want to create a connection that includes user name and password for testing purposes.

The connection information is stored in the connections.xml file along with the other connections in your application. This abstraction of the endpoint URL also allows you to edit the connection after deployment using Enterprise Manager without requiring modification to the client code.

Before you begin:

It may be helpful to have an understanding of web services. For more information, see Section 13.12, "Calling a Web Service from an Application Module."

You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 13.1.2, "Additional Functionality for Application Modules."

To create a new web service connection:

  1. In the Applications window, right-click a web service proxy and choose Create ADF Web Service Connection.

    The New ADF Web Service Connection dialog displays the default settings for a connection associated with the selected proxy.

  2. Modify the connection information as necessary, and click OK.

WARNING:

If you create a new web service connection with the same name as an existing connection, the existing connection will be overwritten with the new information.

After you create a new web service connection, you can modify your client to use this connection. You could use code similar to that shown in Example 13-19 to access the connection from your client.

Example 13-19 Accessing a Web Service Connection from a Client

Context ctx = ADFContext.getCurrent().getConnectionsContext();
WebServiceConnection wsc = (WebServiceConnection) ctx.lookup("MyAppModuleService");
MyAppModuleService proxy = wsc.getJaxWSPort(MyAppModuleService.class);

The argument that you pass to the lookup() method is the name that you gave to the web service connection. In this example, it is MyAppModuleService.

13.12.4 What Happens at Runtime: How the Web Service Proxy Handles a Web Service Invocation

When you invoke a web service from an application module, the web service proxy class handles the lower-level details of using the XML-based web services protocol described in SOAP. In particular, it does the following:

  • Creates an XML document to represent the method invocation

  • Packages any method arguments in XML

  • Sends the XML document to the service URL using an HTTP POST request

  • Unpackages the XML-encoded response from the web service

If the method you invoke has a return value, your code receives it as an appropriately typed object to work with in your application module code.

13.12.5 What You May Need to Know About Web Service Proxies

When you are implementing web service proxies in an application, you might want to use a try-catch block to handle web service exceptions or invoke an application module with a web service proxy class. The following sections contain additional information you might need to know about these and other features with regard to web service proxies.

13.12.5.1 Using a Try-Catch Block to Handle Web Service Exceptions

By using the generated web service proxy class, invoking a remote web service becomes as easy as calling a method in a local Java class. The only distinction to be aware of is that the web service method call could fail if there is a problem with the HTTP request involved. The method calls that you perform against a web service proxy should anticipate the possibility that the request might fail by wrapping the call with an appropriate try...catch block. Example 13-20 improves on the simpler example (shown in Section 13.12.1.3, "Calling a Web Service Method Using the Proxy Class in an Application Module") by catching the web service exception. In this case, it simply rethrows the error as a JboException, but you could implement more appropriate error handling in your own application.

Example 13-20 Wrapping Web Service Method Calls with a Try-Catch Block

// In YourModuleImpl.java
public void performSomeApplicationTask(String symbol) {
  // application-specific code here
  // :
  QuoteInfo quote = null;
  try {
    // Create an instance of the web service proxy class 
    StockQuoteServiceSoapHttpPortClient svc =
               new StockQuoteServiceSoapHttpPortClient();
    // Call a method on the web service proxy class and get the result
    quote = svc.quoteForSymbol(symbol);
  }
  catch (Exception ex) {
    throw new JboException(ex);
  }
  float currentPrice = quote.getPrice();
  // more application-specific code here
}

13.12.5.2 Separating Application Module and Web Services Transactions

You will use some web services to access reference information. However, other services you call may modify data. This data modification might be in your own company's database if the service was written by a member of your own team or another team in your company. If the web service is outside your firewall, of course the database being modified will be managed by another company.

In either of these situations, it is important to understand that any data modifications performed by a web service you invoke will occur in their own distinct transaction, unrelated to the application module's current unit of work. For example, if you have invoked a web service that modifies data and then you later call rollback() to cancel the pending changes in the application module's current unit of work, this has no effect on the changes performed by the web service you called in the process. You may need to invoke a corresponding web service method to perform a compensating change to account for your rollback of the application module's transaction.

13.12.5.3 Setting Browser Proxy Information

If the web service you need to call resides outside your corporate firewall, you need to ensure that you have set the appropriate Java system properties to configure the use of an HTTP proxy server. The Java system properties to configure are:

  • http.proxyHost — Set this to the name of the proxy server.

  • http.proxyPort — Set this to the HTTP port number of the proxy server (often 80).

  • http.nonProxyHosts — Optionally set this to a vertical-bar-separated list of servers not requiring the user of a proxy server (for example, localhost|127.0.0.1|*.yourcompany.com).

Within JDeveloper, you can configure an HTTP proxy server on the Web Browser and Proxy page of the Preferences dialog. When you run your application, JDeveloper includes appropriate -D command-line options to set these three system properties based on the settings you've indicated in this dialog.

13.12.5.4 Invoking Application Modules with a Web Service Proxy Class

If you use a web service proxy class to invoke an Oracle ADF service-based application module, you lose the ability to optimize the call when the calling component and the service you are calling are colocated. As an alternative, you can use the service interface approach described in Chapter 15, "Integrating Service-Enabled Application Modules."