Thursday, September 08, 2011

Oracle WebLogic Integration's Custom Control and SOA Suite Spring Component

(From http://www.oracle.com/technetwork/topics/soa/wli-custom-control-spring-component-091819.html)


Introduction

Custom Java code is an essential part of every Oracle WebLogic Integration (WLI) business process (JPD). Although most components of Oracle SOA Suite are XML-centric, Oracle is adding support for Spring components to give the developer full Java support and a powerful IOC container. The Spring components are available since SOA Suite 11g PS2.
This article explains how a Spring component in SOA Suite provides the same functionality as a Custom control in WLI. It uses the example of a logger component to describe step-by-step how the Spring component is implemented and deployed.
This article is intended for WLI developers and architects who want to get started with SOA Suite 11g.

Custom Control in WLI

WLI uses a custom control to encapsulate Java code (e.g. access to a resource or application functionality) which can then be used in a WLI process (JPD) by dragging-and-dropping the control method into the process.
Users can build their own custom controls that are based on the same framework on which system controls are based. A user designs a custom control from the ground up, designing its interface and implementation, and adding other controls as needed.

Spring Component in SOA Suite

Oracle SOA Suite uses its Spring Java component to implement specific business logic in Java, without ever worrying about XML.
Spring (see SpringSource) is an IOC container (Inversion of Control; see Inversion of Control Containers and the Dependency Injection by Martin Fowler) that allows dependency injection via configuration. So while it presents a little overhead when exposing one JavaBean without any dependencies, the more external components are needed, the easier it becomes to use.
While the main components of Oracle SOA Suite are based on XML as data-exchange format, the goal of this component is to allow seamless Java integration and hence the reuse of Java components and skills. Once a component is implemented, it can be subsequently exposed as service, and invoked from other components such as BPEL.
Using Java classes in a composite can be easily achieved through following a few steps.
a) Create a Java interface, and expose the methods that should be publicly available.
public interface IInternalPartnerSupplier
{
    /**
     * Get a price for a list of orderItems
     * @param pOrderItems the list of orderitems
     * @return the price
     */
    public double getPriceForOrderItemList(List pOrderItems)
        throws InternalSupplierException;
}
b) Create an implementation of this interface.
public class InternalSupplierMediator implements IInternalPartnerSupplier
{
    /**
     * Get the price for a list of orderItems and write the quote via
     * injected reference
     * @param pOrderItems the list of orderItems
     * @return the price for the list of orderItems
     */
    @Override
    public double getPriceForOrderItemList(List pOrderItems)
        throws InternalSupplierException
    {
        // just return a default price - or do something else ..
        return 0.0;
    }
}
c) Create a spring component, which also gives you a spring context, and create a bean, which describes the class created in Step b). Give it a name (so it can be referenced) and declare the class.


d) Create an that exposes a bean as a service. A component must have a service declared, in order to be usable by other components' references.

Once a spring component, including a service, is created, it can be wired to any other component, as illustrated in Figure 1, below.
Figure 1
Figure 1

Use case example: a simple logging component

A very common example of a WLI Custom Control is a custom logger which is used at certain points in a process. In this case, we will log the name of the process, the instance ID and a log message.

Implementing the use case in WLI

This use case is not described in great detail as it is assumed that the audience knows how to create and use custom controls in WLI. The focus area is the Spring component in SOA Suite.
The logger control in WLI consists of two java files:
The interface class LoggerControl.java
package sample.oracle.otn.soaessentials.javainteg.controls;
/**
 * Simple logger interface
 * @author simone.geib@oracle.com
 * @author clemens.utschig@oracle.com
 */
import org.apache.beehive.controls.api.bean.ControlInterface;

@ControlInterface
public interface LoggerControl {

