10 Sharing Application Module View Instances

This chapter describes how to organize your ADF Business Components data model project to most efficiently share read-only data accessed from lookup tables or other static data source, such as a flat file. It describes the differences between ADF application modules that you may share at the application level and those that you may share at the session level.

10.1 About Shared Application Modules

Web applications often utilize data that is required across sessions and does not change very frequently. An example of this type of static data might be displayed in the application user interface in a lookup list. Each time your application accesses the static data, you could incur an unnecessary overhead when the static data caches are repopulated from the database for each application session on every request. In order to optimize performance, a common practice when working with ADF Business Components is to cache the shared static data for reuse across sessions and requests.

10.1.1 Shared Application Module Use Cases and Examples

View accessors in ADF Business Components are value accessor objects that point from an entity object attribute (or view object) to a destination view object or shared view instance in the same application workspace.

Validation rules that you set on the attributes of an entity object. For example, when the end user fills out a registration form, individual validation rules can verify the title, marital status, and contact code against lookup table data queried by view instances of the shared application module.

List of Value (LOV) that you enable for the attribute of any view object. For example, to display a list of values to the end user at runtime.

10.1.2 Additional Functionality for Shared Application Modules

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

10.2 Sharing an Application Module Instance

Declarative support for shared data caches is available in JDeveloper through the Project Properties dialog. Creating a shared application module allows requests from multiple sessions to share a single application module instance which is managed by an application pool for the lifetime of the web server virtual machine.

Best Practice:

Use a shared application module to group view instances when you want to reuse lists of static data across the application. The shared application module can be configured to allow any user session to access the data or it can be configured to restrict access to just the UI components of a single user session. For example, you can use a shared application module to group view instances that access lookup data, such as a list of countries. The use of a shared application module allows all shared resources to be managed in a single place and does not require a scoped managed bean for this purpose.

As shown in Figure 10-1, the Project Properties dialog lets you specify application-level or session-level sharing of the application module's data model. In the case of application-level sharing, any HTTP user session will be able to access the same view instances contained in the shared application module. In contrast, the lifecycle of the session-level shared application module extends to an application module session (SessionImpl) that is in use by a single HTTP user session and applies to a single root application module. In this case, each distinct root application module used by a given HTTP user session will get its own distinct instance of a session-scoped shared application module. In other words, distinct root application modules used by the same HTTP session do not share data in a session-scoped shared application module.

When you create the data model for the application module that you intend to share, be sure that the data in cached row sets will not need to be changed either at the application level or session level. For example, in the application-level shared application module, view instances should query only static data such as state codes or currency types. If a view object instance queries data that depends on the current user, then the query can be cached at the session level and shared by all components that reference the row-set cache. For example, the session-level shared application module might contain a view instance with data security that takes a manager as the current user to return the list of direct reports. In this case, the cache of direct reports would exist for the duration of the manager's HTTP user session. The ADF Business Components application module pool will recreate the session-scoped application module should an HTTP user session be assigned a recycled application module from the pool. This ensures that the duration of the session-scoped application module is tied to the HTTP session for as long as the HTTP session is able to continue to use the same root application module instance. Note that the cache of direct reports of the session-level shared application module cannot be accessed across distinct root application modules.

10.2.1 How to Create a Shared Application Module Instance

To create a shared application module instance, use the Project Properties dialog. You define a logical name for a distinct, separate root application module that will hold your application's read-only data.

On the ADF Business Components: Application Module Instances page, select one of these tabs:

When you want to define the shared application module for the context of the application, select the Application tab.

When you want to define the shared application module for the context of the current user session, select the Session tab

In the Available Application Modules list, select the desired application module and shuttle it to the Application Module Instances list.

Assign the application module a unique instance name.

The shared application module instance (of either scope) must have a unique instance name. Supplying a meaningful name will also help to clarify which shared application module instance a given usage is referencing.

Click OK.

10.2.2 What Happens When You Define a Shared Application Module

JDeveloper automatically creates the AppModuleNameShared configuration when you create an application module. The presence of this configuration in the bc4j.xcfg file informs JDeveloper that the application module is a candidate to be shared, and allows JDeveloper to display the application module in the Available Application Modules list of the Project Properties dialog's Application Module Usage page.

The AppModuleNameShared configuration sets these properties on the application module to enable sharing and help to maintain efficient use of the shared resource at runtime:

