Authoring message flow patterns using WebSphere Message Broker APIs

This article shows you how to author WebSphere Message Broker flow patterns using the Message Broker Java API and Java programming. The Java code can then be executed on any machine with a JRE, without installing the WebSphere Message Broker Toolkit to develop message flow instances from authored patterns.

Rahul Gupta (rahul.gupta@us.ibm.com), Advisory IT Specialist, IBM

Photo of Rahul GuptaRahul Gupta is an Advisory IT Specialist with IBM Global Technology Services. He is a Certified SOA Architect with eight years experience in IBM messaging technologies, and currently, he works as a middleware consultant for various clients in North America. His core experience is in lab testing, performance tuning, and development for WebSphere Message Broker and WebSphere MQ. He has been a speaker on messaging-related topics at various WebSphere conferences, and has been recognized as an inventor by the IBM Innovation Community. He has also authored IBM Redbooks and developerWorks articles on messaging and application infrastructure. You can contact Rahul at rahul.gupta@us.ibm.com.



Devipriya Selvarajan (dselvara@in.ibm.com), Messaging Consultant, IBM

Photo of Devipriya SelvarajanDevipriya Selvarajan is a Messaging Consultant on the WebSphere Lab Services team. She handles Business Partner enablement for WebSphere Transformation Extender, WebSphere Message Broker, WebSphere MQ, and WebSphere DataPower SOA Appliances. You can contact Devipriya at dselvara@in.ibm.com.



02 May 2012

Also available in Chinese

Introduction

A pattern is a reusable solution to a common problem within a given context. It is imperative for customers to create patterns for complex reusable message flows, so that they can reuse the flow in a different scenario simply by changing some of the configuration values. A pattern provides a reusable solution that encapsulates a tested approach to solving a common architecture, design, or deployment task in a particular context. When you decide to use a pattern, much of design and development work has already been completed for you, and you reduce development, testing, and operational efforts which saves time and money.

IBM® WebSphere® Message Broker V8 extends the Message Broker Java™ API, and enables you to modify user-defined pattern instances or develop of new message flow applications using Java code. In the past, you had to use the Message Broker Toolkit to develop message flow applications, but the new Java API enables you to avoid the Toolkit and develop message flows using any Java IDE.

WebSphere Message Broker API

The Message Broker API is a programming interface that enables applications to control brokers and their resources through a remote interface. The Message Broker API is also known as the Configuration Manager Proxy (CMP) API. The Configuration Manager was removed in V7, and the full name of the API has changed, but the terms CMP application and CMP API have been retained, and are used in the information center to refer to the Message Broker API, to provide continuity and consistency with the JAR file ConfigManagerProxy.jar, which provides the required classes. Figure 1 below shows the packages available in ConfigManagerProxy.jar -- the ones circled in red provide classes for Message Broker APIs.

Figure 1. Java packages in ConfigManagerProxy.jar
Java packages in ConfigManagerProxy.jar

The Message Broker API consists solely of a Java implementation, and is referred to as the Message Broker Java API. User applications have complete access to the broker functions and resources through the set of Java classes that constitute the CMP. Use the CMP API to interact with the broker to perform the following tasks:

  • Create and modify message flow applications
  • Deploy BAR files
  • Change broker configuration properties
  • Create, modify, and delete execution groups
  • Inquire and set the status of the broker and its associated resources, and get informed if status changes regarding:
    • Execution groups
    • Deployed message flows
    • Deployed files used by the message flows (such as JAR files)
  • View the Administration log
  • View the Activity log

For applications that interact with Message Broker, the Java classes sit logically between the user application and Message Broker, inside the JVM of the user application. For connectivity, the API requires the WebSphere MQ Classes for Java. As shown in Figure 2, a message flow pattern program is a powerful user application that can instantiate instances of message flows based on a pattern definition:

Figure 2. Message Broker APIs
Message Broker APIs

Scenario

As shown below, JKRetail is a large American retailer with multiple stores around the country (red pins) and a central office in Nebraska (green pin):

Figure 3. JKRetail stores and central office
JKRetail stores and central office

As part of an inventory management and sales forecasting process, each store sends inventory and sales data to the central office in XML format using flat files and FTP. Batch processing is performed on the data and evaluation is done to fulfill the inventory requirements of the stores based on factors such as month, upcoming holidays, and local cultural trends. The central office assigns message flows to each store to read data from the files and perform batch processing. Data is sent in individual records for back-end intelligent processing. Figure 4 shows the various message flows associated with different stores:

