Chapter 11. Building Business Services

In the previous chapter, we discussed the principles involved in designing a good service abstraction. In this chapter, we will look at how to actually implement these strategies to build business services. The focus of this chapter is on building new business services either from scratch or by reusing existing logic. Within the Oracle SOA Suite the most natural languages to use to build new functionality are Java and PL/SQL and we will focus on it. It should be remembered, however, that it is also possible to create new services from scratch in other languages and consume them within the SOA Suite.

Build versus reuse

Earlier we looked at how to reuse existing application functionality by exposing it as a service. When comparing our existing application functionality with our list of desired services we find that our desired services fall into three distinct groups:

  • Services that can be built by reusing existing functionality directly

  • Services that can be built by modifying existing functionality

  • Services that must be built from scratch

Each of the above cases causes us to work in a slightly different way. The first two cases use existing functionality, but differ in how they expose it. In the first case we are able to take the functionality already provided and expose it directly as a web service because it already complies with how we wish our service to perform. In the second case the functionality exists but is not readily exposed in the form we require for our services. Hence, we must first perform a re-factoring of the functionality to better fit it into our architecture. Finally, there are always services that we need that do not already exist, or exist at such a low level that there is a significant amount of development required to create them.

Let us examine how we deal with each of these service scenarios.

Adapters and web service wrappers

In Chapter 3, we looked at the use of adapters to expose service functionality. In this chapter, we use service wrappers to provide a web service interface onto existing code. Adapters support both event driven and request/response services. Service wrappers generally provide just a request/response interaction.

Adapters

Following are the characteristics of adapters:

  • Support request/response interaction

  • Support event notification (the service initiates the call)

  • Support a wide range of technologies and packaged applications

  • By default are co-located with core SOA Suite components

  • Configuration often deployed with clients

  • May support XA transactions for example the database adapter

  • By default don't use SOAP bindings (JCA binding is used by default)

Service wrappers

Following are the characteristics of service wrappers:

  • Support request/response interaction

  • SOA Suite and JDeveloper support wrapping Java and PL/SQL only

  • Must be deployed and run as services in their own right

  • All configuration is held in the service description

  • Any transactional support is handled through SOAP headers

  • By default use SOAP bindings

It should also be noted that applications such as Peoplesoft and Siebel support definition of their own services using the tools provided with the applications.

Reusing existing functionality directly

In this case we are either using existing services exposed by the application or exposing existing functionality directly as services as we did in Chapter 3. If the application already exposes a WSDL interface then we can use it directly and no further work is required on our part other than adapting the interface to support the canonical data model as explained in Chapter 4. If the application does not expose a WSDL interface, then we need to expose the required functionality through a WSDL interface by providing a service wrapper that maps directly onto the functionality. Normally this is achieved by taking existing Java or PL/SQL code and providing a service wrapper directly around it using a JDeveloper wizard. The format of data and the operations supported are determined by the existing application functionality rather than an idealized service design.

Exposing a PL/SQL stored procedure as a service

Often business logic is captured inside a PL/SQL stored procedure. The following PL/SQL code is used to create a new auction. It uses a database sequence to generate a unique auction ID, inserts the auction details into a table and then returns the new auction ID as an out parameter.

PROCEDURE CREATEAUCTION
( userID IN NUMBER
, Title IN VARCHAR2
, Description IN VARCHAR2
, Reserve IN NUMBER
, AuctionID OUT NUMBER
) IS
BEGIN
INSERT
INTO Listing
(Id, Name, Description, Reserve, SellerID)
VALUES
(AuctionIdSeq.nextval, Title, Description, Reserve, userID);
SELECT AuctionIdSeq.currval INTO AuctionID FROM dual;
COMMIT;
END CREATEAUCTION;

When creating a new auction we need to assign it a unique ID and the use of a sequence guarantees that this occurs correctly. Because we want to use the sequence every time we create an auction it is convenient to wrap up the use of the sequence into a stored procedure.

Launching the PL/SQL web service wizard