    /**
     * Implementation of the log method
     * @param pProcessName the name of the originating process
     * @param pInstanceId the instanceID
     * @param pMessage the message to be logged to std.out
     * @see sample.oracle.otn.soaessentials.javainteg.ILoggerComponent#log
     */
    public void log (String pProcessName, String pInstanceId, String pMessage);

}
The implementation LoggerControlImpl.java
package sample.oracle.otn.soaessentials.javainteg.controls;
import org.apache.beehive.controls.api.bean.ControlImplementation;
import java.io.Serializable;
/**
 * Implementation of a simple logger component
 * @see sample.oracle.otn.soaessentials.javainteg.ILoggerComponent
 * @author simone.geib@oracle.com
 * @author clemens.utschig@oracle.com
 */
@ControlImplementation
public class LoggerControlImpl implements LoggerControl, Serializable {
 private static final long serialVersionUID = 1L;
 
    /**
     * Implementation of the log method
     * @param pProcessName the name of the originating process
     * @param pInstanceId the instanceID
     * @param pMessage the message to be logged to std.out
     * @see sample.oracle.otn.soaessentials.javainteg.ILoggerComponent#log
     */
    public void log(String pProcessName, String pInstanceId, String pMessage)
    {  
       StringBuffer logBuffer = new StringBuffer ();
       logBuffer.append("[").append(pProcessName).append("] [Instance: ").
        append(pInstanceId).append("] ").append(pMessage);
 
       System.out.println(logBuffer.toString());
    }
}
Figure 2 shows the logging control in a JPD Data Palette.

Figure 2
Figure 3 shows the use of the logging control in a JPD

Figure 3

Implementing the use case in SOA Suite


In this section, we will create a simple logging component that can be used from other components, such as BPEL Process Manager or Mediator, to log messages, including the originating instance ID, to standard out.

Creating the Spring Component

To get started, create a new Application in JDeveloper, name it " SOASuiteWLIEssentials"...

Figure 4
And create a new Project named " JavaIntegration".

Figure 5
Click " Finish."
Create a new Java Package " sample.oracle.otn.soaessentials.javainteg" (this requires several steps).

Figure 6
Create a new Java Interface, named " ILoggerComponent" in the " sample.oracle.otn.soaessentials.javainteg" package.

Figure 7

Figure 8
Add a new method to the interface, named " log", with parameters for the originating component, the instance ID, and the message.
package sample.oracle.otn.soaessentials.javainteg;

/**
 * Simple logger interface
 * @author simone.geib@oracle.com
 * @author clemens.utschig@oracle.com
 */
public interface ILoggerComponent
{
   
    /**
     * Log a message, including the originating component, its instance id and
     * a message.
     * @param pComponentName the name of the component that sends this log msg
     * @param pInstanceId the instanceId of the component instance
     * @param pMessage the message to be logged
     */
    public void log (String pComponentName,
                     String pInstanceId, String pMessage);
}

Figure 9
Create a Java class (" LoggerComponentImpl") from the interface " ILoggerComponent".

Figure 10
Name the class and click on the plus sign to find the interface on which to base the class.

Figure 11

Figure 12

Figure 13
This is the implementation of the logging component:
package sample.oracle.otn.soaessentials.javainteg.impl;

import sample.oracle.otn.soaessentials.javainteg.ILoggerComponent;

package sample.oracle.otn.soaessentials.javainteg.impl;

import sample.oracle.otn.soaessentials.javainteg.ILoggerComponent;

/**
 * Implementation of a simple logger component
 * @see sample.oracle.otn.soaessentials.javainteg.ILoggerComponent
 * @author simone.geib@oracle.com
 * @author clemens.utschig@oracle.com
 */
public class LoggerComponentImpl implements ILoggerComponent
{

