Monday, January 23, 2017

Dynamic XPath expressions in property mediator

Suppose we have following xml content stored in the registry and we need to read the entry value dynamically by passing the entry element(entry1,entry2) as a parameter.

 <myConfigFile>  
 <entry1>value1</entry1>  
 <entry2>value2</entry2>  
 </myConfigFile>  

The following sequence template reads the xml content from the registry(conf:/myConfigFile) to a property and base on the entry element parameter pass by the call template mediator, a dynamic xpath expression will be built and evaluate the value of the entry element.

 <template xmlns="http://ws.apache.org/ns/synapse" name="myTemplate">  
   <parameter name="entryValue"></parameter>  
   <sequence>  
    <property xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" name="myConfigFile" expression="get-property('registry','conf:/myConfigFile')" scope="default" type="OM"></property>  
    <log level="custom">  
      <property xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" name="+++++++Logging myConfigFile+++++++" expression="get-property('myConfigFile')"></property>  
    </log>  
    <property xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" name="entryparam" expression="$func:entryValue"></property>  
    <property xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" name="xpathExpression" expression="fn:concat('$ctx:myConfigFile//',get-property('entryparam'))"></property>  
    <log>  
      <property xmlns:ns2="http://org.apache.synapse/xsd" xmlns:ns="http://org.apache.synapse/xsd" name="****entry value****" expression="evaluate($ctx:xpathExpression)"></property>  
    </log>  
   </sequence>  
 </template>  

Following API including the call template mediator invokes the above template.


 <api xmlns="http://ws.apache.org/ns/synapse" name="TestApi" context="/sample">  
   <resource methods="GET">  
    <inSequence>  
      <call-template target="myTemplate">  
       <with-param name="entryValue" value="entry2"></with-param>  
      </call-template>  
    </inSequence>  
   </resource>  
 </api>  

Observed the following log on the ESB console.

 INFO - LogMediator +++++++Logging myConfigFile+++++++ = <myConfigFile>  
 <entry1>value1</entry1>  
 <entry2>value2</entry2>  
 </myConfigFile>  
 [2017-01-20 13:21:12,016] INFO - LogMediator To: /sample, MessageID: urn:uuid:8cc61345-3358-4b0b-bddc-c950a863416e, Direction: request, ****entry value**** = value2  


Wednesday, January 18, 2017

Sample java client for IBM Webspear MQ v8

The following sample java client can be used to produce the message to the IBM MQ.

 package test;  
 import com.ibm.msg.client.wmq.*;  
 import com.ibm.mq.jms.*;  
 import javax.jms.*;  
 public class WMQClient {  
       public static void main (String[] args)  
              throws Exception  
             {  
             // Create the QueueConnectionFactory  
             MQQueueConnectionFactory queueConnectionFactory = new MQQueueConnectionFactory();  
             //Configure the connection properties  
             queueConnectionFactory.setHostName ("localhost");  
             queueConnectionFactory.setPort (1414);  
             queueConnectionFactory.setQueueManager ("ESBQManager");  
             queueConnectionFactory.setChannel ("mychannel");  
             queueConnectionFactory.setTransportType (WMQConstants.WMQ_CM_CLIENT);  
             //  Started the queue connection  
             QueueConnection queueConnection = queueConnectionFactory.createQueueConnection ("mqm", "1qaz2wsx@");  
             queueConnection.start();  
             // Set JMS configuration for queue and session  
             Queue queue = new MQQueue ("LocalQueue1");  
             QueueSession session = queueConnection.createQueueSession (false, Session.AUTO_ACKNOWLEDGE);  
             QueueSender sender = session.createSender (queue);  
             //Set the message/property and send to the queue  
             TextMessage message = session.createTextMessage("test");  
                message.setStringProperty("MyCustomProperty", "DUMMY_PROPERTY_VALUE");  
                System.err.println("Sending message:" + message.getText());  
                sender.send (message);  
             System.out.println ("sent message: " + message);   
             //close the session and connection  
             session.close();  
             queueConnection.close();  
             }  
 }  

After producing the messages by the client, the following listener proxy can be used to listen to the queue.

 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="MyJMSProxy"  
     transports="jms"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <inSequence>  
      <log level="full"/>  
      <log level="custom">  
       <property name="JMS_PROPERTY----"  
            expression="get-property('transport','MyCustomProperty')"/>  
      </log>  
      <drop/>  
    </inSequence>  
   </target>  
   <parameter name="transport.jms.Destination">LocalQueue1</parameter>  
   <description/>  
 </proxy>  

The output of the above client and the listener proxy can be seen as follows.

