Architect: SOA
Connect to Your Legacy Code Using Oracle Service Bus New Features
by Francesco Marchioni
Learn how to rehash your legacy code using Oracle Service Bus 3.0's new features and the built-in Eclipse design environment.
Published July 2008
Prior to Version 3.0, the design of all Oracle Service Bus (formerly BEA AquaLogic Enterprise Service Bus) assets (such as business services and proxy services) took place in the Web-based console. In v3.0 you can still choose to use the console, but you can now also choose to design all your assets in WorkSpace Studio using the new Eclipse plug-in.
In this article, I'll also show how to integrate your brand new Oracle Service Bus services with Oracle BPM 6.0, using Process Business Language (PBL).
Using a Transport Typed Service: EJB
If you have developed a Java Enterprise solution in the last few years, chances are that you have some of your legacy coded as EJB. A typical solution to expose your EJBs to other services would be to use a Java Web service to wrap the EJB and publish it as a service. Oracle Service Bus now allows you to define EJBs as business services and call them directly from another service. The example in this article will demonstrate a SOAP proxy service invoking a stateless session bean.
For those who are not familiar with the concepts of Proxy Service and Business Service, I'll provide some brief definitions. Proxy Services are Oracle Service Bus definitions of intermediary Web services that the Oracle Service Bus implements locally on WebLogic Server.
A Proxy Service can route messages to multiple business services; you can choose to configure a proxy service with an interface that is independent of the business services with which the proxy service communicates. In such cases, you would configure a message flow definition to route a message to the appropriate business service, and map the message data into the format required by the business service's interface.
In order to make your EJB code available you need to define a business service: Business services are remote services or external endpoints that are typically not implemented by the Oracle Service Bus server. They are definitions of the enterprise services with which you want to exchange messages.
So, suppose we have some legacy code that connects to a RDBMS and collects flight information for a certain route. Let's build a sample EJB project that contains our business method to be exported to Oracle Service Bus:
package sample.ejb;
import java.sql.*;
import javax.ejb.SessionBean;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import weblogic.ejb.GenericSessionBean;
import weblogic.ejbgen.RemoteMethod;
import weblogic.ejbgen.Session;
import weblogic.ejbgen.JndiName;
import weblogic.ejbgen.FileGeneration;
import weblogic.ejbgen.Constants;
/**
* GenericSessionBean subclass automatically generated by Workshop.
*
*/
@Session(ejbName = "FlightEJB")
@JndiName(remote = "ejb.FlightEJBRemoteHome")
@FileGeneration(remoteClass = Constants.Bool.TRUE, remoteHome =
Constants.Bool.TRUE, localClass = Constants.Bool.FALSE,
localHome = Constants.Bool.FALSE)
public class FlightEJB extends GenericSessionBean implements SessionBean {
private static final long serialVersionUID = 1L;
/* (non-Javadoc)
* @see weblogic.ejb.GenericSessionBean#ejbCreate(
*/
public void ejbCreate() {
// IMPORTANT: Add your code here
}
public Connection getConnection() {
// Get connection here .....
}
@RemoteMethod
public long getFlightPrice(String strSymbol) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
long quote = 0;
conn = getConnection();
try {
stmt = conn.prepareStatement("SELECT flight_price
FROM flights where flight_line = ?");
stmt.setString(1, strSymbol);
rs = stmt.executeQuery();
rs.next();
quote = rs.getLong("flight_price");
} catch (SQLException e) {
e.printStackTrace();
}
finally {
closeConnection(conn, stmt, rs);
}
return quote;
}
private void closeConnection(Connection conn, Statement stmt,
ResultSet rs) {
if (rs != null) {
try { rs.close(); } catch (SQLException e) { ; }
rs = null;
}
if (stmt != null) {
try { stmt.close(); } catch (SQLException e) { ; }
stmt = null;
}
if (conn != null) {
try { conn.close(); } catch (SQLException e) { ; }
conn = null;
}
}
}
The code is fairly trivial: The only business method is getFlightPrice, which returns the price for the chosen flight.
@RemoteMethod
public long getFlightPrice(String strSymbol) {
......
}
Once we have built and deployed our project we need to make the EJB Client jar file available to our Oracle Service Bus project. The recommended way to create the EJB Client jar file is: From the Project root, right-click "Export EJB jar File". Now your EJB module is ready, and you can move on to the Oracle Service Bus configuration.
Every Oracle Service Bus project needs an Oracle Service Bus configuration project; so, first we'll create this.
Since you probably don't plan to deploy your EJB on the same server as the service bus, we need to add a new JNDI Provider to your configuration. Setting up the JNDI Provider is straightforward. From the main menu you should be able to create a new Oracle Service Bus Configuration. Inside your Oracle Service Bus Configuration project, just right-click and add a JNDI Provider. For the sake of simplicity, in this example we'll choose "t3://localhost:7001" as the provider URL.
Now we have a minimal configuration, so we can start the creation of a new Oracle Service Bus project. Right-click on the project explorer, and select "Create new Oracle Service Bus project". Choose a name for the project.
Before creating our proxy services and business services it's necessary to import the EJB classes and the WSDL file for the EJB into the project. Here we won't go too much in detail about WSDL creation: Briefly, WSDL (Web Services Description Language) is an XML-based language for describing Web services and how to access them. Perhaps the quickest way to obtain a WSDL for our EJB is by turning it into a Web service, through the @WebService notation, and then generate the WSDL from it.
Now, let's create two folders beneath the project's root folder: JAR and WSDL. These folders will hold the files we have just created.
First we'll create the business service. Here we'll see how fast and easy creating a new service can be! Simply create a new business service, choose "Transport Type Service" as the Service Type, and, in the next screen (Transport Configuration), select "ejb" as the transport protocol.
We need to define an endpoint URI for the business service. This will be made up of two parameters: the JNDI Provider name and the EJB JNDI name. In our example (see Figure 1), we'll set this to:
ejb:localProvider:ejb.FlightEJBRemoteHome

