Thursday, March 9, 2017

Invoke Salesforce REST API APEX classes using synapse mediators in WSO2 ESB

Invoke through sample synapse config(API/ Sequence/ Proxy) using following steps :

  • Download the salesforce REST connector from store.
  • Here, we use salesforce REST connector to maintain the access token and get the access token from the refresh token.
  • Open the <ESB_HOME>/repository/conf/axis2/axis2.xml and add the <parameter name="HttpsProtocols">TLSv1.1,TLSv1.2</parameter> entry inside the PassThroughHttpSSLSender element as below :
<transportSender name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLSender">
 .....
 <parameter name="HttpsProtocols">TLSv1.1,TLSv1.2</parameter>
 .....
</transportSender>
  • Start the WSO2 ESB Server.
  • Navigate to the management console and deploy the downloaded connector.
  • Click the Main tab on the Management Console, go to Manage -> Services and then click Proxy Service -> Custom Proxy. Click on switch to source view. Then add following and click on Save.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="salesforceApex"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http">
   <target>
      <inSequence>
         <property expression="json-eval($.accessToken)" name="accessToken"/>
         <property expression="json-eval($.apiVersion)" name="apiVersion"/>
         <property expression="json-eval($.hostName)" name="hostName"/>
         <property expression="json-eval($.refreshToken)" name="refreshToken"/>
         <property expression="json-eval($.clientSecret)" name="clientSecret"/>
         <property expression="json-eval($.clientId)" name="clientId"/>
         <property expression="json-eval($.registryPath)" name="registryPath"/>
         <property expression="json-eval($.intervalTime)" name="intervalTime"/>
         <property expression="json-eval($.inputPayload)" name="inputPayload"/>
         <property expression="json-eval($.httpMethod)" name="httpMethod"/>
         <property expression="json-eval($.apexInstanceUrl)" name="apexInstanceUrl"/>
         <property expression="json-eval($.namespacePrefix)" name="namespacePrefix"/>
         <property expression="json-eval($.apexclassName)" name="apexclassName"/>
         <property expression="json-eval($.urlParameters)" name="urlParameters"/>
         <salesforcerest.init>
            <accessToken>{$ctx:accessToken}</accessToken>
            <apiVersion>{$ctx:apiVersion}</apiVersion>
            <clientId>{$ctx:clientId}</clientId>
            <clientSecret>{$ctx:clientSecret}</clientSecret>
            <refreshToken>{$ctx:refreshToken}</refreshToken>
            <hostName>{$ctx:hostName}</hostName>
            <registryPath>{$ctx:registryPath}</registryPath>
            <intervalTime>{$ctx:intervalTime}</intervalTime>
         </salesforcerest.init>
         <payloadFactory media-type="json">
<format>
                    $1
                </format>
            <args>
               <arg evaluator="xml" expression="get-property('inputPayload')"/>
            </args>
         </payloadFactory>
         <script language="js">//url param variables
                var namespacePrefix = mc.getProperty("namespacePrefix");
                var urlParameters = mc.getProperty("urlParameters");
                //url param processing start
                var urlParamString = '';
                if (namespacePrefix != "" &amp;&amp; namespacePrefix != null) {
                namespacePrefix = namespacePrefix + '/';
                }
                if (urlParameters != null &amp;&amp; urlParameters != "" &amp;&amp; urlParameters != {}) {
                var txt = '{"fieldValuesList":' + urlParameters + '}';
                var obj = eval ("(" + txt + ")");
                for(var key in obj.fieldValuesList){
                var fieldValue = obj.fieldValuesList[key];
                var field = key;
                urlParamString += field + "=" + fieldValue + "&amp;";
                }
                }
                if(urlParamString != '') {
                urlParamString = '?' + urlParamString.toString().substring(0, urlParamString.toString().lastIndexOf("&amp;"));
                }
                mc.setProperty('uri.var.namespacePrefix', namespacePrefix);
                mc.setProperty('uri.var.urlParamString', urlParamString);
                //url param processing end</script>
         <property action="remove" name="Accept-Encoding" scope="transport"/>
         <property expression="$ctx:apexInstanceUrl" name="uri.var.apexInstanceUrl"/>
         <property expression="$ctx:apexclassName" name="uri.var.apexclassName"/>
         <filter xpath="($ctx:httpMethod = 'post' or $ctx:httpMethod = 'POST')">
            <then>
               <call>
                  <endpoint>
                     <http method="POST"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
               </call>
            </then>
         </filter>
         <filter xpath="($ctx:httpMethod = 'get' or $ctx:httpMethod = 'GET')">
            <then>
               <call>
    <endpoint>
                     <http method="GET"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
               </call>
            </then>
         </filter>
         <filter xpath="($ctx:httpMethod = 'put' or $ctx:httpMethod = 'PUT')">
            <then>
               <call>
                  <endpoint>
                     <http method="PUT"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
               </call>
            </then>
         </filter>
         <filter xpath="($ctx:httpMethod = 'patch' or $ctx:httpMethod = 'PATCH')">
            <then>
               <call>
                  <endpoint>
                     <http method="PATCH"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
               </call>
            </then>
         </filter>
         <filter xpath="($ctx:httpMethod = 'delete' or $ctx:httpMethod = 'DELETE')">
            <then>
               <call>
                  <endpoint>
                     <http method="DELETE"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
               </call>
            </then>
         </filter>
         <filter xpath="($ctx:httpMethod = 'head' or $ctx:httpMethod = 'HEAD')">
            <then>
               <call>
                  <endpoint>
                     <http method="HEAD"                           uri-template="{uri.var.apexInstanceUrl}/services/apexrest/{+uri.var.namespacePrefix}{uri.var.apexclassName}{+uri.var.urlParamString}"/>
                  </endpoint>
</call>
            </then>
         </filter>
         <respond/>
      </inSequence>
   </target>
   <description/>
</proxy>             

  • Click the Main tab on the Management Console, go to Manage -> Services and then click List. Then click on “salesforceApex”. Under the Endpoints, you can find the http endpoint. With this http endpoint and the following request following payload, you can get the output. Here in this proxy service, we reuse the salesforce REST connector for refreshing the access token.
{ 
"accessToken":"00D6F000001Ndi6!ARMAQPHSxOeI3V1OOtHs8nm4v0cXJGRoqfEMWcPXsPy.1KP.LV_GA8uyM_VTLn3OuI8nWAAsA4Nrq4AGBUTBTBpg0dvEe7fy",
  "apiVersion": "v37.0",
  "clientId": "3MVG9YDQS5WtC11r7PwwtXgMbc11ddO8.v5fACou6XbISTmj5sWLnAFkgpXcjIxCJFtqfDsZL4.yunUQJaohk",
  "refreshToken": "5Aep861..zRMyCurAXnOWvxvIMAnUFVITuyCGAN6mPVNRczzrev5q9h0YI4m45COJYgeLgEorlUMZxm.YAeEE80",
  "clientSecret": "8631600822489897349",
  "hostName": "https://login.salesforce.com",
  "intervalTime" : "100000",
  "registryPath": "connectors/SalesforceRest",
  "apexInstanceUrl":"https://ap4.salesforce.com",
  "namespacePrefix": "TestOrgNew",
  "apexclassName":"AccountRestapiHandler",
  "httpMethod":"post",
  "urlParameters" : {
          "urlParameter1":"value1",
        "urlParameter2":"value2"
   },
  "inputPayload" : {
"AccountDetails":"[{\"getAccout\":{\"Phone\":\"95685695696\",\"Name\":\"TEST\",\"AccountNumber\":\"High\",\"Description\":\"Test\",\"SicDesc\":\"Test\"}}]",
       "TransactionId":"b22518b3",
       "SourceFile":"Sales"
    }
}

