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
|