jbo.ampool.isuseexclusive is set to false to specify that requests from multiple sessions can share a single instance of the application module, which is managed by the application pool for the lifetime of the web server virtual machine. When you do not enable application module sharing, JDeveloper sets the value true to repopulate the data caches from the database for each application session on every request.

jbo.ampool.maxpoolsize is set to 1 (one) to specify that only a single application module instance will be created for the ADF Business Components application module pool. This setting enforces the efficient use of the shared application module resource and prevents unneeded multiple instances of the shared application module from being created at runtime.

You can view the shared application module's configuration by choosing Configurations from the context menu on the application module in the Application Navigator. JDeveloper saves the bc4j.xcfg file in the ./common subdirectory relative to the application module's XML component definition. If you remove the configuration or modify the values of the jbo.ampool runtime properties (isuseexclusive, maxpoolsize), the application module will not be available to use as a shared application module instance.

For example, if you look at the bc4j.xcfg file in the ./src/oracle/fodemo/storefront/lookups/common directory of the Fusion Order Demo application's StoreFrontService project, you will see the two named configurations for the LookupServiceAM application module, as shown in Example 10-1. Specifically, the LookupServiceAMShared configuration sets the jbo.ampool runtime properties on the shared application module instance. For more information about the ADF Business Components application module pooling and runtime configuration of application modules, see Chapter 44, "Tuning Application Module Pools and Connection Pools."

Because the shared application module can be accessed by any data model project (based on ADF Business Components) in the same application workspace, JDeveloper maintains the scope of the shared application module in the ADF Business Components project configuration file (.jpx). This file is saved in the src directory of the project. For example, if you look at the StoreFrontService.jpx file in the ./src directory of the Fusion Order Demo application's StoreFrontService project, you will see that the SharedLookupService application module's usage definition specifies SharedScope = 2, corresponding to application-level sharing, as shown in Example 10-2. An application module that you set to session-level sharing will show SharedScope = 1.

10.2.3 What You May Need to Know About Design Time Scope of the Shared Application Module

Defining the shared application module in the Project Properties dialog makes the application module's data model available to other data model projects of the same application workspace only. When you want to make the data model available beyond the application workspace, you can publish the data model as an ADF Library, as described in Chapter 38, "Reusing Application Components."

When viewing a data control usage from the DataBindings.cpx file in the Structure window, do not set the Configuration property to a shared application module configuration. By default, for an application module named AppModuleName, the Property Inspector will list the configurations named AppModuleNameShared and AppModuleNameLocal. At runtime, Oracle Application Development Framework (Oracle ADF) uses the shared configuration automatically when you configure an application as a shared application module, but the configuration is not designed to be used by an application module data control usage. For more information about data control usage, see Section 13.5, "Working with the DataBindings.cpx File."

10.2.4 What You May Need to Know About the Design Time Scope of View Instances of the Shared Application Module

You define view accessors on the business component definition for the data model project that will permit access to view instances of the shared application module. The view accessor lets you point from an entity object or view object definition in one data model project to a view object definition or view instance in a shared application module. For details about creating view accessors for this purpose, see Section 10.4, "Accessing View Instances of the Shared Service."

10.2.5 What You May Need to Know About Managing the Number of Shared Query Collections

Similar to the way application module pooling works in ADF Business Components, shared query collections are stored in a query collection pool. To manage the query collection pool, the ADF Business Components framework removes query collections based on a maximum idle time setting. This behavior limits the growth of the cache and prevents rarely-used query collections from occupying memory space.

As in application module and connection pooling, a query collection pool monitor wakes up after a user-specified sleep interval and then initiates the cleanup operation. Any query collection that exceeds the maximum idle time (length of time since it was last used), will be removed from the pool.

You can change the default values for the maximum idle time for the shared query collection (default is 900000 ms/15 min) and the sleep period for its pool monitor (default is 1800000 ms/30 min). To configure these values, open the Edit Business Components Configuration dialog, select the AppModuleNameShared configuration, and set these properties in the Properties page of the editor:

jbo.qcpool.monitorsleepinterval the time (ms) that the shared query collection pool monitor should sleep between pool checks.

jbo.qcpool.maxinactiveage the maximum amount of time (ms) that a shared query collection may remain unused before it is removed from the pool.

10.2.6 What You May Need to Know About Shared Application Modules and Connection Pooling

