Create Unit Test for Drools Ruleflow

Introduction

Drools is a Business Rules Management System (BRMS) solution. For more information :
https://www.drools.org/learn/documentation.html

The aim of this article will provide information how to realize a Unit test of drools ruleflow using Junit.

Create a ruleflow

This link will show you how to create a ruleflow with Drools : https://access.redhat.com/documentation/en-US/JBoss_Enterprise_SOA_Platform/4.3/html/JBoss_Rules_Reference_Guide/ch05s08s03.html

Let’s say the ruleflow name is “my_basic_ruleflow.rf”. The processName is my_basic_ruleflow.

Create your Unit Test

This is a simple Junit Test to launch the processName “my_basic_ruleflow”.
It will launch the ruleflow and executes all part of the ruleflow.


import org.drools.SystemEventListenerFactory;
import org.drools.agent.KnowledgeAgent;
import org.drools.agent.KnowledgeAgentConfiguration;
import org.drools.agent.KnowledgeAgentFactory;
import org.drools.definition.KnowledgePackage;
import org.drools.io.ResourceChangeScannerConfiguration;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;

public class TestRuleflow {

    @Test
    public void TestSimpleRuleflow() {
        try {
            init(); 

            final StatefulKnowledgeSession session = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
            String processName = "my_basic_ruleflow";
            session.startProcess(processName);
            session.fireAllRules();

     } catch (Exception e) {
            LOG.fatal("Exception : " + e);
     }
}

The function init() will set properties and load drl and ruleflows. This function will also scan for files and directories with a specific interval.


   public final void init() {
        SystemEventListenerFactory.setSystemEventListener(new Log4jSystemEventListener());

        try {

            final ResourceChangeScannerConfiguration scannerConf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
            scannerConf.setProperty("drools.resource.scanner.interval", scanInterval);
            ResourceFactory.getResourceChangeScannerService().configure(scannerConf);

            final KnowledgeAgentConfiguration agentconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();

            agentconf.setProperty("drools.agent.scanDirectories", "true");
            agentconf.setProperty("drools.agent.newInstance", "true");
            agentconf.setProperty("drools.agent.scanResources", "true");
            agentconf.setProperty("drools.agent.monitorChangeSetEvents", "true");

            kagent = KnowledgeAgentFactory.newKnowledgeAgent("my_appli", aconf);
            String configurationName = "file_rules.xml";

kagent.applyChangeSet(ResourceFactory.newClassPathResource(configurationName));

        } catch (Exception e) {
            LOG.error("Error");
        }
    }
}

The configuration file_rules.xml contains all the drl,functions and ruleflows. This configuration example is used only for our unit tests.


<change-set xmlns='http://drools.org/drools-5.0/change-set'
	xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd'>
	<add>

 		<resource source='classpath:com/mypackage/drl.pack' 
 			type='DRL' />
 			
 		<resource source='classpath:com/mypackage/my_function.function' 
 			type='DRL' /> 	
 		<resource source='classpath:com/mypackage/rule_one.drl'
 			type='DRL' />
 		<resource source='classpath:com/mypackage/my_basic_ruleflow.rf'
			type='DRF' />

      </add>
</change-set>

In production environement we use a PKG ressource. Essentially it is an archive containing all files (DRl,RF,function,etc…).

     <resource
            source='file:/root/dir/archive

.pkg'
            type='PKG' />
Advertisements

Session ID in the URL : is it a vulnerability ?

Problem

I noticed at authentication of several JAVA web applications, the Session ID attached at the url like this http://mywebsite.com/function?value=blah&jsessionid=fgd457dfsd7sde4g4df…

When first authenticated, the website reveals in the URL a sensitive information “the session ID”. This is a security risk according to OWASP reference.
http://owasp-aasvs.readthedocs.io/en/latest/requirement-3.6.html
Indeed if an attacker get the session ID it can lead to the vulnerability of session fixation.

Scanner like Acunetix will detect is as a security risk too:
https://www.acunetix.com/vulnerabilities/web/session-token-in-url

Why the session id is passed to the URL ?

According to this post, it is by design of JavaEE:

