Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g (10.1.3.1.0) Part Number B25947-01 |
|
|
View PDF |
Before diving into each of the key components in subsequent chapters, it's good at the outset to understand a few guiding principles that have gone into the design and implementation of this layer of Oracle ADF.
Like the rest of Oracle ADF, the ADF Business Components technology is implemented in Java. The base components implement a large amount of generic, metadata-driven functionality to save you development time by standing on the shoulders of a rich layer of working, tested code. The metadata for ADF Business Components follow J2EE community best practice of using cleanly-separated XML files to hold the metadata that configures each component's runtime behavior.
Since ADF Business Components is often used for bet-your-business applications, it's important to understand that full source for Oracle ADF, including the ADF Business Components layer, is available to supported customers through Oracle Worldwide Support. The full source code for the framework can be an important tool to assist you in diagnosing problems and in correctly extending the base framework functionality for your needs.
Because your business components are implemented using plain Java classes and XML files, you can use them in any runtime environment where a Java Virtual Machine is present. This means that services built using ADF Business Components are easy to use both inside a J2EE server — known as the "container" of your application at runtime — as well as outside. Customers routinely use application modules in such diverse configurations as command-line batch programs, web services, custom servlets, JSP pages, desktop-fidelity clients built using Swing, and others.
Applications built using ADF Business Components can run on any Java-capable application server, including any J2EE-compliant application server. As described in Section 4.6.1, "Choosing a Connection, SQL Flavor, and Type Map", in addition to building applications that target Oracle databases with numerous optimizations, you can also build applications that work with non-Oracle databases.
The ADF Business Components layer implements all of the popular J2EE design patterns that you would normally need to understand, implement, and debug yourself to create a real-world enterprise J2EE application. If it is important to you to cross-reference the names of some of these design patterns you might have read about in J2EE literature with how they are implemented by ADF Business Components, you can refer to Appendix E, "ADF Business Components J2EE Design Pattern Catalog".
Since ADF Business Components is implemented in Java, it is implemented in Java classes and interfaces that are organized into packages. Java packages are identified by dot-separated names that developers use to arrange code into a hierarchical naming structure. To ensure your code won't clash with reusable code from other organizations, best practice dictates choosing package names that begin with your organization's name or web domain name. So, for example, the Apache organization chose org.apache.tomcat
for a package name related to its Tomcat web server, while Oracle picked oracle.xml.parser
as a package name for its XML parser. Components you create for an your own applications will live in a packages with names like com.
yourcompany
.
yourapp
and subpackages of these.
As a specific example, the ADF Business Components that make up the main business service for the SRDemo application are organized into the oracle.srdemo.model
package, and subpackages. As shown in Figure 4-1, these components reside in the DataModel
project in the workspace, and are organized broadly as follows:
oracle.srdemo.model
contains the SRService
application module
oracle.srdemo.model.queries
contains the view objects
oracle.srdemo.model.entities
contains the entity objects
oracle.srdemo.model.design
contains UML diagrams documenting the service
In your own applications, you can choose any package organization that you believe best organizes them. In particular, keep in mind that you are not constrained to organize components of the same type into a single package as the creators of the SRDemo application have done.
Due to JDeveloper's support for refactoring, you can easily rename or move components to a different package structure at any time. In other words, you don't need to necessarily get the structure right the first time. Your business service's package structure will almost certainly evolve over time as you gain more experience with the ADF environment.
There is no "magic" number that describes the optimal number of components in a package. However, with experience, you'll realize that the correct structure for your team falls somewhere between the two extremes of:
All components in a single package
Each component in its own, separate package
As described in more detail in Section 25.7, "Working with Libraries of Reusable Business Components", since a package of ADF Business Components is the unit of granularity that JDeveloper supports importing for reuse in other projects, sometimes you'll also factor this consideration into how you choose to organize components.
The classes and interfaces that comprise the pre-built code provided by the ADF Business Components layer live in the oracle.jbo
package and numerous subpackages, however in your day to day work with ADF Business Components you'll mostly be working with classes and interfaces in the two key packages oracle.jbo
and oracle.jbo.server
. The oracle.jbo
package contains all of the interfaces that are designed for the business service client to work with, while the oracle.jbo.server
package contains the classes that implement these interfaces.
Figure 4-2 shows a concrete example of the application module component. The client interface for the application module is the ApplicationModule
interface in the oracle.jbo
package. This interface defines the names and signatures of methods that clients can use while working with the application module, but it does not include any specifics about the implementation of that functionality. The class that implements the base functionality of the application module component lives in the oracle.jbo.server
package and is named ApplicationModuleImpl
.
Each kind of component in ADF Business Components comes with built-in runtime functionality that you control through declarative settings. These settings are stored in an XML component definition file with the same name as the component that it represents. When you need to write custom code for a component, you can enable an optional custom Java class for the component in question.
Figure 4-3 illustrates the XML component definition file for an application-specific component like an application module named YourService
that you create in a package named com.yourcompany.yourapp
. The corresponding XML component definition resides in a ./com/yourcompany/yourapp
subdirectory of the JDeveloper's project's source path root directory. That XML file records the name of the Java class it should use at runtime to provide the application module implementation. In this case, the XML records the name of the base oracle.jbo.server.ApplicationModuleImpl
class provided by Oracle ADF.
If you have no need to extend the built-in functionality of a component in ADF Business Components, and no need to write any custom code to handle its built-in events, you can use the component in this XML-only fashion. This means your component is completely defined by its XML component definition and be fully-functionality without requiring any custom Java code or even a Java class file related to the component at all.
When you need to add custom code to extend the base functionality of a component or to handle events, you can enable a custom Java class for any of the key types of ADF Business Components you create. You enable custom classes for a component on the Java panel of its respective component editor in JDeveloper. This creates a Java source file for a custom class related to the component whose name follows a configurable naming standard. This class, whose name is recorded in the component's XML component definition, provides a place where you can write the custom Java code required by that component. Once you've enabled a custom Java class for a component, you can navigate to it at any time using a corresponding Go To... Class option in the component's Application Navigator context menu.
Figure 4-4 illustrates what occurs when you enable a custom Java class for the YourService
application module considered above. A YourServiceImpl.java
source code file is created in the same directory in the source path as your component's XML component definition file. The YourService.xml
file is updated to reflect the fact that at runtime the component should use the com.yourcompany.yourapp.YourServiceImpl
class instead of the base ApplicationModuleImpl
class.
Note: The examples in this guide use default settings for generated names of custom component classes and interfaces. If you want to change these defaults for your own applications, use the Business Components: Class Naming page of the JDeveloper Tools Preferences dialog. Changes you make only affect newly created components. |
You can configure whether JDeveloper generates custom Java files by default for each component type that supports it, as well as whether JDeveloper maintains a list of Oracle ADF business components in each package using a package XML file. This section describes Oracle's recommendations to developers getting started with ADF Business Components on how to configure these options.
Your applications can freely mix XML-only components with components that have related custom Java files. For example, you can define a completely functional, updatable data model with declaratively enforced business rules using XML-only components. On the other end of the spectrum, some developers prefer to proactively generate Java classes for each component they create as part of their team's coding style.
For developers getting started with ADF Business Components, Oracle recommends initially configuring JDeveloper to not generate any custom Java classes by default. This way, you learn the reasons why custom Java is needed and you consciously enable it for the components that require it in your application. Over time, you will develop a personal preference of your own.
Note that this recommended setting is not the default, so you need to perform the following steps to configure the Java generation preferences as recommended here:
Choose Tools | Preferences... from the JDeveloper main menu
Select the Business Components preference category in the tree at the left
Ensure all of the checkboxes are unchecked as shown in Figure 4-5, then click OK.
By default, for upward compatibility with previously releases of Oracle ADF, JDeveloper maintains an XML file in each directory containing the names of the Oracle ADF business components that reside in that package. While previously required by the ADF runtime classes, this package XML file is optional in this version. Since maintaining this "package XML" file can complicate team development, Oracle recommends you disable the use of any package XML files by setting the Copy Package XML Files to Class Path option off in the Business Components: General panel of the IDE preferences as shown in Figure 4-6.
The Java language provides a number of built-in data types for working with strings, dates, numbers, and other data. When working with ADF Business Components, you can use these types, but by default you'll use an optimized set of types in the oracle.jbo.domain
and oracle.ord.im
packages. These types, shown in Table 4-1, improve the performance of working with data from the Oracle database by allowing the data to remain in its native, internal format avoiding costly type conversions when they are not necessary. For working with string-based data, by default ADF Business Components uses the regular java.lang.String
type.
Table 4-1 Basic Data Types in the oracle.jbo.domain and oracle.ord.im Packages
Data Type | Represents |
---|---|
|
Any numerical data |
|
Date with optional time |
|
Sequential integer assigned by a database trigger |
|
Oracle database ROWID |
|
Timestamp value |
|
Timestamp value with Timezone information |
|
Binary File (BFILE) object |
|
Binary Large Object (BLOB) |
|
Character Large Object (CLOB) |
|
Oracle Intermedia Image (ORDIMAGE) |
|
Oracle Intermedia Audio (ORDAUDIO) |
|
Oracle Intermedia Video (ORDVIDEO) |
|
Oracle Intermedia Document (ORDDOC) |
|
User-defined object type |
|
User-defined collection type (e.g. |
Note: Theoracle.jbo.domain.Number class has the same class name as the built-in java.lang.Number type. Since the Java compiler implicitly imports java.lang.* into every class, you need to explicitly import the oracle.jbo.domain.Number class into any class that references this. Typically, JDeveloper will do this automatically for you, but when you begin to write more custom code of your own, you'll learn to recognize compiler or runtime errors related to "Number is an abstract class" mean that you are inadvertently using java.lang.Number instead of oracle.jbo.domain.Number . Adding the:
import oracle.jbo.domain.Number; line at the top of your class, after the |
When working with application modules, view objects, and entity objects, you can choose to use a set of generic APIs or can have JDeveloper generate code into a custom Java class to enable a strongly-typed API for that component. For example, when working with an view object, you can access the value of an attribute in any row of its result using a generic API like:
Row row = serviceRequestVO.getCurrentRow(); Date requestDate = (Date)row.getAttribute("RequestDate");
Notice that using the generic APIs, you pass string names for parameters, and you have to cast the return type to the expected type like Date
shown in the example.
Alternatively, if you enable the strongly-typed style of working you can write code like this:
ServiceRequestsRow row = (ServiceRequestRow)serviceRequestVO.getCurrentRow(); Date requestDate = row.getRequestDate();
In this case, you work with generated method names whose return type is known at compile time, instead of passing string names and having to cast the results. Subsequent chapters explain how to enable this strongly-typed style of working if you prefer it.
By design, the entity objects in the business domain layer of business service implementation are not designed to be referenced directly by clients. Instead, clients work with the data queried by view objects as part of an application module's data model. Behind the scenes, as you'll learn in Section 7.7, "Understanding How View Objects and Entity Objects Cooperate at Runtime", the view object cooperates automatically with entity objects in the business domain layer to coordinate validating and saving the data the user changes.
Therefore, the client-visible components of your business service are the:
Application Module — representing the service itself
View Objects — representing the query components
View Rows — representing each row in a given query component's results
The oracle.jbo
package provides client-accessible API for your business service as a set of Java interfaces. In line with the design mentioned above, this package does not contain any Entity
interface, or any methods that allow the client to directly work with entity objects. Instead, client code works with interfaces like:
ApplicationModule
— to work with the application module
ViewObject
— to work with the view object
Row
— to work with the view rows
When you begin adding custom code to your Oracle ADF business components that you want clients to be able to call, you can "publish" that functionality to clients for any client-visible component. For each of your components that publishes at least one custom method to clients on its client interface, JDeveloper automatically maintains the related Java interface file. So, assuming you were working with an application module like the SRService
module used in the SRDemo application, you can have custom interfaces like:
Custom Application Module Interface
SRService extends ApplicationModule
Custom View Object Interface
StaffListByEmailNameRole extends ViewObject
Custom View Row Interface
StaffListRowClient extends Row
Client code can then cast one of the generic client interfaces to the more specific one that includes the selected set of client-accessible methods you've selected for your particular component.