The default connection behavior for all application modules is to allow each root application module to have its own database connection. When your application defines more than one shared application module, you can change the default to optimize database connection usage by defining a named transaction for each root application module to use. The transaction name is an arbitrary string that you set on the jbo.shared.txn property in the Properties page of the editor for the bc4j.xcfg file of the root application module. At runtime, the root application modules with the same jbo.shared.txn property setting (identified by the string you supply) will share the same database connection and entity cache. This optimization can reduce the database resources that the application uses and is particularly useful in shared application modules cases because they are read only and have longer life than transactional application modules.

Currently, the application module configuration parameter jbo.doconnectionpooling=true is not supported for use with shared application modules. This feature is available to configure non-shared application modules when it is desirable to release JDBC connection objects to the database connection pool.

This feature is intentionally not supported for shared application modules to prevent decreases in performance that would result from managing state for shared access. Instead, the default use of jbo.doconnectionpooling=false is enforced.

10.3 Defining a Base View Object for Use with Lookup Tables

When your application needs to display static data, you can define a shared application module with view instances that most likely will access lookup tables. A lookup table is a static, translated list of data to which the application refers. Lookup table data can be organized in the database in various ways. While it is possible to store related lookup data in separate tables, it is often convenient to combine all of the lookup information for your application within a single table. For example, a column LOOKUP_TYPE created for the ORDERS_LOOKUPS table would serve to partition one table that might contain diverse codes such as FWK_TBX_YES_NO for the values yes and no, FWK_TBX_COUNTRY for country names, and FWK_TBK_CURRENCY for the names of national currencies.

When your database schema organizes lookup data in a single database table, you want to avoid creating individual queries for each set of data. Instead, you will use the overview editor to define a single, base view object that maps the desired columns of the lookup table to the view object attributes you define. Since only the value of the LOOKUP_TYPE column will need to change in the query statement, you can add view criteria on the view object definition to specify a WHERE clause that will set the LOOKUP_TYPE value. In this way, your application encapsulates access to the lookup table data in a single view object definition that will be easy to maintain when a LOOKUP_TYPE value changes or your application needs to query additional lookup types.

10.3.1 How to Create a Base View Object Definition for a Lookup Table

The base view object that queries columns of the lookup table will be a read-only view object, since you do not need to handle updating data or require any of the benefits provided by entity-based view objects. (For a description of those benefits, see Section 5.1, "About View Objects.")

Note:

While read-only view objects you create to access lookup tables are ideal for inclusion in a shared application module, if you intend to share the view object in a shared application module instance, you must create the view object in the same package as the shared application module.

To create a read-only view object, use the Create View Object wizard, which is available from the New Gallery.

To create a base view object for a lookup table:

In the Application Navigator, locate the shared application module you created in which you want to create the view object, right-click its package node, and choose New.

In the New Gallery, expand Business Tier, select ADF Business Components and then select View Object, and click OK.

In the Create View Object wizard, on the Name page, enter a package name and a view object name.

When naming the package, consider creating a separate package for the lookup.

Select SQL query to indicate that you want this view object to manage data with read-only access and click Next.

On the Attribute Settings page, from the Select Attribute dropdown, select the attribute that corresponds to the primary key of the queried table and then enable the Key Attribute checkbox.

Because the read-only view object is not based on an entity object, the Create View Object wizard does not define a key attribute by default. Failure to define the key attribute can result in unexpected runtime behavior for ADF Faces components with a data control based on the read-only view object collection. In the case of read-only view objects, define the key attribute, as shown in Figure 10-3.

Figure 10-3 Create View Object Wizard, Attribute Settings Page

If you want to rename individual attributes to use names that might be more appropriate, from the Select Attributes dropdown, choose the attribute and enter the desired name in the Name field. When you are finished, click Next.

For example, the Fusion Order Demo application renames the default attributes LookupType and LookupCode to Type and Value respectively. Changes you make to the view object definition will not change the underlying query.

On the Java page, click Next.

On the Application Module page, do not add an instance of the view object to the application module data model. Click Finish.

JDeveloper then creates the XML component definition file that represents the view objects's declarative settings and saves it in the directory that corresponds to the name of its package. For example, the XML file created for a view object named LookupsBaseVO in the lookups package is ./lookups/LookupsBaseVO.xml under the project's source path.

To view the view object settings, expand the desired view object in the Application Navigator, select the XML file under the expanded view object, and open the Structure Window. The Structure window displays the list of definitions, including the SQL query and the properties of each attribute. To open the file in the editor, double-click the corresponding .xml node. As shown in Example 10-3, the LookupsBaseVO.xml file defines one <SQLQuery> definition and one <ViewAttribute> definition for each mapped column. Without a view criteria to filter the query results, the view object query returns the LOOKUP_CODE, LOOKUP_MEANING, and LOOKUP_DESCRIPTION and maps them to view instance attribute values for Value, Name, and Description respectively. Key attributes are defined to ensure proper row set navigation when the base view object collection is bound to an ADF Faces component.

