Enriching your data with the Oracle ESB or with the Mediator component in SOA Suite 11g can be hard. It works perfectly in a one-way ( fire and forget ) situation, like described in this
AMIS guide. With the Patch Set 2 of SOA Suite 11g R1 there is a new supported SOA Suite Component called Spring Component which can do this trick perfectly and no limitations.
In this blogpost you will see how easy it is to use Java in the Spring Component, how you can wire this Component to other Components, Services or References adapters. And off course there is no limition in how many times you can enrich or change the data in the Spring Component.
In this example an Employee request with only a Employee Id is enriched with Employee & Department information and this data is forwarded to a logger Spring Component, a processing Mediator and this data is also returned to the initiator of the request. Here is a overview of all the components and adapters
For this example you need an EJB Session Bean and the Employee and Department JPA Entitiy ( Based on the HR demo Schema ). This EJB Session Bean is also exposed as a Web Service.
The HrReference adapter calls the EJB Session Bean interface and the HrWSReference adapter calls the Web Service Interface of this Session Bean. This Model project is included in the example workspace.
Let's start easy with the SpringLogger Spring component. This component will only do a System out. Drop a Spring Component on the composite xml. This create a empty Spring Context XML. Because the plan is to call this component from a other component you need to create a Service interface. For this component this means you need to create a Java Interface class.
package nl.whitehorses.soa.spring.logger;
public interface ILogger {
public void log (String componentName,
String instanceId,
String message);
}
Add a service to the SpringLogger Component, this service has the java interface as type.
<sca:service target="logger" name="LogServiceEJB"
type="nl.whitehorses.soa.spring.logger.ILogger"/>
Next step is to make a implementation of this java interface. This will do the processing ( In this case just a System out println )
package nl.whitehorses.soa.spring.logger;
public class LoggerImpl implements ILogger {
public LoggerImpl() {
}
public void log(String componentName,
String instanceId,
String message) {
StringBuffer logBuffer = new StringBuffer ();
logBuffer.append("[").append(componentName).append("] [Instance: ").
append(instanceId).append("] ").append(message);
System.out.println(logBuffer.toString());
}
}
And you can add this implementation to the SpringLogger Component, The target attribute of the service references to the name of this bean.
<bean class="nl.whitehorses.soa.spring.logger.LoggerImpl" name="logger"/>
This spring component is finished and you can work on the Employee Spring Component which will do the enriching and forwarding of the data.
Before you can start with the java interface or implementation, you need to make some entities which will be used in this interface.
The department entity
package nl.whitehorses.soa.entities;
public class Department {
public Department() {
}
private Integer departmentId;
private String name;
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The employee entity with the department attribute.
package nl.whitehorses.soa.entities;
public class Employee {
public Employee() {
}
private Integer employeeId;
private String firstName;
private String lastName;
private String state;
private Department department;
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public Integer getEmployeeId() {
return employeeId;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setDepartment(Department department) {
this.department = department;
}
public Department getDepartment() {
return department;
}
}
You can now use the employee entity in the java interface class. This interface will be used in the Spring Component Service. The Service has employeeId as parameter and will return the employee entity.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Employee;
public interface IEmployee {
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId);
}
And the implementation. In the enrichEmployee method you will do all the enrichment and forwarding. We will continuous change this method when we wire all the reference adapters.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Employee;
public class EmployeeEnrichmentImpl implements IEmployee {
public EmployeeEnrichmentImpl() {
}
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId) {
Employee employee = new Employee();
return employee;
}
}
Drop a new Spring Component to the Composite, add a Service and a Bean based on these java classes in the Spring Context XML.
<beans>
<sca:service target="employee"
name="EmployeeServiceEJB"
type="nl.whitehorses.soa.spring.enrichment.IEmployee"/>
<bean class="nl.whitehorses.soa.spring.enrichment.EmployeeEnrichmentImpl"
name="employee">
</bean>
</beans>
Wire the reference of the SpringEmployeeEnrichment Component to the service of the SpringLogger Component.
JDeveloper will add a reference in the SpringEmployeeEnrichment Spring Context to the SpringLogger Component.
<beans>
<sca:service target="employee" name="EmployeeServiceEJB"
type="nl.whitehorses.soa.spring.enrichment.IEmployee"/>
<bean class="nl.whitehorses.soa.spring.enrichment.EmployeeEnrichmentImpl"
name="employee">
</bean>
<sca:reference type="nl.whitehorses.soa.spring.logger.ILogger"
name="LogServiceEJB"/>
</beans>
This reference need to be injected to the EmployeeEnrichmentImpl class. Add a property to the bean with a reference to the SpringLogger service.
<bean class="nl.whitehorses.soa.spring.enrichment.EmployeeEnrichmentImpl"
name="employee">
<property name="loggerReference"
ref="LogServiceEJB" />
</bean>
Add the loggerReference variable ( use the ILogger interface and this must match with the property name of the Spring Bean ) to EmployeeEnrichmentImpl and generate the Accessors. Spring will inject the ILoggerImpl to this variable. In the enrichEmployee method you can call the log method and pass on the parameters.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Employee;
import nl.whitehorses.soa.spring.logger.ILogger;
public class EmployeeEnrichmentImpl implements IEmployee {
public EmployeeEnrichmentImpl() {
}
private ILogger loggerReference;
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId) {
// log the request.
loggerReference.log(componentName, instanceId, "Enrich employee: "+employeeId);
Employee employee = new Employee();
return employee;
}
public void setLoggerReference(ILogger loggerReference) {
this.loggerReference = loggerReference;
}
public ILogger getLoggerReference() {
return loggerReference;
}
}
The next step is to expose the Service of the Spring Component. Drag the service to the Exposed Services part of the composite. So you can invoke this service.
You can now choose to expose this as an EJB or a Web Service. Choose Web Service so you can invoke this service in the Enterprise manager.
With this as result.
This is not the best way to expose this Spring Component Service, every change in the java interface will lead to a different WSDL, so let's add a Mediator with an Employee XML Schema to solve this. Now you can change the WSDL or the Java Interface of the Spring Service and only need to update the transformation in the routing rule of the Mediator.
Wire the Mediator to the Spring Component service and add the request and response transformations ( in the routing rule )
Now we can return to the Enrichment part by adding a EJB and Web Service reference adapter and wire this to the Spring component.
First we use the EJB adapter to lookup the employee. You need to change the Implementation by adding a variable based on the Remote Interface of the EJB Session Bean. Add the Service Interface jar of the EJB Session Bean to the dependency of the SOA Project and also put it in the SCA-INF/lib folder. The enrichEmployee method will invoke this EJB and converts the result to a local employee entity.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Employee;
import nl.whitehorses.soa.model.hr.entities.Employees;
import nl.whitehorses.soa.spring.logger.ILogger;
import nl.whitehorses.soa.model.hr.services.HrModelSessionEJB;
public class EmployeeEnrichmentImpl implements IEmployee {
public EmployeeEnrichmentImpl() {
}
private ILogger loggerReference;
private HrModelSessionEJB hrModelReference;
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId) {
// log the request.
loggerReference.log(componentName, instanceId, "Enrich employee: "+employeeId);
// get the employee from the SOA Suite Reference
Employees emp = hrModelReference.getEmployeesFindOne(employeeId);
Employee employee = new Employee();
employee.setEmployeeId(emp.getEmployeeId().intValue());
employee.setFirstName(emp.getFirstName());
employee.setLastName(emp.getLastName());
employee.setState("logged");
return employee;
}
public void setLoggerReference(ILogger loggerReference) {
this.loggerReference = loggerReference;
}
public ILogger getLoggerReference() {
return loggerReference;
}
public void setHrModelReference(HrModelSessionEJB hrModelReference) {
this.hrModelReference = hrModelReference;
}
public HrModelSessionEJB getHrModelReference() {
return hrModelReference;
}
}
Add a new Spring Context Reference based on this Remote interface of the EJB Session Bean. Also add a new property to the Spring Bean which matches with the variable in the Implementation.
<beans>
<sca:service target="employee"
name="EmployeeServiceEJB"
type="nl.whitehorses.soa.spring.enrichment.IEmployee"/>
<bean class="nl.whitehorses.soa.spring.enrichment.EmployeeEnrichmentImpl"
name="employee">
<property name="loggerReference" ref="LogServiceEJB" />
<property name="hrModelReference" ref="HrServiceEJB" />
</bean>
<sca:reference type="nl.whitehorses.soa.spring.logger.ILogger"
name="LogServiceEJB"/>
<sca:reference name="HrServiceEJB"
type="nl.whitehorses.soa.model.hr.services.HrModelSessionEJB"/>
</beans>
Add a new wire for the EJB Reference Adapter by Dragging the not used reference of the Spring Component to the external references of the Composite.
Choose the EJB option.
With this as result.
Open the EJB Reference Adapter and update the JNDI name. ( I deployed the EJB Session Bean on the Soa Suite Server)
The EJB Reference Adapter is finished and wired to the Spring Component.
The next step is to add a Web Service Reference to the Spring Component, I will use this WS to lookup the department of the employee.When you want to use a Web Service in the Spring Component you need to add the Web Service Reference adapter first ( Because I don't have a Web Service Client Proxy )
Add a Web Service Reference Adapter to your Composite.
Wire the WS to the Spring Component Reference.
JDeveloper will generate a WS proxy client and add a Reference to the Spring Context.
<sca:reference type="nl.whitehorses.soa.model.hr.services.HrSessionBeanService"
name="HrWSReference"/>
And add a property to this reference on the Spring Context bean. Change the Spring Component implementation so you can invoke the Web Service to lookup the department.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Department;
import nl.whitehorses.soa.entities.Employee;
import nl.whitehorses.soa.model.hr.entities.Employees;
import nl.whitehorses.soa.spring.logger.ILogger;
import nl.whitehorses.soa.model.hr.services.HrModelSessionEJB;
import nl.whitehorses.soa.model.hr.services.HrSessionBeanService;
public class EmployeeEnrichmentImpl implements IEmployee {
public EmployeeEnrichmentImpl() {
}
private ILogger loggerReference;
private HrModelSessionEJB hrModelReference;
private HrSessionBeanService hrWSModelReference;
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId) {
// log the request.
loggerReference.log(componentName, instanceId, "Enrich employee: "+employeeId);
// get the employee from the SOA Suite Reference
Employees emp = hrModelReference.getEmployeesFindOne(employeeId);
// get the department from the WebLogic SCA Reference
nl.whitehorses.soa.model.hr.services.Departments dept = hrWSModelReference.getDepartmentsFindOne(emp.getDepartmentId());
Department department = new Department();
department.setDepartmentId(dept.getDepartmentId().intValue());
department.setName(dept.getDepartmentName());
Employee employee = new Employee();
employee.setEmployeeId(emp.getEmployeeId().intValue());
employee.setFirstName(emp.getFirstName());
employee.setLastName(emp.getLastName());
employee.setDepartment(department);
employee.setState("logged");
return employee;
}
public void setLoggerReference(ILogger loggerReference) {
this.loggerReference = loggerReference;
}
public ILogger getLoggerReference() {
return loggerReference;
}
public void setHrModelReference(HrModelSessionEJB hrModelReference) {
this.hrModelReference = hrModelReference;
}
public HrModelSessionEJB getHrModelReference() {
return hrModelReference;
}
public void setHrWSModelReference(HrSessionBeanService hrWSModelReference) {
this.hrWSModelReference = hrWSModelReference;
}
public HrSessionBeanService getHrWSModelReference() {
return hrWSModelReference;
}
}
The last part is to connect a Mediator to the Spring Component and pass on the Employee entity so you can for example write this object to a file or insert the employee in a table.
Add a Mediator Component to the Composite and use the Define Interface Later Template.
Create a new Java Interface for this Mediator with the entity you want to pass on.
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Employee;
public interface IEmployeeMediator {
public void processEmployee ( Employee emp );
}
Change the Spring Component xml, add the reference and the property on the bean
<beans>
<sca:service target="employee" name="EmployeeServiceEJB"
type="nl.whitehorses.soa.spring.enrichment.IEmployee"/>
<bean class="nl.whitehorses.soa.spring.enrichment.EmployeeEnrichmentImpl"
name="employee">
<property name="loggerReference" ref="LogServiceEJB" />
<property name="hrModelReference" ref="HrServiceEJB" />
<property name="hrWSModelReference" ref="HrWSReference" />
<property name="mediatorReference" ref="EmployeeMediator" />
</bean>
<sca:reference type="nl.whitehorses.soa.spring.enrichment.IEmployeeMediator"
name="EmployeeMediator"/>
<sca:reference type="nl.whitehorses.soa.spring.logger.ILogger"
name="LogServiceEJB"/>
<sca:reference name="HrServiceEJB"
type="nl.whitehorses.soa.model.hr.services.HrModelSessionEJB"/>
<sca:reference type="nl.whitehorses.soa.model.hr.services.HrSessionBeanService"
name="HrWSReference"/>
</beans>
Change the implementation for the Mediator
package nl.whitehorses.soa.spring.enrichment;
import nl.whitehorses.soa.entities.Department;
import nl.whitehorses.soa.entities.Employee;
import nl.whitehorses.soa.model.hr.entities.Employees;
import nl.whitehorses.soa.spring.logger.ILogger;
import nl.whitehorses.soa.model.hr.services.HrModelSessionEJB;
import nl.whitehorses.soa.model.hr.services.HrSessionBeanService;
public class EmployeeEnrichmentImpl implements IEmployee {
public EmployeeEnrichmentImpl() {
}
private ILogger loggerReference;
private HrModelSessionEJB hrModelReference;
private HrSessionBeanService hrWSModelReference;
private IEmployeeMediator mediatorReference;
public Employee enrichEmployee(Integer employeeId,
String componentName,
String instanceId) {
// log the request.
loggerReference.log(componentName, instanceId, "Enrich employee: "+employeeId);
// get the employee from the SOA Suite Reference
Employees emp = hrModelReference.getEmployeesFindOne(employeeId);
// get the department from the WebLogic SCA Reference
nl.whitehorses.soa.model.hr.services.Departments dept = hrWSModelReference.getDepartmentsFindOne(emp.getDepartmentId());
Department department = new Department();
department.setDepartmentId(dept.getDepartmentId().intValue());
department.setName(dept.getDepartmentName());
Employee employee = new Employee();
employee.setEmployeeId(emp.getEmployeeId().intValue());
employee.setFirstName(emp.getFirstName());
employee.setLastName(emp.getLastName());
employee.setDepartment(department);
employee.setState("logged");
mediatorReference.processEmployee(employee);
return employee;
}
public void setLoggerReference(ILogger loggerReference) {
this.loggerReference = loggerReference;
}
public ILogger getLoggerReference() {
return loggerReference;
}
public void setHrModelReference(HrModelSessionEJB hrModelReference) {
this.hrModelReference = hrModelReference;
}
public HrModelSessionEJB getHrModelReference() {
return hrModelReference;
}
public void setHrWSModelReference(HrSessionBeanService hrWSModelReference) {
this.hrWSModelReference = hrWSModelReference;
}
public HrSessionBeanService getHrWSModelReference() {
return hrWSModelReference;
}
public void setMediatorReference(IEmployeeMediator mediatorReference) {
this.mediatorReference = mediatorReference;
}
public IEmployeeMediator getMediatorReference() {
return mediatorReference;
}
}
Add a wire between the not used reference of the Spring Component and the service of the Mediator.
At last add a File or a Database Adapter to the Composite and wire this to this Mediator.
That's all.
Here is the
example workspace.