This isn’t a bug, it’s by design. When a new session is created, the server isn’t sure if the client supports cookies or not, and so it generates a cookie as well as the jsessionid on the URL. When the client comes back the second time, and presents the cookie, the server knows the jsessionid isn’t necessary, and drops it for the rest of the session. If the client comes back with no cookie, then the server needs to continue to use jsessionid rewriting.
You may not explicitly use cookies, but you do implicitly have a session, and the container needs to track that session.

https://stackoverflow.com/questions/4079378/why-is-my-session-id-in-my-url

What is a Session Fixation ?

Session Fixation is an attack that permits an attacker to hijack a valid user session.
https://www.owasp.org/index.php/Session_fixation

This vulnerability is part of Top 10 2013-A2-Broken Authentication and Session Management

How to test for Session Fixation ?

https://www.owasp.org/index.php/Testing_for_Session_Fixation_(OTG-SESS-003)

What is a Session ?

HTTP protocol and Web Servers are stateless, what it means is that for web server every request is a new request to process and they can’t identify if it’s coming from client that has been sending request previously.

But sometimes in web applications, we should know who the client is and process the request accordingly. For example, a shopping cart application should know who is sending the request to add an item and in which cart the item has to be added or who is sending checkout request so that it can charge the amount to correct client.

http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url-rewriting

This is a link to Servlet specification to understand better the session scope in Java :
https://jcp.org/aboutJava/communityprocess/final/jsr154/index.html

SRV.7.3 Session Scope
HttpSession objects must be scoped at the application (or servlet context) level. The underlying mechanism, such as the cookie used to establish the session, can be the same for different contexts, but the object referenced, including the attributes in that object, must never be shared between contexts by the container.

Solution

Validate Session Id on server side
For sometimes i thought that cookies or hidden input fields is the solution against the “session ID” in the url. According to the link below it is a limited solution. Even if it is hard to copy paste cookies and hidden fields it is still possible to retrieve the Session ID information with special tools on unencrypted website.

Depending of the website it is possible that the sessionId on the URL is not a security risk. If the web application is well designed and the session ID is validated on server side, this is not a problem :
https://security.stackexchange.com/questions/14093/why-is-passing-the-session-id-as-url-parameter-insecure

The best practice , in all case is to validate on the server side.
Other solutions are possible : https://en.wikipedia.org/wiki/Session_fixation

Use Filter to get rid of Session ID in URL

Here is an example of using a Filter to get rid of session Id in the URL :
https://stackoverflow.com/questions/1045668/jsessionid-is-occurred-in-all-urls-which-are-generated-by-jstl-curl-tag/4019476#4019476

I believe this solution is not necessary if good validation of session ID is done on the server Side.

Spring Security Framework

Probably the best solution for JavaEE is to use well tested framework like spring security framework. It is also a default security against other common vulnerabilities.
The authentication form using spring security provide high security against common vulnerabilities :
http://docs.spring.io/spring-security/site/docs/current/guides/html5//helloworld-javaconfig.html

The SecurityConfig will:

Require authentication to every URL in your application

Generate a login form for you

Allow the user with the Username user and the Password password to authenticate with form based authentication

Allow the user to logout

CSRF attack prevention

Session Fixation protection

Security Header integration

HTTP Strict Transport Security for secure requests

X-Content-Type-Options integration

Cache Control (can be overridden later by your application to allow caching of your static resources)

X-XSS-Protection integration

X-Frame-Options integration to help prevent Clickjacking

Integrate with the following Servlet API methods

HttpServletRequest#getRemoteUser()

HttpServletRequest.html#getUserPrincipal()

HttpServletRequest.html#isUserInRole(java.lang.String)

HttpServletRequest.html#login(java.lang.String, java.lang.String)

HttpServletRequest.html#logout()

What is the difference between XSS and CSRF vulnerabilities ?

To sum up ,the vulnerability CSRF allows an attacker to use existing functionalities of a web application. In a bank application , an attacker could force a customer to use the existing feature of transferring money to “attacker’s account”.