10.3.3 How to Define the WHERE Clause of the Lookup View Object Using View Criteria

You create named view criteria definitions in the data model project when you need to filter view object results. View criteria that you define at design time can participate in UI scenarios that require filtering of data.

Use the Edit View Criteria dialog to create the view criteria definition for the lookup base view object you defined to query the lookup table. The editor lets you build a WHERE clause using attribute name instead of the target view object's corresponding SQL column names. The resulting definition will include:

One view criteria row consisting of one view criteria group, with a single view criteria item used to define the lookup view object's Type attribute.

The view criteria item will consist of an Type attribute name, the Equal operator, and the value of the LOOKUP_TYPE that will filter the query results.

Because a single view criteria is defined, no logical conjunctions are needed to bracket the WHERE clause conditions.

To create LOOKUP_TYPE view criteria for the lookup view object:

In the Application Navigator, double-click the lookup base view object you defined.

In the overview editor, click the Query navigation tab.

In the Query page, expand the View Criteria section, and click the Create new view criteria button.

In the Create View Criteria dialog, on the View Criteria page, click the Add Item button to add a single criteria item to the view criteria group.

In the Criteria Item panel, define the criteria item as follows:

Choose Type as the attribute (or other name that you defined for the attribute the view object maps to the LOOKUP_TYPE column).

Choose equal to as the operator.

Keep Literal as the operand choice and enter the value name that defines the desired type. For example, to query the marital status codes, you might enter the value MARITAL_STATUS_CODE corresponding to the LOOKUP_TYPE column.

Leave all other settings unchanged.

The view object WHERE clause shown in the editor should display a simple criteria similar to the one shown in Figure 10-4, where the value MARITAL_STATUS_CODE is set to filter the LOOKUP_TYPE column.

Click OK.

Repeat this procedure to define one view criteria for each LOOKUP_TYPE that you wish to query.

10.3.4 What Happens When You Create a View Criteria with the Editor

The Create View Criteria dialog in JDeveloper lets you easily create view criteria and save them as named definitions. These named view criteria definitions add metadata to the target view object's own definition. Once defined, named view criteria appear by name in the Query page of the overview editor for the view object.

JDeveloper then creates the XML component definition file that represents the view objects's declarative settings and saves it in the directory that corresponds to the name of its package. For example, the XML file created for a view object named LookupsBaseVO in the lookups package is ./lookups/LookupsBaseVO.xml under the project's source path.

To view the view criteria, expand the desired view object in the Application Navigator, select the XML file under the expanded view object, open the Structure window, and expand the View Criteria node. As shown in Example 10-4, the LookupsBaseVO.xml file specifies the <ViewCriteria> definition that allows the LookupsBaseVO to return only the marital types. Other view criteria added to the LookupsBaseVO are omitted from this example for brevity.

10.3.5 What Happens at Runtime: How a View Instance Accesses Lookup Data

When you create a view instance based on a view criteria, the next time the view instance is executed it augments its SQL query with an additional WHERE clause predicate corresponding to the view criteria that you've populated in the view criteria rows.

10.4 Accessing View Instances of the Shared Service

View accessors in ADF Business Components are value accessor objects that point from an entity object attribute (or view object) to a destination view object or shared view instance in the same application workspace. The view accessor returns a row set that by default contains all rows from the destination view object. You can optionally filter this row set by applying view criteria to the view accessor. The base entity object or view object on which you create the view accessor and the destination view object need not be in the same project or application module, but they must be in the same application workspace.

Because view accessors give you the flexibility to reach across application modules to access the queried data, they are ideally suited for accessing view instances of shared application modules. For details about creating a data model of view instances for a shared application module, see Section 10.2.1, "How to Create a Shared Application Module Instance."

Validation rules that you set on the attributes of an entity object. In this case, the view accessor derives the validation rule's values from lookup data corresponding to a view instance attribute in the shared application module.

List of Value (LOV) that you enable for the attribute of any view object. In this case, the view accessor derives the list of values from lookup data corresponding to a view instance attribute in the shared application module.