Figure 4. Store to central office integration for inventory management
Store to central office integration for inventory management

These integration flows are fairly simple and have the functional logic of reading an individual XML record from a file and sending a single record for back-end processing through WebSphere MQ queues. Figure 5 below shows a sample message flow used for Store 106 inventory integration:

Figure 5. Inventory management integration for JKRetail Store 106
Inventory management integration for JKRetail Store 106

JKRetail has a requirement to develop message flows based on a pattern if they have to open new stores in a new location with new store IDs, in order to minimize development time and effort. The solution for this requirement is to implement a pattern using WebSphere Message Broker APIs and is described in detail in the rest of this article.

Creating a pattern-based solution involves three steps:

  1. Pattern definition criteria
  2. Pattern project content
  3. Pattern instantiation

1. Pattern definition criteria

Pattern definition criteria includes capturing information about all of the specific components needed to determine the behavior of a message flow pattern. To define the behavior of the inventory management batch processing pattern, start by identifying the components involved and their properties. Table 1 below shows the components and their associated properties needed to author the batch processing pattern for JKRetail:

Table 1. Components and properties required to design batch processing pattern
ComponentPropertyProperty details
StoreSTORE_IDStore number, such as 107
MessageFlowMF_LOCATIONPhysical location on disk where the message flow will be created
MF_NAMEName of message flow
FileInput NodeFILE_INPUT_NAMEName of FileInput node
FILE_INPUT_DIRLocation of incoming inventory data files
BATCH_FILE_TYPEIncoming file type or name pattern
FILE_INPUT_POLLINGFrequency to scan for new contents
Compute NodeCOMPUTE_NAMEName of Compute node
ESQL_FILE_NAMEName of ESQL module
MQOutput NodeMQOUTPUT_NAMEName of MQOutput node
MQOUTPUT_QM_NAMEName of queue manager MQOutput node should connect
MQOUTPUT_Q_NAMEName of queue to perform MQPUT

2. Pattern project content

The pattern project will contain:

  • Configuration file -- This file will contain the properties defined while setting up pattern definition criteria.
  • Java code class -- This Java class will be used for pattern implementation, and all instances of the inventory integration message flow will be instantiated from this class.

The section shows you how to create the configuration file and the batch processing pattern Java code. Start by creating the configuration file: create a flat named config.txt with the contents shown in Listing 1 below, which are derived from the properties defined in Table 1. Name-value pairs specified in config.txt will be used when instantiating message flows for new retail stores:

Listing 1. Contents of configuration file
STORE_ID=107
MF_LOCATION=C:\JKRetailInventoryIntegration
MF_NAME=InventoryFromStore107
FILE_INPUT_NAME=Inventory 107 Input
FILE_INPUT_DIR=C:\INBOUND\STORE107
BATCH_FILE_TYPE=xml
FILE_INPUT_POLLING=10
COMPUTENODE_NAME=FTP_TO_MQ
ESQL_FILE_NAME=InventoryFromStore107
MQOUTPUT_NAME=Inventory Backend Processing
MQOUTPUT_QM_NAME=ESB01
MQOUTPUT_Q_NAME=INVENTORY.BACKEND

Create a Java class BatchProcessingPattern with a main() method. Add a class variable configMap of type HashMap, which will be used to store and refer pattern configuration properties, as shown in Listing 2:

Listing 2. Create Java class BatchProcessingPattern
packagecom.ibm.broker.pattern;

importjava.util.HashMap;

public class BatchProcessingPattern {

static HashMap <String,String>configMap = new HashMap <String,String>();

   public static void main(String[] args) {
      File msgFlow = null;
      File esql = null;
      FileInputNodefileInput = null;
      ComputeNode compute = null;
      MQOutputNodemqoutput = null;
   }
}

The first step is to read the configuration file and store name-value pairs in configMap. Listing 3 below shows the implementation of the method readConfigFile(). Create this method in class BatchProcessingPattern:

Listing 3. readConfigFile() method to read and store contents of pattern configuration file
public static void readConfigFile(String filename)
   {
      File file = newFile(filename);
      BufferedReaderbr = null;
      try {
         br = newBufferedReader(newFileReader(file));
      } catch (FileNotFoundExceptionfnfe) {
         fnfe.printStackTrace();
      }
      String line = null;
      longtotalLinesProcessed = 0;

      try {
         while((line=br.readLine())!=null){
            totalLinesProcessed ++;
            String element[]=line.split("=");
            configMap.put( element[0], element[1] );
         }
      } catch (IOExceptionioe) {
         ioe.printStackTrace();
      }
      finally
      {
         try {
            br.close();
         } catch (IOExceptionioe) {
            ioe.printStackTrace();
         }
      }
   }