    /**
     * Implementation of the log method
     * @param pComponentName the name of the orginating component
     * @param pInstanceId the instanceid
     * @param pMessage the message to be logged to std.out
     * @see sample.oracle.otn.soaessentials.javainteg.ILoggerComponent#log
     */
    @Override
    public void log(String pComponentName, String pInstanceId,
                    String pMessage)
    {
        StringBuffer logBuffer = new StringBuffer ();
        logBuffer.append("[").append(pComponentName).append("] [Instance: ").
            append(pInstanceId).append("] ").append(pMessage);
        
        System.out.println(logBuffer.toString());
    }
}
In the next few steps, we will create a new Spring context ("logger-context.xml"), define a Spring bean ("logger"), and expose the bean as a service ("logService").

Figure 14

Figure 15
Next, drag a bean from the Component Palette...

Figure 16
Onto the the spring context canvas.

Figure 17
Name it "logger" and declare a class attribute pointing to the implementation.

Figure 18
Now the bean can be exposed as an SCA service.
To do so, change the drop-down in the component palette to " Spring 2.5 SCA" and drag a " service" onto the canvas.

Figure 19
Give the service the name " logService". Its target will be the " logger" bean.

Figure 20
Finally, pick the type, which is the interface of the LoggerComponent class (" sample.oracle.otn.soaessentials.javainteg.ILoggerComponent").

Figure 21

Figure 22
The completed spring context looks like this:
<?xml version="1.0" encoding="windows-1252" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:sca="http://xmlns.oracle.com/weblogic/weblogic-sca">
  <!-- expose the logger bean as service -->
  <sca:service name="logService" target="logger"
               type="sample.oracle.otn.soaessentials.javainteg.ILoggerComponent"/>
  <!-- declaration of the logger bean -->
  <bean name="logger"
    class="sample.oracle.otn.soaessentials.javainteg.impl.LoggerComponentImpl"/>
</beans>
Create a new composite and name it " JavaIntegration".

Figure 23
Use the "create with BPEL Process" option and name the process " BPELProcessWithLogger". Leave the rest with default settings.

Figure 24

Figure 25
Figure 26, below, shows the newly created BPEL process with a receive and a callback activity.

Figure 26
Switch back to the composite view, and drag a " Spring Context" onto the composite canvas. Name it " logger-context" and pick the spring context you created earlier.

Figure 27

Figure 28
Compile the Java classes so you can create a valid WSDL definition that can be used from within a BPEL process.

Figure 29
Drag the service of the spring component over to the BPEL process. This will create a wsdl and a partnerlink in the process.

Figure 30

Figure 31
Next, drag an invoke activity from the component palette onto the BPEL canvas. This will be used to invoke the log() method on the log service created earlier.

Figure 32
Wire invoke to the partnerlink for the logger service.

Figure 33
Create input and output variables. They will be used later to assign the values for component name, component instance id and a log message.

Figure 34
With the finished invoke activity, the process should resemble Figure 35, below.

Figure 35
In order to populate the created variables, drag an assign activity from the palette onto the BPEL process.

Figure 36
In the next three steps you will create the necessary copy rules to populate the input variable.
Double-click the assign activity and add a copy operation to assign the component name to the first parameter.

Figure 37
Add another copy operation to assign the process instance id to the second parameter.

Figure 38
Add a third copy operation to assign a message to the third parameter.

Figure 39
Make sure the assign activity contains all three copy rules.

Figure 40
Once all the copy rules have been built, the process should resemble Figure 41, below, with an initial receive, the assign for the log message values, followed by an invoke of the log service's log method, and finally, a callback, implemented via invoke.

Figure 41

Deploying the SOA Composite

The next step is to deploy the composite with Oracle JDeveloper. Please make sure that your SOA server is running.
Please check Section 43 in Deploying SOA Composite Applications to learn how to deploy SOA composite applications with Oracle JDeveloper and scripting tools and create configuration plans that enable you to move SOA composite applications to and from development, test, and production environments.
Please check Section 5 in Deploying SOA Composite Applications to learn how to deploy, redeploy, and undeploy a SOA composite application from Oracle Enterprise Manager Fusion Middleware Control Console.
When deploying the composite from within JDeveloper, the log should look similar to the one below:
[06:15:55 AM] ----  Deployment started.  ----
[06:15:55 AM] Target platform is  (Weblogic 10.3).
[06:15:55 AM] Running dependency analysis...
[06:15:55 AM] Building...
[06:16:11 AM] Deploying profile...
[06:16:11 AM] Updating revision id for the SOA Project 'JavaIntegration.jpr' to '1.0'..
[06:16:12 AM] Wrote Archive Module to C:\JDeveloper\mywork\SDOStuff\JavaIntegration\
              deploy\sca_JavaIntegration_rev1.0.jar
