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>  


Monday, September 19, 2016

Disable the Task Execution in ESB Cluster Environment


All of us know, one of the key feature of ESB cluster setup is deployment synchronizing. Once you deploy a project in the cluster manager mode, it will sync up with the cluster worker nodes. However, eventually the artifacts will be deployed in manager and worker nodes.

Suppose if we deploy the artifacts having "Task" in the cluster environment, they will be deployed on all the ESB nodes in cluster including manager node. But the task is something like a schedule job. So it will automatically execute in the deployed nodes without any invocation. Simply it will execute in the manager node as well as worker nodes in ESB 4.8.1.

But the issue is basically we are expecting the manager node just do the deployment synchronizing activities and not the service execution. At this point of view, ESB allows us to deploy the tasks in cluster environment and allow the execution of them in predefined nodes. This attribute is called as pinnedServers attribute.
We can specify the pinned server attribute in the task synapse configuration and that will get executed only on that specific pinned servers.

 <?xml version="1.0" encoding="UTF-8"?>  
 <task xmlns="http://ws.apache.org/ns/synapse" name="Task123" class="org.apache.synapse.startup.tasks.MessageInjector" group="synapse.simple.quartz" pinnedServers="worker1, worker2">  
  </task>  

The worker nodes should be configured as the pinned serversWe just need to add the <ServerName> configuration in axis2.xml in each worker node which required to execute that task and start the server with -DSynapseServerName=<ServerName>

  <!-- Synapse Server name parameter -->  
   <parameter name="SynapseConfig.ServerName" locked="false">worker1</parameter>  

Monday, September 12, 2016

Accessing registry property value using class mediator


How to retrieve the properties in Synapse 


The get-property() function allows any XPath expression used in a configuration to look up information from the current message context. Using the Property mediator, we can retrieve properties for different scopes. You can find the different scopes to retrieve properties here.

How to use get-property() to access the property saved in registry.


To retrieve the prorerties saved in registry, we need to use the scope "registry".The property name should be appended to the property path using @ sign.

 get-property('registry', String registryPath@propertyName)  

How to access the property saved in registry using class mediator.


Step 1


We need to write the following logic in the class mediator. In the below sample we have saved the property name as "lastAccessTime" in the registry path  "gov:/tasks/EventAlertScheduledTask".


 package Mypackage;  
 import org.apache.synapse.MessageContext;   
 import org.apache.synapse.mediators.AbstractMediator;  
 import org.apache.synapse.registry.Registry;  
 import org.apache.synapse.config.Entry;  
 import java.util.Properties;  
 public class Sample extends AbstractMediator {   
      public boolean mediate(MessageContext synCtx) {   
           // TODO Implement your mediation logic here  
           String[] regParam = "gov:/tasks/EventAlertScheduledTask@lastAccessTime".split("@");  
            String regPath = regParam[0];  
      String propName = regParam[1];  
     Entry propEntry = synCtx.getConfiguration().getEntryDefinition(regPath);  
     Registry registry = synCtx.getConfiguration().getRegistry();  
     if (registry != null) {  
       registry.getResource(propEntry, new Properties());  
       if (propName != null) {  
         Properties reqProperties = propEntry.getEntryProperties();  
         if (reqProperties != null) {  
           if (reqProperties.get(propName) != null) {  
             System.out.println("Property value is : "+reqProperties.getProperty(propName));  
           }  
         }  
       }  
      }  
     return true;  
 }  
 }  


Step 2


The following proxy service can be used to invoke the above class mediator.

 <?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>  
      <property name="property_value"  
           expression="get-property('registry','gov:/tasks/EventAlertScheduledTask@lastAccessTime')"/>  
      <log>  
       <property name="Access using property mediator :"  
            expression="get-property('property_value')"/>  
      </log>  
      <class name="Mypackage.Sample"/>  
      <drop/>  
    </inSequence>  
   </target>  
   <description/>  
 </proxy>