Time for action – testing InVM transactions

Let us now see the real effect of the invmTransacted attribute on a servic. Follow these steps:

  1. In JBoss Developer Studio, select Chapter5 and expand the esbcontent folder. You will see there is another file called jboss-esb-transacted.xml:
    Time for action – testing InVM transactions
  2. Before we rename it, we need to remove the deployed application from the server. Click on the Servers tab, right click on the Chapter5 application and click Remove.
    Time for action – testing InVM transactions
  3. Rename jboss-esb.xml to jboss-esb-first.xml.
  4. Open jboss-esb-transacted.xml.
  5. Select File | Save As, choose Chapter5/esbcontent/META-INF and enter the File name as "jboss-esb.xml".
    Time for action – testing InVM transactions
  6. Click OK.
  7. Now the esbcontent folder should look like this:
    Time for action – testing InVM transactions
  8. Select the Chapter5 project and click Run | Run As | Run on Server.
  9. Select the src folder, expand it till the SendEsbMessage.java file is displayed in the tree. Now click Run | Run As | Java Application.

    You will notice that the following message is printed six times on the server console:

    INFO  [STDOUT] Body: Chapter 5 says Hello!
    INFO  [STDOUT] About to cause an exception
    

What just happened?

You created a transacted InVM listener and, when a runtime exception was thrown, the transaction was rolled back resulting in the message being placed back in the InVM message queue. This happened five times before the rollback discarded the message, sending it to the DLQ.

Here is the configuration. Examine the highlighted section very carefully:

<providers>
  <jms-provider connection-factory="ConnectionFactory"
                name="JBossMQ">
    <jms-bus busid="Chapter5EsbChannel1">
      <jms-message-filter dest-name="queue/chapter5_Request_esb1"
                          dest-type="QUEUE" transacted="false"/>
    </jms-bus>
    <jms-bus busid="Chapter5EsbChannel2">
      <jms-message-filter dest-name="queue/chapter5_Request_esb2"
                          dest-type="QUEUE" transacted="true"/>
    </jms-bus>
  </jms-provider>
</providers>
<services>
  <service category="Chapter5Sample"
           description="A template for Chapter5"
           name="Chapter5Service">
    <listeners>
      <jms-listener busidref="Chapter5EsbChannel1"
                    name="Chapter5provider"/>
    </listeners>
    <actions mep="OneWay">
      <action class="org.jboss.soa.esb.actions.SystemPrintln"
              name="printMessage">
        <property name="message" value="Incoming"/>
      </action>
      <action class="org.jboss.soa.esb.actions.StaticRouter"
              name="RouteToB">
        <property name="destinations">
          <route-to service-category="Chapter5Sample"
                    service-name="Chapter5BService"/>
        </property>
      </action>
    </actions>
  </service>
  <service category="Chapter5Sample" description="Chapter5 B Service"
           invmScope="GLOBAL" name="Chapter5BService"
           invmTransacted="true">
    <actions mep="OneWay">
      <action class="org.jboss.soa.esb.samples.chapter5.MyAction"
              name="processTransaction"/>
      <!--  Will throw an Exception. This should trigger the transaction to be rolledback and the message placedback onto the InVM queue.  -->
      <action class="org.jboss.soa.esb.samples.chapter5.MyAction"
              name="throwException" process="causesException"/>
      <action class="org.jboss.soa.esb.actions.SystemPrintln"
              name="printMessage">
        <property name="message" value="Outgoing"/>
      </action>
    </actions>
  </service>
</services>

Have a go hero – non transacted InVM listener

Go ahead and remove the invmTransacted attribute and see how the application behaves.

InVM message optimization

One additional optimization available to the InVM transport is the ability to pass messages using pass-by-reference semantics. This removes the necessity to serialize the message in one service scope and deserialize it in the target service scope.

While this does increase the performance of communication over the InVM transport there are caveats which must be understood:

The message parts accessed in the target service must share a ClassLoader scope with the invoking context

  • Care must be taken not to modify the message within multiple services at the same time