Figure 1. Transport configuration
Add the Endpoint URI and move to the Transport Information page (see Figure 2). Here we have to select, in the "Client Jar" textbox, the jar file just included in the project. You'll see that the plug-in automatically discovers the EJB's home, remote interface, and local interface. Choose a Target Namespace (in this example we chose http://www.bookflight.org/), and check that the getFlightPrice method is selected.

Figure 2. Protocol-dependent transport information page
The next step is to build the Proxy Service. Create a "new Proxy service" from the root menu, and choose a convenient name, for example FlightProxyService. In the next screen we choose the service type for our proxy service. Choose "WSDL Web service" and browse to the resource you have in the WSDL folder.
We're almost done. In the next screen, select "HTTP" as the protocol, and choose "/FlightProxy" as the Endpoint URI. Accept the default values in the next screen.
The last step is the message flow, which takes care of routing the message from the proxy service to the business service. A little magic happens here, and you need to be aware of it: We need to route the calling to the EJB getFlightPrice method and replace the value of the SOAP body with the return value of the method.
So, we build a new route to the getFlightPrice method. Inside the request route we need to define two actions: an assign action and a replace action (see Figure 3).

Figure 3. FlightProxyService routing and actions
In the assign action let's define a variable called price, with the value:
$body/Oracle Service Bus:getFlightPriceRequest/Oracle Service Bus:strSymbol/text()
This expression points to the parameter of the getFlightPrice method.
The last step is to replace the body of the SOAP message, having getFlightPrice return the value of the variable price. Add a replace action, choosing body as the variable, and add this expression:
<bookFlight:getFlightPrice>
<bookFlight:strSymbol>{$price}</bookFlight:strSymbol>
</bookFlight:getFlightPrice>
Don't be concerned if you don't understand what bookFlight means. Here we have simply defined a namespace (bookFlight) to make our expression valid. Namespaces can be defined in several points in the plug-in; we chose to do it in the replace action window. Simply add a namespace called bookFlight that points to the namespace already defined as the target namespace (http://www.bookflight.org/). Don't forget the trailing slash!
Now our service configuration is ready to be published. We can test it directly from the plug-in: Right-click on the Proxy Service and select "Run on the Server". You will be required to insert the parameter for the method getFlightPrice.
<Oracle Service Bus:getFlightPriceRequest xmlns:Oracle Service Bus="http://www.Oracle Service Bus.com">
<Oracle Service Bus:strSymbol>AZ1234</Oracle Service Bus:strSymbol>
</Oracle Service Bus:getFlightPriceRequest>
If everything was configured correctly we should see the returning SOAP envelope containing the result of the getFlightPrice method.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"/>
<env:Body xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<m:getFlightPriceResponse xmlns:m="http://www.bookflight.org/">
<m:return>225</m:return>
</m:getFlightPriceResponse>
</env:Body>
</soapenv:Envelope>
What If Your Legacy Component is a POJO?
To allow you to extend the capabilities of Oracle Service Bus in your organization, you can invoke custom Java code from within proxy services. Oracle Service Bus supports a Java exit mechanism via a Java Callout action that allows you to call out to a Plain Old Java Object (POJO). Static methods can be accessed only from a POJO. The POJO and its parameters are visible in the Oracle Service Bus Console at design time; the parameters can be mapped to message context variables.
We're more concerned with demonstrating the invocation model of a POJO in this
exercise than repeating our previous integration demonstrations. Suppose we need to do some custom validation of parameters whose logic has been coded in a POJO:
package sample.pojo;
public class GenericValidator {
class CustomValidator {
public int validate(String parameter) {
if (parameter.equals("correct")) {
return 0;
}
else {
return -1;
}
}
}
public static int customValidator(String parameter) {
CustomValidator customValidator = Factory.customValidator();
int code = customValidator.validate(parameter);
return code;
}
}
Once we have our Java project built and our jar resource exported we'll create a new Oracle Service Bus Project. The main difference between this example and the previous one lies in the Proxy Service. Since request and response will not use XML to communicate, we'll choose text as the Message Type.
In order to collect the return value from our POJO, we'll create a pipeline pair (see Figure 4). A pipeline pair has both a Request and Response branch. In the Request branch we'll use an Assign action to collect the value of $body/text() inside our paramIn.

Figure 4. POJO proxy service showing pipeline pair
Then the real bridge between Oracle Service Bus and the POJO happens in the Java Callout action. Here we point to our jar resource and we discover the method customValidator which is our target method. We choose a convenient variable name for the result value.
We're almost done. In the response pipeline we simply evaluate the return value of our CustomValidator. If it doesn't meet our requirement we'll raise an error code. Basically the error code takes the form of a string argument. The variable $fault is set and the next exception handler in scope is invoked.
If the parameter is validated correctly we simply log the correct execution:
concat('Parameter correctly evaluated:', $paramIn)
Discussion: POJO or EJBs?
The benefit of POJOs is that they are technically simple to create and have little overhead, at least compared to an EJB. But these characteristics of POJOs are also drawbacks. One reason POJOs have little overhead is that they don't include thread management capability. POJOs also don't have offer typical EJB features like CMT demarcation.
However, there are some scenarios in which you are encouraged to use Java Callouts to POJOs in Oracle Service Bus, for example:
- Custom validation: As with our example, where we're doing cross-field semantic validation in Java.
- Custom transformation: Examples of custom transformations can include converting a binary document to base64 binary, or vice versa, or using a custom Java transformation class.
- Custom authentication and authorization: Examples of custom authentication and authorization include scenarios in which a custom token in a message needs to be authenticated and authorized. However, the authenticated user's identity cannot be propagated by Oracle Service Bus to the services or POJOs subsequently invoked by the proxy service.
- Message enrichment: As an example, a file or Java table can be used to look up any piece of data that can enrich a message.
On the other hand, the use of EJBs is recommended over the use of POJOs in the following cases:
- When you already have an EJB implementation.
- When you require read access to a JDBC database. Although POJOs can be used for this purpose, EJBs were specifically designed for this and provide better support for management of, and connectivity to, JDBC resources.
- For the same reason when you plan to access a J2EE transactional resource, EJBs can provide transactional business logic and better support for proper handling of failures. However, transaction and security context propagation is supported with POJOs and they can be used for this purpose.
A final, subtle, consideration: EJBs are usually not written with services in mind. Entity EJBs usually contain little abstraction from the data source and primarily function as a mechanism to mediate between data consumers and the database. Even stateless session beans are rarely written to service oriented standards (rather, they typically exhibit a procedural standard).
Publishing them directly as services might well reduce the level of abstraction and loose coupling in your Enterprise Service Bus (ESB). Low-level implementation details contained in common EJB interfaces can have a dire effect on an enterprise-level service bus. Although it's possible to write service-oriented EJBs, it's rare that an EJB is written to that level. This follows from their very nature.
Seamless Integration with BPM 6.0
Oracle BPM Suite includes new features that improve business efficiency and enterprise scalability. A complete list of these features is beyond the scope of this article; instead, we'll focus on the aspects of integration with the Oracle Service Bus.
In Oracle BPM 6.0, you can easily connect to any instances of Oracle Service Bus. It is no longer necessary to log in to the bus console to get a list of all available services. There is also no need to work with WSDL files and try to guess the URL for particular services. Everything is available directly from Oracle BPM environment.
The product offers a new Introspector wizard that allows users to quickly connect the two products together in a matter of seconds. In just a few clicks you can establish a connection with the bus and gain access to all its proxy services (see Figure 5).

Figure 5. Introspector example
Once you have mapped the external resources with the Introspector and added the needed components to your catalog, you've done the biggest part of the work.
The integration between Oracle Service Bus and Oracle BPM can be carried on with Process Business Language (PBL). PBL, formerly the Fuego Business Language, is the programming language used within Oracle BPM projects where code is required to implement process features or to integrate with external resources.
PBL is a simple high-level language that treats components as objects. PBL can be used to define business rules and logic within activities and certain types of transitions. The PBL development environment is integrated within Oracle BPM.
In order to invoke your Oracle Service Bus service, you must call the method that you want to use in a business activity. Invocation consists of simply declaring a variable (local or instance depending on your needs) that represents your service. Initialize the service calling its constructor:
service as Module.FlightProxyService.GetFlightProxyService =
Module.FlightProxyService.GetFlightProxyService();
Then initialize the request, which will contain the parameters for our service:
request as Module.FlightProxyService.GetFlightPriceRequest =
Module.FlightProxyService.GetFlightPriceRequest();
request.strSymbol = "AZ1234";
Now that your objects are correctly initialized, all you have to do is invoke the service using a simple syntax:
getFlightPrice service
using parameters = request
returning parametersOutput = parametersOutput
display parametersOutput.result
return true
Conclusion
Those of you familiar with previous versions of Oracle Service Bus should find it pretty it easy to dive into the new Eclipse-based design environment. As a matter of fact, developers will experience increased productivity without a steep learning curve.
Looking at the interaction with business process management, Oracle BPM 6.0 sets a new standard in the market, providing a single platform to cover the complete range of human and system business process challenges. Customers who want the capacity to easily find and reuse services deployed throughout the Oracle Service Bus can easily find and consume processes using a simple wizard.
The improvements in usability and simplification of development procedures, combined with rich features and analytic capability, ensure that Oracle Service Bus and Oracle BPM will continue to impress business process analysts and developers long into the future.
Francesco Marchioni joined the Java community in 1997 and is certified as a Sun Enterprise Architect. He is an employee of Pride SpA and has designed and developed many J2EE applications on the WebLogic Platform.
|