To turn this stored procedure into a service we can call from elsewhere in the SOA Suite we use the JDeveloper PL/SQL web service wizard. To invoke this, we select New... from within an existing project. Then under Business Tier, select the Web Services group to find the PL/SQL Web Service wizard as shown.

Launching the PL/SQL web service wizard

Choosing the level of Java Enterprise Edition support

The service we create will need to be deployed to a J2EE container to execute. The wizard wants to know what version of the specification to generate code for. Choose J2EE 1.4 (JAX-RPC) Web Service unless you are deploying to a pre-10.1.3 Oracle Application Server.

Choosing the level of Java Enterprise Edition support

Selecting a database connection and defining service bindings

Having chosen the level of Java support required, we select a database connection that will be introspected to find appropriate candidate stored procedures. When deployed, the database connection will be looked up at JNDI location java:comp/env/jdbc/<ConnectionName> where <ConnectionName> is the name of the connection in JDeveloper. This setting must be configured to point to the correct database in the target Java container.

Selecting a database connection and defining service bindings

Once a Database connection in JDeveloper is selected, we can choose the Database Package containing the procedures we want to expose as a service. We also set the name of the service at this point using the Web Service Name field.

The Java Package is the package used by the wizard when generating Java code.

The final section of this screen allows us to define the service bindings. These define how the services maps onto message protocols. The Oracle SOA Suite components will work with any of the available bindings. However, for maximum interoperability it is probably wise to choose SOAP 1.1 support; this will ensure interoperability with older web services implementations. For more information on these settings see Chapter 17The Importance of Bindings.

Determine message style

The wizard now requires us to select the type of message format. Again for maximum interoperability use Document/Wrapped message format.

Determine message style

Select stored procedures and functions to expose

The wizard will now introspect the database to determine the functions and procedures available to be added to the service. Any procedures that cannot be turned into web services will be greyed out. To discover why a service cannot be exposed as a web service, select the greyed out service and click Why Not?

Select stored procedures and functions to expose

Each procedure or function selected in the wizard will appear as an operation on the generated service interface. The wizard will then ask how the PL/SQL types should be mapped onto XML. The defaults are usually sufficient.

Select stored procedures and functions to expose

Once the desired procedures and functions have been selected, the wizard may be completed by clicking on Finish. Additional steps on the wizard allow customization of data bindings and setting of web service policy. Custom data mappings and serialization are covered in Chapter 17The Importance of Bindings. Policy settings are covered in Chapter 20Defining Management and Security Policies.

Select stored procedures and functions to expose

Finally it is possible to add additional header fields to the service, allowing customization of the headers using JAX-RPC.

Select stored procedures and functions to expose

Modifying existing functionality using service bus

In Chapter 4, we discussed the importance of a canonical form for data. We typically want all our interactions to be in canonical form. This may require us to wrap or modify existing services to convert their data representation to canonical form.

If the functionality we require is already exposed as a service, we can choose to modify it through transformation in the Service Bus. Complicated transformations, where there is a significant mismatch between canonical form and actual service, may require the use of BPEL or more complex request/response pipelines in the Service Bus. In the worst case, we may need to combine several services into a single canonical service. This approach may be characterized as using the SOA Suite to adapt the exposed functionality to our needs.

If the function we need is not already exposed as a service, then we may choose to provide a native language wrapper around the functionality. This wrapper is intended to make it easier to transform the resultant service to canonical form.

We can avoid the need to transform to canonical form by generating a service stub from the canonical form and then implementing it by using our existing functionality. This is similar to creating a new service from scratch except that we don't have to provide the functionality of the service. We just need to provide some code to call the functionality. This approach may be characterized as extending the existing code base before exposing it to the SOA Suite to provide the functionality we need.

Converting an existing service to canonical form

Often we have existing services available but they are not in canonical form. Hence, these services are relatively brittle and enforce their structure on the rest of the infrastructure. To avoid this, we can provide a more flexible interface in the Service Bus that performs the transformation of an existing web service from a service implementation specific interface to the canonical interface.