Validation rules with accessors are useful when you do not want the UI to display a list of values to the user, but you still need to restrict the list of valid values. Alternatively, consider defining an LOV for view object attributes to simplify the task of working with list controls in the user interface. Because you define the LOV on the individual attributes of business components, you can customize the LOV usage for an attribute once and expect to see the list control in the form wherever the attribute appears.

10.4.1 How to Create a View Accessor for an Entity Object or View Object

View accessors provide the means to access a data source independent of the application module. View accessors can be defined at the level of the entity object or individual view objects. However, because at runtime view accessor results are often filtered depending on the usage involved, it is recommended that you create unique view accessors for each usage in your application.

Best Practice:

Oracle recommends creating unique view accessors whenever your application needs to expose an LOV-enabled attribute. Reusing view accessors to create multiple list of values is discouraged because LOV results are often filtered at runtime. For example, the results of a saved search will filter the row set of the target view object until the end user unapplies the search criteria. Consequently, view accessors that get applied to this same destination view object will have their results filter too. To ensure the view accessor always returns the intended row set at runtime, create unique view accessors for each usage.

Defining view accessors on the entity object should be used carefully since view objects that you create based on the entity object will inherit the view accessors of their base entity objects. While defining the view accessor once on the entity object itself allows you to reuse the same view accessor, the view accessor must not be used in different application scenarios. If you intend to define validation rules for the entity object attributes and create LOV-enabled attributes for that entity object's view object, it is recommended that you create separate view accessors.

For example, in the StoreFrontModule package of the Fusion Order Demo application, the AddressEO entity object defines the Shared_CountriesVA view accessor and the AddressesVO view object inherits this view accessor. In this case, defining the view accessor on the entity object is useful: the accessor for AddressEO defines a validation rule on the CountryId attribute. But a different view accessor for AddressesVO should be used to enable an LOV on its CountryId attribute.

When you create a view accessor that accesses a view instance from a shared application module, you may want to use a prefix like Shared_ to name the view accessor. This naming convention will help you identify the view accessor when you need to select it for the entity object or view object.

In the Application Navigator, double-click the entity object or view object on which you want to define the view accessor.

Whether you create the view accessor on the entity object or on the view object will depend on the view accessor's intended usage. Generally, creating view accessors on the entity object ensures the widest possible usage.

In the overview editor, click the View Accessors navigation tab and click the Create new view accessors button to add the accessor to the entity object or view object definition you are currently editing.

In the View Accessors dialog, select the view instance name you created for your lookup table from the shared application module node and shuttle it to the view accessors list.

For example, the View Accessors dialog in the Fusion Order Demo application shows the shared application module LookupServiceAM with the list of view instances, as shown in Figure 10-5.

By default, the view accessor you create will display the same name as the view object instance (or will have an integer appended when it is necessary to distinguish it from a child view object of the same name). You can edit Accessor Name to give it a unique name.

For example, the View Accessors dialog in Figure 10-5 shows the view accessor AddressUsageTypesVA for the AddressUsageTypes view instance selection in the shared application module LookupServiceAM. This view accessor is created on the base entity object AddressUsagesEO and accesses the row set of the AddressUsageTypes view instance.

Figure 10-5 Defining a View Accessor on an Entity Object

Optionally, if you want to apply an existing view criteria to filter the accessor, with the view accessor selected in the overview editor, click the Edit icon.

In the Edit View Accessor dialog, click Edit and perform the following steps to apply the view criteria:

Select the view criteria that you want to apply and shuttle it to the Selected list.

You can add additional view criteria to apply multiple filters (a logical AND operation will be performed at runtime).

Enter the attribute name for the bind variable that defines the controlling attribute for the view accessor row set.

Unlike view criteria that you set directly on a view object (to create a view instance, for example), the controlling attribute of the view accessor's view criteria derives the value from the view accessor's base view object.

Click OK to return to the View Accessors dialog.

Click OK.

10.4.2 How to Validate Against the Attribute Values Specified by a View Accessor

View accessors that you create to access the view rows of a destination view object may be used to verify data that your application solicits from the end user at runtime. For example, when the end user fills out a registration form, individual validation rules can verify the title, marital status, and contact code against lookup table data queried by view instances of the shared application module.

You can apply view accessors you have defined on the entity object to these built-in declarative validation rules:

The Compare validator performs a logical comparison between an entity attribute and a value. When you specify a view accessor to determine the possible values, the compare validator applies the Equals, NotEquals, GreaterThan, LessThan, LessOrEqualTo, GreaterOrEqualTo operator you select to compare against the values returned by the view accessor.

