Expose Inbound EJB interfaces
Services exposed from the SOA Suite – whether they are implemented through Service Bus or SOA composites – can be exposed in various ways. The most common is the web service binding or transport that supports SOAP/XML calls over HTTP. We have discussed support for RESTful services, also over HTTP. And now we will look at exposing the service as an EJB over RMI. Both Service Bus composites – using the JEJB transport – and SOA composites – through the EJB adapter– can easily be exposed as EJBs. Consumers of these services interact with such EJBs like they do with regular EJBs – no specific SOA Suite aspects are involved. The onus of translating from the world of the Java interface and serialized Java objects to WSDL and XML is on the SOA Suite.
Note: with the ever increasing support for web service interaction in Java – through for example JAX-WS and JAX-RS – the relevance of direct EJB interaction is somewhat decreasing. EJBs are primarily used when transaction and security scope are important.
This online complement to chapter 6 describes how to expose both the AircraftMovementService Service Bus project and the AircraftMovementServiceSOAComposite through an EJB interface, next to their existing web service end-points. It introduces various inbound EJB interaction styles supported by the SOA Suite: inbound JEBJ Transport, the inbound EJB adapter and the direct binding facility.
Service Bus composite and the inbound JEJB Transport
Exposing a Service Bus composite as an EJB is done by creating a proxy service that uses JEJB as its transport. The interface of such an JEJB proxy service is defined through a Java interface. That interface is the remote interface through which Java clients access the EJB and indirectly the Service Bus composite. From this interface, a WSDL equivalent can be generated that can be used as the interface for a pipeline that the proxy service is wired to. This pipeline – despite the WSDL interface – will receive the body variable containing a Java payload. If the pipeline routes to a business service that also uses the JEJB transport, then these Java objects never have to be marshalled into XML. However, for any other business service, the Java objects in the payload have to be turned into XML in a custom Java class that is called in a Java Callout activity.
We will now expose the AircraftMovementService as an EJB using the JEJB transport.
Create the Java interface for the AircraftMovementService
The Java interface that is to be exposed by the EJB endpoint has to be created. The easiest way is to simply create a Java interface in the current AircraftMovementService project, along with a bean that holds the properties associated with an aircraft movement that is reported:
package saibot.airport.operations.monitoring;
import saibot.airport.operations.monitoring.beans.AircraftMovement;
public interface AircraftMovementReporter {
public void reportAircraftActivity( AircraftMovement aircraftMovement);
}
And the Java bean:
package saibot.airport.operations.monitoring.beans;
import java.io.Serializable;
import java.util.Date;
public class AircraftMovement implements Serializable{
Date movementTimestamp ;
Integer flightnumber ;
String carrierIataCode ;
String airportIataCode ;
String arrivalOrDeparture ;
String aircraftIataEquipmentCode ;
Integer numberOfPassengers ;
… with a no-arg constructor and a second constructor that takes all properties as input and with all getters and setters for the properties
}
Create a deployment profile of type JAR file for the project. Next, deploy the project according to that profile, resulting in a simple JAR file in the deploy directory under the project root. This JAR file contains the interface and the bean definition.
Create the Proxy Service
Right click in the Exposed Services lane and select Insert Transports | JEJB from the context menu, as shown in Figure 6-46.
Inserting an inbound JEJB transport to the AircraftMovementService Service Bus project
The wizard for configuring the proxy service appears. Set the Service Name to AircraftMovementServiceJEJB and the location to the Proxy folder. Do not generate the pipeline for this proxy service. Click Next.
Set the Endpoint URI also to AircraftMovementServiceJEJB. Press Finish to have the proxy service created.
Double click the generated proxy service to bring up the editor. Go to the Transport Details tab, shown in Figure 6-47.
Ensure that the EJB Spec version is 3.0. Browse for the JAR file that was created during deployment in the previous step. Select the AircraftMovementReporter as the Business interface. Set the Target Namespace to saibot.airport.operations/monitoring.
Configure the transport details for the inbound JEJB transport proxy service
The selected interface contains a single method – reportAircraftActivity – that is preselected. Set the name of the input parameter to aircraftMovement. That is the name under which we can access the Java payload in the $body variable.
Generate WSDL and create pipeline
Before we can create the pipeline that this proxy service is going to route to, we have to generate the WSDL that defines the interface for that pipeline. This WSDL can be derived from the Java interface exposed by the proxy service. Right click the proxy service and from the context menu select Service Bus | Generate WSDL.
Enter AircraftMovementServiceJEJB.wsdl as name for the WSDL to be generated and have it created in the WSDLs folder.
Next we can create the pipeline, based on this WSDL. Right click the WSDL and select Service Bus | Generate pipeline. Call the pipeline AircraftMovementPipelineJEJB.
Wire this pipeline to AircraftMovementPipeline. Also wire the proxy service AircraftMovementServiceJEJB to the AircraftMovementPipelineJEJB, as shown in Figure 6-48.
Wire the JEJB pipeline (wired from the JEJB proxy service) to the dispatcher pipeline
Calls arriving at the EJB interface of this Service Bus project are routed to the AircraftMovementPipelineJEJB. Here, the Java object payload will have to be converted to XML. Subsequently the request is routed to the AircraftMovementPipeline. From then on, the processing is no different from calls arriving at the web service proxy.
Add Java Callout to marshall Java payload to XML
In order for this pipeline to be able to route to the AircraftMovementPipelineJEJB, the $body variable will have to contain the required XML data content rather than the Java object payload it currently has. The method for working with a payload consisting of Java objects is through the Java Callout activity.
The Java Callout activity can be used in a pipeline to invoke a custom and static Java method. Multiple argument values can be passed in this call and a single value can be returned – usually a primitive, String or an XmlObject. In our case, the input to the Java method would be the AircraftMovement bean that constitutes the Java content in $body, as received through the EJB interface. We would like this method to return the XML equivalent of that bean as the AircraftMovementRequestMessage that is the input to the next pipeline.
Variables in Service Pipelines – such as $body – are Java objects of type XmlObject (defined in the Apache XmlBeans library). This is relevant when entire variables are passed in the Java Callout as input parameters and of course for constructing return values that are to be assigned to variables such as $body. The Service Bus runtime ships with the Apache XmlBeans library. In order to develop a custom Java class that can work with XmlObject, we need to have access in our project to the JAR file for that library.
Note: if the Java Callout returns a variable that is not a primitive, a String or an XmlObject, then a reference to the returned object is stored in the pipeline variable. This reference cannot be meaningfully manipulated through XML manipulation. However, when another Java Callout is made or a business service with JEJB or JMS transport is invoked, the underlying Java object is transferred.
Add XmlBeans library to project
The JAR file that contains the required definitions for the XmlBeans library ships with the SOA Suite. It can be found as com.bea.core.xml.xmlbeans_1.0.0.0_2-6-0 under MIDDLEWARE_HOME/Oracle_Home/oracle_common/modules. Add this JAR file to the AircraftMovementService project.
Create Java Class to call out to
The Java class that is the target of a Java Callout has to expose one or more static methods. The class has to be packaged in a JAR file that will be deployed to the SOA Suite along with the Service Bus composite.
Create Java class JavaPayloadDissector according to the source code shown below.
package saibot.airport.operations.monitoring.pipeline;
import javax.xml.namespace.QName;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import saibot.airport.operations.monitoring.beans.AircraftMovement;
public class JavaPayloadDissector {
public static XmlObject getReportAircraftMovementRequestMessage(AircraftMovement aircraftMovement) {
String namespace = “saibot.airport/services/aircraftmovement”;
String localName = “reportAircraftMovementRequestMessage”;
XmlObject result = XmlObject.Factory.newInstance();
XmlCursor cursor = result.newCursor();
QName responseQName = new QName(namespace, localName);
cursor.toNextToken();
cursor.beginElement(responseQName);
cursor.insertElementWithText(new QName(namespace, “ActionDateAndTime”), “2015-09-29T03:49:45″);
cursor.insertElementWithText(new QName(namespace, “FlightNumber”), aircraftMovement.getFlightnumber().toString());
cursor.insertElementWithText(new QName(namespace, “Carrier”), aircraftMovement.getCarrierIataCode());
cursor.insertElementWithText(new QName(namespace, “ArrivalOrDeparture”), aircraftMovement.getArrivalOrDeparture());
cursor.insertElementWithText(new QName(namespace, “ConnectingAirport”), aircraftMovement.getAirportIataCode());
cursor.insertElementWithText(new QName(namespace, “AircraftModel”), aircraftMovement.getAircraftIataEquipmentCode());
cursor.insertElementWithText(new QName(namespace, “NumberOfPassengers”), aircraftMovement.getNumberOfPassengers().toString());
return result;
}
}
Deploy the JAR Deployment Profile once more, to have this class added to the JAR file in the project’s deploy directory.
Configure the Java Callout
Open the AircraftMovementPipelineJEJB pipeline. Add a Java Callout activity to the request pipeline.
Start the configuration of this activity (Figure 6-49) by browsing for the method to call. This will bring up the JAR file browser window. Once you have selected a JAR-file, a list of eligible objects and methods is presented. Select (the only available) method. The list of arguments contains a single argument. Here we want to pass the AircraftMovement bean that was received through the EJB call and that is now the payload of the $body variable. The expression to be used for the value of this argument is:
$body/mon:reportAircraftActivity/mon:aircraftMovement/ctx:java-content
where mon is the prefix for the target namespace in the WSDL generated for the pipeline.
Configuration of the Java Callout activity to invoke the JavaPayloadDissector class
Assign the return value from this Java Callout to a custom variable called aircraftMovementRequest. This variable will be set with the XmlObject constructed in the getReportAircraftMovementRequestMessage method.
Update $body based on the result from the Java Callout
The $body variable has to be updated using the result from the Java Callout. Add a Replace activity to the request pipeline and insert it after the Java Callout, as in Figure 6-50. Set the Location to body and specify that the node contents should be replaced. The expression that specifies the value to be injected in the body variable is $aircraftMovementRequest (which contains the XmlObject created in the Java Callout).
Configuration of the Replace activity to update the $body variable with the result from the Java Callout
This completes the pipeline. At this point you can redeploy the Service Bus composite, for example by running one of the proxy services in the Service Bus composite overview. When you run a proxy service with a JEJB transport, the composite is deployed and the Service Bus tester appears but it does not actually allow you to invoke the EJB. To make such a call, you need to create a Java client.
To verify whether the deployment succeeded, you can check the JNDI Tree in the WLS console. You can access this tree by clicking on the node Default Domain | Environment | Servers in the Domain Structure window, then clicking on the DefaultServer link and finally clicking on the View JNDI Tree link on the DefaultServer overview page. Figure 6-51 shows the EJB exposed by the Service Bus project.
The JNDI Tree browser for the Integrated WLS with the AircraftMovementReporter EJB published by the Service Bus project
This also gives us the Binding Name we need to use in a Java client accessing this EJB endpoint.
Invoke the EJB interface of the AircraftMovementService
To invoke the EJB exposed by the AircraftMovementService composite, create a new Java project, called AircraftMovementServiceJEJBClient. Add the WebLogic 12.1 Remote-Client library to this project and also the AircraftMovementServiceJEJB.jar in the deploy directory of the AircraftMovementService project. This JAR file contains the remote interface and the bean definition that our client will have to use.
Then create a new class called AircraftMovementServiceEJBClient. The implementation for this class is shown below. Note how the JNDI binding name of the EJB is used in the lookup call. This is the linking pin between the client and the remote EJB.
package saibot.airport.operations.client;
import java.util.Date;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import saibot.airport.operations.monitoring.AircraftMovementReporter;
import saibot.airport.operations.monitoring.beans.AircraftMovement;
public class AircraftMovementServiceEJBClient {
public AircraftMovementServiceEJBClient() {
super();
}
public void reportAircraftMovement(AircraftMovement aircraftMovement) {
try{
Hashtable jndiProps = new Hashtable();
jndiProps.put(Context.PROVIDER_URL, “t3://localhost:7101/soa-infra”);
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, “weblogic.jndi.WLInitialContextFactory”);
jndiProps.put(Context.SECURITY_PRINCIPAL, “weblogic”);
jndiProps.put(Context.SECURITY_CREDENTIALS, “weblogic1″);
InitialContext ic = new InitialContext(jndiProps);
AircraftMovementReporter aircraftMovementReporter = (AircraftMovementReporter)ic.lookup(“AircraftMovementServiceJEJB#saibot.airport.operations.monitoring.AircraftMovementReporter”);
aircraftMovementReporter.reportAircraftActivity(aircraftMovement);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new AircraftMovementServiceEJBClient().reportAircraftMovement( new AircraftMovement(new Date(), 450, “AZQ”, “DUB”, “A”, “726″, 159));
}
}
Run this class to make a call to the EJB. The final result should be that either a message is placed on the JMS queue or a call is made from the AircraftMovementService composite to the EJB exposed by the financial department. Whatever took place is of course entirely invisible to this client, just as it should be.
SOA Composite and inbound EJB Adapter
The same EJB Adapter that we used earlier to create an outbound reference to an EJB to allow components in a SOA composite to invoke that EJB, can also be used to expose a SOA composite as an EJB. Using the EJB adapter in inbound mode it will register an EJB with the WebLogic Server with the Java interface specified during development. Java clients can invoke that EJB and in doing so enlist the help of the SOA composite.
The steps to front the SOA composite with an EJB as entry point are straightforward: define the Java interface that describes the EJBs capabilities, add the inbound EJB adapter binding to the composite, based on that interface and wire the adapter binding to a component (typically a mediator) to link the worlds of EJB and Java on the one hand and WSDL and XML on the other.
Expose AircraftMovementServiceSOAcomposite as an EJB
First: create the Java interface that the EJB should expose. Typically, this Java interface is a close Java equivalent of the exposed web service – in this case the AircraftMovementService. Let’s call the interface AircraftMovementReporter in package saibot.airport.operations.aircraftmovement. Specify a single method that takes input parameters for timestamp, number of passengers, airport and aircraft code, airline, flightnumber and departure or arrival indicator. The method does not return a value.
Drag the EJB Adapter to the Exposed Services swimlane. The configuration wizard appears. Specify the name of the service to AircraftMovementServiceEJB. Set the JNDI name to SaibotAirportOperations#AircraftMovementServiceEJB. Select the Java interface AircraftMovementReporter that was just created. Note that if the interface definition had already been available in a JAR file in the project, we could have selected it as well. Additionally, the wizard allows the generation of a Java interface from a WSDL document.
Configuring the EJB Service to expose from the SOA composite
Press OK to complete the configuration. The EJB adapter binding is added to the composite.xml file and displayed in the composite overview.
Create a new mediator component called AircraftMovementEJBtoAircraftMovementMediator to mediate between the exposed EJB interface and the AircraftMovementMediator that routes to the components that do the actual work.
Wire the AircraftMovementServiceEJB to the new mediator AircraftMovementEJBtoAircraftMovementMediator, as is shown in the figure. Also wire this mediator to the AircraftMovementMediator. All that is left to do now is create an XSL Map for the transformation between the XSD generated for the Java interface and the reportAircraftMovementRequestType, and use that XSL Map in the AircraftMovementEJBtoAircraftMovementMediator.
Wire the EJB Service to the AircraftMovementEJBtoAircraftMovementMediator mediator and that mediator to the AircraftMovementMediator that routes to the EJB reference binding.
When the wires are added and the transformation through the XSL Map is configured, the composite can be deployed.
Invoking the SOA composite with exposed EJB service
When the SOA composite has been deployed, a new EJB is published in WebLogic – AircraftMovementServiceEJB – that can be invoked by Java clients. The call to this EJB – that represents the SOA composite – is not any different from calls to ‘normal’ EJBs. It does not require special SOA Suite run time libraries for the service consumer. In fact, the class AircraftMovementServiceEJBClient that was created to invoke the EJB exposed by the Service Bus composite can be reused (provided the same Java interface was implemented) with minimal changes to also invoke the EJB published by the SOA composite. Note that the binding name has to be modified.
Direct Binding
SOA composites can expose services through the direct binding API. Direct binding enables Java clients to directly invoke composite services over RMI, bypassing the need for a JAX-WS proxy required with the web service binding. Note that the client still communicates with the direct binding interface in terms of XML messages.
The direct binding components support both synchronous and asynchronous invocation patterns. It also supports both inbound as well as outbound interactions. The latter is used to connect SOA composites and Service Bus services when they need security or transaction propagation, and that outweighs the increased coupling introduces with the direct binding.
Although somewhat similar to interaction via the EJB adapter, the direct binding does not require a Java interface to be defined for the service to be invoked. A Java client does not interact through a service specific EJB, but accesses the generic Direct Binding Invocation API. The Java client needs to import a number of classes from runtime SOA Suite libraries that constitute this API.
The Direct Binding Invocation API takes the JNDI connection parameters and creates a connection object on behalf of the client. This connection is to the destination SOA Suite server, as well as to the specific direct binding service exposed by a specific version of a specific SOA composite.
Extending the AircraftMovementServiceSOAcomposite with a direct binding interface
Adding a direct binding interface to an existing SOA composite is dead simple. Drag the Direct [Binding] component from the component palette to the Exposed Services lane.
Configuration of the direct binding service in the wizard that appears is simple: define the name of the service as AircraftMovementServiceDirectBinding and select the WSDL and Port Type that the service exposes – just as you would for a [SOAP] Web Service. In this case these are the AircraftMovementService.wsdl in the WSDLs folder and the AircraftMovementServicePortType.
Configuring the Direct Binding Service interface for the AircraftMovementService
The exposed service is displayed in the composite overview, because the service element is added to the composite.xml. We can now wire the direct binding service to components such as the mediator in exactly the same way as we do for Web Service bindings. In such cases we expose the same service using several interfaces. The service consumer can then pick the interface that best suits its needs.
Wire the direct binding service to the AircraftMovementMediator, as shown in the next figure. Requests coming in over the direct binding interface are handled in exactly the same way by the mediator as requests arriving over the SOAP Web Service interface.

SOA composite with the same functional interface exposed as SOAP Web Service and as Direct Binding
Invoke the direct binding interface
Invoking the direct binding interface is done from a Java class that uses a number of SOA Suite runtime libraries to make the connection (over RMI). A very simple Java application that invokes the AicraftMovementService over its direct binding interface can be created as follows.
Create a new Java project in JDeveloper, for example called AircraftMovementServiceDirectBindingClient, with default package saibot.airport.operations.aircraftmovementservice.directbindingclient. Add the libraries WebLogic 12.1 Remote-Client, Oracle XML Parser V2, JRF Runtime and SOA Runtime to the project – to make the classes available that are used when accessing the direct binding.
Create a Java bean AircraftMovement in package saibot.airport.operations.aircraftmovementservice.directbindingclient – a simple POJO with these properties: movementTimestamp, flightNumber, carrierIataCode, airportIataCode, arrivalOrDeparture, aircraftIataEquipmentCode and numberOfPassengers. Generate the getters and setters for this bean.
Create Java Class AircraftMovementReporter in the same package. The essential code sections in this class are:
public void ReportAircraftMovement(AircraftMovement aircraftMovement) {
Hashtable jndiProps = new Hashtable();
jndiProps.put(Context.PROVIDER_URL, “t3://localhost:7101/soa-infra”);
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, “weblogic.jndi.WLInitialContextFactory”);
jndiProps.put(Context.SECURITY_PRINCIPAL, “weblogic”);
jndiProps.put(Context.SECURITY_CREDENTIALS, “weblogic1″);
jndiProps.put(“dedicated.connection”, “true”);
try {
Locator locator = LocatorFactory.createLocator(jndiProps);
DirectConnectionFactory factory = JNDIDirectConnectionFactory.newInstance();
CompositeDN compositeDN = new CompositeDN(“default”, “AircraftMovementServiceSOAcomposite”, “1.1″);
String serviceName = “AircraftMovementServiceDirectBinding”;
DirectConnection dc = locator.createDirectConnection(compositeDN, serviceName);
String inputPayload =
“<ns1:reportAircraftMovementRequestMessage xmlns:ns1=\”saibot.airport/services/aircraftmovement\”>\n” +
“ <ns1:ActionDateAndTime>”+ aircraftMovement.getMovementTimestamp() +”</ns1:ActionDateAndTime>\n” +
“ <ns1:FlightNumber>”+ aircraftMovement.getFlightnumber() +”</ns1:FlightNumber>\n” +
“ <ns1:Carrier>”+ aircraftMovement.getCarrierIataCode() +”</ns1:Carrier>\n” +
“ <ns1:ArrivalOrDeparture>”+ aircraftMovement.getArrivalOrDeparture() +”</ns1:ArrivalOrDeparture>\n” +
“ <ns1:ConnectingAirport>”+ aircraftMovement.getAirportIataCode() +”</ns1:ConnectingAirport>\n” +
“ <ns1:AircraftModel>”+ aircraftMovement.getAircraftIataEquipmentCode() +”</ns1:AircraftModel>\n” +
“ <ns1:NumberOfPassengers>”+ aircraftMovement.getNumberOfPassengers() +”</ns1:NumberOfPassengers>\n” +
“ </ns1:reportAircraftMovementRequestMessage>”;
oracle.xml.parser.v2.DOMParser op = new DOMParser();
op.parse(new InputSource(new StringReader(inputPayload)));
Map partData = new HashMap();
partData.put(“part1″, op.getDocument().getDocumentElement());
// Create the Message and pass in the payload
Payload payload = PayloadFactory.createXMLPayload(partData);
Message request = XMLMessageFactory.getInstance().createMessage();
request.setPayload(payload);
// Define conversation ID
String uuid = “uuid:” + UUID.randomUUID();
System.out.println(“uuid = ” + uuid);
request.setProperty(request.CONVERSATION_ID, uuid);
// Invoke…
dc.post(“reportAircraftMovement”, request);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new AircraftMovementReporter().ReportAircraftMovement( new AircraftMovement(new Date(), 450, “AZQ”, “DUB”, “A”, “726″, 159));
}
When this code is executed, the SOA composite is triggered via its direct binding interface – as is visible in the flow trace in the EM FMW Control.
No response is received of course, because the interaction is still one-way. However, a message will have been published to the JMS queue, based on the contents of the AircraftMovement bean.