Create a new service interface

To do this, we first create a new session in the service bus console, and then create a new project as shown:

Create a new service interface

We give the project a meaningful name. Note that this could also be done in the Oracle WebLogic Workshop.

Create a new service interface

After selecting the project in the Project Explorer, we can start adding the resources that we need. We start by defining the canonical service interface as described by a WSDL definition. Before importing a WSDL, it is best to ensure that any external references within the WSDL, such as references to XML Schema files, are already loaded. If the schema files are unique to this project, they can be loaded into this project; if they are not, they can be placed in a shared common project to ensure that the same resource is used consistently across projects. Note that, in the examples, we have created sub-folders under the project to hold different types of resource. This is not necessary and is done only to make it easier to manage the resources.

Create a new service interface

We are able to browse the file system for WSDL to upload to the project. The WSDL for our canonical interface generally does not need any port or binding details because these will be provided by our wrapper, in this case by the Service Bus.

Create a new service interface

After loading the WSDL, we can verify that it has correctly resolved any external resource references such as XML Schemas by clicking on the newly loaded WSDL and looking at the WSDL definitions. Note that because the referenced XML Schema was pre-loaded into the Service Bus, it has automatically been resolved correctly. If the schema had not been pre-loaded, it would now be necessary to load the schema and manually set the reference between the WSDL and the schema.

Create a new service interface

Now that we have loaded the interface WSDL, then we can create a proxy that will implement this interface. After choosing to create a Proxy resource, we can browse for a pre-loaded WSDL and select it.

Create a new service interface

If the WSDL contains multiple port types or services, then we need to select the appropriate port type or service. We also need to provide a service name. Note that in addition to WSDL, we can also define the proxy service provided in other ways. We would generally want to use these to adapt existing clients to our web service based infrastructure. Note that we have chosen not to stream the content because this service is a simple request/response service with small amounts of data. If large amounts of data were involved, we may have wanted to buffer the data to avoid overwhelming the business endpoint.

Create a new service interface

Having selected the interface to our WSDL, we can skip to the last screen, which is a summary of the proxy service that we are about to create. Note that the summary screen details the options that we have skipped. We have elected to use HTTP as a transport Protocol, but we could have selected another transport such as JMS. We have also chosen to keep the default endpoint identifier or Endpoint URI. Other options we have ignored include the ability to add headers into the message, provide secure socket support (HTTPS) or require HTTP authentication.

Note

Enforce compliance to standards for external services

If a proxy is intended to be used by a consumer external to the company, it is a good idea to enforce WS-I compliance. WS-I is the Web Services Interoperability standard and defines which subsets of the various web service standards can be reliably used to guarantee interoperability between different vendors SOA stacks.

Create a new service interface

Selecting Save completes the initial creation of the proxy.

Adding the non-canonical service

We now need to add the non-canonical web service into the assembly which we do by loading the WSDL of the service into our project. We then create a Business Service resource in our project. We select the target WSDL for this in a similar way in which we selected the WSDL for the proxy service. However, when we are creating a business service, it usually is a concrete WSDL that has specific endpoint locations or ports within it. When selecting the binding or port type it is generally a good idea to select the port rather than the binding, as the port includes a physical endpoint for the service. This is shown in the following screenshot. Note that we could just choose a binding, but this would require us to provide the physical port later in the business service definition.

Adding the non-canonical service

Once the appropriate port has been selected, the business service summary can be viewed by clicking Last. Note that the summary for the business service includes details such as the type of Load Balancing Algorithm to use, although this is only useful if more than one Endpoint URI is specified. Note that it is also possible to specify the retry logic ( Retry Count and Retry Iteration Interval) for the business service.

Adding the non-canonical service

We have now created all the components that we require in the Service Bus and can now wire the proxy to make use of the external business service. Within the Service Bus we now need to map the inbound data from the exposed service onto the input of the external reference and the same for the return from the external reference. We can do this using either an XSL transform or an XQuery operation.

More complex conversions