java client log

 Sending message:test  
 sent message:   
  JMSMessage class: jms_text  
  JMSType:     null  
  JMSDeliveryMode: 2  
  JMSDeliveryDelay: 0  
  JMSDeliveryTime: 1484743690101  
  JMSExpiration:  0  
  JMSPriority:   4  
  JMSMessageID:   ID:414d5120455342514d616e6167657220e40e7f5802650320  
  JMSTimestamp:   1484743690101  
  JMSCorrelationID: null  
  JMSDestination:  queue:///LocalQueue1  
  JMSReplyTo:    null  
  JMSRedelivered:  false  
   JMSXAppID: test.WMQClient         
   JMSXDeliveryCount: 0  
   JMSXUserID: mqm       
   JMS_IBM_PutApplType: 28  
   JMS_IBM_PutDate: 20170118  
   JMS_IBM_PutTime: 12481011  
   MyCustomProperty: DUMMY_PROPERTY_VALUE  
 test  

ESB carbon log 

 [2017-01-18 17:33:28,198] INFO - LogMediator To: , WSAction: urn:mediate, SOAPAction: urn:mediate, MessageID: ID:414d5120455342514d616e6167657220e40e7f5802fa0220, Direction: request, Envelope: <?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><axis2ns19:text xmlns:axis2ns19="http://ws.apache.org/commons/ns/payload">test</axis2ns19:text></soapenv:Body></soapenv:Envelope>  
 [2017-01-18 17:33:28,199] INFO - LogMediator JMS_PROPERTY---- = DUMMY_PROPERTY_VALUE  

Friday, January 13, 2017

Decode base64encoded JSON by wso2 ESB

Wso2 ESB support for message encoding and decoding using following custom XPath functions.

base64Encode() function


The base64Encode function returns the base64-encoded value of the specified string.

  • base64Encode(string value)
  • base64Encode(string value, string charset) 

base64Decode() function


The base64Decode function returns the original value of the specified base64-encoded value.

  • base64Decode(string encodedValue)
  • base64Decode(string encodedValue, string charset)
The following sample illustrates, how to decode the incoming base64 encoded message by ESB.

