Pages

Thursday, February 14, 2008

ESB adapter failover

For 24 uptime systems is it very important to have an easy and quick failover. In this blog I will explain how you can implement an ESB failover without creating adapter for the primary and secondary systems. In this example I use jdeveloper 10.1.3 and I use jms adapters but you can implement this with other out adapters too. To do this I use a xslt to change the header of the jms adapter to set JMSDestinationName with the primary or secondary resource. To know if the backoffice system are in failover I use a domain value map.
The first step is to create two jms queues in the scott schema. The first is called jms_in and the failover queue is called jms_in2. Here is the code to create the queues in plsql

begin
sys.dbms_aqadm.create_queue_table(
queue_table => 'JMS_IN_TABLE',
queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY, ENQ_TIME',
compatible => '10.0.0',
primary_instance => 0,
secondary_instance => 0,
storage_clause => 'tablespace users pctfree 10 initrans 1 maxtrans 255 storage ( initial 64K minextents 1 maxextents unlimited )');
end;
/
begin
sys.dbms_aqadm.create_queue(
queue_name => 'JMS_IN',
queue_table => 'JMS_IN_TABLE',
queue_type => sys.dbms_aqadm.normal_queue);
end;
/
begin
dbms_aqadm.start_queue( queue_name =>'JMS_IN' ,enqueue => true ,dequeue => true );
end;
/

Now we can add the jms adapters to the oc4j-ra.xml of the oc4j soa container ( folder application-deployments\default\JmsAdapter )

<connector-factory location="eis/Jms/scott" connector-name="Jms Adapter">
<config-property name="connectionFactoryLocation" value="java:comp/resource/jms_scott/QueueConnectionFactories/myQCF"/>
<config-property name="factoryProperties" value=""/>
<config-property name="acknowledgeMode" value="AUTO_ACKNOWLEDGE"/>
<config-property name="isTopic" value="false"/>
<config-property name="isTransacted" value="true"/>
<config-property name="username" value="scott"/>
<config-property name="password" value="tiger"/>
<connection-pooling use="none">
</connection-pooling>
<security-config use="none">
</security-config>
</connector-factory>

<connector-factory location="eis/Jms/scott2" connector-name="Jms Adapter">
<config-property name="connectionFactoryLocation" value="java:comp/resource/jms_scott2/QueueConnectionFactories/myQCF"/>
<config-property name="factoryProperties" value=""/>
<config-property name="acknowledgeMode" value="AUTO_ACKNOWLEDGE"/>
<config-property name="isTopic" value="false"/>
<config-property name="isTransacted" value="true"/>
<config-property name="username" value="scott"/>
<config-property name="password" value="tiger"/>
<connection-pooling use="none">
</connection-pooling>
<security-config use="none">
</security-config>
</connector-factory>


We have to change the application.xml to add the two resource adapters


<resource-provider name="jms_scott" class="oracle.jms.OjmsContext">
<description>oc4j-jms loop back resource provider</description>
<property name="url" value="jdbc:oracle:thin:scott/tiger@localhost:1521:orcl" />
</resource-provider>
<resource-provider name="jms_scott2" class="oracle.jms.OjmsContext">
<description>oc4j-jms loop back resource provider</description>
<property name="url" value="jdbc:oracle:thin:scott/tiger@localhost:1521:orcl" />
</resource-provider>

Now we can add the jms adapter to esb project. I use jms as a outgoing adapter and use a file adapter as incoming.

It is important to name the resource provider jms_scott because we added this resource to the application.xml. The destination name is primary location url, in my case java:comp/resource/jms_scott/Queues/SCOTT.JMS_IN . jms_scott is the primary resource and SCOTT.JMS_IN is the schema name with the queue name. The secondary location url looks like this java:comp/resource/jms_scott2/Queues/SCOTT.JMS_IN2.

Connect the router to the file router. It looks like this

The next step is to create a domain value map in the esb console. With this domain we can control the esb to use the failover adapter resources.

the xml looks like this

<?xml version="1.0" encoding="UTF-8"?>
<dvm name="Failover" isNew="null">
<description>failover description</description>
<columns>
<column name="System"/>
<column name="failover"/>
<column name="primary"/>
<column name="secondary"/>
</columns>
<rows>
<row>
<cell>esb</cell>
<cell>Yes</cell>
<cell>java:comp/resource/jms_scott/Queues/SCOTT.JMS_IN</cell>
<cell>java:comp/resource/jms_scott2/Queues/SCOTT.JMS_IN2</cell>
</row>
</rows>
</dvm>

The last step is to create transformation between the router and the jms out adapter. In this xslt I also set the priority on the jms queue. Add the variables above xsl:template match

<xsl:variable name="failover"
select="orcl:lookup-dvm('Failover','System','esb','failover','No')"/>
<xsl:variable name="location">
<xsl:choose>
<xsl:when test="starts-with($failover, 'Yes')">
<xsl:value-of select="orcl:lookup-dvm('Failover','System','esb','primary','No')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="orcl:lookup-dvm('Failover','System','esb','secondary','No')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="outJMSDestinationName"
select="ehdr:setOutboundHeader('/jhdr:JMSOutboundHeadersAndProperties/jhdr:JMSOutboundHeaders/jhdr:JMSDestinationName', $location, 'jhdr=http://xmlns.oracle.com/pcbpel/adapter/jms/;')"/>
<xsl:variable name="priority" select="/imp1:Message/imp1:Priority"/>
<xsl:variable name="tracking" select="/imp1:Message/imp1:RunID"/>
<xsl:variable name="outCorrelationID"
select="ehdr:setOutboundHeader('/jhdr:JMSOutboundHeadersAndProperties/jhdr:JMSOutboundHeaders/jhdr:JMSCorrelationID', $tracking, 'jhdr=http://xmlns.oracle.com/pcbpel/adapter/jms/;')"/>
<xsl:variable name="outJMSPriority"
select="ehdr:setOutboundHeader('/jhdr:JMSOutboundHeadersAndProperties/jhdr:JMSOutboundHeaders/jhdr:JMSPriority', $priority, 'jhdr=http://xmlns.oracle.com/pcbpel/adapter/jms/;')"/>
<xsl:template match="/">

The first step is to know if the system is in failover. Then we now which resource we need and set this value on the JMSDestinationName.
If we change the domain value of the failover column to Yes then the message is added to the jms_in2 queue and if the value is No then the messages is added to the jms_in queue.

1 comment:

  1. Edwin, Thanks for the great work and post, pictorial representation for this failover strategy more appreciated

    ReplyDelete