If the conversion between canonical and actual service is too complicated to do within a mediator, we can use a BPEL process in its place. The principle is the same as using a mediator except now we can access all the power of BPEL to assist us in the conversion. This is usually necessary when there are semantic differences between the services rather than purely syntactic differences.

Exposing a Java class as a service

Although we could expose existing Java classes directly as web services it is generally better to create a thin wrapper class around them to better align the resulting web service with the required canonical formats. This allows us to remove Java specific types from an interface, simplifying the task of mapping the interface onto the canonical form.

Wrapping the Java code

For example, take a Java class that performs encryption and decryption of credit card details. It has three operations — to retrieve a key, encrypt a card using the key, and decrypt a card using the key.

public class EncryptionService {
public SealedObject encryptCard(Key key, CreditCard card) ...
public CreditCard decryptCard(Key key,
SealedObject encryptedCard) ...
public Key getKey(String passPhrase) ...
}

There are two problems with this Java API as a service interface:

  • It is too granular, requiring two calls for every encryption and decryption

  • It uses Java classes that cannot be easily mapped onto XML types

The java.security.Key interface and javax.crypto.SealedObject class cannot be readily mapped to XML types in any way other than as an opaque series of bytes. The CreditCard class is a simple Java Bean that can be easily mapped onto XML.

public class CreditCard implements Serializable {
...
public CreditCard() {}
public void setIssuer(String param) ...
public String getIssuer() ...
public void setName(String param) ...
public String getName() ...
public void setNumber(String param) ...
public String getNumber() ...
public void setExpiry(String param) ...
public String getExpiry() ...
}

To make a better basis for creating a service we can build a wrapper class that removes the extra step of getting a key and only exposes types that can be easily mapped to XML.

public class EncryptionServiceWrapper {
public byte[] encryptCard(String passPhrase, CreditCard card) ...
public CreditCard decryptCard(String passPhrase, byte[]
encryptedCard) ...
Java class, exposing as serviceJava code, wrappering}

Launching the Web Service wizard

To expose this new wrapper class in JDeveloper, we will launch the Create Java Web Service wizard by right-clicking on the class.

Launching the Web Service wizard

Select deployment platform

We can then select how we want the web service to be implemented in Java. Unless we are deploying to an earlier version of OC4J, we should choose J2EE 1.4.

Select deployment platform

The web service version determines how the Java class is wrapped or annotated to expose the web service.

Select service name

The name of the service is arbitrary. Because we started by generating a service specifically for a given Java class, we cannot change the Component To Publish.

Select service name

For maximum interoperability it is best to stay with SOAP 1.1 binding. Auto generation of the service endpoint means that the endpoint name and address will be selected by JDeveloper; at runtime the physical address will be modified to reflect the container that the service is hosted on.

Select message format

The message format determines how the service serializes the data for transmission. The formats determine which options are available later in the wizard. The document wrapped style passes a single parameter on the wire that is a holder for the individual parameters.

Note

Wrapped and literal styles

The different encoding styles cause the message to be packaged differently. The wrapped styles cause each message to have a single message part and a root XML element that has all the native parameters underneath. The literal style causes a message to have multiple parts, each part has its own separate root element that corresponds to the native parameters on the implementing class.

Select message format

Provide custom serializers

Having selected the message format we will be prompted to provide any custom XML to Java mappings. Generally, we will not require these unless we want to use a pre-existing XML Schema for our parameter types. We may also use this to provide precise control about how a Java class is transformed into XML through the use of a serializer. This is a topic outside the scope of this book.

Provide custom serializers

Mapping

If we don't have an existing schema to map onto, the mapping step in the wizard allows us to control the generation of an XML Schema to describe our Java classes. It is here that we specify the namespaces to be used for our service definition and service types.

Mapping

Select methods

In this step, we can verify which methods we wish to include in our service.

Select methods

We have the option to remove unwanted methods from the service. If a method is grayed out, choosing Why Not? will explain why that method cannot be included in the service.

