Wednesday, 10 January 2018

Apache Active MQ, Spring Integration Messaging sending SWIFT MT950 messages...

I need to send MT950 messages to a SWIFT message, I've done this before but I always forget how I did it. This version, however needs to be a little more comprehensive. Specifically, I want to develop this to send messages from a query, but be able to map the query results to the message fields

so first things first I'm going to need to tool up. I downloaded Apache Active MQ and installed it (basically just uncompresses)



/Users/christopherwebster/Dev/apache-activemq-5.8.0




./bin/activemq console




The above starts Active MQ. In a web browser, navigating to http://localhost:8161/admin/index.jsp
you should see the following




  















So now we've got something to send a message to we can code up a simple test.

here's my pom:

    4.0.0
    cwc
    SwiftMessagePublisher
    1.0.0.BUILD-SNAPSHOT
    jar
    SwiftMessagePublisher
    http://www.springsource.org/spring-integration
  
    
        2.2.1
    

    
        UTF-8
        2.2.4.RELEASE
        1.2.17
        4.11
    

    
        
        repo.springsource.org.milestone
        Spring Framework Maven Milestone Repository
        https://repo.springsource.org/milestone
        

        
        repository.jboss.org-public
        JBoss.org Maven repository
        https://repository.jboss.org/nexus/content/groups/public
        

    

    
        
            
                maven-eclipse-plugin
                2.9
                
                    
                        org.springframework.ide.eclipse.core.springnature
                        

                    
                        org.springframework.ide.eclipse.core.springbuilder
                    

                    true
                    true
                

            

            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.0
                
                    1.6
                    1.6
                    -Xlint:all
                    true
                    true
                

            

            
                org.codehaus.mojo
                exec-maven-plugin
                1.2.1
                
                    com.cwc.swiftmessagepublisher.Main
                

            

        

    

    
        
        
            junit
            junit
            ${junit.version}
            test
        

        
            javax.jms
            jms
            1.1
        

        
        
            org.springframework
            spring-jms
            3.1.2.RELEASE
            

        
            org.springframework.integration
            spring-integration-jms
            2.1.3.RELEASE
            

        
            org.apache.activemq
            activemq-core
            LATEST
            

        
            org.apache.activemq
            activemq-pool
            LATEST
            

        
            org.springframework.integration
            spring-integration-core
            ${spring.integration.version}
            

        
            org.springframework.integration
            spring-integration-file
            ${spring.integration.version}
            

        
        log4j
            log4j
            ${log4j.version}
        

        
        
            commons-io
            commons-io
            2.4
        

    


Create a project and add this in eclipse. Here's mine...


I've used STS here and created a Spring project. I added maven and modified the POM. You need a couple of alternative repos because some of the dependencies aren't covered by the defaults.

notice the spring integration context. STS adds this for a Sprint Integration project by default.















You'll notice the testSend() :void test. I added this just to get the go-no-go test proved with Active MQ. Here's the code, no spring in there yet. I just want to prove that I can successfully send a message to the Queue.



@Test

public void testSend(){

try {

            //created ConnectionFactory object for creating connection 

            ConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", "tcp://localhost:61616");

            //Establish the connection
            Connection connection = factory.createConnection();
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Queue queue = session.createQueue("TEST-QUEUE");
            //Added as a producer
            javax.jms.MessageProducer producer = session.createProducer(queue);
            // Create and send the message
            TextMessage msg = session.createTextMessage();
            msg.setText("Hello World");
            producer.send(msg);
        } catch (Exception e) {
            // TODO: handle exception
        e.getMessage();
        }
}

So running the tests...
We're good, all compiles and runs.. but did we send a message?

Switch to the ActiveMQ Console and review Queues. Click the queue name and you'll see there's a message. Click the message to review the payload and we can see we've got a "Hello World" message.


















OK so to review, we've installed Apache Active MQ, retaining the defaults. Created a Spring Integration Project in STS (Spring Source Tool Suite) and added a test that sends a hello world message to Active MQ. We've tested the development harness and we're ready to start generating and testing SWIFT messages.

...not bad for a hour or so's work.

Concurrency Issues in Oracle

Avoiding duplicates in multi-user environments 

Avoiding concurrency issues in stored procedures can be tricky. I'm writing some functionality to add a document ID to a table in Oracle. The requirement is as follows:

The document ID must consist of a string identifying the entity a string identifying the month and a string identifying the year and an increment.

[entity]_[mm]_[yyyy]_[nnn] which might look like 9999_01_2017_1

At first glance this looks like it should be quite easy. query the data by entity, month, year. count and add one. Cast the numeric values to a varchar and Concatenate. This, however doesn't take into account the fact that two concurrent inserts might not see a unique count. In this case you'll end up with the, possibility disastrous, duplicate. This is the scenario that DBMS_LOCK was designed to resolve.

For me the solution was to employ the example here
This very good article clearly shows how to lock a portion of pl/sql while an update is carried out and then release the lock such that the process remains isolated and gets an unimpeded view of the data it's updating and can remain confident that the process will function without concurrency issues.

   v_doc_id varchar2(20);
   v_call_status INTEGER;
   v_lock_handle varchar2(128);

   BEGIN
      -- Calculate the document id
     DBMS_LOCK.allocate_unique( 'SET_APPROVAL_DOCUMENT_ID', v_lock_handle );
     v_call_status := DBMS_LOCK.REQUEST(v_lock_handle, DBMS_LOCK.X_MODE, 5, TRUE);
     IF v_call_status = 0 THEN
      Select ( select to_char(je.legal_entity_cd)||'_'||je.financial_period
                 from me_journal_entry je
                  where je.CFME_ID = p_cfme_id) ||'_'||
               ( select to_char(count(*)+1)
                   from V_ME_JOURNAL_APPROVAL_LOG al,
                        (select je.legal_entity_cd, je.financial_period
                           from me_journal_entry je
                          where je.CFME_ID = p_cfme_id) j
                  where al.is_approved = 'Y'
                    and j.legal_entity_cd = al.legal_entity_cd
                    and j.financial_period = al.financial_period)
        into v_doc_id
        from dual;
       
    -- Insert the approval row
   
    Insert into G79_CFM.ME_APPROVAL_LOG (IS_APPROVED, CFME_ID, APPROVAL_NOTES,USER_ID, APPROVAL_TYPE, CFME_DOCUMENT_ID, APPROVAL_DATE_TIME)
                                 Values (p_is_approved, p_cfme_id,  p_approval_notes, p_user_id, p_approval_type, v_doc_id, sysdate());
   
        COMMIT;
    ELSE