Oracle® Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.7.2) Part Number B31974-15 |
|
|
PDF · Mobi · ePub |
This chapter describes key features that you can use when you begin to work with the ADF Business Components layer of Oracle Application Development Framework (Oracle ADF). It also describes the implementation architecture of ADF Business Components and describes support for the Groovy scripting language with entity objects and view objects.
This chapter includes the following sections:
ADF Business Components and JDeveloper simplify the development, delivery, and customization of business applications for the Java EE platform. With ADF Business Components, developers aren't required to write the application infrastructure code required by the typical Java EE application to:
Connect to the database
Retrieve data
Lock database records
Manage transactions
ADF Business Components addresses these tasks through its library of reusable software components and through the supporting design time facilities in JDeveloper. Most importantly, developers save time using ADF Business Components since the JDeveloper design time makes typical development tasks entirely declarative. In particular, JDeveloper supports declarative development with ADF Business Components to:
Author and test business logic in components which automatically integrate with databases
Reuse business logic through multiple SQL-based views of data, supporting different application tasks
Access and update the views from browser, desktop, mobile, and web service clients
Customize application functionality in layers without requiring modification of the delivered application
The goal of ADF Business Components is to make the business services developer more productive.
ADF Business Components provides a foundation of Java classes that allow your business-tier application components to leverage the functionality provided in the following areas:
Design a data model for client displays, including only necessary data
Include master-detail hierarchies of any complexity as part of the data model
Implement end-user Query-by-Example data filtering without code
Automatically coordinate data model changes with business domain object layer
Automatically validate and save any changes to the database
Declaratively enforce required fields, primary key uniqueness, data precision-scale, and foreign key references
Easily capture and enforce both simple and complex business rules, programmatically or declaratively, with multilevel validation support
Navigate relationships between business domain objects and enforce constraints related to compound components
Automatically reflect changes made by business service application logic in the user interface
Retrieve reference information from related tables, and automatically maintain the information when the user changes foreign-key values
Simplify multistep web-based business transactions with automatic web-tier state management
Handle images, video, sound, and documents without having to use code
Synchronize pending data changes across multiple views of data
Consistently apply prompts, tooltips, format masks, and error messages in any application
Define custom metadata for any business components to support metadata-driven user interface or application functionality
Add dynamic attributes at runtime to simplify per-row state management
Support highly functional web service interfaces for business integration without writing code
Enforce best-practice interface-based programming style
Simplify application security with automatic JAAS integration and audit maintenance
"Write once, run anywhere": use the same business service as plain Java class or web service
Extend component functionality after delivery without modifying source code
Globally substitute delivered components with extended ones without modifying the application
Deliver application upgrades without losing or having to reapply downstream customizations manually
ADF Business Components implements the business service through the following set of cooperating components:
Entity object
An entity object represents a row in a database table and simplifies modifying its data by handling all data manipulation language (DML) operations for you. It can encapsulate business logic for the row to ensure that your business rules are consistently enforced. You associate an entity object with others to reflect relationships in the underlying database schema to create a layer of business domain objects to reuse in multiple applications.
View object
A view object represents a SQL query. You use the full power of the familiar SQL language to join, filter, sort, and aggregate data into exactly the shape required by the end-user task. This includes the ability to link a view object with others to create master-detail hierarchies of any complexity. When end users modify data in the user interface, your view objects collaborate with entity objects to consistently validate and save the changes.
Application module
An application module is the transactional component that UI clients use to work with application data. It defines an updatable data model and top-level procedures and functions (called service methods) related to a logical unit of work related to an end-user task.
While the base components handle all the common cases through built-in behavior, customization is always possible and the default behavior provided by the base components can be easily overridden or augmented.
ADF Business Components provides components that implement functionality similar to that offered by enterprise 4GL tools. Several key components in ADF Business Components map to concepts that you may be familiar with in other 4GL tools.
ADF Business Components implements all of the data-centric aspects of the familiar Oracle Forms runtime functionality, but in a way that is independent of the user interface. In Oracle Forms, each form contains both visual objects (like canvases, windows, alerts, and LOVs), as well as nonvisual objects (like data blocks, relations, and record groups). Individual data block items have both visual properties like Foreground Color
and Bevel
, as well as nonvisual properties like Data Type
and Maximum Length
. Even the different event-handling triggers that Forms defines fall into visual and nonvisual categories. For example, it's clear that triggers like WHEN-BUTTON-PRESSED
and WHEN-MOUSE-CLICKED
are visual in nature, relating to the front-end UI, while triggers like WHEN-VALIDATE-ITEM
and ON-INSERT
are more related to the backend data processing. While merging visual and nonvisual aspects definitely simplifies the learning curve, the flip side is that it can complicate reuse. With a cleaner separation of UI-related and data-related elements, it would be easier to redesign the user interface without disturbing backend business logic and easier to repurpose back-end business logic in multiple different forms.
In order to imagine this separation of UI and data, consider reducing a form as you know it to only its nonvisual, data-related aspects. This reduces the form to a container of data blocks, relations, and record groups. This container would continue to provide a database connection for the data blocks to share and would be responsible for coordinating transaction commits or rollbacks. Of course, you could still use the nonvisual validation and transactional triggers to augment or change the default data-processing behavior as well. This nonvisual object you are considering is a kind of a "smart data model" or a generic application module, with data and business logic, but no user interface elements. The goal of separating this application module from anything visual is to allow any kind of user interface you need in the future to use it as a data service.
Focus a moment on the role the data blocks would play in this application module. They would query rows of data from the database using SQL, coordinate master/detail relationships with other data blocks, validate user data entry with WHEN-VALIDATE-RECORD
and WHEN-VALIDATE-ITEM
triggers, and communicate valid user changes back to the database with INSERT
, UPDATE
, and DELETE
statements when you commit the data service's transaction.
Experience tells you that you need to filter, join, order, and group data for your end-users in a variety of ways to suit the many different tasks. On the other hand, the validation rules that you apply to your business domain data remain basically the same over time. Given these observations, it would be genuinely useful to write business entity validation exactly once, and leverage it consistently anywhere that data is manipulated by users in your applications.
Enabling this flexibility requires further "factoring" of your data block functionality. You need one kind of "SQL query" object to represent each of the many different views of data your application requires, and you need another kind of "business entity" object to enforce business rules and communicate changes to your base table in a consistent way. By splitting things like this, you can have multiple "view objects" with specific SQL queries that present the same business data yet each working with the same underlying "entity object."
Oracle ADF addresses the UI/data split by providing ready-to-use Java components that implement typical Forms functionality. Responsibilities between the querying and entity-related functions are cleanly separated, resulting in better reuse.
The application module component is the "data portion" of the form. The application module is a smart data service containing a data model of master-detail-related queries that your client interface needs to work with. It also provides a transaction and database connection used by the components it contains. It can contain form-level procedures and functions, referred to as service methods, that are encapsulated within the service implementation. You can decide which of these procedures and functions should be private and which ones should be public.
The entity object component implements the "validation and database changes" portion of the data block functionality. In the Forms runtime, this duty is performed by the record manager. The record manager is responsible for keeping track of which of the rows in the data block have changed, for firing the block-level and item-level validation triggers when appropriate, and for coordinating the saving of changes to the database. This is exactly what an entity object does for you. The entity object is a component that represents your business domain entity through an underlying database table. The entity object gives you a single place to encapsulate business logic related to validation, defaulting, and database modification behavior for that business object.
The ViewObject
component performs the "data retrieval" portion of the data block functionality. Each view object encapsulates a SQL query, and at runtime each one manages its own query result set. If you connect two or more view objects in master-detail relationships, that coordination is handled automatically. While defining a view object, you can link any of its query columns to underlying entity objects. By capturing this information, the view object and entity object can cooperate automatically for you at runtime to enforce your domain business logic, regardless of the "shape" of the business data required by the user's task.
If you have developed solutions in the past with PeopleTools, you are familiar with the PeopleTools component structure. ADF Business Components implement the data access functionality you are familiar with from PeopleTools.
Oracle ADF adheres to an MVC pattern and separates the model from the view. Pages, which you are familiar with in the PeopleTools Component, are defined in the view layer, using standard technologies like JSF and ADF Faces components for web-based applications or Swing for desktop-fidelity client displays.
The ADF application module defines the data structure, just like the PeopleTools Component Buffer does. By defining master-detail relationships between ADF query components that produce row sets of data, you ensure that any application module that works with the data can reuse the natural hierarchy as required, similar to the scroll levels in the Component Buffer.
Similar to the Component Interface you are familiar with, the application module is a service object that provides access to standard methods, as well as additional developer-defined business logic. In order to present a "headless" data service for a particular user interface, the Component Interface restricts a number of PeopleTools functions that are related to UI interaction. The application module is similar to the Component Interface in that it provides a "headless" data service, but in contrast it does not do this by wrapping a restricted view of an existing user interface. Instead, the application module is designed to deal exclusively with business logic and data access. Rather than building a Component Interface on top of the component, with ADF Business Components you first build the application module service that is independent of user interface, and then build one or more pages on top of this service to accomplish some end-user task in your application.
The application module is associated with a transaction object in the same way that the PeopleTools Component Buffer is. The application module also provides a database connection for the components it contains. Any logic you associate today with the transaction as Component PeopleCode, in ADF Business Components you would define as logic on the application module.
Logic associated with records in the transaction, that today you write as Component Record PeopleCode or Component Record Field PeopleCode, should probably not be defined on the application module. ADF Business Components has view objects that allow for better re-use when the same record appears in different components.
In summary, PeopleTools uses the component for the container concept, whereas ADF Business Components uses the application module. That is where the similarity ends. Do not assume that all of your component code will migrate to an application module. First, understand the concept of the view object, which is the layer between the entity object and the application module. Then, decide which of your component code is suitable for an application module and which is suitable for view objects.
The entity object is the mapping to the underlying data structure, just like the PeopleTools Record Definition maps to the underlying table or view. You'll often create one entity object for each of the tables that you need to manipulate your application.
Similar to how you declare a set of valid values for fields like "Customer Status" using PeopleTools' translate values, in ADF Business Components you can add declarative validations to the individual attributes of an entity object. Any logic you associate with the record that applies throughout your applications, which today you write as Record PeopleCode or Record Field PeopleCode, can be defined in ADF Business Components on the entity object.
Just like a PeopleTools row set, a view object can be populated by a SQL query. Unlike a row set, a view object definition can contain business logic.
Any logic which you would find in Component Record PeopleCode is a likely candidate to define on the view object. Component Record PeopleCode is directly tied to the component, but a view object can be associated with different application modules. Whereas you can use the same record definition in many PeopleTools components, Oracle ADF allows you to reuse the business logic across multiple applications.
The view object queries data in exactly the "shape" that is useful for the current application. Many view objects can be built on top of the same entity object.
You can define relationships between view objects to create master-detail structures, just as you find them in the scroll levels in the PeopleTools component.
If you have developed solutions in the past with Siebel Tools version 7.0 or earlier, you will find that ADF Business Components implements all of the familiar data access functionality you are familiar with, with numerous enhancements.
Like the Siebel Table object, the ADF entity object describes the physical characteristics of a single table, including column names and physical data types. Both objects contain sufficient information to generate the DDL (data definition language) statements to create the physical tables in the database. In ADF Business Components you define associations between entity objects to reflect the foreign keys present in the underlying tables. These associations allow view object queries used by user interface pages to automatically join business information. ADF Business Components handles list of values (LOV) objects that you reference from data columns through a combination of declarative entity-level validation rules and view object attribute-level LOV definitions. You can also encapsulate other declarative or programmatic business logic with these entity object "table" handlers that is automatically reused in any view of the data you create.
Like the Siebel Business Component, the ADF view object describes a logical mapping on top of the underlying physical table representation. Both the Siebel Business Component and the ADF view object allow you to provide logical field names, data, and calculated fields that match the needs of the user interface. As with the Siebel Business Component, with the ADF view object you can define view objects that join information from various underlying tables. The related ADF view link is similar to the Siebel Link object and allows you to define master-detail relationships. In ADF Business Components, your view object definitions can exploit the full power of the SQL language to shape the data as required by the user interface.
The Siebel Business Object lets you define a collection of business components. The ADF application module performs a similar task, allowing you to create a collection of master-detail view objects that act as a "data model" for a set of related user interface pages. In addition, the application module provides a transaction and database connection context for this group of data views. You can make multiple requests to objects obtained from the application module and these participate in the same transaction.
If you have developed solutions in the past with Visual Studio 2003 or 2005, you are familiar with using the ADO.NET framework for data access. ADF Business Components implements all of the data access functionality you are familiar with from ADO.NET, with numerous enhancements.
The application module component plays the same role as the ADO.NET data set. It is a strongly typed service component that represents a collection of row sets called view object instances, which are similar to ADO.NET data tables. An application module exposes a service interface that surfaces the rows of data in a developer-configurable set of its view instances as an SDO-compatible service (accessible as a web service, or as an SCA composite). The application module works with a related transaction object to provide the context for the SQL queries that the view objects execute. The application module also provides the context for modifications saved to the database by the entity objects, which play the role of the ADO.NET data adapter.
The entity object component is like a strongly-typed ADO.NET data adapter. It represents the rows in a particular table and handles the find-by-primary-key, insert, update, delete, and lock operations for those rows. In ADF Business Components, you don't have to specify these statements yourself, but you can override them if you need to. The entity object encapsulates validation or other business logic related to attributes or entire rows in the underlying table. This validation is enforced when data is modified and saved by the end user using any view object query that references the underlying entity object. One difference in ADF Business Components is that the arbitrary, flexible querying is performed by SQL statements at the view object instance level, but the view objects and entity objects coordinate automatically at runtime.
The view object component encapsulates a SQL query and manages the set of resulting rows. It can be related to an underlying entity object to automatically coordinate validation and saving of modifications made by the user to those rows. This cooperation between a view object's queried data and an entity object's encapsulated business logic offers all of the benefits of the data table with the clean encapsulation of business logic into a layer of business domain objects. Like ADO.NET data tables, you can easily work with a view object's data as XML or have a view object read XML data to automatically insert, update, or delete rows based on the information it contains.
JDeveloper includes comprehensive design time support for ADF Business Components. Collectively, these facilities let you create, edit, diagram, test, and refactor the business components.
The first time you create a component, you'll see the Initialize Business Components Project dialog shown in Figure 3-1. You use this dialog to select a design time application resource connection to use while working on your business components in this data model project or to create a new application resource connection by copying an existing IDE-level connection.
Since this dialog appears before you create your first business component, you also use it to globally control the SQL platform that the view objects will use to formulate SQL statements. SQL platforms that you can choose include:
Oracle SQL platform for an Oracle database connection (the default)
OLite for the Oracle Lite database
SQLServer for a Microsoft SQLServer database
DB2 for an IBM DB2 database
SQL92 for any other supported SQL92- compliant database
Note:
If you plan to have your application run against both Oracle and non-Oracle databases, you should select the SQL92 SQL platform when you begin building your application, not later. While this sacrifices some of the Oracle-specific optimizations that are inherent in using the Oracle SQL platform, it makes the application portable to both Oracle and non-Oracle databases.
Additionally, the dialog lets you determine which set of data types that you want the data model project to use. JDeveloper uses the data type selection to define the data types of attributes when you create entity object and view objects in the data model project. It is therefore important that you make the appropriate selection before you save the settings in the Initialize Business Components Project dialog. The dialog provides these options:
Java Extended for Oracle type map is selected by default if JDeveloper detects you are using an Oracle database driver. The Java Extended for Oracle type map uses standard Java types and the optimized types in the oracle.jbo.domain
package for common data types.
Tip:
New Fusion web applications should use the default Java Extended for Oracle type.
Java type map is provided to support applications that will run on a non-Oracle database and that you create using SQL92-compliance. In this case, you should set the data type map to Java to globally use only the basic Java data types.
Oracle Domains type map is provided for backward compatibility and for ADF applications that do not use ADF Faces as the view layer technology, as explained in Section 3.3.2, "What You May Need to Know About Displaying Numeric Values."Please note that when you migrate an application developed with JDeveloper version 11.1.1.4.0 or earlier, your application will continue to use the Oracle Domains type map and will not change to the current default type map Java Extended for Oracle
Once you save project selections in the Initialize Business Components Project dialog, the project is considered initialized and you will not be able to change the data type map selection. After you initialize the project, you can override the SQL platform in the Business Components page of the overview editor for the adf-config.xml
file, but you must do this before you add business components to the project. You can locate the adf-config.xml
file in the Application Resources pane by expanding the Descriptors and ADF META-INF nodes. Specifying the database type in the adf-config.xml
file supports generating SQL statements during runtime that can require the actual database type of the deployed Fusion web application.
The Java Extended for Oracle type map and the Oracle Domains type map handle numeric data differently. When you create a new application the default type map Java Extended for Oracle maps numeric data to the java.math.BigDecimal
class, which inherits from java.math.Number
. The java.math.BigDecimal
default matches the way the Fusion web application view layer, consisting of ADF Faces components, preserves alignment of numeric data (such as numeric values displayed by ADF Faces input fields in a web page). Whereas the Oracle Domains type map, which maps numeric data to the oracle.jbo.domain.Number
class, may not display the data with the alignment expected by certain ADF Faces components. Aside from this alignment issue, the Oracle Domains type map remains a valid choice and applications without ADF Faces components will function without issue.
In the New Gallery in the ADF Business Components category, JDeveloper offers a wizard to create each kind of business component. Each wizard allows you to specify the component name for the new component and to select the package into which you'd like to organize the component. If the package does not yet exist, the new component becomes the first component in that new package.
The wizard presents a series of panels that capture the necessary information to create the component type. When you click Finish, JDeveloper creates the new component by saving its XML component definition file. If you have set your Java generation options to generate classes by default, JDeveloper also creates the initial custom Java class files.
Once a package exists in the Application Navigator, you can quickly create additional business components of any type in the package by selecting it in the Application Navigator and using one of the options on the context menu shown in Figure 3-2.
Once a business component exists, you can edit its properties using the respective overview editor that you access either by double-clicking the component in the Application Navigator or by selecting it and choosing the Open option from the context menu.
The overview editor presents the same editing options that you see in the wizard but it may arrange them differently. The overview editor allows you to change any aspect of the component. When you make a change in the component's editor, JDeveloper updates the component's XML component definition file and, if necessary, any of its related custom Java files. Because the overview editor is a JDeveloper editor window, rather than a modal dialog, you can open and view the overview editor for as many components as you require.
JDeveloper offers extensive UML diagramming support for ADF Business Components. You can drop components that you've already created onto a business components diagram to visualize them. You can also use the diagram to create and modify components. The diagrams are kept in sync with changes you make in the editors.
To create a new business components diagram, use the Business Components Diagram item in the ADF Business Components category of the JDeveloper New Gallery. This category is part of the Business Tier choices.
Once you have created an application module component, you can test it interactively using the built-in Business Component Browser. To launch the Business Component Browser, select the application module in the Application Navigator or in the business components diagram and choose either Run or Debug from the context menu.
The Business Component Browser presents the view object instances in the application module's data model and allows you to interact with them using a dynamically generated user interface. The tool also provides a list of the application module's client interface methods that you can test interactively by double-clicking the application module node. This tool is invaluable for testing or debugging your business service both before and after you create the web page view layer.
At any time, you can select a component in the Application Navigator and choose Refactor > Rename from the context menu to rename the component. The Structure window also provides a Rename context menu option for details of components, such as view object attributes or view instances of the application module data model, that do not display in the Application Navigator. You can also select one or more components in the navigator by using Ctrl + click and then choosing Refactor > Move from the context menu to move the selected components to a new package. References to the old component names or packages in the current data model project are adjusted automatically.
One of the key simplifying benefits of using ADF Business Components for your business service implementation is the application module's support for a "UI-aware data model" of row sets. The data model defines the business objects specific to your application, while the row sets of each business object contain the data. In the UI portion of the application, the UI components interact with these business objects to perform retrieve, create, edit, and delete operations. When you use ADF Business Components in combination with the ADF Model layer and ADF Faces UI components, the data model is "UI aware" because your UI components will automatically update to reflect any changes to the row sets of these business objects
Thus, the UI-aware data model represents a solution that works across application technology layers to ensure that the UI and data model remain synchronized.
Using a typical Java EE business service implementation makes the client developer responsible for:
Invoking service methods to return data to present
Tracking what data the client has created, deleted, or modified
Passing the changes back to one or more different service methods to validate and save them
Retrieving, creating, editing, deleting, and saving is a typical sequence of tasks performed during application development. As a result, the ADF application module represents a smarter, more generic solution. Using the application module for your business service, you simply bind client UI components like fields, tables, and trees to the active view object instances in the application module's data model. Your UI components in JSP or JSF pages for the web or mobile devices (as well as desktop-fidelity UIs comprising windows and panels that use Swing) automatically update to reflect any changes to the rows in the view object row sets of the data model. This active data notification also extends to custom business service methods that happen to produce changes to the data model.
Under the covers, the application module component implements a set of generic service methods that allow users to leverage its UI-aware data model in a service-oriented architecture (SOA). Both web service and UI clients can easily access an application module's data model using simple APIs. These APIs enable you to search for and modify any information that the application module makes available.
When you build UIs that take advantage of the ADF Model layer for declarative data binding, you generally won't need to write client-side code. Because the data model is UI-aware, your UI components will be bound declaratively to view objects in the data model and to custom business service methods.
Without a UI-aware data model, you would need to write more code in the client to handle the straightforward, everyday CRUD-style operations. In addition, to keep pages up to date, you would need to manage "refresh flags" that clue the controller layer in to requesting a "repull" of data from the business service to reflect data that might have been modified. When using an ADF application module to implement your business service, you can focus on the business logic at hand, instead of the plumbing to make your business work as your end users expect.
Consider the following three simple, concrete examples of the UI-aware data model:
New data appears in relevant displays without requerying
A customer logs into the Fusion Order Demo application and displays a list of items in their shopping cart. Then if the customer visits some product pages and creates a new order item, when they return back to display their shopping cart, the new item appears in their list without requiring the application to requery the database.
Changes caused by business domain logic automatically reflected
A back office application causes an update to the order status. Business logic encapsulated in the Orders
entity object in the business domain layer contains a simple rule that updates the last update date whenever the order status attribute is changed. The user interface updates to automatically reflect the last update date that was changed by the logic in the business domain layer.
Invocation of a business service method requeries data and sets current rows
In a tree display, the user clicks on a specific node in a tree. This action declaratively invokes a business service method on your application module that requeries master-detail information and sets the current rows to an appropriate row in the row set. The display updates to reflect the new master-detail data and current row displayed.
Because the application module supports the UI-aware data model, your client user interface will remain up to date. This means you will not need to write code in the client that is related to setting up or manipulating the data model.
Another typical type of client-side code you no longer have to write using ADF Business Components is code that coordinates detail data collections when a row in the master changes. By linking the view objects, you can have the coordination performed automatically for you.
However, when you do need to write custom code, encapsulate that code inside custom methods of your application module component. For example, whenever the programmatic code that manipulates view objects is a logical aspect of implementing your complete business service functionality, you should encapsulate the details by writing a custom method in your application module's Java class. This includes, but is not limited to, code that:
Configures view object properties to query the correct data to display
Iterates over view object rows to return an aggregate calculation
Performs any kind of multistep procedural logic with one or more view objects
By centralizing these implementation details in your application module, you gain the following benefits:
You make the intent of your code more clear to clients.
You allow multiple client pages to easily call the same code if needed.
You simplify regression-testing of your complete business service functionality.
You keep the option open to improve your implementation without affecting clients.
You enable declarative invocation of logical business functionality in your pages.
Before you begin implementing specific ADF business components, it is a good idea to have some familiarity with the Oracle ADF business services layer's design and implementation.
As is the case with all Oracle ADF technologies, ADF Business Components is implemented in Java. The working, tested components in the framework provide generic, metadata-driven functionality from a rich layer of robust code. ADF Business Components follows the Java EE community best practice of using cleanly separated XML files to store metadata that you define to configure each component's runtime behavior.
Since ADF Business Components is often used for business critical applications, it's important to understand that the 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 Oracle ADF can be an important tool to assist you in diagnosing problems, as described in Section 31.7, "Using the ADF Declarative Debugger." Working with the full source code for Oracle ADF also helps you understand how to correctly extend the base framework functionality to suit your needs, as described in Section 37.2, "Customizing Framework Behavior with Extension Classes."
Applications built using ADF Business Components can run on any Java-capable application server, including any Java EE-compliant application server. Because 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 Java EE server — known as the "container" of your application at runtime — and outside.
Customers routinely use application modules in such diverse configurations as command-line batch programs, web services, custom servlets, JSP pages, and desktop-fidelity clients built using Swing.
You can also build applications that work with non-Oracle databases, as described in Section 3.3.1, "Choosing a Connection, SQL Flavor, and Type Map." However, applications that target Oracle databases will find numerous optimizations built into ADF Business Components.
The ADF Business Components layer implements all of the popular Java EE design patterns that you would normally need to understand, implement, and debug yourself to create a real-world enterprise Java EE application. If it is important to you to cross-reference the names of these design patterns from the Java EE specifications with their ADF Business Components counterparts, you can refer to Appendix F, "ADF Business Components Java EE Design Pattern Catalog."
Since ADF Business Components is implemented in Java, its classes and interfaces are organized into packages. Java packages are identified by dot-separated names that developers use to arrange code into a hierarchical naming structure.
The classes and interfaces that comprise the source code provided by ADF Business Components reside in the oracle.jbo
package and numerous subpackages. However, in day to day work with ADF Business Components, you'll work typically with classes and interfaces in these two key packages:
The oracle.jbo
package, which contains all of the interfaces that are designed for the business service client to work with
The oracle.jbo.server
package, which contains the classes that implement these interfaces
Note:
The term client here refers to any code in the model, view, or controller layers that accesses the application module component as a business service.
Figure 3-3 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 resides in the oracle.jbo.server
package and is named ApplicationModuleImpl
.
Since ADF Business Components is implemented in Java, the components of your application (including their classes, interfaces, and metadata files) will also be organized into packages.
To ensure that your components won't clash with reusable components from other organizations, choose 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 your own applications might reside in 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 Fusion Order Demo application are organized into the oracle.fodemo.storefront
package and its subpackages. As shown in Figure 3-4, these components reside in the StoreFrontService
project in the StoreFrontModule
application, and are organized broadly as follows:
oracle.fodemo.storefront.account.queries
contains the view objects used in the customer registration process
oracle.fodemo.storefront.client
contains test client .java
files
oracle.fodemo.storefront.entities
contains the entity objects
oracle.fodemo.storefront.lookups
contains static data view objects and the LookupServiceAM
shared application module
oracle.fodemo.storefront.store.queries
contains the view objects used to manage the storefront
oracle.fodemo.storefront.store.service
contains the StoreServiceAM
application module
In your own applications, you can choose any package organization that you believe best. In particular, keep in mind that you are not constrained to organize components of the same type into a single package.
Because JDeveloper supports component refactoring, you can easily rename components or move them to a different package at any time. This flexibility allows you to easily incorporate inevitable changes into the application as your application evolves.
There is no optimal number of components in a package. However, with experience, you'll realize that the best structure for your team falls somewhere between the two extremes of placing all components in a single package and placing each component in its own, separate package.
One thing to consider is that the package in ADF Business Components is the unit of granularity that JDeveloper supports for reuse in other data model projects. So, you might factor this consideration into how you choose to organize components. For more information, see Section 37.6, "Working with Libraries of Reusable Business Components."
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, for example to augment the component's behavior, you can enable an optional custom Java class for the component in question. Figure 3-5 shows how the Application Navigator displays the XML component definition and optional custom Java class for an application module.
Figure 3-6 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 data model 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.
When used without customization, your component is completely defined by its XML component definition and it will be fully functional without custom Java code or even a Java class file for the component. 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.
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 the generation of custom classes for a component on the Java page of its respective overview editor in JDeveloper. When you enable this option, JDeveloper 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 using a corresponding Go To componentName Class option in the component's Application Navigator context menu.
Figure 3-7 illustrates what occurs when you enable a custom Java class for the YourService
application module. A YourServiceImpl
.java
source code file is created in the same source path directory as your component's XML component definition file. The YourServiceImpl
.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 Preferences dialog. Changes you make only affect newly created components.
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 3-1, allow data accessed from the Oracle database to remain in its native, internal format. You will achieve better performance using the optimized data types provided by ADF Business Components by avoiding costly type conversions when they are not necessary. To work with string-based data, by default ADF Business Components uses the regular java.lang.String
type.
Table 3-1 Basic Data Types in the oracle.jbo.domain and oracle.ord.im Packages
Data Type | Package | Represents |
---|---|---|
|
|
Any numerical data |
|
|
Date with optional time |
|
|
Sequential integer assigned by a database trigger |
|
|
Oracle database ROWID |
|
|
Timestamp value |
|
|
Timestamp value with time zone information |
|
|
Timestamp value with local time zone information retrieved from JavaVM or from the ADF Context when configured in the application's
The EL expression will be evaluated to determine the time zone of the current user; otherwise, the value defaults to the time zone of the JavaVM. |
|
|
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:
The oracle.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 it. Typically, JDeveloper will follow this practice 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" as indicating 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 package
line, prevents these kinds of errors.
When working with application modules, view objects, and entity objects, you can choose to use a set of generic APIs or you 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, if you wanted to access the value of an attribute in any row of its result, the generic API would look like this:
Row row = ordersVO.getCurrentRow(); Date shippedDate = (Date)row.getAttribute("OrderShippedDate");
Notice that using the generic APIs, you pass string names for parameters to the accessor, and you have to cast the return type to the expected type, as with Date
shown in the example.
Alternatively, when you enable the strongly typed style of working you can write code like this:
OrdersRow row = (OrdersRow)ordersVO.getCurrentRow(); Date shippedDate = row.getOrderShippedDate();
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. Typically, it is necessary to use strongly typed accessors when you need to invoke the methods from the business logic code without sacrificing compile-time safety. This can also be useful when you are writing custom validation logic in setter methods, although in this case, you may want to consider using Groovy expressions instead of generating entity and view row implementation classes for Business Components. Subsequent chapters explain how to enable this strongly typed style of working by generating Java classes for business logic that you choose to implement using Java.
Only these components of the business service as visible to the client:
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 entity objects in the business service implementation is intentionally 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, the view object cooperates automatically with entity objects in the business domain layer to coordinate validating and saving data that the user changes. For more information about this runtime interaction, see Section 6.3.9, "What Happens at Runtime: When View Objects and Entity Objects Cooperate."
The Java interfaces of the oracle.jbo
package provide a client-accessible API for your business service. This package intentionally does not contain an Entity
interface, or any methods that would allow clients 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 objects
Row
, to work with the view rows
When you begin adding custom code to your 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 StoreServiceAM
in the Fusion Order Demo application, you could have custom interfaces like:
Custom application module interface
StoreServiceAM extends ApplicationModule
Custom view object interface
OrderItemsInfo extends ViewObject
Custom view row interface
OrderItemsInfoRowClient 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.
Groovy is a scripting language with Java-like syntax for the Java platform. Groovy language expressions in ADF Business Components differs from the Java code that you might use in a Business Components custom Java class. The Groovy scripting language simplifies the authoring of code by employing dot-separated notation, yet still supporting syntax to manipulate collections, Strings, and JavaBeans. In Groovy expressions, type checking is done at runtime, whereas, in Java, type checking is done during compile time. Additionally, because Groovy expressions are dynamically compiled, they are stored in the XML definition files of the business components where you use it.ADF Business Components supports the use of the Groovy scripting language in places where access to entity object and view object attributes is useful, including attribute validators (for entity objects), attribute default values (for either entity objects or view objects), transient attribute value calculations (for either entity objects or view objects), bind variable default values (in view object query statements and view criteria filters), and placeholders for error messages (in entity object validation rules). Additionally, ADF Business Components provides a limited set of built-in keywords that can be used in Groovy expressions.
Specifically, the ADF Business Components framework provides support for the use of Groovy to perform the following tasks:
Define a Script Expression validator or Compare validator (see Section 7.5, "Using Groovy Expressions For Validation and Business Rules")
Define error message tokens for handling validation failure (see Section 7.7.4, "How to Embed a Groovy Expression in an Error Message")
Handle conditional execution of validators (see Section 7.7.3, "How to Conditionally Raise Error Messages Using Groovy")
Set the default value of a bind variable in the view object query statement (see Section 5.10, "Working with Bind Variables")
Set the default value of a bind variable that specifies a criteria item in the view criteria statement (see Section 5.11, "Working with Named View Criteria").
Define the default value for an entity object attribute (see Section 4.10.6, "How to Define a Static Default Value")
Calculate the value of a transient attribute of an entity object or view object (see Section 4.14, "Adding Transient and Calculated Attributes to an Entity Object" and Section 5.15, "Adding Calculated and Transient Attributes to a View Object")
For more information about the Groovy language, refer to the following web site:
There is one top-level object named adf
that allows you access to objects that the framework makes available to the Groovy script. The accessible Oracle ADF objects consist of the following:
adf.context
- to reference the ADFContext
object
adf.object
- to reference the object on which the expression is being applied (which can also be referenced using the keyword object
, without the adf
prefix). Other accessible member names come from the context in which the Groovy script is applied.
Entity object attributes: The context is an instance of the entity implementation class. Through this object you can reference custom methods of the custom entity implementation class, any methods defined by the base implementation class as specified by the JavaDoc for EntityImpl
, and you can reference the attributes of the entity instance.
Entity object script validation rules: The context is the validator object (JboValidatorContext
) merged with the entity on which the validator is applied. For details about keywords that you can use in this context, see Section 3.6.2.1, "Referencing Members of the Same Business Component."
View object attributes: The context is an instance of the view row implementation class. Through this object, you can reference custom methods of the custom view row implementation class, any methods defined by the base implementation class as specified by the JavaDoc for ViewRowImpl
, and you can reference the attributes of the view row instance as defined by the query row set.
Bind variable in view objects: The context is the variable object itself not the view row. You can reference the structureDef
property to access other information as well as the viewObject
property to access the view object in which the bind variable participates. However, access to view object attributes is not supported.
Bind variable in view accessors: The context is the current view row. The view accessor with bind variable is used to create a cascading List of Value (LOV). The view accessor can derive Groovy-driven values from the current view row in the view accessor view object used to formulate the list of valid choices.
Transient attributes: The context is the current entity or view row. You can reference attributes by name in the entity or view row in which the attribute appears, as well as public methods on that entity or view row. To access methods on the current object, you must use the object
keyword to reference the current object (for example, object.methodName( )
). The object
keyword is equivalent to the this
keyword in Java. Without it, in transient expressions, the method will be assumed to exist on the dynamically compiled Groovy script object itself.
adf.error
- in validation rules, to access the error handler that allows the validation expression to generate exceptions or warnings
adf.userSession
- returns a reference to the ADF Business Components user session (which you can use to reference values in the userData
hashmap that is part of the session)
You can also reference the current date (time truncated) or current date and time using the following expressions:
adf.currentDate
adf.currentDateTime
Groovy script language simplifies the authoring of code that you might write to access methods and attributes of your entity object and view objects.
The simplest example of referencing business component members, including methods and attributes that the entity object and view object define, is to reference attributes that exist in the same entity object or view object as the attribute that you apply the expression.
For example, you could define a Groovy expression to calculate the value of a transient attribute AnnualSalary
on an entity object with an attribute Sal
that specifies the employee's monthly salary:
Sal * 12
Or, with Groovy you can write a simple validation rule to compare the attributes of a single view object using syntax like:
PromotionDate > HireDate
Using Java, this same comparison would look like:
((Date)getAttribute("PromotionDate")).compareTo((Date)getAttribute("HireDate")) > 0
Note that the current object is passed in to the script as the this
object, so you can reference an attribute in the current object by simply using the attribute name. For example, in an attribute-level or entity-level Script Expression validator, to refer to an attribute named "HireDate", the script can simply reference HireDate
.
Similar to referencing attributes, when you define custom methods in an entity implementation class, you can invoke those methods as part of your expression. For example, to define an attribute default value:
adf.object.getDefaultSalaryForGrade()
A method reference requires the prefix adf.object
which allows you to reference the same entity that defines the attribute on which the expression is applied. This same prefix also allows you to reference the methods of the base class of the entity implementation class (EntityImpl.java
) that your custom implementation class extends.
Note that when you want to reference the method of an entity implementation class in a validation rule, you use the source
prefix:
source.getDefaultSalaryForGrade()
Use of the source
prefix is necessary in validators because the object
keyword implies the validation rule object instead of the entity object (where the method is defined).
To allow you to reference members of the validator object (JboValidatorContext
), you can use these keywords in your validation rule expression:
newValue
: in an attribute-level validator, to access the attribute value being set
oldValue
: in an attribute-level validator, to access the current value of the attribute being set
For example, you might use the following expression to specify a dynamic validation rule check of the salary for a salesman.
if (Job == "SALESMAN") { return newValue < source.getMaxSalaryForGrade(Job) } else return true
You can also reference the methods and attributes that entity objects and view objects defines in the expressions you apply to a different entity object attribute or validation rule. This is accomplished by referencing the accessor in the entity association.
For example, if you define an entity with a master-detail association for Dept
and Emp
, by default the accessor for the entity association will be named Dept
and Emp
, to identity the source and destination data source. Using that accessor in a Groovy expression to set the default value for a new employee's salary based on the location of their department:
adf.object.getDefaultSalaryForGrade(Dept.Loc)
This expression does not reference the entity even though it has the same name (Dept
) as the accessor for the association. Instead, assuming a master-detail relationship between departments and employees, referencing the accessor allows the Groovy expression for the employee entity object to walk back to the master department entity and pass in the value of Loc
from that master.
You can use the following built-in aggregate functions on Oracle Business Components RowSet
objects:
rowSetAttr
.sum(
GroovyExpr
)
rowSetAttr
.count(
GroovyExpr
)
rowSetAttr
.avg(
GroovyExpr
)
rowSetAttr
.min(
GroovyExpr
)
rowSetAttr
.max(
GroovyExpr
)
These aggregate functions accept a string-value argument that is interpreted as a Groovy expression that is evaluated in the context of each row in the row set as the aggregate is being computed. The Groovy expression must return a numeric value (or number domain).
For example, in a Dept
entity object you could add a transient attribute that displays the sum of all employee salaries that is calculated by this expression:
EmployeesInDept.sum("Sal")
To reference the employees of a specific department, the expression supplies the name of the master-detail association's accessor for the destination Emp
entity. In this case, the accessor is EmployeesInDept
and salary is interpreted for each record of the Emp
entity object.
Or, assume that you want the calculation of the salary total for specific departments to include each employee's benefits package, which varies with job role:
EmployeesInDept.sum("Sal + adf.object.getBenefitsValue(Job)")