As shown in Listing 4 below, create the physical message flow file by creating a method createMessageFlowFile() in class BatchProcessingPattern. A message flow with the name valueof(MF_NAME).msgflow will be created in location valueof(MF_LOCATION). (valueof() represents a technique to retrieve values from the entries in the HashMap object configMap.)

Listing 4. createMessageFlowFile() method to create new .msgflow file
public static File createMessageFlowFile()
{
File msgFlow = newFile(configMap.get("MF_LOCATION").toString()+"\\"+
               configMap.get("MF_NAME").toString()+".msgflow");

   if(!msgFlow.exists())
   {
      try {
         msgFlow.createNewFile();
      } catch (IOExceptionioe) {
         ioe.printStackTrace();
      }
   }
returnmsgFlow;
}

Listing 5 below shows the implementation to generate a physical ESQL file by creating a method createESQLFile() in class BatchProcessingPattern. The ESQLfile with name valueof(ESQL_FILE_NAME).esql will be created in location valueof(MF_LOCATION):

Listing 5. createESQLFile() method to create new .esql file
public static File createESQLFile()
{
File esql = newFile(configMap.get("MF_LOCATION").toString()+"\\"+
            configMap.get("ESQL_FILE_NAME").toString()+".esql");

   if(!esql.exists())
   {
      try {
         esql.createNewFile();
      } catch (IOExceptionioe) {
         ioe.printStackTrace();
      }
   }
returnesql;
}

Now the .msgflow and .esql files are created. Add FileInput node to the message flow. Some of the FileInput node properties are set based on the configuration values in config,txt. Create method addFileInputNode() as shown in Listing 6:

Listing 6. addFileInputNode() method to create FileInputNode
public static FileInputNode addFileInputNode(MessageFlowmfST)
{
   FileInputNodefileInput = (FileInputNode)mfST.getNodeByName
                            (configMap.get("FILE_INPUT_NAME").toString());
   if(fileInput  == null)
   {
      fileInput=newFileInputNode();
      fileInput.setNodeName(configMap.get("FILE_INPUT_NAME").toString());
      fileInput.setInputDirectory(configMap.get("FILE_INPUT_DIR").toString());
      fileInput.setFilenamePattern("*"+configMap.get("STORE_ID").toString()+
         "*."+configMap.get("BATCH_FILE_TYPE").toString());
      fileInput.setProcessedFileAction(ENUM_FILEINPUT_PROCESSEDFILEACTION.
         moveToArchiveWithTimestamp);
      fileInput.setRecordDetection(ENUM_FILEINPUT_RECORDDETECTION.delimited);
      fileInput.setRecordDelimiter(ENUM_FILEINPUT_RECORDDELIMITER.eitherLineend);
      fileInput.setWaitInterval(Integer.parseInt(configMap.get
         ("FILE_INPUT_POLLING").toString()));
      mfST.addNode(fileInput);
   }
   returnfileInput;
}

Create method addComputeNode() in class BatchProcessingPattern to add ComputeNode, as shown in Listing 7:

Listing 7. addComputeNode() method to create ComputeNode
public static ComputeNode addComputeNode(MessageFlowmfST)
{
   ComputeNode compute = (ComputeNode)mfST.getNodeByName
                         (configMap.get("COMPUTENODE_NAME").toString());
   if(compute == null)
   {
      compute = newComputeNode();
      compute.setNodeName(configMap.get("COMPUTENODE_NAME").toString());
      mfST.addNode(compute);
   }
return compute;
}

Create method addMQOutputNode() in class BatchProcessingPattern to add MQOutputNode, as shown in Listing 8:

Listing 8. addMQOutputNode() method to create MQOutputNode
public static MQOutputNode addMQOutputNode(MessageFlowmfST)
{
   MQOutputNodemqoutput = (MQOutputNode)mfST.getNodeByName(configMap.
                          get("MQOUTPUT_NAME").toString());
   if(mqoutput == null)
   {
      mqoutput = newMQOutputNode();
      mqoutput.setNodeName(configMap.get("MQOUTPUT_NAME").toString());
      mqoutput.setQueueManagerName(configMap.get("MQOUTPUT_QM_NAME").toString());
      mqoutput.setQueueName(configMap.get("MQOUTPUT_Q_NAME").toString());
      mfST.addNode(mqoutput);
   }
returnmqoutput;
}