The List validator compares an entity attribute against a list of values. When you specify a view accessor to determine the valid list values, the List validator applies an In or NotIn operator you select against the values returned by the view accessor.

The Collection validator performs a logical comparison between an operation performed on a collection attribute and a value. When you specify a view accessor to determine the possible values, the Collection validator applies the Sum, Average, Count, Min, Max operation on the selected collection attribute to compare against the values returned by the view accessor.

Validation rules that you define to allow runtime validation of data for entity-based view objects are always defined on the attributes of the entity object. You use the editor for the entity object to define the validation rule on individual attributes. Any view object that you later define that derives from an entity object with validation rules defined will automatically receive attribute value validation.

In the Compare With or List Type dropdown list, select View Accessor Attribute.

In the Select View Accessor Attribute group box, expand the desired view accessor from the shared service and select the attribute you want to provide as validation.

Figure 10-6 shows what the dialog looks like when you use a List validator to select a view accessor attribute.

Figure 10-6 List Validator Using a View Accessor

Click the Failure Handling tab and enter a message that will be shown to the user if the validation rule fails.

Click OK.

10.4.3 What Happens When You Define a View Accessor Validator

When you use a List validator, a <ListValidationBean> tag is added to an entity object's XML file. Example 10-5 shows the XML code for the CountryId attribute in the Address entity object. A List validator has been used to validate the user's entry against the list of country ID values as retrieved by the view accessor from the Countries view instance.

10.4.4 What You May Need to Know About Dynamic Filtering with View Accessors

The View Object API setWhereClause() method allows you to add a dynamic WHERE clause to a view instance whose view accessor may already have view criteria specified at design time. At runtime, when your view accessor and its view criteria is applied to the view instance and you call the setWhereClause() method on the view instance to add an extra WHERE clause, the programmatically set WHERE clause is AND-ed with the WHERE clause of any already applied view criteria.

10.4.5 How to Create an LOV Based on a Lookup Table

View accessors that you create to access the view rows of a destination view object may be used to display a list of values to the end user at runtime. You first create a view accessor with the desired view instance as its data source, and then you can add the view accessor to an LOV-enabled attribute of the displaying view object. You will edit the view accessor definition for the LOV-enabled attribute so that it points to the specific lookup attribute of the view instance. Because you want to populate the row set cache for the query with static data, you would locate the destination view instance in a shared application module.

While the list usage is defined on the attribute of a view object bound to a UI list control, the view accessor definition exists on either the view object or the view object's base entity object. If you choose to create the view accessor on the view object's entity object, the View Accessors page of the overview editor for the view object will display the inherited view accessor, as shown in Figure 10-7. Alternatively, if you choose to create the view accessor on the attribute's view object, you can accomplish this from either the editor for the LOV definition or from the View Accessors page of the overview editor.

In the Application Navigator, right-click the view object that contains the desired attribute and choose OpenViewObjectName.

In the overview editor, click the View Accessors navigation tab.

In the View Accessors page, check to see whether the view object inherited the desired view accessor from its base entity object. If no view accessor is present, either create the view accessor on the desired entity object or click the Create new view accessors icon to add the accessor to the view object you are currently editing.

Validation rules that you define are always defined on the attributes of the view object's base entity object. It may therefore be convenient to define view accessors at the level of the base entity objects when you know that you will also validate entity object attributes using a view accessor list.

In the Attributes page, select the attribute that is to display the LOV, and then click the List of Values tab and click the Add list of values icon.

In the Create List of Values dialog, select the view accessor from the List Data Source dropdown list.

The view accessor you select, will be the one created for the lookup table view object instances to use as the data source.

Select the attribute from this view accessor from the List Attribute dropdown list that will return the list of values for the attribute you are currently editing.

The editor creates a default mapping between the view object attribute and the LOV-enabled attribute. In this use case, the attributes are the same. For example, the attribute OrderId from the OrdersView view object would map to the attribute OrderId from the Shared_OrdersVA view accessor.

Optionally, when you want to specify supplemental values that your list returns to the base view object, click Add icon in List Return Values and map the desired view object attributes to the same attributes accessed by the view accessor. Supplemental attribute return values are useful when you do not require the user to make a list selection for the attributes, yet you want those attributes values, as determined by the current row, to participate in the update.

For example, to map the attribute StartDate from the OrdersView view object, you would choose the attribute StartDate from the Shared_OrdersVA view accessor. Do not remove the default attribute mapping for the attribute for which the list is defined.