[06:16:12 AM] Deploying sca_JavaIntegration_rev1.0.jar to soa_server1 
              [sta00251.us.oracle.com:8001] 
[06:16:12 AM] Processing sar=/C:/JDeveloper/mywork/SDOStuff/JavaIntegration/deploy/
              sca_JavaIntegration_rev1.0.jar
[06:16:12 AM] Adding sar file - C:\JDeveloper\mywork\SDOStuff\JavaIntegration\deploy\
              sca_JavaIntegration_rev1.0.jar
[06:16:12 AM] Preparing to send HTTP request for deployment
[06:16:12 AM] Creating HTTP connection to host:sta00251.us.oracle.com, port:8001
[06:16:13 AM] Sending internal deployment descriptor
[06:16:13 AM] Sending archive - sca_JavaIntegration_rev1.0.jar
[06:16:41 AM] Received HTTP response from the server, response code=200
[06:16:41 AM] Successfully deployed archive sca_JavaIntegration_rev1.0.jar to 
              soa_server1 [sta00251.us.oracle.com:8001] 
[06:16:41 AM] Elapsed time for deployment:  46 seconds
[06:16:41 AM] ----  Deployment finished.  ----

Testing the BPEL Process

After successful deployment, you can initiate the composite service through Oracle Enterprise Manager Fusion Middleware Control Console (Enterprise Manager).
To log in to Enterprise Manager, use Internet Explorer 7, Mozilla Firefox 2.0.0.2, or Firefox 3.0.x to access the following URL: http://host_name:port/em. (Where host_name is the name of the host on which Enterprise Manager is installed and port is a number that is dynamically set during installation.)
Enter weblogic/password and click Login.
Please check Getting Started with Administering Oracle SOA Suite for more information.

Figure 42
Locate the JavaIntegration composite on the EM dashboard and click on it. This will get you to the composite homepage:

Figure 43
Once on the page, you can test a composite service.

Figure 44
Fill in " clemens" as input and click " Test Web Service"

Figure 45
Once the instance is created, you can click on the Launch Message Flow Trace which will get you to the composite instance:

Figure 46
You can check the BPEL instance flow as well, which will show you the actual message that was passed to the spring component:

Figure 47
Check the standard output of the server, that hosts the soa suite. It should show an entry similar to the one below:
==> CubeEngine deploy BPELProcessWithLogger took 4 seconds
INFO: DeploymentEventPublisher.invoke Publishing deploy event for 
default/JavaIntegration!1.0*c39dc7a2-5031-424e-9ae0-aeec949769b3
[BPELProcessWithLogger] [Instance: 20009] Got input: clemens

Download the complete project

A zip file contiaining the complete project, including the java sources and the composite, is available for download: wli-soaessentials-JavaIntegration-source.zip. To open it in JDeveloper, create a new Application, and then open the project file (JavaIntegration.jpr)

Key Takeaways and Recommendations

  • Java can be seamlessly embedded into the composite / xml based world.
  • Multiple Java beans can be easily exposed as services, or get external references injected - just by declaring, and later wiring them.
  • No need to code around XML, inside the Spring component - it's POJOs.
In order to create reusable entities and beans, a spring context can be packaged and deployed itself, without composite, into the WebLogic Server, and beans can be exposed as EJBs / webservices.
This makes it very easy to create reusable Java components that can be used from within a BPEL process or a Mediator component in the same way as a WLI JPD uses custom controls.

No comments: