Salesforce Integration with WSO2 Enterprise Integrator

  • By Ushani Balasooriya
  • 27 Aug, 2017

WSO2 Enterprise Integrator is designed to create integration solutions that enable communication among various applications. Instead of your applications communicating directly with each other in different message formats, each application simply communicates with WSO2 Enterprise Integrator, which transforms and routes the messages to their appropriate destinations. WSO2 Enterprise Integrator allows you to implement all enterprise integration patterns. This product is lightweight, versatile and 100% open source, released under the Apache Software License Version 2.0 — one of the most business-friendly licenses available today.

Its native support for REST, JSON and XML as well as support for popular connectors like Facebook, Twitter and Salesforce makes WSO2 Enterprise Integrator a powerful solution. Below is a list of components that are packaged in WSO2 Enterprise Integrator:

  • Integrator profile - Can be used to manage short-running, stateless integration flows
  • Business process runtime - Used as long-running, stateful business processes
  • Analytics runtime - Can be used for comprehensive monitoring of requests and responses
  • Message broker runtime - Can be used for reliable message delivery between applications and systems
  • MSF4J runtime - Can be used to run microservices of the integration flows
  • Tooling - An Eclipse-based development environment

The integration runtime (enterprise service bus or ESB) allows integration architects to exploit the value of messaging in a clear understandable way.

WSO2 Enterprise Integrator tooling provides capabilities of a complete Eclipse-based development environment. The below tutorial is done using WSO2 Enterprise Integrator tooling.

Salesforce connector

A WSO2 connector allows you to interact with a third-party product and its data from your enterprise integrator message flow, enabling you to connect to and interact with the APIs of services such as Twitter, Salesforce, and JIRA. If you enable the Salesforce connector, you can perform Salesforce actions inside the enterprise integrator.

Nowadays most companies use Salesforce to monitor, maintain and manage their customer relationships in order to optimize revenue growth. Salesforce is known as the world’s first CRM platform that can be accessed from anywhere over the Internet and also perfectly utilizes cloud computing concepts. Salesforce App Cloud provides an integrated architecture that lets you focus on building solutions using Salesforce to improve enterprise business generation. Developers can now assemble applications with a few clicks or code and then instantly launch them across any device to connect with customers, employees or partners.

Below are some of the advantages that you can gain by using WSO2 Enterprise Integrator along with a Salesforce connector. You can

  • Easily integrate with Salesforce APIs
  • Insert or update data within WSO2 Enterprise Integrator
  • You can enrich queried results into standard coding formats like JSON, XML
  • Connect to other third party backends where you can easily send the enriched data

User story

In enterprise Salesforce integration scenarios, most often than not there is a backend that expects Salesforce user account details in a JSON object format. We will demonstrate how easy it is to query Salesforce objects and construct a JSON object as expected by the backend, using WSO2 Enterprise Integrator and the Salesforce connector.

Figure 1: User story

Used tools and techniques

  • Create an API and query the records using Salesforce SOAP connector
  • Retrieve the data by XPath
  • Transform the record into a JSON object using particular transformation functions and build the JSON object.
  • Send it to a backend which expects the enriched JSON object
  • WSO2 Enterprise Integrator tooling - Developer Studio is used to create a carbon application with the synapse configuration

Resources

Enterprise Integrator 6.1.1 Distribution
Salesforce SOAP Connector
Salesforce SOAP Connector Documentation
WSO2 Enterprise Integrator Tooling 6.1.1

Prerequisites

  • The user should have a Salesforce Dev account with a username, password and security token.
    Login URL - E.g. https://login.salesforce.com/services/Soap/u/40.0
    Note: 40.0 is the API version
  • The user should have installed WSO2 Enterprise Integrator tooling pack.

Coding in the WSO2 Enterprise Integrator profile

Step 1: Start the WSO2 Enterprise Integrator tooling pack

Once you have downloaded the tooling pack, extract it and run the Eclipse file. If you are in Windows, double click or run the .exe file. If you are in a Linux environment, execute the below command.

./eclipse

You will be asked to select the workspace.

Click on the Developer Studio tab and open the dashboard as shown below.

Figure 2: Developer Studio dashboard

Step 2: Create an ESB project

In the dashboard click on the ESB config project and provide the required information to create an ESB project.

The new project has now been created in the workspace. If you browse the project, you will see a project structure as follows, with folders created for different resources such as endpoints, inbound endpoints, local entries, message processors, message stores, proxy services, sequences and more.

Figure 3: The project structure

Step 3: Add the Salesforce connector into the ESB project

You can develop configurations with connectors, and deploy the configurations and connectors as composite application archive (CAR) files into WSO2 Enterprise Integrator using its tooling to add the connector to our ESB project.

Right click on the ESB project and select the Add or Remove Connector option and add the Salesforce connector by providing the location. You can download the Salesforce SOAP connector here.

Figure 4: Add connector

When you have added the connector you should be able to view the connector operations available at the end of your synapse artifact once you create one of them.

Step 4: Create an API

To create an API, click on the REST API option in the dashboard and provide the API name and context and provide the project location to be saved and set the required properties. For more information, please refer to the documentation on working with APIs via tooling.

  • name="sfquery"
  • context="/sfquery"
  • resource methods="POST"
  • url-mapping="/*"

When you open your API in design view, you will be able to see the Salesforce connector operations as shown in the below illustration.

Figure 5: API in design view with the connector operations

Step 5: Log into Salesforce

In order to log into Salesforce, we should provide our credentials as shown below.

MySFConfig

<salesforce.init>  
   <username>ushanib@gmail.com</username>  
   <password><password><security token></password>  
   <loginUrl>https://login.salesforce.com/services/Soap/u/40.0</loginUrl>  
   <blocking>false</blocking>  
 </salesforce.init>
  • username: The username to access the Salesforce account.
  • password: The password provided here is a concatenation of the user password and the security token provided by Salesforce.
  • loginUrl: The login URL to access the Salesforce account.
  • blocking: Indicates whether the connector needs to perform blocking invocations to Salesforce.

Here, we have used the Salesforce credentials as a local entry and have referred it in the synapse configurations.

To create a local entry via tooling, click on the Local Entry option in the dashboard as shown below.

  • Local Entry Name - MySFConfig
  • Local Entry Creation Type - In-Line Text Entry
  • Save Local entry in - Select the particular ESB Project
  • Value - Provide credentials as value

Figure 6: Create Local Entry

Drag and drop the getUserInfo connector operation into inSequence of the API and provide the Config Ref as ‘MySFConfig’ as illustrated in figure 7 below.

It will also include the synapse configuration below in the Source view.

<salesforce.getUserInfo configKey="MySFConfig"/>

Figure 7: getUserInfo operation

Step 6: Query Salesforce

You can drag and drop a property mediator which is under the Mediators section in the API. Properties should be set as follows.

  • New Property Name - SFQuery
  • Value - Query should be set as the value

This will add a synapse configuration for the property mediator as below in the source view. Figure 8 illustrates this.

<property name="SFQuery" value="Select u.Username, u.ProfileId, u.Name, u.LastName, u.Email From User u where Username = 'ushani@wso2.com'" scope="default" type="STRING"/>

We are going to query a user object by providing an email address. Here the email address is unique. Hence the result will be one record.

Select u.Username, u.ProfileId, u.Name, u.LastName, u.Email From User u where Username = 'ushani1@wso2.com'

Figure 8: Property mediator with Salesforce query

We can include a Salesforce query operation from the Salesforce operations as illustrated in Figure 9. Set the below properties in the query operation:

  • batchSize - Set batchSize as 1 since there will be one record queried
  • queryString - set as $ctx:SFQuery

The below synapse configuration will be created in the source view.

     <salesforce.query>
        <batchSize>1</batchSize>
            <queryString>{$ctx:SFQuery}</queryString>
     </salesforce.query>

You can refer to our documentation for more information on working with records in Salesforce SOAP connector.

Figure 9: Salesforce query operation

Note: You can directly provide login local entry just by setting the Config Ref as “MySFConfig” in the properties section as illustrated in Figure 9. If you include it, you will not need to include the salesforce.getUserInfo operation.

         <salesforce.query configKey="MySFConfig">
                <batchSize>1</batchSize>
                <queryString>{$ctx:SFQuery}</queryString>
         </salesforce.query>

Step 7: Transform the Salesforce search result into a JSON payload

Using XPath we can retrieve each value into a property as shown below. The property value will be determined during mediation by evaluating an expression. More information on the property mediator can be found in our documentation.

You can add property mediators to include the XPath of each. Figure 10 illustrates this.

Set the below properties in each property mediator.

  • New Property Name - Property name e.g. ProfileId
  • Value Type - Expression
  • Value Expression - Namespaced property
    E.g. //ns:queryResponse/ns:result/ns:records/sf:ProfileId/text()

Figure 10: XPath properties

Namespaces should be added as illustrated in figure 11 for each property.

Figure 11: Namespaced property

Below is the list of XPath expressions that need to be added to each property.

Name Expression Namespace
ProfileId //ns:queryResponse/ns:result/ns:records/sf:ProfileId/text() urn:partner.soap.sforce.com
urn:sobject.partner.soap.sforce.com
Name //ns:queryResponse/ns:result/ns:records/sf:Name/text() urn:partner.soap.sforce.com
urn:sobject.partner.soap.sforce.com
Username //ns:queryResponse/ns:result/ns:records/sf:Username/text() urn:partner.soap.sforce.com
urn:sobject.partner.soap.sforce.com
LastName //ns:queryResponse/ns:result/ns:records/sf:LastName/text() urn:partner.soap.sforce.comurn:sobject.partner.soap.sforce.com
Email //ns:queryResponse/ns:result/ns:records/sf:Email/text() urn:partner.soap.sforce.comurn:sobject.partner.soap.sforce.com

Table 1: XPath properties

Once the properties are added, the synapse configuration below will be added to the source view.

         <property xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:ns="urn:partner.soap.sforce.com" name="ProfileId" expression="//ns:queryResponse/ns:result/ns:records/sf:ProfileId/text()" scope="default" type="STRING"/>
         <property xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:ns="urn:partner.soap.sforce.com" name="Name" expression="//ns:queryResponse/ns:result/ns:records/sf:Name/text()" scope="default" type="STRING"/>
         <property xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:ns="urn:partner.soap.sforce.com" name="Username" expression="//ns:queryResponse/ns:result/ns:records/sf:Username/text()" scope="default" type="STRING"/>
         <property xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:ns="urn:partner.soap.sforce.com" name="LastName" expression="//ns:queryResponse/ns:result/ns:records/sf:LastName/text()" scope="default" type="STRING"/>
         <property xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:ns="urn:partner.soap.sforce.com" name="Email" expression="//ns:queryResponse/ns:result/ns:records/sf:Email/text()" scope="default" type="STRING"/>

The next step should be to construct the JSON payload using the PayloadFactory mediator as below which we need to send to backend.

We have configured the format of the payload and have passed the arguments. For more information on the PayloadFactory mediator, read this document.

To configure the PayloadFactory mediator via tooling, drag and drop a PayloadFactory mediator from the Palette Mediator list and configure the properties as shown below.

  • Payload Format - Inline
  • Payload - { "Profile": { "source": "SALESFORCE", "id": "$1" }, "Name": "$2", "Username": "$3", "LastName": "$4", "Email": "$5" }
  • Args - Add each argument one by one as illustrated in figure 12.
  • Media Type - json

Figure 12 illustrates the design view of the PayloadFactory mediator added via WSO2 Enterprise Integrator tooling.

Figure 12: PayloadFactory mediator

Once the format and arguments have been added, the below synapse configuration can be seen in the source view.

         <payloadFactory media-type="json">
            <format>{ "Profile": { "source": "SALESFORCE", "id": "$1" },  "Name": "$2", "Username": "$3", "LastName":  "$4", "Email": "$5"  }</format>
            <args>
               <arg evaluator="xml" expression="$ctx:ProfileId"/>
               <arg evaluator="xml" expression="$ctx:Name"/>
               <arg evaluator="xml" expression="$ctx:Username"/>
               <arg evaluator="xml" expression="$ctx:LastName"/>
               <arg evaluator="xml" expression="$ctx:Email"/>
            </args>
         </payloadFactory>

Include a property mediator to set the messageType in to application/json. Then it will include the below synapse configuration.

Set the below properties:

  • New Property Name - messageType
  • Value - application/json
         <property name="messageType" value="application/json" scope="axis2" type="STRING"/>

Step 8: Send the request to the backend

In order to send the request to the backend the user needs to add a send mediator and set the endpoint via tooling by picking the send mediator and AddressEndpoint from the palette list as illustrated in figure 13.

Set the backend URI in the URI property under Basic.

Figure 13: Send mediator and Address endpoint

The below synapse configuration will be added to the source view.

      <send>
            <endpoint>
               <address uri="http://www.mocky.io/"/>
            </endpoint>
       </send>

Configure the outSequece to get the response to the client from the backend by dragging a send mediator to the outSequence. It will generate the synapse configuration as shown below.

<outSequence>
         <send/>
</outSequence>

Step 9: Add the Salesforce Connector into a project

You should create a separate project to include the Salesforce connector as a CAR app. For more information refer to the documentation on creating a CAR file including connectors.

To create a project follow the steps below:

  1. Click File > New > Other and select Connector Exporter Project under WSO2 > Extensions > Project Types and click Next.
  2. Alternatively, open the Developer Studio Dashboard (click Developer Studio > Open Dashboard) and click Connector Exporter Project in the Enterprise Service Bus area, enter a project name and click Finish.
  3. Then right-click on the created connector exporter project, point to New. Then click Add/Remove Connectors as shown in figure 14 and provide the path to the Salesforce connector jar.

Figure 14: Add the Salesforce connector

Step 10: The whole project in design and source view

Once you are done with your API, you can view the whole project in the Developer Studio design view as shown in figure 15.

Figure 15: Design view of the API

The whole synapse configuration of the API is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<api context="/sfquery" name="sfquery" xmlns="http://ws.apache.org/ns/synapse">
    <resource methods="POST" url-mapping="/*">
        <inSequence>
            <salesforce.getUserInfo configKey="MySFConfig"/>
            <property name="SFQuery" scope="default" type="STRING" value="Select u.Username, u.ProfileId, u.Name, u.LastName, u.Email From User u where Username = 'ushani1@wso2.com'"/>
            <salesforce.query>
                <batchSize>1</batchSize>
                <queryString>{$ctx:SFQuery}</queryString>
            </salesforce.query>
            <property expression="//ns:queryResponse/ns:result/ns:records/sf:ProfileId/text()" name="ProfileId" scope="default" type="STRING" xmlns:ns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com"/>
            <property expression="//ns:queryResponse/ns:result/ns:records/sf:Name/text()" name="Name" scope="default" type="STRING" xmlns:ns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com"/>
            <property expression="//ns:queryResponse/ns:result/ns:records/sf:Username/text()" name="Username" scope="default" type="STRING" xmlns:ns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com"/>
            <property expression="//ns:queryResponse/ns:result/ns:records/sf:LastName/text()" name="LastName" scope="default" type="STRING" xmlns:ns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com"/>
            <property expression="//ns:queryResponse/ns:result/ns:records/sf:Email/text()" name="Email" scope="default" type="STRING" xmlns:ns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com"/>
            <payloadFactory description="" media-type="json">
                <format>{ "Profile": { "source": "SALESFORCE", "id": "$1" },  "Name": "$2", "Username": "$3", "LastName":  "$4", "Email": "$5"  }</format>
                <args>
                    <arg evaluator="xml" expression="$ctx:ProfileId"/>
                    <arg evaluator="xml" expression="$ctx:Name"/>
                    <arg evaluator="xml" expression="$ctx:Username"/>
                    <arg evaluator="xml" expression="$ctx:LastName"/>
                    <arg evaluator="xml" expression="$ctx:Email"/>
                </args>
            </payloadFactory>
            <property description="property" name="messageType" scope="default" type="STRING" value="application/json"/>
            <send>
                <endpoint>
                    <address uri="http://www.mocky.io/v2/5951f1c60f00000e01a3d6a5"/>
                </endpoint>
            </send>
        </inSequence>
        <outSequence>
            <send/>
        </outSequence>
        <faultSequence/>
      </resource>