Creating REST APIs using Apex REST

The Salesforce REST API allow you to integration with Salesforce applications using standard HTTP methods such as GET, POST, PUT, PATCH, DELETE, and HEAD. This API provides a way to expose the data you have within your Salesforce application to external applications.

Follow steps to create the Apex REST API. Under App Setup expand Developer and click Apex Classes. Click New to create a new class.

Paste the following code into Apex Class Editor:

@RestResource(urlMapping='/Widgets/*')
global class WidgetController {

    @HttpGet
    global static List<Widget__c> getWidgets() {
        List<Widget__c> widgets = [SELECT Name from Widget__c];
        return widgets;
    }

    @HttpPost 
    global static String createNewWidget(String Name) {
        Widget__c w = new Widget__c();
        w.Name = Name;
        insert w;

        return '{"Status":"Done"}';
   }

    @HttpDelete
    global static String deleteWidgetById() {
        String Id = RestContext.request.params.get('Id');
        String status = RestContext.request.params.get('status');
        List<Widget__c> w = [ Select ID from Widget__c where Id= :Id];

        delete w;

        return '{"Status":"Deleted Widget"}' + status;
    }

    @HttpPut
    global static String updateWidget(String Id, String NewName) {
        Widget__c w = [ Select ID, Name from Widget__c where Id= :Id];

        w.Name = NewName;
        update w;

        return '{"Status":"Widget Updated"}';
    }
}


Tuesday, February 14, 2017

Sample ESB sequence and Inbound to receive the message from the queue using the ESB Amazon SQS streaming connector and then send that message into another queue using the ESB Amazon SQS connector

Sample ESB Sequence

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="request" onError="fault" xmlns="http://ws.apache.org/ns/synapse">
    <log level="custom">
        <property expression="$body/*" name="------------" xmlns:ns="http://org.apache.synapse/xsd"/>
    </log>
    <property name="POST_TO_URI" scope="axis2" value="true"/>
    <call blocking="true">
        <endpoint>
            <http method="GET" uri-template="https://httpbin.org/get"/>
        </endpoint>
    </call>
    <property expression="$body/*" name="messageBody" xmlns:ns="http://org.apache.synapse/xsd"/>
    <amazonsqs.init>
        <secretAccessKey>xxxxxxxxxxxxxxxxxxxxx</secretAccessKey>
        <accessKeyId>xxxxxxxxxxxxxxxxxxxxx</accessKeyId>
        <version>2009-02-01</version>
        <region>us-east-1</region>
    </amazonsqs.init>
    <amazonsqs.sendMessage>
        <queueId>141823495686</queueId>
        <queueName>SQS_Inbound</queueName>
        <messageBody>{$ctx:messageBody}</messageBody>
    </amazonsqs.sendMessage>
</sequence>

Sample ESB Inbound

<?xml version="1.0" encoding="UTF-8"?>
<inboundEndpoint xmlns="http://ws.apache.org/ns/synapse"
                 name="amazon"
                 sequence="request"
                 onError="fault"
                 class="org.wso2.carbon.inbound.amazonsqs.AmazonSQSPollingConsumer"
                 suspend="false">
   <parameters>
      <parameter name="inbound.behavior">polling</parameter>
      <parameter name="interval">2000</parameter>
      <parameter name="sequential">true</parameter>
      <parameter name="coordination">true</parameter>
      <parameter name="attributeNames">attributeName1,contentType</parameter>
      <parameter name="accessKey">xxxxxxxxxxxxxxxxxxxxxxxxxx</parameter>
      <parameter name="waitTime">19</parameter>
      <parameter name="maxNoOfMessage">10</parameter>
      <parameter name="secretKey">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</parameter>
      <parameter name="contentType">text/plain</parameter>
      <parameter name="destination">https://sqs.us-east-1.amazonaws.com/141823495686/SQS_Queue</parameter>
   </parameters>
</inboundEndpoint>