Thursday, May 3, 2018

Your First Gradle Project with Intellij Idea

To create a new Gradle project go to File->New->Project and it will open the following New Project window.




Select Gradle form left menu and check Java as additional libraries and frameworks. In addition to that, you need to select the run time java version as the project SDK.
Click on Next button and select the Group Id, Artifact Id and Version values as below.
The Artifact Id and the Version parameters are combined to generate the name of the deployable(jar,war etc...). However the Group Id is required only if we are planning to deploy the output in the maven repository which can be use as a dependency to another project. 


Click on the Next button and check the 'Use Auto Import' in the following window. Keep the other parameters as it is.

The importance of Check icon the 'Use Auto Import' is Once we add or remove dependency from build.gradle file, those changes will automatically reflect to the IDE. 
Click on the Next button and select the Project Name, Project Location and then click on the Finish button.  
The project will be created as below.
However we can't see the folder structure. To generate the source folder, go to the File->Settings->Build,Execution,Deployment->Build Tools->Gradle. In the below window, check the Use auto-import and Create directories for empty content root automatically.


Click on the OK and you can find the project folder structure has been created as below.

Then click on the java folder and create a simple java class as below.


 public class HelloWorld {  
   public static void main(String[] args) {  
     System.out.println("Hello Gradle............");  
   }  
 }  

In addition to that, open the build.gradle file and select the correct version of java run time for the sourceCompatibility.

 plugins {  
   id 'java'  
 }  
 group 'com.randika'  
 version '1.0-SNAPSHOT'  
 sourceCompatibility = 1.7  
 repositories {  
   mavenCentral()  
 }  
 dependencies {  
   testCompile group: 'junit', name: 'junit', version: '4.12'  
 }  


After that we can build the project with Gradle. Open the Gradle tool window which is in the upper right side of the IDE and double click on the build button. After that you can find the "test-gradle-1.0-SNAPSHOT.jar" has been generated in the build->libs folder.
Run the jar file from its location with the below command.

 java -jar test-gradle-1.0-SNAPSHOT.jar  

However you will prompt the bellow error due to unable of finding the main class.

To overcome this issue, we can add the manifest information to the build.gradle file as bellow and build the jar again.

 plugins {  
   id 'java'  
 }  
 jar {  
   manifest {  
     attributes 'Main-Class': 'HelloWorld'  
   }  
 }  
 group 'com.randika'  
 version '1.0-SNAPSHOT'  
 sourceCompatibility = 1.7  
 repositories {  
   mavenCentral()  
 }  
 dependencies {  
   testCompile group: 'junit', name: 'junit', version: '4.12'  
 }  

You can get the below result.



Tuesday, March 28, 2017

Message transformation using Iterate and Aggregate pattern without using the send/call

Iterate mediator will always have to be accompanied by an Aggregate mediator. Iterate will be used for situations where split messages will be sent to a target and collected by aggregate in a different flow. The current implementation is expecting to send the iterated requests to the back end service and aggregate will trigger only after the response received from the back end.
However following sample illustrate how to use iterate/aggregate pattern without sending the iterated messages to the backend service.

To get this work, we need to follow the below steps inside the iterate mediator in each iteration.

1) Apply any needed transformations to your message.
2) Define it as a response message (set property RESPONSE to true)

 <property name="RESPONSE" value="true"/>  

3) Define the aggregate mediator in a sequence and invoke that at the end of each iteration.


 <sequence key="AggregateSequence"/>  


Applied the above changes to the "AggregateProxy" and Created a new sequence "AggregateSequence" containing the Aggregate mediator logic.

AggregateProxy.xml
 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="AggregateProxy"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <inSequence>  
      <iterate xmlns:abc="http://abc.com" id="iteratorId" expression="//abc:Request">  
       <target>  
         <sequence>  
          <payloadFactory media-type="xml">  
            <format>  
             <abc:Result>$1</abc:Result>  
            </format>  
            <args>  
             <arg evaluator="xml" expression="//abc:Request"/>  
            </args>  
          </payloadFactory>  
          <log level="full"/>  
          <property name="RESPONSE" value="true"/>  
          <sequence key="AggregateSequence"/>  
         </sequence>  
       </target>  
      </iterate>  
    </inSequence>  
   </target>  
   <description/>  
 </proxy>  



AggregateSequence.xml
 <sequence xmlns="http://ws.apache.org/ns/synapse" name="AggregateSequence">  
   <property name="ResultTag" scope="default">  
    <test:result xmlns:test="http://test.com"></test:result>  
   </property>  
   <aggregate id="iteratorId">  
    <completeCondition>  
      <messageCount></messageCount>  
    </completeCondition>  
    <onComplete xmlns:abc="http://abc.com" xmlns:ns="http://org.apache.synapse/xsd" expression="//abc:Result" enclosingElementProperty="ResultTag">  
      <log level="full"></log>  
      <respond></respond>  
    </onComplete>  
   </aggregate>  
 </sequence>  


Invoked the "AggregateProxy.xml" with the below request.

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
   <soapenv:Header/>  
   <soapenv:Body>  
 <ns0:getDBGateDataRequest xmlns:ns0="http://abc.com">  
 <ns0:Request>1</ns0:Request>   
 <ns0:Request>2</ns0:Request>   
 <ns0:Request>3</ns0:Request>   
 </ns0:getDBGateDataRequest>  
 </soapenv:Body>  
 </soapenv:Envelope>  


Observed the transformed aggregated message.

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">  
   <soapenv:Body>  
    <test:result xmlns:test="http://test.com">  
      <abc:Result xmlns:abc="http://abc.com">1</abc:Result>  
      <abc:Result xmlns:abc="http://abc.com">2</abc:Result>  
      <abc:Result xmlns:abc="http://abc.com">3</abc:Result>  
    </test:result>  
   </soapenv:Body>  
 </soapenv:Envelope>  

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>