Articles
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: EJBIf 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
@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
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 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
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
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
So, we build a new route to the
In the
$body/Oracle Service Bus:getFlightPriceRequest/Oracle Service Bus:strSymbol/text() This expression points to the parameter of the
The last step is to replace the body of the SOAP message, having
<bookFlight:getFlightPrice>
<bookFlight:strSymbol>{$price}</bookFlight:strSymbol>
</bookFlight:getFlightPrice>
Don't be concerned if you don't understand what
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
<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
<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
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
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
We're almost done. In the response pipeline we simply evaluate the return value of our
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:
On the other hand, the use of EJBs is recommended over the use of POJOs in the following cases:
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.0Oracle 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). 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
ConclusionThose 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. |
||||||||||||||||||||||||||||||||||||||||||||||