In my earlier blogpost explaining the Oracle Service Bus Report Action I already mentioned the fact that Oracle allows you to create a custom report provider. Quote:
If you do not wish to use the JMS Reporting Provider that is provided with your Oracle Service Bus installation, you can untarget it and create your own reporting provider using the Reporting Service Provider Interface (SPI). If you configure your own reporting provider for messages, no information is displayed in the Oracle Service Bus Administration Console. You must to create your own user interface.
Since the report action places a java object on an internal JMS queue named wli.reporting.jmsprovider.queue we can start building our own reporting provider from their.

I’ve created a simple EJB project as an example named it CustomOsbReportHandler:
package local.rubix;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import weblogic.logging.LoggingHelper;
import com.bea.wli.reporting.jmsprovider.runtime.ReportMessage;
@MessageDriven(mappedName = "wli.reporting.jmsprovider.queue",
name = "CustomReportHandler")
public class CustomOsbReportHandler implements MessageListener
{
@Resource private MessageDrivenContext mdc;
public void onMessage(Message inMessage)
{
TextMessage msg = null;
Logger logger = LoggingHelper.getServerLogger();
logger.warning("=====================");
logger.warning("MDB inMessage: " + inMessage);
try
{
if (inMessage instanceof TextMessage)
{
msg = (TextMessage) inMessage;
logger.info("MDB unexpected text message received: " + msg.getText());
}
else if (inMessage instanceof ObjectMessage)
{
ObjectMessage myObject = (ObjectMessage) inMessage;
logger.warning("MDB ObjectClass: " + myObject.getObject().getClass());
String str_inMessageClassName = myObject.getObject().getClass().getSimpleName();
logger.warning("MDB ObjectName: " + str_inMessageClassName);
if (str_inMessageClassName.equals("ReportMessage"))
{
logger.warning("MDB ReportMessage found");
ReportMessage myReportMessage = (ReportMessage)myObject.getObject();
logger.warning("MDB getMetadata: " + myReportMessage.getMetadata());
logger.warning("MDB getStrPayload: " + myReportMessage.getStrPayload());
logger.warning("MDB getXmlPayload: " + myReportMessage.getXmlPayload());
logger.warning("MDB getBinPayload: " + myReportMessage.getBinPayload());
}
else
{
logger.warning("MDB NO ReportMessage");
}
}
else
{
logger.info("MDB unknown message");
}
logger.warning("=====================");
}
catch (JMSException e)
{
e.printStackTrace();
mdc.setRollbackOnly();
}
catch (Throwable te)
{
te.printStackTrace();
}
}
}
This project was build with WLS/OSB 11.1.1.5 and the project uses the following libs:
- com.bea.alsb.reporting.impl.jar
- com.bea.core.xml.xmlbeans_2.1.0.0_2-5-1.jar
- org.eclipse.persistence_1.1.0.0_2-1.jar
When you deploy your project don’t forget to untarget the default JMS Reporting Provider in the Weblogic console.
Output (in this case the weblogic log files, but you really don’t want this in production):
#### .... <BEA-000000> <=====================>
#### .... <BEA-000000> <MDB inMessage: ObjectMessage[ID:<786041.1329324233629.0>,com.bea.wli.reporting.jmsprovider.runtime.ReportMessage@9f0e4f]>
#### .... <BEA-000000> <MDB ObjectClass: class com.bea.wli.reporting.jmsprovider.runtime.ReportMessage>
#### .... <BEA-000000> <MDB ObjectName: ReportMessage>
#### .... <BEA-000000> <MDB ReportMessage found>
#### .... <BEA-000000> <MDB getMetadata: <rep:messagecontext xmlns:rep="http://www.bea.com/wli/reporting">
<rep:content-encoding>UTF-8</rep:content-encoding>
<rep:labels>CorrelationID=1234567890</rep:labels>
<rep:inbound-endpoint name="ProxyService$LocalTest$services$ProxyService">
<rep:service>
<rep:operation>getEmployeeDetails</rep:operation>
</rep:service>
<rep:transport>
<rep:uri>/service/employeedetails/v1</rep:uri>
<rep:mode>request-response</rep:mode>
<rep:qualityOfService>best-effort</rep:qualityOfService>
</rep:transport>
</rep:inbound-endpoint>
<rep:origin>
<rep:state>REQUEST</rep:state>
<rep:node>PipelinePairNode1</rep:node>
<rep:pipeline>PipelinePairNode1_request</rep:pipeline>
<rep:stage>stageValidate</rep:stage>
</rep:origin>
<rep:timestamp>2012-01-11T16:20:08.874+01:00</rep:timestamp>
</rep:messagecontext>>
<BEA-000000> <MDB getStrPayload: null>
#### .... <BEA-000000> <MDB getXmlPayload: <head:myHeader xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sr01="http://rubix.nl/schemas/cdm/sr01" xmlns:head="http://rubix.nl/schemas/cdm/header">
<head:CurrentDateTime>2012-01-11T14:44:29.857Z</head:CurrentDateTime>
<head:CorrelationID>1234567890</head:CorrelationID>
<head:MessageID>1234567890.1</head:MessageID>
</head:myHeader>>
#### .... <BEA-000000> <MDB getBinPayload: null>
#### .... <BEA-000000> <=====================>
Which shows us that:
As expected the getXmlPayload & getBinPayload return either the expression you selected in the report action or null. Depending on what kind of input data you decided to use in your mapping. Much more interesting is the getMetadata method which returns the message reporting context, which is an XML type defined in the Oracle Service Bus MessageReporting.xsd. The coolest part here is the fact that it always contains the origin segment with variables you normally don’t have at your disposal in your OEPE mapper. This origin segment contains information as the state (REQUEST/RESPONSE/ERROR), node, pipeline and stage of the running process.
<rep:origin>
<rep:state>REQUEST</rep:state>
<rep:node>PipelinePairNode1</rep:node>
<rep:pipeline>PipelinePairNode1_request</rep:pipeline>
<rep:stage>stageValidate</rep:stage>
</rep:origin>
Why …
From here you can decide on multiple solutions like storing the messagecontext and/or expression in a Oracle database (either relational or XML Type) and by doing so creating your own event tracing specific for your organization needs. Two of the biggest problems I have with the default reporting provider is the fact the messagecontext contains interesting data as a timestamp but the record is stored containing only the message date. Besides that the default version dumps the full expression in a BLOB field. Both result in a limitation regarding querying for specific events.
Report actions + Custom Report provider + a custom SOAP Header definition + proper correlation through your services + good database model = very nice audit and tracing capabilities.