The first issue usually arises when a message part is defined using different definitions of a common class or interface, leading to ClassCastExceptions being raised when the message part is accessed. This will normally occur when the two service scopes are each deployed with a JAR containing the common class or interface. If this cannot be rectified then the pass-by-reference semantics can be explicitly disabled, forcing the message to be serialized in the originating context and deserialized in the target context.

The second issue occurs when the message reference has been passed by reference to the target service yet the originating context continues to modify the contents of the message. These modifications will be visible to the target service although, as a result of the concurrent nature of the execution, it will always be uncertain as to when this will occur. This leads to undesirable race conditions within the application, often hard to track down. If it is not possible to modify the behavior of the services then disabling the pass-by-reference semantics will cause a separate instance of the message to be delivered to the target service as a consequence of the serialization/deserialization.

The pass-by-reference semantics are disabled by explicitly enabling pass-by-value on the service, done by setting the inVMPassByValue property on the <service> element to true. An example configuration would look like this:

<service category="Chapter5Sample" name="Chapter5Service"
         invmScope="GLOBAL">
  <property name="inVMPassByValue" value="true"/>
</service>

Have a go hero – examine the body address

Modify the custom action to print the body object's address using Integer.toHexString(System.identityHashCode(message.getBody())) and see what gets printed when it is printed both from Chapter5Service and Chapter5BService. You will have to add MyAction to your service like this:

<service category="Chapter5Sample"
         description="A template for Chapter5"
         name="Chapter5Service">
  <listeners>
    <jms-listener busidref="Chapter5EsbChannel1"
                  name="Chapter5provider"/>
  </listeners>
  <actions mep="OneWay">
    <action class="org.jboss.soa.esb.actions.SystemPrintln"
            name="printMessage">
      <property name="message" value="Incoming"/>
    </action>

    <action class="org.jboss.soa.esb.samples.chapter5.MyAction"
            name="printAddress"/>
    <action class="org.jboss.soa.esb.actions.StaticRouter"
            name="RouteToB">
      <property name="destinations">
        <route-to service-category="Chapter5Sample"
                  service-name="Chapter5BService"/>
      </property>
    </action>
  </actions>
</service>
<service category="Chapter5Sample" description="Chapter5 B Service"
         invmScope="GLOBAL" name="Chapter5BService">
  <actions mep="OneWay">
    <action class="org.jboss.soa.esb.samples.chapter5.MyAction"
            name="printAddress"/>   
  </actions>
</service>

Your MyAction.java file would look like this:

public Message process(Message message) throws Exception {
    System.out.println("Body: " + Integer.toHexString(System.identityHashCode(message.getBody())));
    return message;
}

Does it change when inVMPassByValue is set to true?

Controlling InVM message delivery

One of the problems which may surface when using the InVM transport is that the target service may become swamped by the incoming messages, with the message originators being able to send messages to the service faster than the service can process them.

JBoss ESB includes a mechanism which enables the automatic throttling of the message originator in order to prevent this scenario, known as lock-step delivery.

The "lock-step" delivery mechanism blocks the originator until the service is in a position to consume the message or until a specified timeout has occurred, preventing the originator from producing messages at a significantly faster rate than the consumer can process.

It should be noted that this is not a synchronous delivery mechanism, it is the delivery of the message which releases the originator and not a response from the service.

Lock-step delivery is disabled by default but can be explicitly enabled on a service using the inVMLockStep and inVMLockStepTimeout properties.

  • inVMLockStep: Set this to true to enable lock-step delivery.
  • inVMLockStepTimeout: The maximum number of milliseconds that the originator will be blocked while awaiting the consumption of the message by the target service. If not specified then it will default to 10 seconds.

An example configuration with lock-step delivery enabled would look like this:

<service category="Chapter5Sample" name="Chapter5Service"
         invmScope="GLOBAL">
  <property name="inVMLockStep" value="true"/>
  <property name="inVMLockStepTimeout" value="4000"/>
</service>

Note

When using InVM within the scope of a transaction, lock-step delivery will be disabled. The reason for this is that the transactional delivery of the message will not occur until the enclosing transaction successfully commits.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.218.215