This 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.
This chapter includes the following sections:
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. 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.
A view accessor in ADF Business Components is a value accessor object that points from an entity object attribute (or view object) to a destination view object or shared view instance in the same application workspace.
This ability to access view objects in different application modules makes view accessors particularly useful for:
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.
You may find it helpful to understand other Oracle ADF features before you start working with shared application modules. Following are links to other functionality that may be of interest.
For details about configuring application module instances to improve runtime performance, see Chapter 50, "Using State Management in a Fusion Web Application" and Chapter 51, "Tuning Application Module Pools."
For a quick reference to the most common code that you will typically write, use, and override in your custom application module classes, see Appendix D, "Most Commonly Used ADF Business Components Methods."
For API documentation related to the oracle.jbo
package, see the following Javadoc reference document:
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 14-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 re-create 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.
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.
It may be helpful to have an understanding of lookup data. For more information, see Section 14.3, "Defining a Base View Object for Use with Lookup Tables."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You will need to complete this task:
To create a shared application module instance:
In the Application window, right-click the project in which you want to create the shared application module and choose Project Properties.
In the Project Properties dialog, expand ADF Business Components and select Application Module Instances.
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.
JDeveloper automatically creates the AppModuleName
Shared
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 AppModuleName
Shared
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 opening the application module in the overview editor and choosing Configurations from the navigation menu. JDeveloper saves the bc4j.xcfg
file in the ./common
subdirectory relative to the application module's XML document. 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/summit/model/services/common
directory of the SummitADF
application workspace, you will see the two named configurations for the BackOfficeAppModule
application module, as shown in Example 14-1. Specifically, the BackOfficeAppModuleShared
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 51, "Tuning Application Module Pools."
Example 14-1 LookupServiceAMShared Configuration in the bc4j.xcfg File
<BC4JConfig version="11.1" xmlns="http://xmlns.oracle.com/bc4j/configuration"> ... <AppModuleConfigBag ApplicationName="oracle.summit.model.services.BackOfficeAppModule"> <AppModuleConfig name="BackOfficeAppModuleLocal" jbo.project="oracle.summit.model.Model" ApplicationName="oracle.summit.model.services.BackOfficeAppModule" DeployPlatform="LOCAL" JDBCName="summit_adf"> <Database jbo.TypeMapEntries="Java"/> <Security AppModuleJndiName="oracle.summit.model.services.BackOfficeAppModule"/> </AppModuleConfig> <AppModuleConfig name="BackOfficeAppModuleShared" jbo.project="oracle.summit.model.Model" ApplicationName="oracle.summit.model.services.BackOfficeAppModule" DeployPlatform="LOCAL" JDBCName="summit_adf"> <AM-Pooling jbo.ampool.maxpoolsize="1" jbo.ampool.isuseexclusive="false"/> <Database jbo.TypeMapEntries="Java"/> <Security AppModuleJndiName="oracle.summit.model.services.BackOfficeAppModule"/> </AppModuleConfig> </AppModuleConfigBag> </BC4JConfig>
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 Model.jpx
file in the ./src
directory of the application's Model
project, you will see that the SharedLookupService
application module's usage definition specifies SharedScope = 2
, corresponding to application-level sharing, as shown in Example 14-2. An application module that you set to session-level sharing will show SharedScope = 1
.
Example 14-2 Application Module Usage Configuration in the .jpx File
<JboProject xmlns="http://xmlns.oracle.com/bc4j" Name="Model" SeparateXMLFiles="true" PackageName="oracle.summit.model"> . . . <AppModuleUsage Name="SharedLookupService" FullName="oracle.summit.model.services.BackOfficeAppModule" ConfigurationName="oracle.summit.model.services.BackOfficeAppModuleShared" SharedScope="2"/> </JboProject>
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 44, "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 window 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 17.5, "Working with the DataBindings.cpx File."
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 14.4, "Accessing View Instances of the Shared Service."
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 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.
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 configure the application to nest them under the same transaction in order to use a single database connection. This optimization allows the shared application module instances to share the same connection and entity cache and reduces the database resources that the application uses. This is particularly useful for shared application modules cases because they are read only and have longer life than transactional application modules.
Best Practice:
Oracle recommends nesting shared application module instances under a single transaction to reduce the database resources required by the application. You can make this shared application module optimization by setting thejbo.shared.txn
property to use the same transaction name (an arbitrary identifier you supply) for each shared application module configuration the application defines.Set the jbo.shared.txn
property using the Edit Configuration dialog that you open from the Configurations page of the overview editor for the shared application module, as shown in Figure 14-2. Repeat the jbo.shared.txn
property setting using the same transaction name for each shared application module configuration that your application defines.
Currently, the application module configuration parameter jbo.doconnectionpooling=true
is not supported for use with shared application modules. This feature is available to configure nonshared 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.
The default connection pooling configuration ensures that each shared application module instance holds onto the JDBC connection object that it acquires from the pool until the application module instance is removed from the application module pool. For more information about the jbo.doconnectionpooling
parameter and connection pool behavior, see Section 51.1.2, "Deployment Environment Scenarios and Pooling."
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.
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.
It may be helpful to have an understanding of lookup data. For more information, see Section 14.3, "Defining a Base View Object for Use with Lookup Tables."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You will need to complete this task:
To create a base view object for a lookup table:
In the Application window, locate the shared application module, right-click its package node, and choose New and then View Object.
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 Custom SQL query to indicate that you want this view object to manage data with read-only access and click Next.
On the Query page, enter your SQL statement directly into the Select text box.
Your query names the columns of the lookup table, and should look similar to the SQL statement shown in Figure 14-3 which queries the LOOKUP_CODE
, MEANING
, and DESCRIPTION
columns in the LOOKUP_CODES
table.
After entering the query statement, no other changes are required. Click Next.
On the Bind Variables page, click Next.
On the Attribute Mappings page, note the mapped view object attribute names displayed and click Next.
By default, the wizard creates Java-friendly view object attribute names that correspond to the SELECT
list column names.
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 14-4.
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, you might rename 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.
The shared application module data model will include view instances based on view criteria that you add to the base view object definition. In this way, you do not need to create an individual view object to query each LOOKUP_TYPE
value. For details about adding the view object instances to the data model, see Section 13.2.3.2, "Adding Master-Detail View Object Instances to an Application Module."
When you create the view object definition for the lookup table, JDeveloper first describes the query to infer the following from the columns in the SELECT
list:
The Java-friendly view attribute names (for example, LookupType
instead of LOOKUP_TYPE
)
By default, the wizard creates Java-friendly view object attribute names that correspond to the SELECT
list column names.
The SQL and Java data types of each attribute
JDeveloper then creates the XML document 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 window, 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 14-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.
Example 14-3 LookupsBaseVO SQL Query and Attribute Mapping Definition
<ViewObject xmlns="http://xmlns.oracle.com/bc4j" Name="LookupsBaseVO" BindingStyle="OracleName" CustomQuery="true" PageIterMode="Full" UseGlueCode="false" FetchMode="FETCH_AS_NEEDED" FetchSize="500"> <SQLQuery> <![CDATA[SELECT L.LOOKUP_TYPE ,L.LOOKUP_CODE ,L.MEANING ,L.DESCRIPTION FROM LOOKUP_CODES L WHERE L.LANGUAGE = USERENV('CLIENT_INFO') ORDER BY L.MEANING]]> </SQLQuery> <DesignTime> <Attr Name="_codeGenFlag2" Value="Access|VarAccess"/> <Attr Name="_isExpertMode" Value="true"/> </DesignTime> <ViewAttribute Name="Type" IsUpdateable="false" IsPersistent="false" IsNotNull="true" PrecisionRule="true" Precision="255" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="LOOKUP_TYPE" Expression="LOOKUP_TYPE" SQLType="VARCHAR"> <DesignTime> <Attr Name="_DisplaySize" Value="30"/> </DesignTime> ... </ViewAttribute> <ViewAttribute Name="Value" IsUpdateable="false" IsPersistent="false" IsNotNull="true" PrecisionRule="true" Precision="30" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="LOOKUP_CODE" Expression="LOOKUP_CODE" SQLType="VARCHAR"> <DesignTime> <Attr Name="_DisplaySize" Value="30"/> </DesignTime> ... </ViewAttribute> <ViewAttribute Name="Name" IsUpdateable="false" IsPersistent="false" IsNotNull="true" PrecisionRule="true" Precision="80" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="MEANING" Expression="MEANING" SQLType="VARCHAR"> <DesignTime> <Attr Name="_DisplaySize" Value="80"/> </DesignTime> ... </ViewAttribute> <ViewAttribute Name="Description" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="240" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="DESCRIPTION" Passivate="true" Expression="DESCRIPTION" SQLType="VARCHAR"> <DesignTime> <Attr Name="_DisplaySize" Value="240"/> </DesignTime> ... </ViewAttribute> <AttrArray Name="KeyAttributes"> <Item Value="Type"/> <Item Value="Value"/> </AttrArray> . . . </ViewObject>
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.
It may be helpful to have an understanding of lookup data. For more information, see Section 14.3, "Defining a Base View Object for Use with Lookup Tables."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You may also find it helpful to have an understanding of view criteria. For more information, see Section 5.9, "Working with Named View Criteria."
You will need to complete this task:
To create LOOKUP_TYPE view criteria for the lookup view object:
In the Application window, double-click the lookup base view object you defined.
In the overview editor, click the View Criteria navigation tab 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 Equals 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 14-5, 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.
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 View Criteria page of the overview editor for the view object.
JDeveloper then creates the XML document 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 window, select the XML file under the expanded view object, open the Structure window, and expand the View Criteria node. As shown in Example 14-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.
Example 14-4 listMaritalStatusTypes View Criteria in the Lookup View Object Definition
<ViewObject xmlns="http://xmlns.oracle.com/bc4j" Name="LookupsBaseVO" BindingStyle="OracleName" CustomQuery="true" PageIterMode="Full" UseGlueCode="false"> <SQLQuery> <![CDATA[SELECT L.LOOKUP_TYPE ,L.LOOKUP_CODE ,L.MEANING ,L.DESCRIPTION FROM LOOKUP_CODES L WHERE L.LANGUAGE = SYS_CONTEXT('USERENV','LANG') ORDER BY L.MEANING]]> </SQLQuery> ... <ViewCriteria Name="listMaritalStatusTypes" ViewObjectName="oracle.summit.model.lookups.LookupsBaseVO" Conjunction="AND" Mode="3" <Properties> <CustomProperties> <Property Name="autoExecute" Value="false"/> <Property Name="showInList" Value="true"/> <Property Name="mode" Value="Basic"/> </CustomProperties> </Properties> <ViewCriteriaRow Name="vcrow24"> <ViewCriteriaItem Name="Type" ViewAttribute="Type" Operator="=" Conjunction="AND" Value="MARITAL_STATUS_CODE" Required="Optional"/> </ViewCriteriaRow> </ViewCriteria>
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.
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 14.2.1, "How to Create a Shared Application Module Instance."
This ability to access view objects in different application modules makes view accessors particularly useful for:
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.
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, assume 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.
It may be helpful to have an understanding of view accessors. For more information, see Section 14.4, "Accessing View Instances of the Shared Service."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You will need to complete these tasks:
Create the entity object or view object that you want to access, as described in Chapter 4, "Creating a Business Domain Layer Using Entity Objects" and Chapter 5, "Defining SQL Queries Using View Objects."
Enable application module sharing, as described in Section 14.2.1, "How to Create a Shared Application Module Instance."
Create the base view object for the lookup data, as described in Section 14.3.1, "How to Create a Base View Object Definition for a Lookup Table."
You can optionally refine the list returned by a view accessor by applying view criteria that you define on the view object. To create view criteria for use with a view accessor, see Section 14.3.3, "How to Define the WHERE Clause of the Lookup View Object Using View Criteria."
In the Application window, 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 Accessors navigation tab and then, in the View Accessors section, 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.
The dialog will display all view objects and view instances from your application. For example, the View Accessors dialog in Figure 14-6 shows the shared application module LookupServiceAM
with the list of view instances, as shown .
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 14-6 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.
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.
In the View Accessors dialog, click OK.
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.
It may be helpful to have an understanding of view accessors. For more information, see Section 14.4, "Accessing View Instances of the Shared Service."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You will need to complete this task:
To validate against a view accessor comparison, list, or collection type:
In the Application window, double-click the desired entity object.
In the overview editor, click the Business Rules navigation tab.
In the Business Rules page, expand the entity object, select the attribute to be validated, and then click the Create new validator button to add the validation rule to the entity object attribute.
In the Add Validation Rule dialog, in the Rule Type dropdown list, select Compare, List, or Collection.
Make the selections required by the validator selection.
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 14-7 shows what the dialog looks like when you use a List validator to select a view accessor attribute.
Click the Failure Handling tab and enter a message that will be shown to the user if the validation rule fails.
Click OK.
When you use a List validator, a <ListValidationBean>
tag is added to an entity object's XML file. Example 14-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.
Example 14-5 List Validator with View Accessor List Type XML Code
<Attribute Name="CountryId" IsNotNull="true" Precision="2" ColumnName="COUNTRY_ID" Type="java.lang.String" ColumnType="CHAR" SQLType="VARCHAR" TableName="ADDRESSES"> RetrievedOnUpdate="true" RetrievedOnInsert="true"> <DesignTime> <Attr Name="_DisplaySize" Value="2"/> </DesignTime> <ListValidationBean xmlns="http://xmlns.oracle.com/adfm/validation" Name="CountryId_Rule_1" ResId="CountryId_Rule_0" OnAttribute="CountryId" OperandType="VO_USAGE" Inverse="false" ViewAccAttrName="Value" ViewAccName="SharedCountriesVA"> <ResExpressions> <Expression Name="0"><![CDATA[SharedCountriesVA.Value]]> </Expression> </ResExpressions> </ListValidationBean> <Properties> <SchemaBasedProperties> <LABEL ResId="CountryId_LABEL"/> </SchemaBasedProperties> </Properties> </Attribute>
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.
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 Accessors page of the overview editor for the view object will display the inherited view accessor, as shown in Figure 14-8. 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 Accessors page of the overview editor.
To ensure that the view accessor for the LOV always queries the latest data from the database table, you can enable the auto-refresh feature on the view accessor's destination view object.
It may be helpful to have an understanding of view accessors. For more information, see Section 14.4, "Accessing View Instances of the Shared Service."
You may also find it helpful to understand functionality that can be added using other Oracle ADF features. For more information, see Section 14.1.2, "Additional Functionality for Shared Application Modules."
You may also find it helpful to understand additional examples of how to work with LOV-enabled attributes. For more information, see Section 5.12, "Working with List of Values (LOV) in View Object Attributes."
You will need to complete these tasks:
Create the view object that is the data source for the view accessor, as described in Section 5.2.1, "How to Create an Entity-Based View Object," and Section 5.8.1, "How to Create a Custom SQL Mode View Object."
Create the view object that is the data source for the view accessor, as described in Section 5.2.1, "How to Create an Entity-Based View Object," and Section 5.8.1, "How to Create a Custom SQL Mode View Object."
Optionally, enable auto refresh for the view object, as described in Chapter 5, "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.
To create an LOV that displays values from a lookup table:
In the Application window, double-click the view object that contains the desired attribute.
In the overview editor, click the Accessors navigation tab.
In the Accessors page, in the View Accessors list, 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 button 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 overview editor, click the Attributes navigation tab.
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 button.
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.
If you want to specify supplemental values that your list returns to the base view object, click the Add button 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.
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 14-6 shows that the PaymentTypeId
attribute refers to the LOV_PaymentTypeId
LOV and sets the choice
control type to display the LOV. The LOV definition for LOV_PaymentTypeId
appears in the <ListBinding>
element.
Example 14-6 View Object with LOV List Binding XML Code
<ViewObject xmlns="http://xmlns.oracle.com/bc4j" Name="CustomerRegistrationVO" ... <ViewAttribute Name="PaymentTypeId" LOVName="LOV_PaymentTypeId" PrecisionRule="true" EntityAttrName="PaymentTypeId" EntityUsage="OrdEO" AliasName="PAYMENT_TYPE_ID"> <Properties> <SchemaBasedProperties> <CONTROLTYPE Value="choice"/> </SchemaBasedProperties> </Properties> </ViewAttribute> ... <ListBinding Name="LOV_PaymentTypeId" ListVOName="PaymentTypeVA" ListRangeSize="-1" NullValueFlag="start" NullValueId="LOVUIHints_NullValueId" MRUCount="0"> <AttrArray Name="AttrNames"> <Item Value="PaymentTypeId"/> </AttrArray> <AttrArray Name="ListAttrNames"> <Item Value="Id"/> </AttrArray> <AttrArray Name="ListDisplayAttrNames"> <Item Value="Payment Type"/> </AttrArray> <DisplayCriteria/> </ListBinding> ... </ViewObject>
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.
Unlike entity-based view objects, read-only, custom SQL view objects that you create, 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 custom SQL 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 an 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.
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 5.12.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. Calling the processChangeNotification()
method before refreshing the view instance ensures that the shared application module cache gets updated if the corresponding queried data has changed in the database.
To programmatically refresh a view instance of a shared application module, follow these steps (as illustrated in Example 14-7 from the processChangeTestClient.java
example in the SummitADF_Examples
workspace):
Call the processChangeNotification()
method.
Get the view instance from the shared application module.
Refresh the view instance.
Example 14-7 Programmatically Invoking a View Instance and Processing the Database Change Notification
public class processChangeTestClient { public static void main(String[] args) { processChangeTestClient processChangeTestClient = new processChangeTestClient(); ApplicationModuleHandle handle = null; String amDef = "oracle.summit.model.services.BackOfficeAppModule"; String config = "BackOfficeAppModuleLocal"; try { handle = Configuration.createRootApplicationModuleHandle(amDef, config); ApplicationModule am = handle.useApplicationModule(); // 1. Update the shared application module cache with changed data. am.processChangeNotifications(); // 2. Get the view instance to refresh. ViewObject vo = am.findViewObject("Inventory"); // 3. Refresh the view instance with updated data. ((ViewObjectImpl)vo).refreshCollection(null, false, false); vo.reset(); while (vo.hasNext()) { Row r = vo.next(); System.out.println((String)r.getAttribute("Name")); } } finally { if (handle != null) Configuration.releaseRootApplicationModuleHandle(handle, false); } } }
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 16.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."
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 11, "Defining Validation and Business Rules Declaratively."
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.
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 window.
It may be helpful to have an understanding of Oracle ADF Model Tester. For more information, see Section 14.5, "Testing View Object Instances in a Shared 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 14.1.2, "Additional Functionality for Shared Application Modules."
You may also find it helpful to understand the diagnostic messages specific to ADF Business Components debugging. For more information, see Section 8.3.10, "How to Enable ADF Business Components Debug Diagnostics."
You will need to complete this task:
To test view objects in an application module configuration:
In the Application 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. 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. The debugger process panel opens in the Log window and the various debugger windows.
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 14-9. The fields in the tester panel of a read-only view object will always appear disabled since the data it represents is not editable.
To test the LOV you created for a view object attribute, use the Oracle ADF Model Tester, which is accessible from the Application window. For details about displaying the tester and the supported control types, see Section 5.12.8, "How to Test LOV-Enabled Attributes Using 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 14-9 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 14-9.
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.
You can also scroll through the data using the toolbar buttons.
The Oracle ADF Model Tester becomes even more useful when you create entity-based view objects that allow you to simulate inserting, updating, and deleting rows, as described in Section 8.3.4, "How to Test Entity-Based View Objects Interactively."
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.
Session-scoped shared application modules are simply created as nested application module instances within the data model of the root, user application module. For details about nested application modules, Section 13.4, "Defining Nested Application Modules."