Click OK.

10.4.6 What Happens When You Define an LOV for a View Object Attribute

When you add an LOV to a view object attribute, JDeveloper updates the view object's XML file with an LOVName property in the <ViewAttribute> element. The definition of the LOV appears in a new <ListBinding> element. The metadata in Example 10-6 shows that the MaritalStatusCode attribute refers to the MaritalStatusLOV LOV and sets the choice control type to display the LOV. The LOV definition for MaritalStatusLOV appears in the <ListBinding> element.

10.4.7 How to Automatically Refresh the View Object of the View Accessor

If you need to ensure that your view accessor always queries the latest data from the lookup table, you can set the Auto Refresh property on the destination view object. This property allows the view object instance to refresh itself after a change in the database. The typical use case is when you define a view accessor for the destination view object.

Because the auto-refresh feature relies on the database change notification feature, observe these restrictions when enabling auto-refresh for your view object:

The view objects should query as few read-only tables as possible. This will ensure the best performance and prevent the database invalidation queue from becoming too large.

The database user must have database notification privileges. For example, to accomplish this with a SQL*Plus command use grant change notification to <user name>.

When these restrictions are observed, the refresh is accomplished through the Oracle database change notification feature. Prior to executing the view object query, the framework will use the JDBC API to register the query for database notifications. When a notification arrives, the row sets of the corresponding view object instance are marked for refresh during the next checkout of the application module. Because the shared application module waits until the next checkout, the row set currency of the current transaction is maintained and the end user is not hampered by the update.

For example, assume that an LOV displays a list of zip codes that is managed in read-only fashion by a database administrator. After the administrator adds a new zip code as a row to the database, the shared application module detects a time when there are no outstanding requests and determines that a pending notification exists for the view instance that access the list of zip codes; at that point, the view object refreshes the data and all future requests will see the new zip code.

To enable auto-refresh for a view instance of a shared application module:

In the Application Navigator, double-click the view object that you want to receive database change notifications.

In the overview editor, click the General navigation tab.

In the Property Inspector expand the Tuning section, and select True for the Auto Refresh property.

10.4.8 What Happens at Runtime: How the Attribute Displays the List of Values

The ADF Business Components runtime adds functionality in the attribute setters of the view row and entity object to facilitate the LOV-enabled attribute behavior. In order to display the LOV-enabled attribute values in the user interface, the LOV facility fetches the data source, and finds the relevant row attributes and mapped target attributes.

10.4.9 What You May Need to Know About Displaying List of Values From a Lookup Table

Unlike entity-based view objects, read-only view objects that you create in expert mode, will not define a key attribute by default. While it is possible to create a read-only view object without defining its key attribute, in expert mode it is a best practice to select the attribute that corresponds to the queried table's primary key and mark it as the key attribute. The presence of a key attribute ensure the correct runtime behavior for row set navigation. For example, the user interface developer may create a LOV component based on the read-only view object collection. Without a key attribute to specify the row key value, the LOV may not behave properly and a runtime error can result.

10.4.10 What You May Need to Know About Programmatically Invoking Database Change Notifications

When you create a databound UI component in a web page, you can enable the auto-refresh feature on the corresponding view object, as described in Section 10.4.7, "How to Automatically Refresh the View Object of the View Accessor." In this case, the ADF Model layer and ADF Business Components will handle processing database change notifications at runtime and the shared application module cache will be updated for you. However, when you create a method to programmatically refresh a view instance of a shared application module, your method needs to invoke the processChangeNotification() method on the shared application module before you refresh the view instance. Example 10-7 shows how to use the processChangeNotification() method to ensure the shared application module cache gets updated if the corresponding queried data has changed in the database.

10.4.11 What You May Need to Know About Inheritance of AttributeDef Properties

When one view object extends another, you can create the LOV-enabled attribute on the base object. Then when you define the child view object in the overview editor, the LOV definition will be visible on the corresponding view object attribute. This inheritance mechanism allows you to define an LOV-enabled attribute once and apply it later across multiple view objects instances for the same attribute. For details about extending a view object from another view object definition, see Section 12.8.2, "How To Extend a Component After Creation."

You can also use the overview editor to extend the inherited LOV definition. For example, you may add extra attributes already defined by the base view object's query to display in selection list. Alternatively, you can create a view object instance that uses a custom WHERE clause to query the supplemental attributes not already queried by the base view object. For information about customizing entity-based view objects, see Section 5.10, "Working with Bind Variables."

