Most Commonly Used Methods in ADF Business Components
Oracle JDeveloper Tip
Most Commonly Used Methods in
ADF Business ComponentsAuthor: Steve Muench, ADF Development
Team Date: January 19, 2006 Revision 1.9 (Revision History)Abstract
This paper provides a high-level description of the key ADF Business
Components classes in the Oracle Application Development Framework, summarizing
the methods that ADF developers write, call, and override most
frequently.
Contents Overview Logical Architecture of Services Built with ADF Business
Components Most Commonly Used Methods in the Client Tier ApplicationModule Interface Transaction Interface ViewObject Interface RowSet Interface RowSetIterator Interface Row Interface StructureDef Interface AttributeDef Interface AttributeHints Interface Most Commonly Used Methods In the
Business Service Tier Controlling Custom Java Files For Your
Components ApplicationModuleImpl Class DBTransactionImpl2 Class EntityImpl Class EntityDefImpl Class ViewObjectImpl Class ViewRowImpl Class Setting Up Your Own Layer of Framework
Base Classes Conclusion
Overview
Service-oriented J2EE Applications built using the
ADF framework encapsulate their business logic into one or more business
services. Clients access these business services either as web services or,
when the client is a user interface, using the
ADF
data-binding layer that implements the Data Controls and Bindings from
JSR-227.
The data controls abstract the back-end business service implementations and
binding objects link front-end user interface controls in a declarative way to
back-end data.
ADF supports business services implemented as
simple Java objects, web services, EJB Session beans, and framework-based Java
objects that inherit built-in functionality from the ADF Business Components
base classes. These ADF Business Components are business-tier building-block
classes, and related design-time extensions to JDeveloper, that give you a
prescriptive architecture for building richly-functional and cleanly layered
J2EE business services with great performance. This paper offers a high-level
description of the key components that comprise ADF Business Components, and
provides a summary of the methods that developers leveraging ADF BC base
classes write, call, and override most frequently while building their
J2EE-compliant business services.
Logical Architecture of Services Built with ADF Business
Components
You can use business services you build with ADF Business Components in
one of three ways:
- As lightweight local Java
service classes,
- As EJB session beans,
or
- As stateless web
services
In all three cases, there is a
clean separation between the client tier code that invokes the service and the
business service tier where the service's implementation details reside.
With the J2EE web service option, your web service client interacts with
the service using a web service proxy class generated by the client tool
environment based on the service's WSDL service description. The methods that
appear on your web service are the custom methods you've written on your
business service component.
With the local Java service class and
the EJB session bean options, your Java client code interacts with either the
base ADF component interfaces or custom component interfaces that JDeveloper
10g generates for you automatically after indicating which custom methods
should appear on the component's client interface.
Since ADF
adopts this best-practice approach of having your client work with interfaces
instead of directly with implementation classes, it offers the additional
benefit of allowing you to change between deploying your business service as a
local Java class or an EJB session bean without changing your client code.
Along with the custom service interface, JDeveloper
generates appropriate client-side proxy implementation classes that implement
your custom interface. As such, it's an implementation detail you don't need to
worry about yourself. With either 2-tier or 3-tier deployment of your
application modules, thing just work...which is nice.
Figure 1 shows the relationships between the key
components in the Oracle Application Development Framework. The dashed vertical
line in the diagram represents the clean separation of component interfaces
that are available on the client, and which ones are only available in the
business tier implementation.
 Figure 1: Relationship Between Key ADF Business
