Java CAPS Tip : Simple Message Tracker and Dynamic JMS Based Message Validator

Building upon my previous Blog entry "Simple Visual Web Pack Implementation of the Work List Manager GUI" I will demonstrate a simple dynamic, JMS based, Message Validation solution that integrates with the Java CAPS Work List Manager (WLM). Although this project is built using Java CAPS 5.1.x it can be imported into the Java CAPS 6 and used in the same way. I also extend the previously defined eInsight Workflow and associated WLM application but I will not describe in detail the implementation of the WLM project or the configuration because these are described in previous entries. I intend to write a future article that will revisit this functionality based on the new features available within Java CAPS 6 and Open ESB.

Resources

Java CAPS Message Validation

The Message Validation and Tracker implementation is based on the Common Message Envelope defined below. This provides a number of elements, in addition to the payload, that will be used to define how the message is tracked, routed and validated. The advantage of using such and enveloping strategy is that we can essentially ignore the actual message content within the common code. Obviously the actual validation components will need to understand the contents of the payload but beyond that the core code is agnostic. The actual XSD associated with this message can be found in the src/wsdl sub-directory of the WebApplication.

XML Message Structure

Given the above structure I envisage using the elements as follows:

Element / Attribute
Description
attribute:alert
Simple flag used as a quick indication that an Alert has been raises for the current message / validation step.
element:id
Unique message id that will be used throughout the message tracking and validation process. This can be either supplied / generated before entering the message tracking system or the first call the the message tracking can be done as a JMS Request-Reply with a null id and one will be generated.
element:type
Free text used to logically group messages. This will be defined within you system.
element:description
Free test description to add any useful information
element:status
Current status of the message; you should should define your own hierarchy.
element:error
Error Message
element:reason
Reason for Error
element:resubmissionQueue
Resubmission Queue for reprocessing
element:resubmissionTopic
Resubmission Topic for reprocessing
element:lastValidationStepProcessed
Last step processed in the repeating Validation steps. This will be incremented on successful validation.
attribute:validation.name
Name of validation step
attribute:validation.jndiName Reference to the location of the validation code. In this example it will refer to the Request-Reply Validation Queue but in a future blog is will have a different meaning.
element:validation.passed Boolean to indicate it is has passed the validation step.
element:validation.reprocessed Boolean to indicate if the step has been reprocessed
element:validation.value Reprocessing count
element:attribute.name Repeating Name / Value pair to be used as required
element:attribute.value
element:payload Actual Message.

The messages tracked using the tracking system will be stored in the same Oracle database where the Java CAPS WLM tables reside. This will allow the development of a simple VWP Front-end that can be used for viewing the Tracked messages and also resolving the associated Message Validation failures written to WLM.

Message Validation

I will assume that prior to entering the Message Validation JCD the appropriate steps, within the XML, will have been populated via some other portion of your application. To facilitate this within the example I have built a Tester project (within the Java CAPS export) and its associated test XML file.

cmValidation

The Message validation functionality will be initiated when a message (of the above structure) appears on the qValidation. At this point the JCD will unmarshall the Message Envelope structure and start to process the Validation Steps from the Last Step Processed. By default it will start at 0 but if we have failed it will restart where it stopped. Messages will be sent to the appropriate Request-Reply Queue, to initiate the Validation, and the returned message will be checked to see if an Alert is to be raised or an error has occurred. In this situation message will be written to the tAlerts Topic and the Validation JCD terminated. Once written to the tAlerts Topic the processing for the message will be under the control of the Message tracking system. Throughout the message Validation steps the tracking system will be called to track the progress of the message. It can be seen from the code below that if no message id is passed to the system it will use the Message Tracking Request-Reply option to generate an id.

    private static final String VALIDATION_QUEUE = "qValidation";

    public void receive( com.stc.connectors.jms.Message input, com.stc.connectors.jms.JMS jmsRequestReply, com.stc.connectors.jms.JMS jmsResponse, com.stc.connectors.jms.JMS jmsAlert, stcgen.fcxotd.urn_xsd_jcaps_wlm_tracking_services_types.MessageDocument trackMessage, com.stc.connectors.jms.JMS jmsTrack )
        throws Throwable
    {
        long msgTimeout = 60000L;
        trackMessage.unmarshalFromString( input.getTextMessage() );
        trackMessage.getMessage().setDescription( "Message Validation" );
        trackMessage.getMessage().setAction( "Validation" );
        com.stc.connectors.jms.Message validationMsg;
        com.stc.connectors.jms.Message trackMsg;
        com.stc.connectors.jms.Message replyMsg;
        int i1 = 0;
        /\*
          Ultimately Request-Reply validation is not the way to do this. Instead we should be calling the SessionBeans directly
          hence the reason the RequestReply queue name is stored in jndiName because when we get to 6 we will call them directly.
         \*/
        try {
            /\*
              Check if this messaged has been tracked before. If so just send a tracker message and if not await a reply with the
              generated message id
             \*/
            if (trackMessage.getMessage().hasId()) {
                jmsTrack.sendText( trackMessage.marshalToString() );
            } else {
                trackMsg = jmsTrack.createTextMessage( trackMessage.marshalToString() );
                replyMsg = jmsTrack.requestReply( msgTimeout, trackMsg );
                if (replyMsg != null) {
                    trackMessage.unmarshalFromString( replyMsg.getTextMessage() );
                }
            }
            // Loop through validation steps
            int startMsg = 0;
            if (trackMessage.getMessage().hasLastValidationStepProcessed()) {
                startMsg = trackMessage.getMessage().getLastValidationStepProcessed();
            }
            for (i1 = startMsg; i1 < trackMessage.getMessage().countValidation(); i1++) {
                trackMessage.getMessage().setLastValidationStepProcessed( i1 );
                validationMsg = jmsRequestReply.createTextMessage( trackMessage.marshalToString() );
                replyMsg = jmsRequestReply.requestReplyTo( msgTimeout, validationMsg, trackMessage.getMessage().getValidation( i1 ).getJndiName() );
                if (replyMsg == null) {
                    trackMessage.getMessage().setAlert( true );
                    trackMessage.getMessage().setError( "Validation Step " + trackMessage.getMessage().getValidation( i1 ).getName() + " failed to return" );
                    trackMessage.getMessage().getValidation( i1 ).setPassed( false );
                    trackMessage.getMessage().getValidation( i1 ).setReprocess( true );
                    trackMessage.getMessage().setStatus( "ALERT" );
                    trackMessage.getMessage().setResubmissionQueue( VALIDATION_QUEUE );
                    jmsAlert.sendText( trackMessage.marshalToString() );
                    break;
                }
                trackMessage.unmarshalFromString( replyMsg.getTextMessage() );
                if (trackMessage.getMessage().getAlert()) {
                    trackMessage.getMessage().setStatus( "ALERT" );
                    trackMessage.getMessage().setResubmissionQueue( VALIDATION_QUEUE );
                    jmsAlert.sendText( trackMessage.marshalToString() );
                    break;
                }
            }
        } catch ( Exception e ) {
            trackMessage.getMessage().setAlert( true );
            trackMessage.getMessage().setError( "Validation Step " + trackMessage.getMessage().getValidation( i1 ).getName() + " throw Exception " + e.getMessage() );
            trackMessage.getMessage().getValidation( i1 ).setPassed( false );
            trackMessage.getMessage().getValidation( i1 ).setReprocess( true );
            trackMessage.getMessage().setResubmissionQueue( VALIDATION_QUEUE );
            trackMessage.getMessage().setStatus( "ALERT" );
            jmsAlert.sendText( trackMessage.marshalToString() );
        }
    }

