OC4J, Spring and messaging

I ran into several issues during the development of an application which is to be run in OC4J 10.1.3.1 and needs to use SOAP web services and Oracle AQ (Advanced Queueing) messaging:

  • Classpath hell debugging
  • Oracle XML parser crashes on SOAP response
  • Using custom AQ message payload (Oracle ADT message)

If anyone encountered such problems, read the rest of the article for tips and solutions.

Classpath hell

Really useful technique for solving classpath issues is to turn on OC4J class load tracing. It can be done by passing special arguments to VM.

If starting OC4J manually via oc4j/bin/oc4j.cmd you can run the following one-line command before:

SET OC4J_JVM_ARGS=-Dclass.load.trace=class+loader
-Dclass.load.log.file=c:/classloadlog.txt
-Dclass.load.log.level=all

If you’re running OC4J server directly from Eclipse’s Server view, put these arguments into VM arguments section of Run dialog.

Oracle XML parser crashes on SOAP response

Oracle XML parser is somewhat buggy and crashes on manually created SOAP response if the message body isn’t surrounded with <Envelope> element (the same one which surrounds the whole SOAP message).

One way of getting rid of this is to completely replace Oracle XML parser with e.g. Apache Xerces parser. If you have full access to application server you can try adding Xerces as OC4J’s shared library. As this wasn’t our case (we weren’t allowed to change the configuration of production server) we needed to find another way.

The first step was to add Xerces jars to our application.

If you only deploy manually via server’s web interface, second step is quite easy as it is sufficient to remove oracle.xml shared library at the very last step of the deployment process.

If you use Eclipse’s automatic publishing (which you probably are because nobody wants to manually deploy the application after every modification when developing) things get more complicated.

Upon every publishing, new orion-application.xml file for our application is created. We need it to keep containing the following snippet:

[xml]



[/xml]

This can be achieved by:

  1. creating deployment plan with removed reference to oracle.xml shared library (via manual web deployment)
  2. saving the plan to some place on disk
  3. modifying oracle.10.1.3.xml file in [eclipse_dir]/plugins/org.eclipse.jst.server.generic.oc4j/buildfiles:
    [xml]



Using custom AQ message payload (Oracle ADT message)

Using standard JMS message types for AQ works just fine (see this great techblog’s article for description). To turn on JTA transactions, add the following to your Spring configuration file:
[xml]



[/xml]

A little more advanced is to use custom objects as message payload. Follow these steps:

  1. Create custom type & queue in your Oracle database
  2. Use jpub to generate Java class for the type
  3. Sending message is pretty straightforward
  4. For receiving message, an extension of Spring’s DefaultMessageListenerContainer is needed

Ad 1)

For type:
CREATE OR REPLACE TYPE MyCustomType...

For queue table:
execute dbms_aqadm.create_queue_table(
queue_table => 'MyQueueTable',
queue_payload_type => 'MyCustomType'
...

Ad 2)

Download JPublisher, unpack it to e.g. c:\oracle\sqlj and run it:

SET CLASSPATH = <path_to_driver>\ojdbc14.jar; c:\oracle\sqlj\lib\translator.jar; c:\oracle\sqlj\lib\runtime12.jar;

SET PATH = c:\Program Files\Java\j2sdk1.4.2_16\bin

java -cp %CLASSPATH% oracle.jpub.Doit -user=autopub/autopub -url=<url to your db> -sql=<name of type> -case=mixed -compatible=CustomDatum -usertypes=oracle

Ad 3)

[java]
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
Message msg = null;
if (session instanceof AQjmsSession) {
MyCustomType type = new MyCustomType();
msg = ((AQjmsSession)session).createAdtMessage(vzp);
return msg;
} else {
//this is bad… deal with it
}
}
}
[/java]

Ad 4)

We need to extend DefaultMessageListenerContainer’s createConsumer method to slip payload factory which can handle our new custom object type:

[java]
public class MyCustomTypeMessageListenerContainer
extends DefaultMessageListenerContainer {
protected MessageConsumer createConsumer(Session session, Destination destination)
throws JMSException {
if (session instanceof AQjmsSession) {
return ((AQjmsSession)session).createConsumer(
destination,
getMessageSelector(),
new MyCustomType(),
null,
false
);
} else {
//…strange…we can always failback to super.createConsumer()
}
}
}
[/java]

Tags: , , , , ,

Comments are closed.