Suppose that the backend(http://www.mocky.io/v2/5878a8c626000052011c3503) is returning the base64encoded string "eyJuYW1lIjoiUmFuZGlrYSJ9" for the json "{"name": "Randika"}".

The following proxy service can be used to decode the incoming encoded message.

 <?xml version="1.0" encoding="UTF-8"?>  
 <api xmlns="http://ws.apache.org/ns/synapse" name="SampleDecoder" context="/test">  
   <resource methods="GET">  
    <inSequence>  
      <send>  
       <endpoint>  
         <http method="GET" uri-template="http://www.mocky.io/v2/5878a8c626000052011c3503" />  
       </endpoint>  
      </send>  
    </inSequence>  
    <outSequence>  
      <property name="messageBody" expression="$body/*" scope="default" />  
      <log level="custom">  
       <property name="************Incoming Encoded Payload*************" expression="get-property('messageBody')" />  
      </log>  
      <property name="DecodeBody" expression="base64Decode(get-property('messageBody'))" scope="default" />  
      <log level="custom">  
       <property name="************Decoded Payload************" expression="get-property('DecodeBody')" />  
      </log>  
      <log level="full" />  
      <payloadFactory media-type="json">  
       <format>$1</format>  
       <args>  
         <arg evaluator="xml" expression="get-property('DecodeBody')" />  
       </args>  
      </payloadFactory>  
      <log level="full" />  
      <property name="messageType" value="application/json" scope="axis2" />  
      <send />  
    </outSequence>  
   </resource>  
 </api>  

The incoming encoded message can be stored in the property after decoding with the following configuration.

<property name="DecodeBody" expression="base64Decode(get-property('messageBody'))" scope="default" />

The output message will be seen an follows.

{"name": "Randika"}

Tuesday, January 10, 2017

Update Registry Properties Using Class Mediator

The current implementation of updateResource(String key, Object value) method supports only for update the registry resources and not support for update the registry properties. Also that the synapse registry API has not provided direct method to update the registry properties.
However following logic inside the class mediator can be use to update the registry properties in terms of carbon mediation registry implementation.


 package Mypackage;  
 import org.apache.synapse.MessageContext;  
 import org.apache.synapse.mediators.AbstractMediator;  
 import org.wso2.carbon.registry.core.*;  
 import org.wso2.carbon.registry.core.service.RegistryService;  
 import org.wso2.carbon.registry.core.exceptions.RegistryException;  
 import org.wso2.carbon.context.CarbonContext;  
 import org.wso2.carbon.mediation.registry.RegistryServiceHolder;  
 public class RegistryPropertyUpdate extends AbstractMediator {  
      public static final String CONFIG_REGISTRY_PREFIX = "conf:";  
      public static final String GOVERNANCE_REGISTRY_PREFIX = "gov:";  
      public static final String LOCAL_REGISTRY_PREFIX = "local:";  
      private Registry configRegistry;  
      private Registry localRegistry;  
      private Registry governanceRegistry;  
      public RegistryPropertyUpdate() throws RegistryException {  
           RegistryService registryService = RegistryServiceHolder.getInstance()  
                     .getRegistryService();  
           configRegistry = registryService.getConfigSystemRegistry(CarbonContext  
                     .getThreadLocalCarbonContext().getTenantId());  
           governanceRegistry = registryService  
                     .getGovernanceSystemRegistry(CarbonContext  
                               .getThreadLocalCarbonContext().getTenantId());  
           localRegistry = registryService.getLocalRepository(CarbonContext  
                     .getThreadLocalCarbonContext().getTenantId());  
      }  
      public boolean mediate(MessageContext mc) {  
           try {  
                RegistryPropertyUpdate prop = new RegistryPropertyUpdate();  
                prop.updateRegistryProperty("gov:/tasks/EventAlertScheduledTask",  
                          "registry property modified", "lastAccessTime");  
           } catch (Exception e) {  
                e.printStackTrace();  
           }  
           return true;  
      }  
      public void updateRegistryProperty(String key, String content,  
                String propertyName) throws RegistryException {  
           Registry registry = getRegistry(key);  
           String resolvedKey = resolvePath(key);  
           try {  
                Resource resource;  
                resource = registry.newCollection();  
                resource.setProperty(propertyName, content);  
                registry.put(resolvedKey, resource);  
           } catch (RegistryException e) {  
                System.out.println("Error while saving a resource at " + e);  
           }  
      }  
      private Registry getRegistry(String path) {  
           if (path.startsWith(GOVERNANCE_REGISTRY_PREFIX)) {  
                return governanceRegistry;  
           } else if (path.startsWith(CONFIG_REGISTRY_PREFIX)) {  
                return configRegistry;  
           } else if (path.startsWith(LOCAL_REGISTRY_PREFIX)) {  
                return localRegistry;  
           } else {  
                return governanceRegistry;  
           }  
      }  
      private String resolvePath(String path) {  
           if (path.startsWith(GOVERNANCE_REGISTRY_PREFIX)) {  
                path = path.substring(GOVERNANCE_REGISTRY_PREFIX.length());  
           } else if (path.startsWith(CONFIG_REGISTRY_PREFIX)) {  
                path = path.substring(CONFIG_REGISTRY_PREFIX.length());  
           } else if (path.startsWith(LOCAL_REGISTRY_PREFIX)) {  
                path = path.substring(LOCAL_REGISTRY_PREFIX.length());  
           }  
           return path;  
      }  
 }  

we can pass the following parameters to the "updateRegistryProperty()" method.

 updateRegistryProperty(registry path, content need to update, property name);  

Example:

 updateRegistryProperty("gov:/tasks/EventAlertScheduledTask",  
                          "registry property modified", "lastAccessTime");  

How to set template sequence parameters to registry stored XML?

Suppose we have the following XML template stored in the location of "gov:/metadata1.0.0.xml".

 <?xml version="1.0" encoding="UTF-8"?>  
 <MetaData>  
   <MessageVersion />  
   <Destinations>  
    <Destination>  
      <Branches />  
      <Brands />  
    </Destination>  
   </Destinations>  
 </MetaData>  

We have created the following sequence template and the call template which pass "version" parameter to invoke the template.

 <?xml version="1.0" encoding="UTF-8"?>  
 <template xmlns="http://ws.apache.org/ns/synapse" name="metadata-creator-v1">  
   <parameter name="version" />  
   <sequence>  
    <property expression="get-property('registry','gov:/metadata1.0.0.xml')" name="xmlTemplate" scope="default" type="OM" />  
    <log level="custom">  
      <property expression="$ctx:xmlTemplate//MessageVersion" name="****logging empty tag****" />  
    </log>  
    <enrich>  
      <source clone="true" type="custom" xpath="$func:version" />  
      <target action="replace" type="custom" xpath="$ctx:xmlTemplate//MessageVersion" />  
    </enrich>  
    <log level="custom">  
      <property expression="get-property('xmlTemplate')" name="****xmlTemplate***" />  
    </log>  
   </sequence>  
 </template>  


 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse" name="TestProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">  
   <target>  
    <inSequence>  
      <call-template target="metadata-creator-v1">  
       <with-param name="version" value="version 1.0.0" />  
      </call-template>  
    </inSequence>  
    <outSequence>  
      <send />  
    </outSequence>  
   </target>  
   <description />  
 </proxy>  

In the above sequence template, the xml stored in the registry can be read into the property as follows.


 <property expression="get-property('registry','gov:/metadata1.0.0.xml')" name="xmlTemplate" scope="default" type="OM" />  

After setting into the property, it's possible access the <MessageVersion> element of the xml by xpath "$ctx:xmlTemplate//MessageVersion".
The enrich mediator is used to set the value of the version coming as a parameter with the call template to set the text of <MessageVersion> element.

<enrich>  
      <source clone="true" type="custom" xpath="$func:version" />  
      <target action="replace" type="custom" xpath="$ctx:xmlTemplate//MessageVersion" />  
    </enrich>  

The output will be appeared as follows.

 <?xml version="1.0" encoding="UTF-8"?>  
 <MetaData>  
   <MessageVersion>version 1.0.0</MessageVersion>  
   <Destinations>  
    <Destination>  
      <Branches />  
      <Brands />  
    </Destination>  
   </Destinations>  
 </MetaData>