In other hand XSS vulnerability allow an attacker to “create new functionalities” on the website using Javascript code :

  • Deface the website
  • Send cookies information to an attacker’s website


  • More detailed explanation of the differences :

    Fundamental difference is that CSRF (Cross-site Request forgery) happens in authenticated sessions when the server trusts the user/browser, while XSS (Cross-Site scripting) doesn’t need an authenticated session and can be exploited when the vulnerable website doesn’t do the basics of validating or escaping input.

    https://www.quora.com/What-is-the-difference-between-XSS-and-CSRF-from-their-execution-perspective

    Owasp made a top-10 of the most common vulnerabilities in web applications.This classification did not change from 2013 to 2017.

  • XSS corresponds to A3 – Cross-site scripting
  • CSRF corresponds to A8- Cross-site request forgery
  • https://www.owasp.org/index.php/Top_10_2013-Top_10

    CSRF prevention

    Basically one solution against this attack is to append a unique identifier to the POST form and let the server verify the identifier. POST form request is usually used to modify data. That’s usually what attacker will try to use when exploiting CSRF vulnerability. GET requests are normally used to retrieve information.

    In Java the framework Spring Security used an unique identifier as anti CSRF technique : https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html

    How to test for CSRF vulnerability ?

    https://www.owasp.org/index.php/Testing_for_CSRF_(OTG-SESS-005)

    XSS types

    XSS happens when we don’t escape characters and validate input .Typically this vulnerability allows an attacker to send input with the intention to retrieve sensitive information(for example cookie) from the website.

    There are different types of XSS attacks :

  • Stored XSS attacks
  • Reflected XSS attack
  • Stored XSS attacks

    This is the worse XSS vulnerability to have on one website. Indeed if the malicious javascript code is stored in the database, potentially this malicious code could be executed in different webpages of the website.

    Reflected XSS attack

    It is very similar to a stored XSS attack except the malicious code is not stored. The malicious code can be executed on the web browser.

    How to test for XSS vulnerability ?

    Test Reflected XSS attack
    In the following example i have added some Javascript code into the input “info”.If the cookie is written back to the screen , this website is sensitive to XSS attack :

    function.do?info=blah<script>alert(document.cookie)</script>
    

    https://www.owasp.org/index.php/Testing_for_Reflected_Cross_site_scripting_(OTG-INPVAL-001)

    Test Stored XSS attack
    This webpage explained how to test a website for stored XSS vulnerability.
    https://www.owasp.org/index.php/Testing_for_Stored_Cross_site_scripting_(OTG-INPVAL-002)

    XSS prevention

    Basically input should be checked for special characters. Input should be validated and verified.

  • One solution is to use Regex to escape characters.
  • Another solution is to use existing libraries to avoid XSS. In Java ESAPI seems like a robust library : https://github.com/esapi/esapi-java-legacy
  • How to avoid XSS and allow HTML tags with javascript :
    https://stackoverflow.com/questions/19824338/avoid-xss-and-allow-some-html-tags-with-javascript/19943011#19943011

    Detailed XSS Explanation

    There are many websites explaining in details XSS attacks. This one explained in details the scenarios of attacks :
    https://excess-xss.com/.

    This other website gives an overview of the difference between the XSS types
    http://deadlytechnology.com/web-development/xss/

    Framework Gwt offers some protection

    On one application ,the scanner Zap Proxy did not found any of these vulnerabilities(XSS-CSRF). This webapp used the framework Gwt. By default it has limited protection against these vulnerabilities. But it is possible to test Gwt more in depth for vulnerabilities with this tool : https://github.com/GDSSecurity/GWT-Penetration-Testing-Toolset

    How to verify your java libraries have known security vulnerabilities ?

    A maven plugin can check you Java libaries for known vulnerabilities. It is called dependency-check-maven.

    The OWASP Dependency Check utility uses NIST’s National Vulnerability Database (NVD) to identify the vulnerable dependencies, so the list is always up-to-date.

      <plugin>
                    <groupId>org.owasp</groupId>
                    <artifactId>dependency-check-maven</artifactId>
                    <version>1.4.4</version>
                    <configuration>
                        <skip>false</skip>
                        <skipTestScope>false</skipTestScope>
                        <skipProvidedScope>false</skipProvidedScope>
                        <skipRuntimeScope>false</skipRuntimeScope>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>check</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
    

    https://blog.lanyonm.org/articles/2015/12/22/continuous-security-owasp-java-vulnerability-check.html

    Requirements

    You will need the following to use Owasp Maven dependency Check.

  • Maven version superior to 3.1
  • Tips to quickly check only some libraires

    Let’s say you can not compile all the project because some jars/files are missing. Then you cannot use the plugin immediately. You need to compile the project first. If you don’t need to compile the project entirely, you can just create a simple pom with all dependencies to check.

    Example :

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.mytest.framework</groupId>
    	<artifactId>mytestframe</artifactId>
    	<packaging>pom</packaging>
    	<name>com.mytest.framework.mytestframe</name>
    	<version>1.0.0-SNAPSHOT</version>
    		
    	<properties>
    		<spring.version>1.0.0.RELEASE</spring.version>
            </properties>
    
    
    	<build>
    		<pluginManagement>
    			<plugins>
    				
    				  <plugin>
                    <groupId>org.owasp</groupId>
                    <artifactId>dependency-check-maven</artifactId>
                    <version>1.4.4</version>
                    <configuration>
                        <skip>false</skip>
                        <skipTestScope>false</skipTestScope>
                        <skipProvidedScope>false</skipProvidedScope>
                        <skipRuntimeScope>false</skipRuntimeScope>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>check</goal>
                            </goals>
                        </execution>
                    </executions>
                   </plugin>
                          </plugins>
            </pluginManagement>
             </build>
    
           <dependencies>
    	   <dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-webmvc</artifactId>
    		<version>${spring.version}</version>
    	  </dependency>
           </dependencies>
    </project>
    
    

    Check maven dependencies with this command :

    mvn dependency-check:check
    

    Reporting

    Check the link above to use reporting for your continuous integration. Otherwise here is an example of reporting once you launch the maven plugin :

    One or more dependencies were identified with known vulnerabilities in my_project:
     
    logback-core-1.1.3.jar (ch.qos.logback:logback-core:1.1.3, cpe:/a:logback:logback:1.1.3) : CVE-2017-5929
    commons-collections-3.2.1.jar (commons-collections:commons-collections:3.2.1, cpe:/a:apache:commons_collections:3.2.1) : CVE-2015-6420

    Troubleshooting

    If you have the following error

    -Dmaven.multiModuleProjectDirectory system property is not set
    

    then you need to modify the java configuration like this in eclipse :owasp_check_maven

    Unusable INDEX on PARTITION table

    When index is unusable on table, it prevents the updating/inserting of new data

    Everyday a clean up task would messed up a partitioned table. Specifically the following command would make the indexes unusable :


    ALTER TABLE table_name DROP PARTITION partition_name;

    Thus the table would have unusable indexes. This problem prevents from importing new data.

     

    Description of the partitionned table

    The table with unusable indexes is partitioned and has two indexes. One index is on the primary key and the other index on a date column MY_TABLE_DATE.
    The table is partitioned with the method “Range Partitioning”

    Range partitioning maps data to partitions based on ranges of partition key values that you establish for each partition. It is the most common type of partitioning and is often used with dates. For example, you might want to partition sales data into monthly partitions.

    https://docs.oracle.com/cd/B10500_01/server.920/a96524/c12parti.htm

    The table is partitionned with the date and has a primary key :


    create table MY_TABLE
    (
    ID NUMBER GENERATED BY DEFAULT AS IDENTITY ,
    MY_TABLE_DATE DATE NOT NULL,
    NAME VARCHAR2(3) NOT NULL,
    SURNAME VARCHAR2(20) NOT NULL,
    PRIMARY KEY(ID))
    )
    PCTFREE 10
    TABLESPACE tab_p_specified_space
    PARTITION BY RANGE (MY_TABLE_DATE )
    (PARTITION P_20100101 VALUES LESS THAN (TO_TIMESTAMP('2010/01/01 00:00:00','YYYY/MM/DD HH24:MI:SS') )
    PCTFREE 10
    TABLESPACE tab_p_specified_space
    );

    Actually this primary key is a problem according to Oracle documentation. Indeed the partitionned column should be part of the primary key. Read on from « Partitioned Index-Organized Tables » :

    For partitioning an index-organized table
    Partition columns must be a subset of primary key columns

    https://docs.oracle.com/cd/B10500_01/server.920/a96524/c12parti.htm

    To make the partitionned column part of the primary key , do something like this:


    ALTER TABLE MY_TABLE DROP CONSTRAINT TABLE_PK;
    ALTER TABLE MY_TABLE ADD CONSTRAINT TABLE_PK PRIMARY KEY (ID, MY_TABLE_DATE) USING INDEX LOCAL TABLESPACE tab_p_specified_space;

    Unfortunately this modification of the partitioned table did not fix the problem either.

    Solution

    In order to fix unusable indexes I used the command “UPDATE INDEXES” suggested by this article https://docs.oracle.com/database/121/VLDBG/GUID-1D59BD49-CD86-4BFE-9099-D3B8D7FD932A.htm#VLDBG1122

    “UPDATE INDEXES” will rebuild the indexes after the command DROP PARTITION is executed.


    requestDeletePartition := 'ALTER TABLE BASE.MY_TABLE DROP PARTITION TO_CHAR(Date,'YYYYMMDD') || 'UPDATE INDEXES' ;

    Unfortunately the result was the following error :

    SQLCODE : -14048
    SQLERRM : ORA-14048: a partition maintenance operation may not be combined with other operations

    I spend sometimes trying to figure out the solution for this error . The solution is simple . I added a space between ‘ and UPDATE INDEXES like this :


    requestDeletePartition := 'ALTER TABLE BASE.MY_TABLE DROP PARTITION TO_CHAR(Date,'YYYYMMDD') || ' UPDATE INDEXES' ;

    The solution will rebuild indexes after dropping the partition. This fix is not sustainable for every scenario. Because it means to launch the command of rebuilding indexes everyday on a table with potentially millions of data. When the indexes are being rebuilt, the table cannot be used. Thus this command should be launched when nobody is using the application.

    Annexes

    Another tested solution

    On google we can quickly find interesting articles how to fix the problem :


    ALTER INDEX index_name REBUILD

    https://docs.oracle.com/database/121/SPATL/alter-index-rebuild.htm#SPATL1017

    This is a similar solution to the previous one. The table is not usable when the indexes are being rebuilt.

    Other solution possible
    I did not test this solution but it should fix the problem too.

    https://www.toadworld.com/platforms/oracle/b/weblog/archive/2014/09/26/the-trick-of-drop-a-table-partition-without-impact-the-global-index

    Basics IBM Websphere MQ Series

    This article introduced a simple MQ Server composed of a queue manager, local queues, channels. Channels allow the queues to communicate between each other. Aliases can also be used to give an alias to queues.

    Create a queue manager

    Queue managers are the main components in a WebSphere MQ messaging network.

    https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pro.doc/q004390_.htm

    Display queue managers before

    dspmq
    

    If the queue manager does not already exist create a queue manager

    crtmqm QM1
    

    Start the queue manager

    strmqm QM1
    

    https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pro.doc/q004390_.htm

    This command will modify the queue manager. For example here channel authentication are not recorded :

    ALTER QMGR CHLAUTH(DISABLED) | runmqsc QM1
    

    https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.ref.adm.doc/q085320_.htm

    Create a channel

    Definition of a channel

    WebSphere MQ uses two different types of channels:

  • A message channel, which is a unidirectional communications link between two queue managers.
  • An MQI channel, which is bidirectional and connects an application (MQI client) to a queue manager on a server machine.
  • https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.explorer.doc/e_channels.htm

    How to create a Channel ?

    https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.ref.adm.doc/q085520_.htm

    In our app we use a “receiver channel”

    A receiver channel is a message channel that the queue manager uses to receive messages from other queue managers.

    Verify existence of channel

    dspmqfls -m QM1 -t CHAN_RCV
    

    Create a receiver channel

     runmqsc QM1  <<e@
    DEFINE CHANNEL(CHAN_RCV) CHLTYPE(RCVR) TRPTYPE(TCP);
    

    Also we use “Sender channel”

    A sender channel is a message channel that the queue manager uses to send messages to other queue managers.

    Create a receiver channel

     runmqsc QM1  <<e@
    DEFINE CHANNEL(CHAN_SEN) CHLTYPE(SDR) TRPTYPE(TCP) CONNAME(CON_X) XMITQ(XMIT_X) REPLACE DISCINT(SCINT_);
    

    What is a purpose of a transmission queue ?

    We need this queue to send a message to another queue.

    Create a transmission queue :

    runmqsc QM1 <<e@
        DEFINE QLOCAL(SDF.45.78.0DF) USAGE(XMITQ) TRIGGER INITQ(SYSTEM.CHANNEL.INITQ) DEFPSIST(YES) MAXDEPTH(5000) REPLACE DESCR('Reception queue');
    

    https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/ic12510_.htm

    Create a local queue/in for the reception of message

    runmqsc QM1 <<e@
        DEFINE QLOCAL(SDF.45.78.0DF) USAGE(NORMAL) PUT(ENABLED) GET(ENABLED)                      DEFPRTY(0) REPLACE MSGDLVSQ(FIFO) DEFSOPT(SHARED) NOTRIGGER ;
    

    Create a corresponding alias of the queue. It is a link to the queue.

    DEFINE QALIAS(QRECEPT) REPLACE TARGQ(SDF.45.78.0DF) DEFPSIST(YES);
    

    Create a local queue/out to send messages

    It is the same thing as for the reception of the message. Only the name of the queue is different.

    What is the difference between queue and channel in MQ ?

    https://stackoverflow.com/questions/31745360/what-is-the-difference-between-a-message-channel-and-the-message-queue-itself

    For IBM MQ one endpoint is always the queue manager (a type of messaging engine) and the other is an application or another queue manager.

    Based on this example, it should be obvious that channel as used in the book and channel as defined by any messaging transport are at different levels of abstraction. As used by MQ, a channel is a specific set of configuration parameters that define a communication path and includes such attributes as CONNAME, MAXMSGL, tuning parameters, SSL parameters,
    etc.

    Once an MQ channel is successfully started, you can see a running instance of it by displaying the channel status. In the case of CLUSRCVR, SVRCONN, and (less commonly) RCVR or RQSTR channels, you may see multiple instances of the same channel active simultaneously.

    How to connect to a queue manager in MQ ?

    I actually use the mqexplorer(mqj.cmd) from Windows. The project is opensource at https://www.openhub.net/p/mqjexplorer .

    Run the program MQ explorer and from “Show Queue Manager” choose a remote queue for distant server MQ.

    show_queue_manager - Copy

    TROUBLESHOOTING MQexplorer

    If there is an error in mqjexplorer(example with MQRC_Q_MGR_NOT_AVAILABLE)
    http://www-01.ibm.com/support/docview.wss?uid=swg21227679 , verify that queue is started:

    strmqm QM1
    

    If it is OK then verify that the listener is started :

    runmqlsr -m QM1 -t TCP -p PORT_MQ &
    

    Normally it fixes the issue of queue manager not being accessible from mqexplorer.

    How to simulate a MQ server ?

    The problem

    Our application is retrieving information from a distant server using IBM Websphere Mq messaging system. In production we need to install two MQ servers , one on machine A and another one on machine B:

    Creation Fil MQ

    We want to avoid installing MQ Server on two machines for the qualification platform. How to simulate machine B ‘s MQ Server ?

    The solution

    This article will explain several steps taken to simulate the communication between two MQ servers. These are the steps explained :

  • Create a MQ server on machine A
  • Run a Java application on machine B within tomcat which listens to inqueue QueueManager and send back information to Outqueue MQ queue manager
  • Create a MQ server on machine A

    A IBM MQ server is composed of a queue manager, local queues, channels. Channels allow the queues to communicate between each other. Aliases can also be used to give an alias to queues.

    https://wordpress.com/post/julienprog.wordpress.com/1235

    Simulate a MQ server on machine B

    First of all install tomcat on the machine B. The solution is using Java to catch JMS information from our MQ Server on machine A. To simulate the MQ Server these are the steps :

  • Add a listener in web.xml
  • The Java class listener will be launched at tomcat startup.
  • At statup , the listener starts one Thread or multiple ones to listen one or multiples queue managers
  • Let’s assume we have one thread listening to one Queue manager
  • When a Thread is cathing a JMS message, from receiver/in queue of machine A, it will parse the message
  • Based on the parsed message we check a database or filesystem for a DataSet response
  • Finally we send the dataset response to the Out/sender queue of machine A
  • The application in machine A reads the out/sender queue and process it like normal not knowing it is consuming messages from the simulator
  • That’s it : the machine B simulated a MQ Server
  • Add a listener to tomcat web.xml

    <web-app>
    	<display-name>MQ-Sim</display-name>
    
    	<listener>
    		<listener-class>my.com.MQListener</listener-class>
    	</listener>
    
    

    At startup of tomcat the MQlistener will be launched. The thread is started within the listener like this :

    final MqThread mq= new MqThread (mqinfo);
    MqThread .start();
    

    Read MQ configuration detailed from a file

    We need to know to which receiver/in queue we will listen to and which sender/out queue we will send message to.

    Example of properties file containing these information :

    hostname	  = myserver
    port		  = 9999
    queueManager = MYQUEUEMANAGER
    queue.in	  = QUEUE.OUT
    queue.out	  = QUEUE.IN
    

    “queue.in” represents the queue we are lestening to. “queue.out” is the queue we are going to send message to.

    Start a thread listening to a receiver queue

    The MqThread extends Thread class. It contains a run() method which will be executed when the thread is started.

    The MqThread constructor prepares an active connection with the queue manager and the queue receiver and sender in order to communicate with the MQ server .

    
    import javax.jms.QueueConnection;
    ...
    public MqThread (MqInfo mqInfo) throws JMSException {
           
    final MQQueueConnectionFactory queueConnectionFactory = new MQQueueConnectionFactory();
    			queueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
    			queueConnectionFactory.setQueueManager(mqInfo.getQueueManager());
    			queueConnectionFactory.setHostName(mqInfo.getHostname());
    			queueConnectionFactory.setPort(mqInfo.getPort());
    
          queueConnection = queueConnectionFactory.createQueueConnection(mqInfo.user, mqInfo.password);
          queueConnection.start();
          // A QueueConnection object is
          // an active connection to a point-to-point JMS provider.
    
          this.queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
          // A QueueConnection can be used 
          // to create a QueueSession, 
          // from which specialized 
          // queue-related objects can be created
          this.receiver = session.createReceiver(mqInfo.receiverQueue);
          // Creates a QueueReceiver object to receive 
          // messages from the specified queue.
          this.sender = session.createSender(mqInfo.senderQueue);
          // Creates a QueueSender object to send 
          // messages to the specified queue.
    }
    

    More information about QueueConnection
    http://docs.oracle.com/javaee/6/api/javax/jms/QueueConnection.html

    The thread will be listening to MQ receiver queue. When a JMS message is sent to that queue the thread will consume and parse the message.

    public run() {
    
    		this.queueManager = queueManager;
                    while (isThreadTerminated) {
    		    final Message message = receiver.receive(1000);
    		    proccessMessage(message );
                     } 
    }
    

    The run() method is listening to queue receiver to handle messages from this queue.

    Receives the next message that arrives within the specified timeout interval.

    http://docs.oracle.com/javaee/6/api/javax/jms/MessageConsumer.html#receive(long)

    Based on the parsed message we check a database or filesystem for a DataSet response

    Once the message is parsed we can retrieve a DataSet response from a file system. This example is not complet but give an idea what to do :

    
    	private String getDataSetResponse(String inputMessage) {
    
    		final String filename = getFileNameDataSet(inputMessage);
    		return getFile(filename );
    	}
    

    Finally we send the dataset to the Out/sender queue of machine A

    private void sendMessage(String message, String messageId) throws JMSException {
           final TextMessage dataSetMessage = session.createTextMessage(message);
           dataSetMessage.setJMSCorrelationID(messageId);
           dataSetMessage.setJMSMessageID(messageId);
           sender.send(dataSetMessage );
    }
    

    That ‘s it