This is generally a good point to click the Finish button to generate the web service. This service may now be deployed to an application server and used within the SOA Suite. Actual deployment steps will depend on the target application server. However, the steps are the same as for deploying any JEE application to an application server.

Creating services from scratch

There are times when the functionality that we require does not already exist and so we need to create it from scratch. The languages of choice for doing this with SOA Suite are Java and PL/SQL. The choice of language will be determined by several factors including:

  • Available skills

  • Complexity of logic — more computational and conditional centric logic favours Java

  • Complexity of data — more data-centric logic favours PL/SQL

Creating a Java service from a WSDL

Previously we have created services from existing functionality. Now let us look at how we can generate the service wrappers to let us implement the functionality we need.

Starting the wizard

We begin with a project into which we import a WSDL document or create one using the WSDL builder in JDeveloper. The WSDL we will use describes a credit card encryption service similar to the one we have previously used. To launch the wizard we select New... from the File menu of JDeveloper. Within the New Gallery, we then select the Java Web Service from WSDL item under the Business Tier Web Services category.

Starting the wizard

Choosing the WSDL

Within the wizard we first need to choose the appropriate WSDL document from which we want to generate a web service implementation. The WSDL Document URL drop down not only shows all the WSDL documents within this JDeveloper application but also allows us to browse for WSDL in the file system or in a UDDI repository.

Choosing the WSDL

The optional Mapping File field allows us to control the names and types of Java classes corresponding to our XML Schema.

Choosing the mapping options

When we come to Step 2 — Default Mapping Options we have some new choices to make. This screen allows us to describe the name and packages of generated Java classes.

Soa.bookGenerated Java classes will be created in the Java package identified by the Package Name. Classes generated to describe parameters and return types are created in the Java package identified by Root Package for Generated Types.

Choosing the mapping options

A couple of extra fields provide more control over the mapping. If the WSDL identifies the use of any specific SOAP headers, Map Headers to Parameters allows these to be mapped as additional parameters to the Java class, avoiding the need to write message handlers to extract the headers. If the underlying parameter types have already been mapped and exist, checking Reuse Existing Type Classes will cause the code generator to not generate any classes for parameter types, however the mapping file should have been used in this case to map existing classes onto the appropriate XML types.

Clicking Finish at this point will cause the wizard to generate appropriate Java classes.

The generated Java

The wizard will generate a number of different classes:

  • An implementation class — CreditCardEncryptionServiceImpl — that we must use to provide the functionality of the service.

  • An interface — CreditCardEncryptionService — that defines the service interface in Java.

  • A number of data structure classes — CreditCard, DecryptCardRequest, DecryptCardResponse, EncryptCardRequest, — and EncryptCardResponse that represent the parameters into the service and/or its return value as well as any other data types required.

  • A descriptor to map the service WSDL and associated XML Schema onto the generated Java classes — CreditCardEncryptionServiceService-java-wsdl-mapping.xml.

    The generated Java

The only class that needs to be altered is the implementation class. This is shown as follows:

public class CreditCardEncryptionServiceImpl {
public DecryptCardResponse decryptCard(DecryptCardRequest request) {
return null;
}
public EncryptCardResponse encryptCard(EncryptCardRequest request) {
return null;
}
}

Any class initialization must go into the class constructor. Any other functionality should be referenced from the methods generated for that functionality, such as decryptCard being used to provide a mechanism for decrypting an encrypted credit card.

Once the methods have been implemented, the new service can be deployed to an application server and is available for use.

Summary

In this chapter we have explored how we can create business focussed services that conform to the canonical model principles discussed in Chapter 10. Some services can be exposed directly using the web services wizard in JDeveloper. Other services may need to be transformed through the Service Bus before they match the canonical form. Finally, we can map to canonical form using methods in the native language and then expose those methods as a canonical service. Choice of language for creating new services is largely driven by the skills available and the nature of the service — data centric or computational logic centric.

Services can also be specified first and then a Java template generated. Currently JDeveloper only supports generation of Java templates.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.97.170