Message Tracking

The message tracking portion of the system will be initiated by either a message on the qMessageTrack Queue or one on the tAlert Topic. In addition any message appearing in the iAlerts Topic will start the WLM Business Process that will allow designated users to fix the message and then resubmit if required.

cmMessageTracker

The main Message Tracker JCD will simply read the message Envelope and then write it to the Tracking tables. If this is the first time that the message has been received, i.e. no id, the JCD will create an entry in the WLM_MT_TRANSACTION table. This will be used to group all tracking events associated with this message. Next it will take the message passed and store the current information in the WLM_MT_MESSAGE table and followingthis if their are any specific Attributes associated with the message these will be stored in the WLM_MT_ATTRIBUTE table. If this is the first time that this Message has been tracked and the calling process has supplied a ReplyTo Destination then the Message is modified adding the generated id and returned.

Workflow

If the message is placed on the tAlerts Topic the Workflow Business Process will be initiated, see below, this will initiate the standard Java CAPS Work List Manager functionality and allow the User(s) to interact and process Alert messages as described in my previous blog.

bpWLM

On returning from the WLM applications the Business Process will then make a decision in terminating and hence stopping all processing on the message or resubmitting it to the appropriate Queue/Topic for reprocessing.

The Web Application supplied will provide a simple interface to the WLM functionality and can be expanded to add Message tracking functionality as well.

Testing

One the projects have been built and deployed (I am assuming Windows) creating a file called C:\\Temp\\validationIn.xml with the following content will initiate the processing. This will cause the Message Validation JCD to write (Request-Reply) to the qValidation1 and qValidation2 queues and the messages will simply be read by the Test code and response returned. If a value of "Fail" is passed to Validation2 in the value element it will cause this to fail thus allowing you to simulate a failure situation.

<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2007 sp2 (http://www.altova.com)-->
<params:Message alert="false" xsi:schemaLocation="urn:xsd:jcaps:wlm:tracking:services:types MessageValidatorComplexTypes.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:params="urn:xsd:jcaps:wlm:tracking:services:types">
    <params:description>String</params:description>
    <params:lastValidationStepProcessed>0</params:lastValidationStepProcessed>
    <params:validation jndiName="qValidation1" name="Validation1">
        <params:value>String</params:value>
    </params:validation>
    <params:validation jndiName="qValidation2" name="Validation2">
        <params:value>Pass</params:value>
    </params:validation>
    <params:attribute>
        <params:name>Attr1</params:name>
        <params:value>String</params:value>
    </params:attribute>
    <params:attribute>
        <params:name>Attr2</params:name>
        <params:value>String</params:value>
    </params:attribute>
    <params:payload>String</params:payload>
</params:Message>

A future blog entry will show how this functionality can be implemented / integrated using the new Java CAPS 6 features (although this will work as a Java CAPS 6 application) and how we could rebuild within Open ESB.



Resources


Comments:

Post a Comment:
Comments are closed for this entry.
About

As a member of the Oracle A-Team we specialise in enabling and supporting the Oracle Fusion Middleware communities.

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today