Create method addESQLContents() in class BatchProcessingPattern to add contents in ESQL file, as shown in Listing 9:

Listing 9. addESQLContents() method to create ESQL code
public static void addESQLContents(File esql)
{
   DataOutputStream data =  null;
   try
   {
   data = newDataOutputStream(newFileOutputStream(esql,false));
   data.write(new String(
   "CREATE COMPUTE MODULE Store_"+configMap.get("STORE_ID").toString()+
   "      "_FTP_TO_MQ_Compute\n"+
   "   CREATE FUNCTION Main() RETURNS BOOLEAN\n"+
   "   BEGIN\n"+
   "      -- CALL CopyMessageHeaders();\n"+
   "      CALL CopyEntireMessage();\n"+
   "      RETURN TRUE;\n"+
   "   END;\n\n"+
   "   CREATE PROCEDURE CopyMessageHeaders() BEGIN\n"+
   "      DECLARE I INTEGER 1;\n"+
   "      DECLARE J INTEGER;\n"+
   "      SET J = CARDINALITY(InputRoot.*[]);\n"+
   "      WHILE I < J DO\n"+
   "         SET OutputRoot.*[I] = InputRoot.*[I];\n"+
   "         SET I = I + 1;\n"+
   "      END WHILE;\n"+
   "   END;\n\n"+
   "   CREATE PROCEDURE CopyEntireMessage() BEGIN\n"+
   "      SET OutputRoot = InputRoot;\n"+
   "   END;\n"+
   "END MODULE;").getBytes());
   }
   catch(FileNotFoundExceptionfnfe)
   {
   fnfe.printStackTrace();
   }
   catch(IOExceptionioe)
   {
   ioe.printStackTrace();
   }
   finally
   {
      try {
         data.close();
         } catch (IOExceptionioe) {
         ioe.printStackTrace();
      }
   }
}

Create method connectNodes() in class BatchProcessingPattern to connect nodes with each other, as shown in Listing 10:

Listing 10. connectNodes() method to connect nodes in message flow
public static void connectNodes(MessageFlowmfST,FileInputNodefileInput, 
      ComputeNode compute, MQOutputNodemqoutput)
{
   mfST.connect(fileInput.OUTPUT_TERMINAL_OUT, compute.INPUT_TERMINAL_IN);
   mfST.connect(compute.OUTPUT_TERMINAL_OUT, mqoutput.INPUT_TERMINAL_IN);
}

Create method attachESQLModule() in class BatchProcessingPattern to attach ESQL module with compute node, as shown in Listing 11:

Listing 11. attachESQLModule() method to attach ESQL module with compute node
public static void attachESQLModule(File esql, ComputeNode compute)
{
   try {
   ESQLFileesqlFile = newESQLFile(esql);
   Vector<ESQLModule>esqlModules = esqlFile.getEsqlModules();
   compute.setComputeExpression(esqlModules.get(0));
   } catch (IOExceptionioe) {
      ioe.printStackTrace();
   }
}

Update the main method to call the previously created methods in a logical sequence, as shown in Listing 12:

Listing 12. Update main() method
public static void main(String[] args) 
{

   File msgFlow = null;
   File esql = null;
   FileInputNodefileInput = null;
   ComputeNode compute = null;
   MQOutputNodemqoutput = null;

   try
   {
   readConfigFile(args[0]);
       msgFlow = createMessageFlowFile();
       esql = createESQLFile();
       MessageFlowmfST = FlowRendererMSGFLOW.read(msgFlow);
       fileInput = addFileInputNode(mfST);
       compute = addComputeNode(mfST);
       mqoutput = addMQOutputNode(mfST);
       addESQLContents(esql);
       connectNodes(mfST, fileInput, compute, mqoutput);
       attachESQLModule(esql, compute);
       FlowRendererMSGFLOW.write(mfST,configMap.get("MF_LOCATION").toString());
   }
   catch(IOExceptionioe)
   {
       ioe.printStackTrace();
   }
   catch(MessageBrokerAPIExceptionmbae)
   {
       mbae.printStackTrace();
}

3. Pattern instantiation

In pattern instantiation, you apply the pattern and create an instance of the pattern, which is identified by the properties in the pattern definition criteria. Multiple instances of a pattern instance can exist at one time. Pattern instances are independent of one another, although they can share the same argument values. This section explains how to execute the pattern generation program that creates an instance of the reusable message flow application.

To develop and process Java applications that use the Message Broker Java API, install the following software on your local development environment:

  • An IBM JDK to develop Message Broker Java API applications. Message Broker does not supply a JDK, so a supported JDK environment should be installed separately.
  • An IBM Java Runtime Environment (JRE) to run the applications.
  • A Java IDE for development, such as Eclipse or IBM Rational Application Developer.

Running the code in an Eclipse environment

Once the program is ready for execution, you can use the Java IDE or the command line to execute the program. Here are the steps to execute the sample program provided in this article using Eclipse:

  1. In your Eclipse environment, import the sample project, which you can download at the bottom of the article.
  2. Right click on the project and select Properties
  3. Click on Java Build Path, select the Libraries tab, and click Add External Jars.
  4. To set up the build environment, navigate to the install_dir/classes subdirectory. For example, for Version 8.0.0.0 on Windows 32-bit operating system editions, navigate to the directory C:\Program Files\IBM\MQSI\8.0.0.0\classes. Select the file ConfigManagerProxy.jar, and click Open. The file is added to the list in the window for the Libraries tab.
  5. The sample program expects the location of configuration file to be passed as a program argument, which you can set in Run Configuration properties, as shown below:
    Figure 6. Set program argument to pass location of configuration file
    Set program argument to pass location of configuration file
  6. Edit config.txt, which holds the configuration parameters, and enter the values for your system environment.
  7. Build and run the sample project.

Running the code from the command-line

You can also use system facilities to configure environment variables on Windows machines to run your Message Broker Java API applications:

  1. Update the CLASSPATH environment variable: Add the Message Broker Java API JAR file to your CLASSPATH. For example: set CLASSPATH = %CLASSPATH%;%install_dir%\classes\ConfigManagerProxy.jar.
  2. In the same way, add your Java development directory to the CLASSPATH in the same way.
  3. Use the tools provided by your JDK to build and run the sample project.

Automation extension

After the message flows are instantiated, you can automate the tasks of BAR file creation and deployment. BAR files can only be created by using the Message Broker toolkit or the mqsicreatebar command. For more information on creating BAR files, see the topic mqsicreatebar command in the WebSphere Message Broker V8 information center. You use the mqsicreatebar command with Java System APIs to execute external commands. You can automate the deployment process by authoring a small Java program, as explained in Deploying a broker archive file using the CMP API.

Conclusion

This article showed you how to create message flow patterns to reduce the development life cycle of reusable flows. You also:

  • Learned about WebSphere Message Broker APIs
  • Learned how to use these API to create message flow patterns
  • Created a message flow pattern project for instantiating message flows
  • Instantiated a message flow instance from a pattern
  • Learned about further BAR file compile and deployment options

Acknowledgement

The authors would like to thank Dominic Storey, a Software Engineer on the WebSphere Message Broker Development team at the IBM Hursley Laboratory in the UK, for his valuable suggestions and feedback.


Download

DescriptionNameSize
Code sampleMessageBrokerPattern.zip4 KB

Resources

  • WebSphere Message Broker patterns resources
  • General WebSphere Message Broker resources
  • WebSphere resources
  • developerWorks resources
    • Trial downloads for IBM software products
      No-charge trial downloads for selected IBM® DB2®, Lotus®, Rational®, Tivoli®, and WebSphere® products.
    • developerWorks blogs
      Join a conversation with developerWorks users and authors, and IBM editors and developers.
    • developerWorks cloud computing resources
      Access the IBM or Amazon EC2 cloud, test an IBM cloud computing product in a sandbox, see demos of cloud computing products and services, read cloud articles, and access other cloud resources.
    • developerWorks tech briefings
      Free technical sessions by IBM experts to accelerate your learning curve and help you succeed in your most challenging software projects. Sessions range from one-hour virtual briefings to half-day and full-day live sessions in cities worldwide.
    • developerWorks podcasts
      Listen to interesting and offbeat interviews and discussions with software innovators.
    • developerWorks on Twitter
      Check out recent Twitter messages and URLs.
    • IBM Education Assistant
      A collection of multimedia educational modules that will help you better understand IBM software products and use them more effectively to meet your business requirements.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=812687
ArticleTitle=Authoring message flow patterns using WebSphere Message Broker APIs
publish-date=05022012