</api>

Step 11: Create a CAR app using the ESB project and Salesforce connector project

Now we have completed the ESB project and Salesforce connector project. We can create a CAR app (capp) using both projects via tooling.

You can open the dashboard and click on the Composite Application Project option to create a capp. As illustrated in figure 16, select the ESB and connector project to be included and provide a capp name.

Then right click on the capp in the navigator, click on Export and select WSO2 Platform Distribution > Composite Application Archive (CAR) and click Next to provide the export destination.

Then you can select all the artifacts to be included in the CAR file by selecting the artifacts in the next window. Click Finish to complete.

Figure 16: Create a CAR app

Step 12: Start the WSO2 Enterprise Integrator profile

  • First we should export the Salesforce certificate into the file system. To do so log into your Salesforce account in the browser (i.e. https://login.salesforce.com), click the lock on the address bar to view the certificate and export the certificate to the file system.
  • Import the certificate into the ESB client keystore using the management console or by using the following command:
    keytool -importcert -file  -keystore /repository/resources/security/client-truststore.jks -alias "Salesforce"
    
  • In order to start the WSO2 Enterprise Integrator profile, go to <wso2ei_home>/bin and type ‘sh integrator.sh’ for UNIX based systems or ‘integrator.bat’ for Windows.
  • You will see the log below with the management console URL.
    [EI-Core]  INFO - StartupFinalizerServiceComponent Server           :  WSO2 Enterprise Integrator-6.1.1
    [EI-Core]  INFO - StartupFinalizerServiceComponent WSO2 Carbon started in 30 sec
    [EI-Core]  INFO - CarbonUIServiceComponent Mgt Console URL  : https://:9443/carbon/
    

You can open the management console in your browser, using the following URL.

http://<ip>:9443/carbon 

Step 13: Upload the CAR file into WSO2 Enterprise Integrator and invoke the API

The admin user should log into the management console and upload the created CAR file into Carbon Applications section as displayed in figure 17.

Figure 17: Upload connector

Once you refresh you can see that the carbon application and relevant artifacts have been deployed. In this CAR app, you can see the artifacts below have been deployed.

  • Salesforce connector
  • sfquery api
  • MySFConfig local entry

Invoke the API with the following command.

   curl -v -X POST http://<host>:8280/sfquery

You will get the response from the backend if it returns a response to the client.

If you enable wire logs, you will be able to see the constructed payload message in the logs as shown below.

Salesforce object returned:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>53</current>
            <limit>5000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <queryResponse>
         <result xsi:type="QueryResult">
            <done>true</done>
            <queryLocator xsi:nil="true" />
            <records xsi:type="sf:sObject">
               <sf:type>User</sf:type>
               <sf:Id xsi:nil="true" />
               <sf:Username>ushani1@wso2.com</sf:Username>
               <sf:ProfileId>00e90000001aVwiAAE</sf:ProfileId>
               <sf:Name>Balasooriya</sf:Name>
               <sf:LastName>Balasooriya</sf:LastName>
               <sf:Email>ushani@wso2.com</sf:Email>
            </records>
            <size>1</size>
         </result>
      </queryResponse>
   </soapenv:Body>
</soapenv:Envelope>

Transformed JSON payload:

 {
   "Profile": {
      "source": "SALESFORCE",
      "id": "00e90000001aVwiAAE"
   },
   "Name": "Balasooriya",
   "Username": "ushani1@wso2.com",
   "LastName": "Balasooriya",
   "Email": "ushani@wso2.com"
}

Conclusion

WSO2 Enterprise Integrator and its extensive functionality enables a developer to build their own APIs. This is done using the user friendly tooling component to invoke commonly used third-party APIs such as Salesforce to construct any type of message into the standard format expected by the backend. WSO2 Enterprise Integrator works as an enterprise service bus whilst the ESB Salesforce connector is used to query the Salesforce object, which can all be easily deployed in WSO2 Enterprise Integrator as a carbon app (CAR) built using the tooling component.

References