|Oracle® Fusion Applications Developer's Guide
11g Release 1 (11.1.2)
Part Number E15524-02
|PDF · Mobi · ePub|
This chapter describes how customers can develop new business applications using existing services in the context of new or modified business processes.
This chapter contains the following sections:
Service-oriented development is based on the concept of services. A service is defined in terms of its interface, which is the way the service is exposed to the outside world. This includes a set of parameters (defining data required for interaction with the service) and communication protocol used for data transfer and actual service invocation. The service interface is defined by a service name and a set of operations the service supports. Grouping of the methods in the service interface is defined by business functionality of the service.
The following characteristics are typical for services and should be reflected in the service interface:
In Oracle Fusion, applications use both ADF Business Components services and service-oriented architecture (SOA) services. ADF Business Components services should be created to manage business objects and SOA services are for orchestration and business processes. SOA services use business object services to encapsulate business processes as illustrated in Figure 5-1:
This chapter focuses on business object services that are implemented using ADF Business Components services.
In Oracle Fusion, you make business objects and related business logic available via user interfaces (UIs) and services. A single general-purpose service can satisfy multiple use cases such as:
Programmatic application programming interface (API) calls required by external customers, cross-pillar integration, or third-party integration.
Business Process Execution Language (BPEL) process flows and composite applications
Business-to-business (B2B) integration through standardized documents
Foreign UI technologies such as Microsoft .NET framework
Desktop applications such as Excel and Access.
Designing services from the service provider perspective include: how to identify business objects, service operations on business objects, and services, as well as how to define service exceptions and information.
Identify which business objects that you want to expose from the service interface.
These are the actions that can be performed on business objects, such as create and delete. These operations are used to identify the service operations.
Standard operations and Custom operations are the two types of service operations that are supported by ADF Business Components service.
The primary purpose of standard service operations is to locate a business object and handle its persistence. This includes storage, manipulation and retrieval of data, locking, transaction management, business rule validation, and bulk processing. ADF Business Components auto-generates the following groups of standard service operations:
CRUD (Create, Read, Update, Delete) Operations:
get<businessObjectName>: get a single business object by primary key.
create<businessObjectName>: create a single business object.
update<businessObjectName>: update a single business object.
delete<businessObjectName>: delete a single business object by primary key.
merge<businessObjectName>: update a business object if exists, otherwise create new one.
ind<businessObjectName>: find and return a list of business objects by find criteria.
Bulk Processing Operations:
process<businessObjectName>: process a list of business objects via a CRUD command.
processCS<businessObjectName>: process a list of business objects via a change summary.
Control Hints Operations:
getDfltCtrlHints(String viewName, String localeName): takes the view object name and a locale and returns the base UI hints for that locale.
This group of operations are mainly used by the ADF Business Components Service framework for service based entity object and view object support. For more information about service-based entity objects and view objects, see Section 5.4.1, "How to Invoke a Synchronous Service."
Custom service operations encapsulate complex business rules and may coordinate execution of two or more data-centric operations within one atomic transaction.
All core business functions should be exposed in services. When developing a list of business object operations, consider the entire application life cycle from creation to deletion. Also, consider potential use cases that are required by others. For example, the following list includes many of the operations associated with requisitions and purchase orders:
Operations associated with Requisitions:
delete requisition line
delete requisition distribution
approve (including all approval states such as approve, reject, and pre-approve)
view approval history
Operations associated with Purchase Order:
delete purchase order
delete purchase order line
delete purchase order shipment
delete purchase order distribution
copy purchase order
get purchase order
cancel purchase order
cancel purchase order line
approve (including all approval states)
view approval history
Typically, you should include all the standard operations, although the delete operation should only be included if supported by the business object. If you only need to delete a child object, then you must have specific delete operations on the child objects. This is because you are not able to delete a child object using the delete method on its parent object. For example,
deletePurchaseOrder will delete a purchase order and all of its lines, but won't only delete a specific line or lines.
There are general guidelines you must follow when defining service operations.
Be generic where it makes sense
Since most Oracle Fusion services serve multiple use cases as listed in Section 220.127.116.11, services should not be designed narrowly for only one use case at the exclusion of others. Instead, services should be designed from the start to be general purpose and contain APIs that can serve the widest use cases. This is especially important to consider for common business functions that are initially required for the UI or to meet enhancement requests from other products. It should be the conceptual essence of the use case that drives the interface, not the fine-grained specifics of one consumer. A consumer can be seen as a representative of a specific use case, but the provider should always apply well-measured foresight when defining the interface details. Creating general purpose APIs from the beginning will:
Prevent method explosion as other similar use cases are requested.
Increase reuse by multiple use case.
GetPersonName() operation: The provider, at a minimum, requires the primary keys to access a person's name as input. However, the output could be either a formatted name in a form of a simple String or a complex document representing Name object. The list of returned attributes must be determined by the consumers' business requirements. If the first consumer of an interface only requires
LastName to be returned, it would be possible to only return these two values. However, it is likely that a popular service operation such as
GetPersonName() will soon be adopted by more consumers, which will require other attributes of a name. In this example, it makes sense to include
LegalName, and so on into the first specification of the service interface. This will avoid the creation of a new interface version in the foreseeable future.
Leverage standards wherever possible
Enterprise Business Object (EBO) standards, introduced by the AIA (Application Integration Architecture), are canonical forms of interfaces, which represent an abstract intermediary shape that integration parties go from and to in the integration. If existing Enterprise Business Object shapes are a good fit for the business requirements of your specific use case, they should be leveraged. Even if the EBO shape is not identical, the names of the EBO objects and attributes should be reused as much as possible. If your service needs to be consumed by either an internal stakeholder or an outside party, using a standard is definitely recommended to avoid costly negotiation of proprietary interfaces.
However, in many situations either no standard exists or the standard does not optimally support your business need. In this case you should make the interface as generic as possible for your given group of consumers. This will make sure that the interface stays stable as more consumers adopt it, while being highly useful for your given business processes. With good strategic planning it is possible to define generic interfaces for a defined subset of stakeholders.
Service operation granularity
Because it is possible to call services across a network, the service operations should be generally coarse-grained. That is, a service operation should wrap a substantial body of application logic, delivering value that justifies the latency cost of a network request. Similarly, services should expose coarse-grained operations. Rather than expose many operations that each manipulate small amounts of state, services should expose fewer operations that allow a single request to perform a complete function.
Service operation naming convention
Service operations should follow a consistent naming convention. A
verbNoun syntax has proven ideal to express the behavioral aspect of a business object. Operation names should be meaningful and clearly express the function performed. They should not be generic or ambiguous. For example: A Person service operation name should not be
invoke(), but should be
Service operation versioning
Changes to an interface can be either compatible or incompatible. If, for example, only optional attributes are added to an existing parameter, current consumers are not impacted. If however the parameter list changes, then this is an incompatible change.
Compensating service operations
For operations that involve data manipulation, a clear strategy for compensation must be defined. Services are frequently distributed remotely and there is no central transaction coordinator with sufficient control over all resources. This is inherent in Simple Object Access Protocol (SOAP), which is predominantly used in the web services space and therefore, a two-phase commit protocol cannot be enforced. Also, two-phase commit implies resource locking, which may lead to scalability and availability issues if locks are held for longer periods.
In order to allow for service operations to be undone, in certain business scenarios it may be possible to offer compensating service operations. These operations are used to revert the system back to the state before the original operation was invoked. Providers and consumers must agree on the conditions under which an original operation can be undone and what information is required to achieve the compensating effect.
In most cases, the decision to provide a compensating operation is primarily functional. It might technically be possible to delete an existing purchase order, but functionally it is only correct to cancel it once it has been submitted for approval. Not all operations should, by default, be paired with a compensating operation. Compensating operations should be provided only if the business process demands that the system can be rolled back into the original state.
Service operation parameters
Each service operation can have zero or more parameters. Each parameter can be a primitive type (String, Date, and so on), a complex type represented as a Service Data Object (SDO), or a List of a primitive type or SDO. Complex types can in turn contain nested complex types.
Long Parameter List or Complex Types?
You should consider using complex types in a service operation instead of using a long list of individual parameters unless the parameter list can be reduced to a short list of simple types (3-5).
A service operation
updatePerson() takes a compound complex type of Person, which includes several individual attributes such as
BirthDate, a collection of
PersonName, and a collection of
PersonAddress, and so on. The reasons are:
Taking a list of individual parameters leads to a not so clean operation signature:
Adding an optional attribute on a complex type doesn't break compatibility, but adding a new parameter in a method does.
updatePerson example, if the person's email address needs to be updated, the operation that takes a Person can stay unchanged.
Complex Types or Primary Keys?
As an alternative to complex types, business object Primary Keys can be used in operation signatures in certain cases.
Auto-generated data-centric standard operations, such as create, update, delete, merge, and Bulk Processing take complex business object types as parameters. Auto-generated
get() takes primary keys.
Most custom methods may take business object primary keys as parameters. Complex business object documents should be passed primarily to the data-centric custom methods:
formatPersonAddress(), and so on. Primary keys should be passed only if you need the primary key information to look up the business object in the database, such as
terminateEmployee() that takes an employee Id.
A service is a grouping of operations. Often this grouping is by the business object it maintains, which is especially true for the CRUD operations. In most cases, one service per business object provides a more manageable hierarchy. For example, the business object Person could be offering all operations that can be performed on it as a service called
After you have identified your services and what business object(s) they include, the list(s) of the corresponding operations that were identified in Section 18.104.22.168 provide the list of candidate methods for each service.
Services from other products that may compliment this list are not included. For example, a
InvoiceService provide detailed information about suppliers and invoices respectively. The procurement services should identify only who the supplier is in various transactions and provide information on procurement-specific supplier data such as, supplier price, quality and on-time delivery performance. It should not provide core supplier operations like creating, updating, deleting, and so on because that is the responsibility of the
It's important that the Oracle Fusion services compliment one other. Therefore, once you've identified your working list of services, coordinate with related products to ensure that you have not duplicated efforts or created confusing and conflicting APIs. Also, communicate any expectations that you have of their services.
You can define service exceptions, partial failure and bulk processing, and informal messages.
Once the required criteria for successful execution of a service operation is agreed upon, all stakeholders must then define a complete set of error conditions. You must define which exceptions can happen and which information should be reported back to the consumer due to an exception. Exception processing should be consistently implemented across all operations in the application. If one operation throws an exception while another returns an empty collection, the consumers perceive the services as unstable and unpredictable. The reported exception should contain as much information as possible so that the consumers can pinpoint the problem easily.
All service operations are delegated to the underlying ADF Business Components objects and their methods. As a service provider, you just need to implement your validation logic and business rules in your server side objects, define appropriate error messages declaratively, or throw appropriate
Oracle ADF has one generic exception or fault to handle all ADF Business Components exceptions. Whenever an exception is thrown from the underlying ADF Business Components object for one of the service standard or custom methods, the exception is thrown as a Service Exception, which contains all of the information available from the original thrown exception. This also includes support for bundled exceptions.
Services can support partial failure during bulk processing of data, which can be very useful. For example, if the client loads a large amount of data using batch load applications, the occurrence of one or more failures does not prevent the continued posting of other unrelated data.
During design of your services, you need to decide whether partial failure should be enabled for a business object including details. For example, a purchase order business object includes a header, lines for each header, and shipments for each line. The partial failure switch is set on each level including header, line, and shipment. Usually the top level object should allow partial failure, but the decision on the detail level depends on whether it make sense to simply skip that object if it fails. You must ask yourself the question: "Does it make sense to still post the other lines and the header if one line fails?" In some cases, you may need to preserve the integrity of the business object and not allow the object to be posted with partially populated children.
Caution:The partial failure mode is only used in the
processXXXAPI and this API also uses a runtime partial failure flag in the
ProcessControlparameter. This means the partial failure feature is only enabled when both the design time flag and the runtime flag are enabled.
Informational messages are not exceptions and won't affect the current transaction. However, these messages may be useful to the clients. For example, you may want to know when the system automatically transfers money from your saving account to your checking account because there may not enough funds in your checking account when your check is cashed out.
The service provider needs to define a complete list of informational messages as well as the conditions that these messages should be returned.
After you design the service interface, you now must implement those services.
Note:This is from the service provider perspective.
In Oracle Fusion, service data objects (SDOs) are used to expose business objects in services. Each SDO must be backed by a view object. For more information about how to generate a service data object out of a view object, see the "How to Service-Enable Individual View Objects" section of the "Integrating Service-Enabled Application Modules" chapter in the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
It is recommended that you have a separate view object for the service, rather than using the same view object in the UI. The dedicated service view object should represent the shape of your business object.
For parent-child relationships, you should define two view objects, one for the parent and one for the child, and then define a view link between them. You must also have the destination accessor generated so that the service framework is unable to query or post the child along with the parent.
For composite object, you should create a composite association between the parent entity object and the child entity object, and base the view link on the association. However, in cases where composite associations cannot be defined you must add a custom property,
SERVICE_PROCESS_CHILDREN=true, to the entity association or view link. This allows for the child objects to be processed along with the parent object (in
processXXX). Reasons for cases where composite associations cannot be defined include:
A child has multiple parents but the relationship is really composite.
When there is an entity association and the association has the destination accessor generated, then you should add the custom property in the association. When an association doesn't exist such as flexfield or the association doesn't have the destination accessor generated, then you must add the same property to the view link.
Enabling Partial Failure
The default setting for partial failure is not enabled. To enable partial failure, add the
PARTIAL_FAILURE_ALLOWED custom property on the view object and set the value to true.
To determine if you should enable partial failure, see Section 22.214.171.124, "Defining Partial Failure and Bulk Processing."
Enabling Support Warnings
There is a design time flag to indicate whether the informational messages are enabled or not for each view object and service data object. The default setting for this flag is off, and you need to go to the view object editor's Java tab and select the Support Warnings field.
Note:Signatures of the service operations that ADF Business Components generate vary depending on this Support Warnings flag. If you change this flag in a future release, your service will no longer be backward compatible. In addition, when partial failure is on, the exceptions are not thrown from the service invocation. Instead, the exceptions are reported as warnings, and the caller can only receive these warnings if the Support Warnings flag on the service view object is turned on. Therefore, you must turn on the Support Warnings flag for the top-level service data objects that are exposed directly in the process methods.
For the purchase order header, line, and shipment example, if your service includes the
processPurchaseOrders API that takes a list of purchase order headers, then you must enable Support Warnings in the purchase order header view object. If your service also includes the
processLines API that takes a list of purchase order lines, then you also need to enable Support Warnings in the line view object. For the other detail level service data objects, you should take a more proactive approach and define your business object as supporting informational messages if you think you will need this feature in the future.
The service interface is generated from an ADF application module. For more information, see "Integrating Service-Enabled Application Modules" in the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Oracle recommends that you have a separate application module for the service, which is different from the application module used in the UI.
This section discusses what happens during design time with application modules and the runtime object.
No Service Data Object in the Application Module
The custom methods in the Application Module do not take Data Object or a Data Object list as parameters. Instead, the Application Module's custom methods take
AttributeList or a list of
AttributeList as parameters. When you publish these methods in the service interface, ADF Business Components service will convert these to Data Object or a list of Data Object in the service interface during design time, and then performs conversion between Data Object and
AttributeList during runtime.
The informational messages (and warnings) are reported as part of the return object. ADF Business Components generates appropriate wrappers as the return objects when necessary, and the wrappers contain the actual method return as well as the informational messages. Table 5-1 lists some examples:
Table 5-1 Return Objects Examples
|Operation without Informational Messages (Support Warnings Flag is off)||Operation with Informational Messages (Support Warnings Flag is on)||Comments|
The list of
If the Support Warnings design time flag is off, no informational messages are returned (the first column in the above table). If the flag is on (the second column in the above table), then:
getXXX returns the original object
processXXX returns the wrapper object that contains a list of the original object and a list of information messages
deleteXXX returns the informational message
Each custom method can be configured individually about whether to return informational messages
Each service method can be exposed as both synchronous version and asynchronous version.
To generate synchronous and asynchronous service methods:
Go to the Application Module Design Time wizard.
Choose the Service Interface tab.
Choose the Service Interface category. See Figure 5-2.
Select Generate Asynchronous Web Service Methods. Click OK.
Save your changes.
All ADF Business Components services have both synchronous and asynchronous versions for the same method. The service consumer must decide which version of the service method to use.
A service method can be invoked synchronously if all of the following conditions are met:
The invoked method takes a simple payload, such as a single document or a fixed number of documents, (including parent and children), and the payload is still small.
The invoked method is expected to be finished in real time and takes no longer than a few seconds.
The consumer should consider invoking the method asynchronously if one of the following conditions is met:
The method takes a flexible number of documents, such as a list of service data objects.
The method may be long-running.
You can invoke a synchronous service using service factory, service-based entity object and view object, Java API for XML Web Services (JAX-WS) client, or from SOA.
Using Service Factory
If you need to invoke a synchronous service from a Java client, including an ADF Business Components component, UI, or Oracle Enterprise Scheduler (ESS), then using a service factory is recommended. It is easier to write a service client using service factory than using JAX-WS. If the service is co-located, the service invocation is more performant because it does not invoke XML serialization and de-serialization.
For more information about invoking a service using service factory, see Chapter 41, "Synchronously Invoking an ADF Business Components Service from an Oracle ADF Application."
Using Service-Based Entity Object and View Object
When you need to work with output from a service in the format of an ADF Business Components component, such as rendering the data in a UI table or creating a view link to it, then you should consider using service-based entity objects and view objects.
For more information about working with data from a remote ADF Business Components service, see Chapter 39, "Working with Data from a Remote ADF Business Components Service."
Using JAX-WS Client
Generally, you should not use JAX-WS or Java APIs for XML-Based Remote Procedure Call (JAX-RPC) client to access an ADF Business Components service. You can use JAX-WS to access BPEL or a third-party service.
When you invoke an ADF Business Components service from BPEL, you usually use the asynchronous version unless you are sure the service satisfies the synchronous invocation condition that was discussed previously.
For more information, see Part VI, "Common Service Use Cases and Design Patterns".
Caution:For more information, see the "How to Create Service-Enabled Entity Objects and View Objects" section in the Integrating Service-Enabled Application Modules chapter of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
PL/SQL calling Web Service is also an anti-pattern that is not allowed because of security issues.
If you need to invoke an asynchronous service, then you must use BPEL. Invoking an asynchronous service from Java is not allowed. If you need to invoke an ADF Business Components service from Java that does not meet the synchronous condition, then you must use one of the following alternate approaches:
Asynchronous Invocation (The caller-side must wait for response)
If the caller is ADF UI: The UI must raise an event, which is received by a mediator. The mediator invokes a BPEL process that invokes the asynchronous service and then invokes a second service after receiving the callback. The second service is responsible for notifying the UI side that the process has completed and then the UI uses the Active Data Service to refresh the UI.
For information about how to enable the UI for dynamic update via Active Data Service, see Chapter 42, "Implementing an Asynchronous Service Initiation with Dynamic UI Update."
If the caller is Oracle Enterprise Scheduler Service: Oracle Enterprise Scheduler Service Java Jobs can invoke the asynchronous service via a JAX-WS proxy, but must set the asynchronous callback service to that of the Oracle Enterprise Scheduler Service Web Service. During this time, the Job's status will be Running and when the asynchronous callback comes through the Oracle Enterprise Scheduler Service Web Service callback port, the Job code will be notified with the response and can Complete.
One-way Invocation (The caller fires and forgets)
The caller must raise an event, which is received by a mediator. The mediator invokes a BPEL process, which invokes the asynchronous service. A callback is received from the asynchronous service.