10.4.12 What You May Need to Know About Using Validators

If you have created an LOV-enabled attribute for a view object, there is no need to validate the attribute using a List validator. You use an attribute validator only when you do not want the list to display in the user interface but still need to restrict the list of valid values. A List validator may be a simple static list or it may be a list of possible values obtained through a view accessor you define. Alternatively, you might prefer to use a Key Exists validator when the attribute displayed in the UI is one that references a key value (such as a primary, foreign, or alternate key). For information about declarative validation in ADF Business Components, see Chapter 7, "Defining Validation and Business Rules Declaratively."

10.5 Testing View Object Instances in a Shared Application Module

JDeveloper includes an interactive application module testing tool that you can use to test all aspects of its data model without having to use your application user interface or write a test client program. Running the Oracle ADF Model Tester can often be the quickest way of exercising the data functionality of your business service during development.

10.5.1 How to Test the Base View Object Using the Oracle ADF Model Tester

The application module is the transactional component that the Oracle ADF Model Tester (or UI client) will use to work with application data. The set of view objects 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. You can use the Oracle ADF Model Tester to test that the accessors you defined yield the expected validation result and that they display the correct LOV attribute values.

To test the view objects you added to an application module, use the Oracle ADF Model Tester, which is accessible from the Application Navigator.

To test view objects in an application module configuration:

In the Application Navigator, expand the project containing the desired application module and view objects.

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. For example, when debugging using the Oracle ADF Model Tester, you can view status message and exceptions, step in and out of source code, and manage breakpoints. JDeveloper opens the debugger process panel in the Log window and the various debugger windows.

In the Select Business Components Configuration dialog, choose the desired application module configuration from the Business Component Configuration Name list to run the Oracle ADF Model Tester.

By default, an application module has only its default configurations, named AppModuleNameLocal and AppModuleNameShared. If you have created additional configurations for your application module and want to test it using one of those instead, just select the desired configuration from the Business Components Configuration dropdown list on the Connect dialog before clicking Connect.

Click Connect to start the application module using the selected configuration.

To execute a view object in the Oracle ADF Model Tester, expand the tree list and double-click the desired view object node.

Note that the view object instance may already appear executed in the testing session. In this case, the tester panel on the right already displays query results for the view object instance, as shown in Figure 10-8. The fields in the tester panel of a read-only view object will always appear disabled since the data it represents is not editable.

Figure 10-8 Testing the Data Model in the Oracle ADF Model Tester

10.5.2 How to Test LOV-Enabled Attributes Using the Oracle ADF Model Tester

10.5.3 What Happens When You Use the Oracle ADF Model Tester

When you launch the Oracle ADF Model Tester, JDeveloper starts the tester tool in a separate process and the Oracle ADF Model Tester appears. The tree at the left of the dialog displays all of the view object instances in your application module's data model. Figure 10-8 shows just one instance in the expanded tree, called ProductImages. After you double-click the desired view object instance, the Oracle ADF Model Tester will display a panel to inspect the query results, as shown in Figure 10-8.

The test panel will appear disabled for any read-only view objects you display because the data is not editable. But even for the read-only view objects, the tool affords some useful features:

You can validate that the UI hints based on the Label Text control hint and format masks are defined correctly.

10.5.4 What Happens at Runtime: How Another Service Accesses the Shared Application Module Cache

When a shared application module with application scope is requested by an LOV, then the ADF Business Components runtime will create an ApplicationPool object for that usage. There is only one ApplicationPool created for each shared usage that has been defined in the ADF Business Components project configuration file (.jpx). The runtime will then use that ApplicationPool to acquire an application module instance that will be used like a user application module instance, to acquire data. The reference to the shared application module instance will be released once the application-scoped application module is reset. The module reference is released whenever you perform an unmanaged release or upon session timeout.

Since multiple threads will be accessing the data caches of the shared application module, it is necessary to partition the iterator space to prevent race conditions between the iterators of different sessions. This will help ensure that the next request from one session does not change the state of the iterator that is being used by another session. The runtime uses ADF Business Components support for multiple iterators on top of a single RowSet to prevent these race conditions. So, the runtime will instantiate as many iterators as there are active sessions for each RowSet.

An application-scoped shared application module lifecycle is similar to the lifecycle of any application module that is managed by the ApplicationPool object. For example, once all active sessions have released their shared application module, then the application module may be garbage-collected by the ApplicationPool object. The shared pool may be tuned to meet specific application requirements.