Components Classes
Whenever you deploy an ADF
Business Components project using a Business Components deployment profile in
JDeveloper 10g, two separate JAR files get created, further emphasizing this
logical separation between business tier and client tier:
-
YourProjectNameCSMT.jar
This archive contains all of the implementation classes that comprise
your project's business service application module components and other ADF BC
components that your application modules use. We picked the MT suffix in the
name to represent Middle Tier. When deploying your application module as an EJB
Session Bean, this JAR file lives on the EJB middle tier. It never is
downloaded to the remote client.
-
YourProjectNameCSCommon.jar
This archive contains any custom client interfaces, generated custom
remote client proxy classes, custom domains, and message bundles that are
accessible by both the client-tier and the business service tier. We picked the
suffix Common in the archive name to remind you that this
jar is common to both tiers. This file is generally relatively quite small
compared to the middle-tier JAR.
The
following sections briefly explain each component and give tips about the
methods J2EE developers using ADF Business Components will use most frequently
for each kind of component.
Most Commonly Used Methods in the Client Tier
All of the interfaces described in this section are designed for use by
client-layer code and are part of the oracle.jbo.*
package.
| NOTE: |
The corresponding implementation classes for these
oracle.jbo.* interfaces are consciously designed to
not be directly accessed by client code. As we'll see in
the Most Commonly Used Methods In the
Business Service Tier section below, the implementation
classes live in the oracle.jbo.server.* package and
generally have the suffix Impl in their name to help remind
you not to using them in your client-layer code.
|
ApplicationModule Interface
The
ApplicationModule
is a business service component that acts as a transactional container for
other ADF components and coordinates with them to
implement a number of
J2EE
design patterns important to business application developers. These
design pattern implementations enable your client code to work easily with
updateable collections of value objects, based on
fast-lane
reader SQL queries that retrieve only the data needed by the client, in
the way the client wants to view it. Changes made to these value objects are
automatically coordinated with your persistent business domain objects in the
business service tier to enforce business rules consistently and save changes
back to the database.
| If you want to... |
Call this ApplicationModule interface
method... |
| Access an existing view object instance by name |
findViewObject() |
| Creating a new view object instance from an existing
definition
|
createViewObject() |
| Creating a new view object instance from a SQL
Statement
|
createViewObjectFromQueryStmt()
| Note: |
This incurs runtime overhead to describe the "shape" of the dynamic
query's SELECT list. We recommend using this only when you
cannot know the SELECT list for the query at design-time. Furthermore, if you
are creating the dynamic query based on some kind of custom runtime repository,
you can
follow
this tip to create (both read-only and updateable) dynamic view objects
without the runtime-describe overhead with a little more work. If only the
WHERE needs to be dynamic, create the view object at design
time, then set the where clause dynamically as needed using ViewObject API's.
|
|
| Access a nested
application module instance by name
|
findApplicationModule() |
| Create a new nested application module instance from an
existing definition
|
createApplicationModule() |
| Find a view object instance in a nested application
module
|
findViewObject()
| Note: |
To find an instance of a view object belonging to a nested application
module you use a dot notation
nestedAMInstanceName.VOInstanceName
|
|
| Accessing the current transaction object |
getTransaction() |
In addition to generic
ApplicationModule access, JDeveloper 10g can generate you a
custom YourApplicationModuleName
interface containing service-level custom methods that you've chosen to expose
to the client. You do this by visiting the Client
Interface tab of the Application Module editor, and shuttling the
methods you'd like to appear in your client interface into the
Selected list. JDeveloper will also generate an
appropriate
YourApplicationModuleNameClient
client proxy implementation class that is used automatically by your remote
client in the case that you deploy your application module as an EJB Session
Bean or whenever you use your application module in
Batch
Mode.
Transaction Interface
The
Transaction
interface exposes methods allowing the client to manage pending changes in the
current transaction.
| If you want to... |
Call
this Transaction interface method... |
| Commit pending changes |
commit() |
| Rollback pending changes |
rollback() |
| Execute a one-time database command or block of
PL/SQL
|
executeCommand()
| Note: |
Commands
that require retrieving OUT parameters, that will be
executed more than once, or that could benefit by using bind variables should
not use this method. Instead, expose a custom method on your application module
class as described here.
|
|
| Validate all pending invalid changes in the
transaction
|
validate() |
| Change the default locking mode |
setLockingMode()
| Note: |
You can
set the locking mode in your configuration by setting the property
jbo.locking.mode to one of the four supported values:
none, optimistic,
pessimistic, optupdate. If you don't
explicitly set it, it will default to pessimistic. For web
applications, we recommend using optimistic or
optupdate modes.
|
|
| Decide whether to use bundled exception reporting mode or
not.
|
setBundledExceptionMode()
| Note: |
ADF controller layer support sets this parameter to
true automatically for web
applications.
|
|
| Decide
whether entity caches will be cleared upon a successful commit of the
transaction.
|
setClearCacheOnCommit()
|
| Decide whether entity caches will be cleared upon a rollback of
the transaction.
|
setClearCacheOnRollback()
|
| Clear the entity cache for a specific entity
object.
|
clearEntityCache() |
ViewObject Interface
A
ViewObject
encapsulates a database query and simplifies working with the
RowSet of results it produces.
You use view objects to project, filter, join, or sort business data using SQL
from one or more tables into exactly the format that the user should see it on
the page or panel. You can create "master/detail" hierarchies of any level of
depth or complexity by connecting view objects together using view links. View
objects can produce read-only query results, or by associating them with one
ore more entity objects at design time, can be fully updateable. Updateable
view objects can support insertion, modification, and deletion of rows in the
result collection, with automatic delegation to the correct business domain
objects.
Every ViewObject aggregates a "default
rowset" for simplifying the 90% of use cases where you work with a single
RowSet of results for the
ViewObject's query. A ViewObject
implements all the methods on the RowSet interface by
delegating them to this default RowSet. That means you can
invoke any RowSet methods on
any ViewObject as well.
Every
ViewObject implements the StructureDef interface to
provide information about the number and types of attributes in a row of its
rowsets. So you can call StructureDef methods right on any
view object.
| If you want to... |
Call this ViewObject interface
method... |
| Set an
additional runtime WHERE clause on the rowset
|
setWhereClause()
| Note: |
This WHERE clause augments any
WHERE clause specified at design time in the base view
object. It does not replace it.
|
|
| Set a dynamic ORDER BY clause |
setOrderByClause() |
| Create a Query-by-Example criteria collection |
createViewCriteria()
| Note: |
You
then create one or more ViewCriteriaRow objects using the
createViewCriteriaRow() method on the ViewCriteria object
you created. Then, you add() these view criteria rows to the
view criteria collection and apply the criteria using the method
below.
|
|
| Apply a Query-by-Example criteria collection |
applyViewCriteria() |
| Set a query optimizer hint |
setQueryOptimizerHint() |
| Access the attribute definitions for the key attributes
in the view object
|
getKeyAttributeDefs() |
| Add a dynamic attribute to rows in this view object's
rowsets
|
addDynamicAttribute() |
| Clear all rowsets produced by a view object |
clearCache() |
| Remove view object instance an its resources |
remove() |
| Set an upper limit on the number of rows that the view
object will attempt to fetch from the database.
|
setMaxFetchSize()
| Note: |
Default is -1
which means to impose no limit on how many rows would be retrieved from the
database if you iterate through them all. By default they are fetched lazily as
you iterate through them.
|
|
In addition to generic
ViewObject access, JDeveloper 10g can generate you a custom
YourViewObjectName interface
containing view-object level custom methods that you've chosen to expose to the
client. You do this by visiting the Client Interface tab
of the View Object editor, and shuttling the methods you'd like to appear in
your client interface into the Selected list. JDeveloper
will also generate an appropriate
YourViewObjectNameClient client
proxy implementation class that is used automatically by your remote client in
the case that you deploy your application module as an EJB Session Bean or
whenever you use your application module in
Batch
Mode.
RowSet Interface
A
RowSet
is a set of rows, typically produced by executing a
ViewObject's query.
Every
RowSet aggregates a "default rowset iterator" for
simplifying the 90% of use cases where you only need a single iterator over the
rowset. A RowSet implements all the methods on the
RowSetIterator interface by delegating them to this default
RowSetIterator. This means you can invoke any
RowSetIterator method
on any RowSet (or ViewObject, since it
implements RowSet as well for its default RowSet).
| If
you want to... |
Call this RowSet interface
method... |
| Set a where clause bind variable value |
setWhereClauseParam()
| Note: |
Bind
variable ordinal positions are zero-based
|
|
| Avoid view object row caching if data is being read only
once
|
setForwardOnly() |
| Force a rowset's query to be (re)executed |
executeQuery() |
| Estimate the number of rows in a view object's query
result
|
getEstimatedRowCount() |
| Produce XML document for rows in View Object
rowset
|
writeXML() |
| Process all rows from an incoming XML
document
|
readXML() |
| Set whether rowset will automatically see new rows based
on the same entity object created through other rowsets
|
setAssociationConsistent() |
| Create secondary iterator to use for programmatic
iteration
|
createRowSetIterator()
| Note: |
If you plan
to find and use the secondary iterator by name later, then pass in a string
name as the argument, otherwise pass null for the name and
make sure to close the iterator when done iterating by calling its
closeRowSetIterator()
method.
|
|
RowSetIterator Interface
A
RowSetIterator
is an iterator over the rows in a RowSet. By default it
allows you to iterate both forward and backward through the rows.
| If you want to... |
Call
this RowSetIterator interface method... |
| Get the first row of the iterator's rowset |
first() |
| Test whether there are more rows to iterate |
hasNext() |
| Get the next row of iterator's rowset |
next() |
| Find row in this iterator's rowset with a given Key
value
|
findByKey()
| Note: |
It's important
that the Key object that you pass to
findByKey be created using the exact
same datatypes as the attributes that comprise the key of the rows in the view
object you're working with.
|
|
| Create a new row to populate for insertion |
createRow()
| Note: |
The new row
will already have default values set for attributes which either have a static
default value supplied at the entity object or view object level, or if the
values have been populated in an overridden create() method
of the underlying entity object(s).
|
|
| Create a view row with an initial set of foreign key
and/or discriminator attribute values
|
createAndInitRow()
| Note: |
You use this
method when working with view objects that can return one of a "family" of
entity object subtypes. By passing in the correct discriminator attribute value
in the call to create the row, the framework can create you the correct
matching entity object subtype underneath.
|
|
| Insert a new row into the iterator's rowset |
insertRow()
| Note: |
It's a good
habit to always immediately insert a newly created row into the rowset. That
way you will avoid a common gotcha of creating the row but forgetting to insert
it into the rowset.
|
|
| Get the last row of the iterator's rowset |
last() |
| Get the previous row of the iterator's rowset |
previous() |
| Reset the current row pointer to the slot before the
first row
|
reset() |
| Close an iterator when done iterating |
closeRowSetIterator() |
| Set a given row to be the current row |
setCurrentRow() |
| Remove the current row |
removeCurrentRow() |
| Remove the current row to later insert it at a different
location in the same iterator.
|
removeCurrentRowAndRetain() |
| Remove the current row from the current collection
but do not remove it from the transaction.
|
removeCurrentRowFromCollection() |
| Set/change the number of rows in the range (a "page"
of rows the user can see)
|
setRangeSize() |
| Scroll to view the Nth page of rows (1-based) |
scrollToRangePage() |
| Scroll to view the range of rows starting with row number
N
|
scrollRangeTo() |
| Set row number N in the range to be the current
row
|
setCurrentRowAtRangeIndex() |
| Get all rows in the range as a Row array |
getAllRowsInRange() |
Row Interface
A
Row
is generic value object. It contains attributes appropriate in name and Java
type for the ViewObject that it's related to.
| If you want to... |
Call this Row interface method... |
| Get the value of an attribute by name |
getAttribute() |
| Set the value of an attribute by name |
setAttribute() |
| Produce an XML document for a single row |
writeXML() |
| Eagerly validate a row |
validate() |
| Read row attribute values from XML |
readXML() |
| Remove the row |
remove() |
| Flag a newly created row as temporary (until updated
again)
|
setNewRowState(Row.STATUS_INITIALIZED) |
| Retrieve the attribute structure definition
information for a row
|
getStructureDef() |
| Get the Key object for a row |
getKey() |
In addition to generic Row access, JDeveloper 10g can
generate you a custom
YourViewObjectNameRow interface
containing your type-safe attribute getter and setter methods, as well as any
desired row-level custom methods that you've chosen to expose to the client.
You do this by visiting the Client Row Interface tab of
the View Object editor, and shuttling the methods you'd like to appear in your
client interface into the Selected list. JDeveloper will
also generate an appropriate
YourViewObjectNameRowClient
client proxy implementation class that is used automatically by your remote
client in the case that you deploy your application module as an EJB Session
Bean or whenever you use your application module in
Batch
Mode.
StructureDef Interface
A
StructureDef
is an interface that provides access to runtime metadata about the structure of
a Row.
In addition,
for convenience every ViewObject implements the
StructureDef interface as well, providing access to metadata
about the attributes in the resulting view rows that its query will
produce.
| If you want to... |
Call this StructureDef interface
method... |
| Access attribute definitions for all attributes in the
view object row
|
getAttributeDefs() |
| Find an attribute definition by name |
findAttributeDef() |
| Get attribute definition by index |
getAttributeDef() |
| Get number of attributes in a row |
getAttributeCount() |
AttributeDef Interface
An
AttributeDef
provides attribute definition information for any attribute of a View Object
row or Entity Object instance like attribute name, Java type, and SQL type. It
also provides access to custom attribute-specific metadata properties that can
be inspected by generic code you write, as well as UI hints that can assist in
rendering an appropriate user interface display for the attribute and its
value.
| If you want to... |
Call this
AttributeDef interface method... |
| Get the Java type of the attribute |
getJavaType() |
| Get the SQL type of the attribute |
getSQLType()
| Note: |
The
int value corresponds to constants in the JDBC class
java.sql.Types
|
|
| Determine the kind of attribute |
getAttributeKind()
| Note: |
If it's
a simple attribute, it returns one of the constants
ATTR_PERSISTENT, ATTR_SQL_DERIVED,
ATTR_TRANSIENT, ATTR_DYNAMIC,
ATTR_ENTITY_DERIVED. If it is an 1-to-1 or many-to-1
association/viewlink accessor it returns
ATTR_ASSOCIATED_ROW. If it is an 1-to-many or many-to-many
association/viewlink accessor it returns
ATTR_ASSOCIATED_ROWITERATOR
|
|
Get the Java type of elements contained in an
Array-valued attribute
|
getElemJavaType() |
Get the SQL type of elements contained in an
Array-valued attribute
|
getElemSQLType() |
| Get the name of the attribute |
getName() |
| Get the index position of the attribute |
getIndex() |
| Get the precision of a numeric attribute or the maximum
length of a String attribute
|
getPrecision() |
| Get the scale of a numeric attribute |
getScale() |
| Get the underlying column name corresponding to the
attribute
|
getColumnNameForQuery() |
| Get attribute-specific custom property values |
getProperty(),
getProperties() |
Get the UI AttributeHints object for
the attribute
|
getUIHelper() |
| Test whether the attribute is mandatory |
isMandatory() |
| Test whether the attribute is queriable |
isQueriable() |
| Test whether the attribute is part of the primary key for
the row
|
isPrimaryKey() |
AttributeHints Interface
The
AttributeHints
interface related to an attribute exposes UI hint information that attribute
that you can use to render an appropriate user interface display for the
attribute and its value.
| If you want to... |
Call this
AttributeHints interface method... |
| Get the UI label for the attribute |
getLabel() |
| Get the tool tip for the attribute |
getTooltip() |
| Get the formatted value of the attribute, using any
format mask supplied
|
getFormattedAttribute() |
| Get the display hint for the attribute |
getDisplayHint()
| Note: |
Will have
a String value of either Display or
Hide.
|
|
| Get the preferred control type for the attribute |
getControlType() |
| Parse a formatted string value using any format mask
supplied for the attribute
|
parseFormattedAttribute() |
Most Commonly Used Methods In the
Business Service Tier
The implementation classes corresponding to
the oracle.jbo.* interfaces described above are consciously
designed to not be directly accessed by client code. They
live in a different package named oracle.jbo.server.* and
have the Impl suffix in their name to help remind you not to
using them in your client-layer code.
In your business service
tier implementation code, you can use any of the same methods that are
available to clients above, but in addition you can also:
- Safely cast any
oracle.jbo.* interface to
its oracle.jbo.server.* package implementation class and use
any methods on that Impl class as well.
- Override any of the base framework implementation class'
public or protected methods to augment or
change its default functionality by writing custom code in your component
subclass before or after calling
super.methodName().
This section provides a summary of the most frequently called, written,
and overridden methods for the key ADF Business Components classes.
Controlling Custom Java Files For Your
Components
Before examining the specifics of individual classes,
it's important to understand how you can control which custom Java files each
of your components will use. When you don't need a customized subclass for a
given component, you can just let the base framework class handle the
implementation at runtime.
Each business component you create
comprises a single XML component descriptor, and zero or more related custom
Java implementation files. Each component that supports Java customization has
a Java tab in its component editor in the JDeveloper 10g
IDE. By checking or unchecking the different Java classes, you control which
ones get created for your component. If none of the boxes is checked, then your
component will be an XML-only component, which simply uses the base framework
class as its Java implementation. Otherwise, tick the checkbox of the related
Java classes for the current component that you need to customize. JDeveloper
10g will create you a custom subclass of the framework
base class in which you can add your code.
| NOTE: |
You can setup
global IDE preferences for which Java classes should be generated by default
for each ADF business component type by selecting
Tools | Preferences... |
Business Components and ticking the checkboxes to
indicate what you want your defaults to be.
|
A best practice
is to always generate Entity Object and View Row classes,
even if you don't require any custom code in them other than the
automatically-generated getter and setter methods. These getter and setter
methods offer you compile-time type checking that avoids discovering errors at
runtime when you accidentally set an attribute to an incorrect kind of
value.
ApplicationModuleImpl Class
The
ApplicationModuleImpl
class is the base class for application module components. Since the
application module is the ADF component used to implement a business service,
think of the application module class as the place where you can write your
service-level application logic. The application module coordinates with view
object instances to support updateable collections of value objects that are
automatically "wired" to business domain objects. The business domain objects
are implemented as ADF entity objects.
Methods
You Typically Call on ApplicationModuleImpl
| If you want to... |
Call this
method of the ApplicationModuleImpl class |
| Perform any of the common application module operations
from inside your class, which can also be done from the client
|
See the ApplicationModule Interface section
above.
|
| Access a view object instance that you added to the
application module's data model at design time
|
getViewObjectInstanceName()
| Note: |
JDeveloper 10g generates this type-safe view object instance getter
method for you to reflect each view object instance in the application module's
design-time data-model.
|
|
| Access the current DBTransaction object |
getDBTransaction() |
| Access a nested application module instance that you
added to the application module at design time
|
getAppModuleInstanceName()
| Note: |
JDeveloper 10g generates this type-safe application module instance
getter method for you to reflect each nested application module instance added
to the current application module at design time.
|
|
Methods You
Typically Write in Your Custom ApplicationModuleImpl Subclass
| If
you want to... |
Write a method like this in your
custom ApplicationModuleImpl class |
| Invoke a database stored procedure |
someCustomMethod()
| Note: |
Use appropriate method on the DBTransaction interface to
create a JDBC PreparedStatement. If the stored procedure has
OUT parameters, then create a
CallableStatement instead.
See
this
sample project for a robust code example of encapsulating a call to a
PL/SQL stored procedure inside your application
module.
|
|
| Expose custom
business service methods on your application module
|
someCustomMethod()
| Note: |
Select the method name on the Client Interface
panel of the application module editor to expose it for client access if
required.
|
|
JDeveloper 10g can generate you a custom
YourApplicationModuleName
interface containing service-level custom methods that you've chosen to expose
to the client. You do this by visiting the Client
Interface tab of the Application Module editor, and shuttling the
methods you'd like to appear in your client interface into the
Selected list.
Methods You Typically Override in Your Custom ApplicationModuleImpl
Subclass
| If
you want to... |
Override this method of the
ApplicationModuleImpl class |
| Perform custom setup code the first time an application
module is created and each subsequent time it gets used by a different client
session.
|
prepareSession()
| Note: |
This is
the method you'd use to setup per-client context info for the current user in
order to use database Oracle's Virtual Private Database (VPD) features. It can
also be used to set other kinds of PL/SQL package global variables, whose
values might be client-specific, on which other stored procedures might
rely.
This method is also useful to perform setup code that is
specific to a given view object instance in the
application module. If instead of being instance-specific you want the view
object setup code to be initialized for every instance ever created of that
view object component, then put the setup logic in an overridden
create() method in your ViewObjectImpl
subclass instead.
|
|
| Perform custom setup code after the application module's
transaction is associated with a database connection from the connection
pool.
|
afterConnect()
| Note: |
Can be a useful place to write a line of code that uses
getDBTransaction().executeCommand() to perform an
ALTER SESSION SET SQL TRACE TRUE to enable database SQL
Trace logging for the current application connection. These logs can then be
processed with the
TKPROF
utility to study the SQL statements being performed and the query optimizer
plans that are getting used.
|
|
| Perform custom setup code before the application module's
transaction releases its database connection back to the database connection
pool.
|
beforeDisconnect()
| Note: |
If you have set jbo.doconnectionpooling to true, then
the connection is released to the database connection pool each time the
application module is returned to the application module
pool.
|
|
| Write custom
application module state to the state management XML snapshot
|
passivateState() |
| Read and restore custom application module state from the
state management XML snapshot
|
activateState() |
DBTransactionImpl2 Class
The
DBTransactionImpl2
class — which extends the base
DBTransactionImpl
class, and is constructed by the
DatabaseTransactionFactory
class — is the base class that implements the
DBTransaction
interface, representing the unit of pending work in the current transaction.
Methods You Typically Call on DBTransaction
| If
you want to... |
Call this method on the
DBTransaction
object |
| Commit the
transaction
|
commit() |
| Rollback the transaction |
rollback() |
| Eagerly validate any pending invalid changes in the
transaction
|
validate() |
Create a JDBC PreparedStatement using
the transaction's Connection object
|
createPreparedStatement() |
Create a JDBC CallableStatement using
the transaction's Connection object
|
createCallableStatement() |
Create a JDBC Statement using the
transaction's Connection object
|
createStatement() |
| Add a warning to the transaction's warning list. |
addWarning() |
Methods You Typically Override in Your Custom DBTransactionImpl2
Subclass
| If
you want to... |
Override this method in your custom
DBTransactionImpl2 class |
| Perform custom code before or after the transaction
commit operation
|
commit() |
| Perform custom code before or after the transaction
rollback operation
|
rollback() |
In order to have your custom
DBTransactionImpl2 subclass get used at runtime, there are two steps you must
follow:
-
Create a custom subclass of
DatabaseTransactionFactory that overrides the create method
to return an instance of your custom DBTransactionImpl2
subclass like this:
package com.yourcompany.adfextensions;
import oracle.jbo.server.DBTransactionImpl2;
import oracle.jbo.server.DatabaseTransactionFactory;
import com.yourcompany.adfextensions.CustomDBTransactionImpl;
public class CustomDatabaseTransactionFactory extends DatabaseTransactionFactory {
/**
* Return an instance of our custom CustomDBTransactionImpl class
* instead of the default implementation.
*
* @return An instance of our custom DBTransactionImpl2 implementation.
*/
public DBTransactionImpl2 create() {
return new CustomDBTransactionImpl();
}
}
- Tell the framework to use your
custom transaction factory class by setting the value of the
TransactionFactory configuration property to the
fully-qualified class name of your custom transaction factory. As with other
configuration properties, if not supplied in the configuration XML file, it can
be provided alternatively as a Java system parameter of the same
name.
EntityImpl Class
The
EntityImpl
class is the base class for entity objects, which encapsulate the data,
validation rules, and business behavior for your business domain
objects.
Methods You Typically Call on EntityImpl
| If
you want to... |
Call this method in your EntityImpl
subclass |
| Get the value of an attribute |
getAttributeName()
| Note: |
Code-generated getter method calls
getAttributeInternal() but provides compile-time type
checking.
|
|
| Set the value of an attribute |
setAttributeName()
| Note: |
Code-generated setter method calls
setAttributeInternal() but provides compile-time type
checking.
|
|
| Get the value
of an attribute by name
|
getAttributeInternal() |
| Set the value of an attribute by name |
setAttributeInternal() |
| Eagerly perform entity object validation |
validate() |
| Refresh the entity from the database |
refresh() |
| Populate the value of an attribute without
marking it as being changed, but sending
notification of its being changed so UI's refresh the
value on the screen/page.
|
populateAttributeAsChanged() |
| Access the definition object for an entity |
getDefinitionObject() |
| Get the Key object for an entity |
getKey() |
| Determine the state of the entity instance, irrespective
of whether it has already been posted in the current transaction (but not yet
committed)
|
getEntityState()
| Note: |
Will
return one of the constants STATUS_UNMODIFIED,
STATUS_INITIALIZED, STATUS_NEW,
STATUS_MODIFIED, STATUS_DELETED, or
STATUS_DEAD indicating the status of the entity instance in
the current transaction.
|
|
| Determine the state of the entity instance |
getPostState()
| Note: |
This method
is typically only relevant if you are programmatically using the
postChanges() method to post but not yet commit entity
changes to the database and need to detect the state of an entity with regard
to its posting state
|
|
| Get the value originally read from the database for a
given attribute
|
getPostedAttribute() |
| Eagerly lock the database row for an entity
instance
|
lock() |
Methods You
Typically Write in Your Custom EntityImpl Subclass
| If you want to... |
Write a method
like this in your EntityImpl subclass |
| Perform attribute-specific validation |
public boolean
validateSomething(AttrType
value)
| Note: |
Register the attribute validator method by adding a
"MethodValidator" on correct attribute in the Validation
panel of the Entity Object editor. When you register the method
validation
|
|
| Perform entity-level validation |
public boolean
validateSomething()
| Note: |
Register
the entity-level validator method by adding a "MethodValidator" on the entity
in the Validation panel of the Entity Object
editor.
|
|
| Calculate the value of a transient attribute |
Add your calculation code to the generated
getAttributeName()
method.
|
Methods
You Typically Override on EntityImpl
| If
you want to... |
Override this method in your custom
EntityImpl subclass... |
| Set calculated default attribute values, including
programmatically populating the primary key attribute value of a new entity
instance.
|
create()
| Note: |
After calling
super.create(), call the appropriate
setAttrName() method(s) to set
the default values for that(/those) attributes.
|
|
| Modify attribute values before changes are posted to the
database
|
prepareForDML() |
| Augment/change the standard INSERT, UPDATE, or DELETE DML
operation that the framework will perform on your entity object's behalf to the
database
|
doDML()
| Note: |
Check the value of the operation flag to the constants
DML_INSERT, DML_UPDATE, or
DML_DELETE to test what DML operation is being
performed.
|
|
| Perform complex, SQL-based validation after all
entity instances have been posted to the database but before those changes are
committed.
|
beforeCommit() |
| Insure that a related, newly-created, parent entity gets
posted to the database before the current child entity on
which it depends
|
postChanges()
| Note: |
If the parent entity is related to this child entity via a
composition association, then the framework already handles this automatically.
If they are only associated (but not composed) then you need to override
postChanges() method to force a newly-created parent entity
to post before the current, dependent child entity. See
this
OTN article for the code you typically write in your overridden
postChanges() method to accomplish this.
|
|
| NOTE: |
It is possible to write
attribute-level validation code directly inside the appropriate
setAttributeName method of your
EntityImpl class, however adopting the
MethodValidator approach suggested above results in having a
single place on the Validation tab of the Entity Object
editor to look in order to understand all of the validations in effect for your
entity object, so it can result in easier to understand
components.
|
It is also possible to override the
validateEntity() method to write entity-level validation
code, however if you want to maintain the benefits of the ADF bundled exception
mode — where the framework collects and reports a maximal
set of validation errors back to the client user interface — it is recommended
to adopt the MethodValidator approach suggested in the table
above. This allows the framework to automatically collect all of your
exceptions that your validation methods throw without your having to understand
the bundled exception implementation mechanism. Overriding the
validateEntity() method directly shifts the responsibility
on your own code to correctly catch and bundle the
exceptions like the ADF framework would have done by default, which is
non-trivial and a chore to remember and hand-code each
time.
EntityDefImpl Class
The
EntityDefImpl
class is a singleton, shared metadata object for all entity objects of a given
type in a single Java VM. It defines the structure of the entity instances and
provides methods to create new entity instances and find existing instances by
their primary key.
Methods You Typically Call on
EntityDefImpl
| If
you want to... |
Call the EntityDefImpl
method |
| Find an entity
object of a this type by its primary key
|
findByPrimaryKey()
| Note: |
See this
tip
for getting findByPrimaryKey() to find entity instances of
subtype entities as well.
|
|
Access the current DBTransaction
object
|
getDBTransaction() |
Find any EntityDefImpl object by its
fully-qualified name
|
findDefObject() (static method)
|
| Retrieve the value of an entity object's custom
property
|
getProperty(),
getProperties() |
| Set
the value of an entity object's custom property
|
setProperty() |
| Create a new instance of an entity object |
createInstance()
| Note: |
This
method has protected access, so you'll need visit the
Java tab of the Entity Object editor to indicate you want
a custom EntityDefImpl subclass for your entity object in
question. Then, from code you write inside this custom subclass, you can invoke
this method.
Alternatively, you can expose custom
createXXX() methods with your own
expected signatures in that same custom EntityDefImpl
subclass. See the next section for details.
|
|
| Iterate over the entity instances in the cache of this
entity type.
|
getAllEntityInstancesIterator() |
Access ArrayList of entity
definition objects for entities that extend the current one.
|
getExtendedDefObjects() |
Methods
You Typically Write on EntityDefImpl
| If
you want to... |
Write a method like this in your
custom EntityDefImpl class |
| Allow other classes to create an entity instance with an
initial type-safe set of attribute values or setup information.
|
createXXXX(Type1arg1, ..., TypeNargN)
| Note: |
Internally, this would
create and populate an instance of a NameValuePairs object
(which implements AttributeList) and call the protected method
createInstance(), passing that NameValuePairs object. Make
sure the method is public if other classes need to be able
to call it.
|
|
Methods You Typically Override on EntityDefImpl
| If
you want to... |
Call the EntityDefImpl
method |
| Perform custom
metadata initialization when this singleton metaobject is loaded.
|
createDef() |
Avoid using the RETURNING INTO clause
to support refresh-on-insert or refresh-on-update attributes
|
isUseReturningClause()
| Note: |
Return false to disable the use of RETURNING INTO,
necessary sometimes when your entity object is based on a view with
INSTEAD OF triggers that doesn't support RETURNING
INTO at the database level.
|
|
| Control whether the UPDATE statements issued for this
entity update only changed columns, or all columns
|
isUpdateChangedColumns()
|
| Find any EntityDefImpl object by its fully-qualified
name
|
findDefObject()
|
| Set
the value of an entity object's custom property
|
setProperty() |
| Allow other classes to create a new instance an entity
object without doing so implicitly via a view object.
|
createInstance()
| Note: |
If you
don't write a custom create method as noted in the previous section, you'll
need to override this method and widen the visibility from
protected to public to allow other
classes to construct an entity instance.
|
|
ViewObjectImpl Class
The
ViewObjectImpl
class the base class for view objects.
Methods You Typically Call on ViewObjectImpl
| If you want to... |
Call this
ViewObjectImpl method |
| Perform any of the common view object, rowset, or rowset
iterator operations from inside your class, which can also be done from the
client
|
See the ViewObject Interface,
RowSet Interface, and RowSetIterator Interface sections
above.
|
| Set an additional runtime WHERE
clause on the default rowset
|
setWhereClause() |
| Set bind variable values on the default rowset |
setWhereClauseParam() |
| Retrieved a subset of rows in a view object's row
set based on evaluating an in-memory filter expression.
|
getFilteredRows() |
| Retrieved a subset of rows in the current range of a view
object's row set based on evaluating an in-memory filter expression.
|
getFilteredRowsInRange() |
| Set the number of rows that will be fetched from the
database per round-trip for this view object.
|
setFetchSize()
| Note: |
The default fetch
size is a single row at a time. This is definitely not optimal if your view
object intends to retrieve many rows, so you should either set the fetch size
higher at design time on the Tuning tab of the View Object
editor, or set it at runtime using this API.
|
|
Methods You Typically Write in Your Custom ViewObjectImpl
Subclass
| If
you want to... |
Write a method like this in your
ViewObjectImpl subclass |
| Provide clients with type-safe methods to set bind variable
values without exposing positional details of the bind variables themselves
|
someMethodName(Type1arg1, ..., TypeNargN)
| Note: |
Internally, this method
would call the setWhereClauseParam() API to set the correct bind variables with
the values provided in the type-safe method
arguments.
|
|
JDeveloper 10g can generate you a custom
YourViewObjectName interface
containing view object custom methods that you've chosen to expose to the
client. You can accomplish this by visiting the Client
Interface tab of the View Object editor, and shuttling the methods
you'd like to appear in your client interface into the
Selected list.
Methods You Typically Override in Your Custom ViewObjectImpl
Subclass
| If
you want to... |
Override this ViewObjectImpl
method |
| Initialize
custom view object class members (not row attributes!) when the view object
instance is created for the first time.
|
create()
| Note: |
This method is
useful to perform setup logic that is applicable to every instance of a view
object that will ever get created, in the context of any application
module.
If instead of generic view object
setup logic, you need to perform logic specific to a given view object
instance in an application module, then override the
prepareSession() method of your application module's
ApplicationModuleImpl subclass and perform the logic there
after calling findViewObject() to find the view object
instance whose properties you want to set.
|
|
| Write custom view object instance state to the state
management XML snapshot
|
passivateState() |
| Read and restore custom view object instance state
from the state management XML snapshot
|
activateState() |
Customize the behavior of view object query execution,
independent of whether the query was executed explicitly by calling
executeQuery() or implicitly, for example, by navigating to
the first() row when the query hadn't yet been
executed.
|
executeQueryForCollection() |
Change/augment the way that the
ViewCriteria collection of
ViewCriteriaRows is converted into a query-by-example
WHERE clause.
|
getViewCriteriaClause() |
ViewRowImpl Class
The
ViewRowImpl
class the base class for view row objects.
Methods You Typically Call on ViewRowImpl
| If
you want to... |
Write a method like this in your
custom ViewRowImpl class |
| Perform any of the common view row operations from inside
your class, which can also be done from the client
|
See the Row Interface section above.
|
| Get the value of an attribute |
getAttrName() |
| Set the value of an attribute |
setAttrName() |
| Access the underlying entity instance to which this
view row is delegating attribute storage.
|
getEntityUsageAliasName()
| Note: |
You can change the name of the entity usage alias name on the
Entity Objects tab of the View Object
Editor
|
|
Methods You Typically Write on
ViewRowImpl
| If
you want to... |
Write a method like this in your
custom ViewRowImpl class |
| Calculate the value of a view object level transient
attribute
|
getAttrName()
| Note: |
JDeveloper generates the skeleton of the method for you, but you
need to write the custom calculation logic inside the method
body.
|
|
| Perform custom
processing of the setting of a view row attribute
|
setAttrName()
| Note: |
JDeveloper generates the skeleton of the method for you, but you
need to write the custom logic inside the method body if
required.
|
|
| Determine the
updateability of an attribute in a conditional way.
|
isAttributeUpdateable() |
| Custom methods that expose logical operations on the
current row, optionally callable by clients
|
doSomething()
| Note: |
Often these view-row
level custom methods simply turn around and delegate to a method call on the
underlying entity object related to the current row.
|
|
JDeveloper 10g can generate you a custom
YourViewObjectNameRow interface
containing view row custom methods that you've chosen to expose to the client.
You can accomplish this by visiting the Client Row
Interface tab of the View Object editor, and shuttling the methods
you'd like to appear in your client interface into the
Selected list.
Methods You Typically Override in Your Custom ViewRowImpl
Subclass
| If
you want to... |
Write a method like this in your
custom ViewRowImpl class |
| Determine the updateability of an attribute in a
conditional way.
|
isAttributeUpdateable() |
Setting Up Your Own Layer of Framework
Base Classes
Before you begin to develop application specific
business components, we recommend creating yourself a layer of classes that
extend all of the ADF Business Components framework base implementation classes
described in this paper. An example of a customized framework base class for
application module components might look like this:
package com.yourcompany.adfextensions;
import oracle.jbo.server.ApplicationModuleImpl;
public class CustomApplicationModuleImpl extends ApplicationModuleImpl {
/*
* We might not yet have any custom code to put here yet, but
* the first time we need to add a generic feature that all of
* our company's application modules need, we will be very happy
* that we thought ahead to leave ourselves a convenient place
* in our class hierarchy to add it so that all of the application
* modules we have created will instantly benefit by that new feature,
* behavior change, or even perhaps, bug workaround.
*/
}
A common set of customized framework base classes in a
package name of your own choosing like
com.yourcompany.adfextensions,
each importing the oracle.jbo.server.* package, would
consist of the following classes.
public class CustomEntityImpl extends
EntityImpl
public class
CustomEntityDefImpl extends EntityDefImpl
public class CustomViewObjectImpl extends
ViewObjectImpl
public class
CustomViewRowImpl extends ViewRowImpl
public class CustomApplicationModuleImpl extends
ApplicationModuleImpl
public class CustomDBTransactionImpl extends
DBTransactionImpl2
public
class CustomDatabaseTransactionFactory extends
DatabaseTransactionFactory
For
completeness, you may also want to create customized framework classes for the
following classes as well, but overriding anything in these classes would be a
fairly rare requirement.
public
class CustomViewDefImpl extends ViewDefImpl
public class CustomEntityCache extends
EntityCache
public class
CustomApplicationModuleDefImpl extends
ApplicationModuleDefImpl
Conclusion
Hopefully this short list
of methods will assist you in getting started with Oracle ADF Business
Components to focus your attention on these most frequently used methods
instead of feeling bewildered about the many other methods that could be
overridden but which aren't often done in practice.
If you have
already been using ADF Business Components for some time and notice some
methods you use frequently that didn't make my list, please
send me an email to let me
know what I should add to the list. Include in your email a brief description
of how you're using the method, or what functionality you often providing in
the overridden version of the method. Thanks!
Revision History
| Date |
Comments |
| 18-Nov-2004 |
Created |
| 19-Nov-2004 |
Updated
diagram to include StructureDef, AttributeDef, and AttributeHints, and added
some text on the generated client proxy classes.
|
| 20-Nov-2004 |
Added a
comment about passing null to the createRowSetIterator
method
|
| 30-Nov-2004 |
Added
getPostedAttribute() and getEntityState()
|
| 1-Dec-2004 |
Clarified getPostState() and getEntityState() |
| 1-Jan-2005 |
Added some use case information for
prepareSession()
|
| 14-Mar-2005 |
Clarified when to use VOImpl.create() vs
AMImpl.prepareSession()
|
| 15-Mar-2005 |
Clarified when to prepareForDML() vs
postChanges()
|
| 14-Jun-2005 |
Clarified that EntityImpl.create() is used for programmatically
populating primary key attributes as well
|
| 19-Jan-2006 |
Updated javadoc
links
|
|