Friday, December 2, 2016

Introducing WSO2 ESB Connector for Kill Bill

Kill Bill is an open source platform for subscription billing and payments integration.Kill Bill helps enterprises by scaling their billing and payment infrastructure. It provides analytics and financial reports to make sure the businesses remain compliant.Its plug-in architecture allows us to apply custom logic easily and to integrate with dozens of payment gateways like PayPal, ACH,...

Now WSO2 ESB supports connecting Kill Bill via its Kill Bill connector. Kill Bill connector allows you to access the Kill Bill through its REST API. Let’s see how to configure the Kill Bill connector.

Requirements 
  • WSO2 ESB
  • Kill Bill connector
  • Kill Bill platform

Setup the Kill Bill
  • Follow the steps in here to install the Kill Bill.
  • Once you installed use the following curl command to create a tenant in Kill Bill.

curl -v \
     -X POST \
     -u admin:password \
     -H 'Content-Type: application/json' \
     -H 'X-Killbill-CreatedBy: admin' \
     -d '{"apiKey": "bob", "apiSecret": "lazar"}' \
     "http://127.0.0.1:8080/1.0/kb/tenants"


Setup the WSO2 ESB with Kill Bill Connector
  • Download the ESB from here and start the server.
  • Download the Kill Bill connector from WSO2 Store.
  • Add and enable the connector via ESB Management Console.
  • Create Proxy service to retrieve prospects details from Kill Bill and invoke the proxy with the following request.

Proxy Service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="createAccount"
       transports="http https"
       startOnLoad="true">
   <description/>
   <target>
      <inSequence>
         <property name="apiUrl" expression="json-eval($.apiUrl)"/>
         <property name="username" expression="json-eval($.username)"/>
         <property name="password" expression="json-eval($.password)"/>
         <property name="apiKey" expression="json-eval($.apiKey)"/>
         <property name="apiVersion" expression="json-eval($.apiVersion)"/>
         <property name="apiSecret" expression="json-eval($.apiSecret)"/>
         <property name="blocking" expression="json-eval($.blocking)"/>
         <property name="externalKey" expression="json-eval($.externalKey)"/>
         <property name="name" expression="json-eval($.name)"/>
         <property name="email" expression="json-eval($.email)"/>
         <property name="currency" expression="json-eval($.currency)"/>
         <property name="createdBy" expression="json-eval($.createdBy)"/>
         <killbill.init>
            <apiUrl>{$ctx:apiUrl}</apiUrl>
            <username>{$ctx:username}</username>
            <password>{$ctx:password}</password>
            <apiKey>{$ctx:apiKey}</apiKey>
            <apiVersion>{$ctx:apiVersion}</apiVersion>
            <apiSecret>{$ctx:apiSecret}</apiSecret>
            <blocking>{$ctx:blocking}</blocking>
         </killbill.init>
         <killbill.createAccount>
            <externalKey>{$ctx:externalKey}</externalKey>
            <name>{$ctx:name}</name>
            <email>{$ctx:email}</email>
            <currency>{$ctx:currency}</currency>
            <createdBy>{$ctx:createdBy}</createdBy>
         </killbill.createAccount>
         <respond/>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
</proxy>

Request

{
    "apiUrl":"http://127.0.0.1:8080",
    "apiVersion":"1.0",
    "username":"admin",
    "password":"password",
    "apiKey":"bob",
    "apiSecret":"lazar",
    "externalKey": "myAccount",
    "currency":"USD",
    "name": "testAccount",
    "email": "johndoe@gmail.com",
    "createdBy":"demo"
}

References
  1. https://killbill.io/
  2. https://docs.wso2.com/display/ESBCONNECTORS/Kill+Bill+Connector

Wednesday, November 9, 2016

Dynamic registry lookup in WSO2 ESB

Dynamic lookup allows for seamless data changes without any service interruption. In a dynamic lookup information is derived from the data, rather than modeled at design time. This enables you to specify the information during at runtime (dynamically). You need not define data at design time. You can achieve this in WSO2 ESB by using dynamic XPath expression.

First, we need to create the XPath expression using the property mediator.

<property name="xpathExpr" expression="fn:concat('//',$ctx:name)" scope="default" type="STRING"/>

Then we can use evaluate function as below

<property name="xpathValue" expression="evaluate($ctx:xpathExpr)" scope="default" type="STRING"/>

The result of the evaluate function is the result of evaluating the composed XPath expression. This is useful where an XPath expression needs to be constructed at run-time. Let's see how we can use dynamic XPath expression for dynamic registry lookup in WSO2 ESB.

First, store the below data as an XML file in the registry.
  • Log on to ESB management console.
  • Click the "Main" button to access the "Manage" menu.
  • Click on "Browse," in the left "Registry" menu.
  • Goto _system > config > click on the "Add Resource" link.
  • Add the following data with name as productlist.xml and Media type as application/xml.

<productlist>
   <product>
      <id>API Cloud</id>
      <plans>
         <plan>
            <name>Trial</name>
            <price>$0</price>
            <feature>10 portal users</feature>
         </plan>
         <plan>
            <name>Starter</name>
            <price>$129</price>
            <feature>100 portal users</feature>
         </plan>
         <plan>
            <name>Getting Traction</name>
            <price>$298</price>
            <feature>2000 portal users</feature>
         </plan>
         <plan>
            <name>Medium</name>
            <price>$698</price>
            <feature>7000 portal users</feature>
         </plan>
         <plan>
            <name>Large</name>
            <price>$2980</price>
            <feature>Unlimited portal users</feature>
         </plan>
         <plan>
            <name>Extra-large</name>
            <price>$9980</price>
            <feature>Unlimited portal users</feature>
         </plan>
      </plans>
   </product>
   <product>
      <id>APP Cloud</id>
      <plans>
         <plan>
            <name>Beta</name>
            <price>$0</price>
            <feature>Greater application compatibility with a separate docker container per application version</feature>
         </plan>
      </plans>
   </product>
</productlist>


Use the following proxy service to dynamically lookup on the registry and send back as a response.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="dynamicLookup"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http,https">
   <target>
      <inSequence>
         <property expression="//productName" name="productName"/>
         <property expression="//productPlan" name="productPlan"/>
         <property expression="get-property('registry','conf:/productlist.xml')"
                   name="cloud"
                   scope="default"
                   type="OM"/>
         <property expression="fn:concat(&#34;$ctx:cloud//product[id='&#34;,$ctx:productName,&#34;']/plans/plan[name='&#34;,$ctx:productPlan,&#34;']/price&#34;)"
                   name="priceExpr"
                   scope="default"
                   type="STRING"/>
         <property expression="fn:concat(&#34;$ctx:cloud//product[id='&#34;,$ctx:productName,&#34;']/plans/plan[name='&#34;,$ctx:productPlan,&#34;']/feature&#34;)"
                   name="featureExpr"
                   scope="default"
                   type="STRING"/>
         <property expression="evaluate($ctx:priceExpr)"
                   name="price"
                   scope="default"
                   type="STRING"/>
         <property expression="evaluate($ctx:featureExpr)"
                   name="feature"
                   scope="default"
                   type="STRING"/>
         <payloadFactory media-type="xml">
            <format>
               <product>
                  <name>$1</name>
                  <plan>$2</plan>
                  <price>$3</price>
                  <feature>$4</feature>
               </product>
            </format>
            <args>
               <arg evaluator="xml" expression="$ctx:productName"/>
               <arg evaluator="xml" expression="$ctx:productPlan"/>
               <arg evaluator="xml" expression="$ctx:price"/>
               <arg evaluator="xml" expression="$ctx:feature"/>
            </args>
         </payloadFactory>
         <respond/>
      </inSequence>
   </target>
   <description/>
</proxy>

Request :

<request>
    <productName>API Cloud</productName>
    <productPlan>Getting Traction</productPlan>
</request>

Response:

<product xmlns="http://ws.apache.org/ns/synapse">
    <name>API Cloud</name>
    <plan>Getting Traction</plan>
    <price>$298</price>
    <feature>2000 portal users</feature>
</product>

Here proxy service takes the product name & plan details from the incoming message and builds the required XPath expression at the runtime to fetch the data from the registry.

Here you can change the product/product plan details without any service interruption by modifying only the productlist.xml file in the registry.  So with the dynamic lookup in WSO2 ESB, you can facilitate the seamless integration.

Monday, October 24, 2016

Introducing WSO2 ESB Connector for Pardot

Pardot is one of the leading marketing automation tools. It provides a full suite of tools that help marketers create meaningful connections, generate more pipeline, and empower sales to close more deals.

Now WSO2 ESB supports connecting Pardot via its Pardot connector. Pardot connector allows you to access the Pardot through its REST API. Let’s see how to configure the Pardot connector.


Requirements 
  • WSO2 ESB
  • Pardot connector
  • Pardot account

Get the credentials from Pardot account
  • Obtain the email, password, and user_key from your Pardot account.
  • For user_key, click {your email address} > Settings > API User Key.

Setup the WSO2 ESB with Pardot Connector
  • Download the ESB from here and start the server.
  • Download the Pardot connector from WSO2 Store.
  • Add and enable the connector via ESB Management Console.
  • Create Proxy service to retrieve prospects details from Pardot and invoke the proxy with the following request.

Proxy Service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="getProspects"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http,https">
   <target>
      <inSequence>
         <property expression="//apiUrl" name="apiUrl"/>
         <property expression="//email" name="email"/>
         <property expression="//password" name="password"/>
         <property expression="//userKey" name="userKey"/>
         <property expression="//apiVersion" name="apiVersion"/>
         <property expression="//createdAfter" name="createdAfter"/>
         <property expression="//limit" name="limit"/>
         <property expression="//sortBy" name="sortBy"/>
         <property expression="//sortOrder" name="sortOrder"/>
         <pardot.init>
            <apiUrl>{$ctx:apiUrl}</apiUrl>
            <email>{$ctx:email}</email>
            <password>{$ctx:password}</password>
            <userKey>{$ctx:userKey}</userKey>
            <apiVersion>{$ctx:apiVersion}</apiVersion>
         </pardot.init>
         <pardot.getProspects>
            <createdAfter>{$ctx:createdAfter}</createdAfter>
            <limit>{$ctx:limit}</limit>
            <sortBy>{$ctx:sortBy}</sortBy>
            <sortOrder>{$ctx:sortOrder}</sortOrder>
         </pardot.getProspects>
         <respond/>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description/>
</proxy>

Request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<request>
   <apiUrl>https://pi.pardot.com/api</apiUrl>
   <email>johndoe@gmail.com</email>
   <password>johnpass</password>
   <userKey>1oic7694habc85lkgng965ut85</userKey>
   <apiVersion>3</apiVersion>
   <createdAfter>yesterday</createdAfter>
   <sortBy>created_at</sortBy>
   <sortOrder>descending</sortOrder>
   <limit>2</limit>
</request>


References
  1. http://www.pardot.com/
  2. https://docs.wso2.com/display/ESBCONNECTORS/Pardot+Connector

Saturday, October 22, 2016

Search with WSO2 NetSuite Connector- Advanced Search

This is the final post in the series, 'Search operation with WSO2 NetSuite Connector'. In this post, I am discussing how we can use search method in WSO2 NetSuite connector to perform the advanced search in NetSuite.

Advanced search


An advanced search allows you to search for a record type in which you specify search filter fields and/or search return columns or joined search columns. Using advanced search, you can also return an existing saved search.

What is saved search?


A Saved Search is a reusable search definition that can have many advanced search filters and results display options.

To create a saved search
  • Go to Reports > Saved Searches > All Saved Searches > New and select the record type for the saved search.


  • On a saved search definition page, enter a title for the saved search.
  • If you want the search to be available to all users, check the Public box. 
  • On the Criteria subtab, define criteria to filter saved search records. These criteria can include dynamically calculated field values, including join fields; formulas containing SQL functions, as well as AND/OR expressions.


  • On the Results subtab, define display options for saved search results.
  • After you have completed saved search definitions, you can click preview to review search results without saving the search definitions.



  • Then click Return to Criteria button to go back to the saved search page and click Save to save search definitions and make the search available to be run by yourself and other members.

How to reference an existing saved search via NetSuite Connector?


First, you must obtain the saved search ID to reference an existing saved search. You can do so through the UI by going to Lists > Search > Saved Searches. The saved search ID appears in the ID column.



This request sample shows how to execute a saved search on customers via NetSuite connector, and you can use the proxy service mentioned in the first post to perform this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="wso2.connector.netsuite">
  <soapenv:Header/>
   <soapenv:Body>
      <urn:apiUrl>https://webservices.na1.netsuite.com/services/NetSuitePort_2016_1</urn:apiUrl>
      <urn:applicationId>32XXX75-CXXE-47X7-BX7-A3EXXXX9D</urn:applicationId>
      <urn:email>johndoe@abc.com</urn:email>
      <urn:password>john4doe</urn:password>
      <urn:account>TSTXXXXXX12</urn:account>
      <urn:searchRecord>
         <q1:searchRecord xmlns:q1="urn:relationships_2016_1.lists.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="q1:CustomerSearchAdvanced" savedSearchId="748" />
      </urn:searchRecord>
   </soapenv:Body>
</soapenv:Envelope>

Friday, October 14, 2016

Search with WSO2 NetSuite Connector - Joined Search

This is the second post in the series, 'Search operation with WSO2 NetSuite Connector'. In this post, I am discussing how we can use search method in WSO2 NetSuite connector to perform the joined search in NetSuite.

Joined search


A joined search allows you to search for a specific record type using the fields on an associated record as search filters. 

In SuiteTalk, all search joins are listed in the < Record > Search object. For example, to find available search joins for the Contact or Customer record, see the relationships XSD.

You can use the proxy service mentioned in the first post to perform the joined search via WSO2 NetSuite connector.

This request sample shows how to execute a customer search in which the contact email address is specified as the search criteria.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="wso2.connector.netsuite">
   <soapenv:Header />
   <soapenv:Body>
      <urn:apiUrl>https://webservices.na1.netsuite.com/services/NetSuitePort_2015_2</urn:apiUrl>
      <urn:applicationId>32XXX75-CXXE-47X7-BX7-A3EXXXX9D</urn:applicationId>
      <urn:email>johndoe@abc.com</urn:email>
      <urn:password>john4doe</urn:password>
      <urn:account>TSTXXXXXX12</urn:account>
      <urn:searchRecord>
         <searchRecord xmlns:ns4="urn:relationships_2015_1.lists.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns4:ContactSearch">
            <ns4:basic xmlns:ns5="urn:common_2015_1.platform.webservices.netsuite.com" xsi:type="ns5:ContactSearchBasic">
               <ns5:email xmlns:ns6="urn:core_2015_1.platform.webservices.netsuite.com" operator="is" xsi:type="ns6:SearchStringField">
                  <ns6:searchValue xsi:type="xsd:string">dave@cleanenergy.com</ns6:searchValue>
               </ns5:email>
            </ns4:basic>
            <ns4:customerJoin xmlns:ns7="urn:common_2015_1.platform.webservices.netsuite.com" xsi:type="ns7:CustomerSearchBasic">
               <ns7:entityId xmlns:ns8="urn:core_2015_1.platform.webservices.netsuite.com" operator="is" xsi:type="ns8:SearchStringField">
                  <ns8:searchValue xsi:type="xsd:string">Clean Energy</ns8:searchValue>
               </ns7:entityId>
            </ns4:customerJoin>
         </searchRecord>
      </urn:searchRecord>
   </soapenv:Body>
</soapenv:Envelope>

Monday, October 3, 2016

Search with WSO2 NetSuite Connector - Basic Search

This is the first post in the series, 'Search operation with WSO2 NetSuite Connector'. The search operation in SuiteTalk is used to execute a search on a specific record type based on a set of criteria. The search operation can be used to perform the following types of searches.
  • Basic search
  • Joined search
  • Advanced search 
In this post, I am discussing how we can use search method in WSO2 NetSuite connector to perform the basic search in NetSuite.

Basic search

A basic search lets you to search records of a specific type using the fields on that record as search filters.

To perform a basic search in which you specify search filter criteria only, use:
  •  < Record > Search
  •  < Record > SearchBasic
In SuiteTalk, any record that supports search operation has a corresponding < Record > Search object, which contains a basic element. The basic element references a < Record > SearchBasic object, which defines all available search criteria (filter fields) specific to that record type.

You can find the search types which are used throughout web services to populate the system defined lists in the schema browser.

The enumerations (the available values that should be used to populate these fields in your web services requests. ) are defined in the platformCoreTyp XSD.

SuiteTalk provides a collection of operators, and they differ depending on the field type you are searching. For example, the following are the collection of operators supported by the SearchStringFieldOperator.
  • contains
  • doesNotContain
  • doesNotStartWith
  • empty
  • hasKeywords
  • is
  • isNot
  • notEmpty
  • startsWith
Let see how to perform basic customer search via WSO2 NetSuite Connector.

Create Proxy service to search customer with given email Id from NetSuite and invoke the proxy with the following request.

Proxy Service 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="netsuiteSearch"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http,https">
   <target>
      <inSequence>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:apiUrl/text()"
                   name="apiUrl"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:applicationId/text()"
                   name="applicationId"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:email/text()"
                   name="email"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:password/text()"
                   name="password"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:account/text()"
                   name="account"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:bodyFieldsOnly/text()"
                   name="bodyFieldsOnly"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:returnSearchColumns/text()"
                   name="returnSearchColumns"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:pageSize/text()"
                   name="pageSize"/>
         <property xmlns:ns="wso2.connector.netsuite"
                   expression="//ns:searchRecord/*"
                   name="searchRecord"/>
         <netsuite.init>
            <apiUrl>{$ctx:apiUrl}</apiUrl>
            <applicationId>{$ctx:applicationId}</applicationId>
            <password>{$ctx:password}</password>
            <email>{$ctx:email}</email>
            <account>{$ctx:account}</account>
         </netsuite.init>
         <netsuite.search>
            <bodyFieldsOnly>{$ctx:bodyFieldsOnly}</bodyFieldsOnly>
            <returnSearchColumns>{$ctx:returnSearchColumns}</returnSearchColumns>
            <pageSize>{$ctx:pageSize}</pageSize>
            <searchRecord>{$ctx:searchRecord}</searchRecord>
         </netsuite.search>
         <respond/>
      </inSequence>
      <outSequence>
         <log/>
         <send/>
      </outSequence>
   </target>
   <description/>
</proxy>

Request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="wso2.connector.netsuite">
   <soapenv:Header />
   <soapenv:Body>
      <urn:apiUrl>https://webservices.na1.netsuite.com/services/NetSuitePort_2015_2</urn:apiUrl>
      <urn:applicationId>32XXX75-CXXE-47X7-BX7-A3EXXXX9D</urn:applicationId>
      <urn:email>johndoe@abc.com</urn:email>
      <urn:password>john4doe</urn:password>
      <urn:account>TSTXXXXXX12</urn:account>
      <urn:searchRecord>
         <platformMsgs:searchRecord xmlns:platformMsgs="urn:messages_2015_2.platform.webservices.netsuite.com" xmlns:ns1="urn:relationships_2015_2.lists.webservices.netsuite.com" xmlns:platformCore="urn:core_2015_2.platform.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:CustomerSearch">
            <basic>
               <email operator="is" xsi:type="platformCore:SearchStringField">
                  <searchValue>dave@cleanenergy.com</searchValue>
               </email>
            </basic>
         </platformMsgs:searchRecord>
      </urn:searchRecord>
   </soapenv:Body>
</soapenv:Envelope>

Sunday, September 25, 2016

How to Configure Transport Layer Security (TLS) in WSO2 ESB

The SaaS applications like Salesforce, Zuora and Stripe announced that they would begin to disable the TLS 1.0/TLS 1.1 encryption protocols in a phased approach.

If you use Java 7, when using the Salesforce Connector with WSO2 ESB you may receive the following error when trying to connect to Salesforce API.

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sf="urn:fault.partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>sf:UNSUPPORTED_CLIENT</faultcode>
         <faultstring>UNSUPPORTED_CLIENT: TLS 1.0 has been disabled in this organization. Please use TLS 1.1 or higher when connecting to Salesforce using https.</faultstring>
         <detail>
            <sf:UnexpectedErrorFault xsi:type="sf:UnexpectedErrorFault">
               <sf:exceptionCode>UNSUPPORTED_CLIENT</sf:exceptionCode>
               <sf:exceptionMessage>TLS 1.0 has been disabled in this organization. Please use TLS 1.1 or higher when connecting to Salesforce using https.</sf:exceptionMessage>
               <sf:upgradeURL>https://cs27.salesforce.com/secur/weakhttps.jsp?l=1</sf:upgradeURL>
               <sf:upgradeMessage>Stronger security is required</sf:upgradeMessage>
            </sf:UnexpectedErrorFault>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>

You are getting this error because TLS v1.0 is enabled by default in Java 7. Let's see how to configure WSO2 ESB to TLSv1.1/ 1.2 being used by the Salesforce Connector.

Open the <ESB_HOME>/repository/conf/axis2/axis2.xml and add the <parameter name="HttpsProtocols">TLSv1.1,TLSv1.2</parameter>entry inside the PassThroughHttpSSLListener and PassThroughHttpSSLSender elements.

<transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">
    .....
    <parameter name="HttpsProtocols">TLSv1.1,TLSv1.2</parameter>
    .....
</transportReceiver>


<transportSender name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLSender">
    .....
    <parameter name="HttpsProtocols">TLSv1.1,TLSv1.2</parameter>
    .....
</transportSender>

To make sure that the configurations are all set correctly, build the TestSSLServer.jar from GitHub and run it.

$ java -jar TestSSLServer.jar <server_name_or_ip> <port>

e.g.:
$ java -jar TestSSLServer.jar localhost 8243

For Java 8 TLSv1.2 is the default, so if you use Java 8, you don't need to configure the above parameter.

References

  1. https://docs.wso2.com/display/ESB490/Configuring+Transport+Level+Security
  2. https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https
  3. https://help.salesforce.com/apex/HTViewSolution?id=000221207
  4. http://community.zuora.com/t5/Zuora-Announcements/Action-Required-Zuora-is-Disabling-TLS-1-0/ba-p/2177
  5. https://stripe.com/blog/upgrading-tls
  6. https://blogs.oracle.com/java-platform-group/entry/java_8_will_use_tls
  7. http://www.bolet.org/TestSSLServer/

Tuesday, September 6, 2016

Cloud to Cloud Integration with WSO2 ESB Connectors

This is the continuation of my article "Cloud to Cloud Integration with WSO2 ESB Connectors."

Sequences

A sequence is a logical arrangement of a set of mediators where each mediator is a functional unit and performs a predefined task on a given message. In the zuoraNetsuiteIntegration sequence, we use the query operation from zuorasoap connector to fetch the newly created invoices from Zuora. Since our requirement is only to get the newly created invoices, we use the property mediator to read the last runtime from the registry, construct the query with it and pass the query through the queryString parameter to Zuora. Then we use the script mediator to build the current runtime in the required format. Thereafter, we use the sequence mediator to refer the generateNetsuiteObjects sequence, which is used to process the invoice records. Once the records have been processed, we update the registry with the current runtime by using the property mediator with the registry scope.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="zuoraNetsuiteIntegration" trace="disable">
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('registry', 'netsuite/dateTime')" name="dateTime" scope="default" type="STRING" />
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('registry', 'netsuite/subsidiaryId')" name="subsidiaryId" scope="default" type="STRING" />
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('registry', 'netsuite/itemId')" name="itemId" scope="default" type="STRING" />
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="fn:concat(&quot;Select Id, AccountId, InvoiceNumber, InvoiceDate, Amount From Invoice WHERE CreatedDate &gt;= '&quot;,get-property('dateTime'),&quot;'&quot;)" name="query" scope="default" type="STRING" />
   <script language="js"><![CDATA[var d = new Date();                         
        var dateTime = d.getFullYear()+ "-"+ ("0" + (d.getMonth()+1)).slice(-2)  + "-"  +("0" + d.getDate()).slice(-2)
                 + "T" + ("0" + d.getHours()).slice(-2)+ ":" + ("0"+d.getMinutes()).slice(-2) + ":" + ("0"+d.getSeconds()).slice(-2)+".000";
            mc.setProperty("dateTime", dateTime.toString());]]></script>
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('dateTime')" name="netsuite/dateTime" scope="registry" type="STRING" />
   <zuorasoap.query configKey="zuoraSoapConfig">
      <queryString>{$ctx:query}</queryString>
      <batchSize>2000</batchSize>
   </zuorasoap.query>
   <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:urn="http://api.zuora.com/" expression="//urn:size/text()" name="records" scope="default" type="STRING" />
   <filter xmlns:ns="http://org.apache.synapse/xsd" xpath="get-property('records') &gt;'0'">
      <then>
         <sequence key="generateNetsuiteObjects" />
         <iterate xmlns:zuora="http://wso2.org/zuorasoap/adaptor" continueParent="true" expression="//zuora:iterator">
            <target>
               <sequence>
                  <zuorasoap.queryMore>
                     <batchSize>2000</batchSize>
                  </zuorasoap.queryMore>
                  <sequence key="generateNetsuiteObjects" />
               </sequence>
            </target>
         </iterate>
      </then>
      <else />
   </filter>
   <property xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('dateTime')" name="netsuite/dateTime" scope="registry" type="STRING" />
</sequence>

In the generateNetsuiteOjects sequence, we use operations from zuora and zuorasoap connectors to get the relevant data from Zuora and check whether the particular customer is already created or not in the NetSuite using the search operation from the netsuite connector. If the customer is already existing, we create the invoice using the createInvoice sequence. Else we create the customer using the createCustomer sequence and create the invoice using the createInvoice sequence.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="generateNetsuiteObjects" trace="disable">
   <iterate xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns1="http://api.zuora.com/" continueParent="true" expression="//ns1:records" id="invoicesIterator" preservePayload="true" sequential="true">
      <target>
         <sequence>
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:Id/text()" name="invoiceId" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:InvoiceNumber/text()" name="invoiceNumber" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:InvoiceDate/text()" name="invoiceDate" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:AccountId/text()" name="accountId" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:Amount/text()" name="amount" scope="default" type="STRING" />
            <property expression="fn:concat(&quot;select FirstName,WorkEmail,LastName, WorkPhone, State, PostalCode, PersonalEmail, Country, City, Address2, Address1 from Contact WHERE AccountId = '&quot;,get-property('accountId'),&quot;'&quot;)" name="query" scope="default" type="STRING" />
            <zuorasoap.query configKey="zuoraSoapConfig">
               <queryString>{get-property('query')}</queryString>
               <batchSize>200</batchSize>
            </zuorasoap.query>
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:LastName)[1]/text()" name="lastName" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:FirstName)[1]/text()" name="firstName" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:WorkEmail)[1]/text()" name="workEmail" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:Address1)[1]/text()" name="address1" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:Address2)[1]/text()" name="address2" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:City)[1]/text()" name="city" scope="default" type="STRING" />
            <property xmlns:urn="http://object.api.zuora.com/" expression="(//urn:Country)[1]/text()" name="country" scope="default" type="STRING" />
            <property expression="fn:concat(&quot;select Name from Account WHERE Id = '&quot;,get-property('accountId'),&quot;'&quot;)" name="accountQuery" scope="default" type="STRING" />
            <zuorasoap.query configKey="zuoraSoapConfig">
               <queryString>{get-property('accountQuery')}</queryString>
               <batchSize>200</batchSize>
            </zuorasoap.query>
            <property xmlns:urn="http://object.api.zuora.com/" expression="//urn:Name/text()" name="accountName" scope="default" type="STRING" />
            <zuora.getInvoices configKey="zuoraRestConfig">
               <accountKey>{get-property('accountId')}</accountKey>
            </zuora.getInvoices>
            <property expression="fn:concat(&quot;//invoices[id='&quot;,get-property('invoiceId'),&quot;']/invoiceItems[1]/serviceStartDate/text()&quot; )" name="exprStartDate" scope="default" type="STRING" />
            <property expression="fn:concat(&quot;//invoices[id='&quot;,get-property('invoiceId'),&quot;']/invoiceItems[1]/serviceEndDate/text()&quot; )" name="exprEndDate" scope="default" type="STRING" />
            <property expression="fn:concat(&quot;//invoices[id='&quot;,get-property('invoiceId'),&quot;']/invoiceItems[1]/chargeName/text()&quot; )" name="exprChargeName" scope="default" type="STRING" />
            <property expression="evaluate($ctx:exprStartDate)" name="serviceStartDate" scope="default" type="STRING" />
            <property expression="evaluate($ctx:exprEndDate)" name="serviceEndDate" scope="default" type="STRING" />
            <property expression="evaluate($ctx:exprChargeName)" name="chargeName" scope="default" type="STRING" />
            <payloadFactory media-type="xml">
               <format>
                  <urn:searchRecord xmlns:urn="wso2.connector.netsuite">
                     <platformMsgs:searchRecord xmlns:platformMsgs="urn:messages_2014_1.platform.webservices.netsuite.com" xmlns:ns1="urn:relationships_2014_1.lists.webservices.netsuite.com" xmlns:platformCore="urn:core_2014_1.platform.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:CustomerSearch">
                        <ns1:basic>
                           <ns2:email xmlns:ns2="urn:common_2014_1.platform.webservices.netsuite.com" operator="is" xsi:type="platformCore:SearchStringField">
                              <ns3:searchValue xmlns:ns3="urn:core_2014_1.platform.webservices.netsuite.com">$1</ns3:searchValue>
                           </ns2:email>
                        </ns1:basic>
                     </platformMsgs:searchRecord>
                  </urn:searchRecord>
               </format>
               <args>
                  <arg evaluator="xml" expression="get-property('workEmail')" />
               </args>
            </payloadFactory>
            <netsuite.search configKey="netsuiteConfig">
               <searchRecord xmlns:urn="wso2.connector.netsuite">{//urn:searchRecord/*}</searchRecord>
            </netsuite.search>
            <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:status/@isSuccess" name="status" scope="default" type="STRING" />
            <filter xpath="get-property('status') = 'true'">
               <then>
                  <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:totalRecords/text()" name="totalRecords" scope="default" type="STRING" />
                  <filter xpath="get-property('totalRecords') ='1'">
                     <then>
                        <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:record/@internalId" name="customerId" scope="default" type="STRING" />
                        <sequence key="createInvoice" />
                        <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:status/@isSuccess" name="status" scope="default" type="STRING" />
                        <filter xpath="get-property('status')= 'true'">
                           <then>
                              <log level="custom">
                                 <property expression="fn:concat('Invoice created in Netsuite ',get-property('invoiceNumber'))" name="status" />
                              </log>
                           </then>
                           <else>
                              <log level="custom">
                                 <property expression="fn:concat('Unable to create the invoice in Netsuite for ',get-property('invoiceNumber'))" name="status" />
                              </log>
                           </else>
                        </filter>
                     </then>
                     <else>
                        <sequence key="createCustomer" />
                        <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:status/@isSuccess" name="status" scope="default" type="STRING" />
                        <filter xpath="get-property('status')= 'true'">
                           <then>
                              <property xmlns:urn="urn:messages_2014_1.platform.webservices.netsuite.com" expression="//urn:baseRef/@internalId" name="customerId" scope="default" type="STRING" />
                              <sequence key="createInvoice" />
                              <property xmlns:urn="urn:core_2014_1.platform.webservices.netsuite.com" expression="//urn:status/@isSuccess" name="status" scope="default" type="STRING" />
                              <filter xpath="get-property('status')= 'true'">
                                 <then>
                                    <log level="custom">
                                       <property expression="fn:concat('Invoice created in Netsuite ',get-property('invoiceNumber'))" name="status" />
                                    </log>
                                 </then>
                                 <else>
                                    <log level="custom">
                                       <property expression="fn:concat('Unable to create invoice in Netsuite for ',get-property('invoiceNumber'))" name="status" />
                                    </log>
                                 </else>
                              </filter>
                           </then>
                           <else>
                              <log level="custom">
                                 <property expression="fn:concat('Unable to create customer and invoice in Netsuite for invoice ',get-property('invoiceNumber'))" name="status" />
                              </log>
                           </else>
                        </filter>
                     </else>
                  </filter>
               </then>
               <else>
                  <log level="custom">
                     <property expression="fn:concat('Unable to create Netsuite objects for invoice ',get-property('invoiceNumber'))" name="status" />
                  </log>
               </else>
            </filter>
         </sequence>
      </target>
   </iterate>
</sequence>

In the createCustomer sequence, we generate the desired form of the message payload using the PayloadFactory mediator and insert the payload to the addList operation in the netsuite connector.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="createCustomer" trace="disable">
   <payloadFactory media-type="xml">
      <format>
         <urn:records xmlns:urn="wso2.connector.netsuite">
            <platformMsgs:record xmlns:platformMsgs="urn:messages_2014_1.platform.webservices.netsuite.com" xmlns:RecordRef="urn:core_2014_1.platform.webservices.netsuite.com" xmlns:listRel="urn:relationships_2014_1.lists.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="listRel:Customer">
               <listRel:entityId>$1</listRel:entityId>
               <listRel:email>$2</listRel:email>
               <listRel:companyName>$1</listRel:companyName>
               <listRel:addressbookList replaceAll="true">
                  <listRel:addressbook>
                     <listRel:addr1>$3</listRel:addr1>
                     <listRel:addr2>$4</listRel:addr2>
                     <listRel:city>$5</listRel:city>
                  </listRel:addressbook>
               </listRel:addressbookList>
               <listRel:subsidiary>
                  <RecordRef:internalId>$6</RecordRef:internalId>
                  <RecordRef:type>subsidiary</RecordRef:type>
               </listRel:subsidiary>
            </platformMsgs:record>
         </urn:records>
      </format>
      <args>
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('accountName')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('workEmail')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('address1')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('address2')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('city')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" evaluator="xml" expression="get-property('subsidiaryId')" />
      </args>
   </payloadFactory>
   <netsuite.addList configKey="netsuiteConfig">
      <records xmlns:ns3="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:urn="wso2.connector.netsuite">{//urn:records/*}</records>
   </netsuite.addList>
</sequence>

In the createInvoice sequence, we generat the desired form of the message payload using the PayloadFactory mediator and insert the payload to the addList operation in the netsuite connector.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="createInvoice" trace="disable">
   <payloadFactory media-type="xml">
      <format>
         <urn:records xmlns:urn="wso2.connector.netsuite">
            <platformMsgs:record xmlns:platformMsgs="urn:messages_2014_1.platform.webservices.netsuite.com" xmlns:tranSales="urn:sales_2014_1.transactions.webservices.netsuite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tranSales:Invoice">
               <tranSales:entity internalId="$1" type="customer" />
               <tranSales:tranId>$5</tranSales:tranId>
               <tranSales:dueDate>$6</tranSales:dueDate>
               <tranSales:itemList>
                  <tranSales:item>
                     <tranSales:item internalId="$8" />
                     <tranSales:quantity>1</tranSales:quantity>
                     <tranSales:amount>$2</tranSales:amount>
                     <tranSales:revRecStartDate>$3</tranSales:revRecStartDate>
                     <tranSales:revRecEndDate>$4</tranSales:revRecEndDate>
                     <tranSales:description>$7</tranSales:description>
                  </tranSales:item>
               </tranSales:itemList>
            </platformMsgs:record>
         </urn:records>
      </format>
      <args>
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="get-property('customerId')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="get-property('amount')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="fn:concat(get-property('serviceStartDate'),'T00:00:00.000Z')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="fn:concat(get-property('serviceEndDate'),'T00:00:00.000Z')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="get-property('invoiceNumber')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="fn:concat(get-property('invoiceDate'),'T00:00:00.000Z')" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="fn:concat(get-property('chargeName'),' from ',get-property('serviceStartDate'),' to ',get-property('serviceEndDate'))" />
         <arg xmlns:ns="http://org.apache.synapse/xsd" evaluator="xml" expression="get-property('itemId')" />
      </args>
   </payloadFactory>
   <netsuite.addList configKey="netsuiteConfig">
      <records xmlns:urn="wso2.connector.netsuite">{//urn:records/*}</records>
   </netsuite.addList>
</sequence>

Local Entries

We use these local entries to specify the init element of connectors. As we mentioned earlier, we use aliases instead of plain text to specify passwords. We set the blocking parameter as true to invoke blocking calls to Zuora and NetSuite.


1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<localEntry xmlns="http://ws.apache.org/ns/synapse" key="zuoraSoapConfig">
   <zuorasoap.init>
      <apiUrl>https://www.zuora.com/apps/services/a/77.0</apiUrl>
      <username>johndoe@gmail.com</username>
      <password>{wso2:vault-lookup('zuora.password')}</password>
      <blocking>true</blocking>
   </zuorasoap.init>
</localEntry>


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?xml version="1.0" encoding="UTF-8"?>
<localEntry xmlns="http://ws.apache.org/ns/synapse" key="zuoraRestConfig">
   <zuora.init>
      <apiUrl>https://api.zuora.com/rest</apiUrl>
      <apiVersion>v1</apiVersion>
      <apiAccessKeyId>johndoe@gmail.com</apiAccessKeyId>
      <apiSecretAccessKey>{wso2:vault-lookup('zuora.password')}</apiSecretAccessKey>
      <blocking>true</blocking>
   </zuora.init>
</localEntry>


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<localEntry xmlns="http://ws.apache.org/ns/synapse" key="netsuiteConfig">
   <netsuite.init>
      <apiUrl>https://webservices.na1.netsuite.com/services/NetSuitePort_2014_1</apiUrl>
      <warningAsError>{$ctx:warningAsError}</warningAsError>
      <disableSystemNotesForCustomFields>{$ctx:disableSystemNotesForCustomFields}</disableSystemNotesForCustomFields>
      <ignoreReadOnlyFields>{$ctx:ignoreReadOnlyFields}</ignoreReadOnlyFields>
      <disableMandatoryCustomFieldValidation>{$ctx:disableMandatoryCustomFieldValidation}</disableMandatoryCustomFieldValidation>
      <roleInternalId>{$ctx:roleInternalId}</roleInternalId>
      <partnerId>{$ctx:partnerId}</partnerId>
      <applicationId>{$ctx:applicationId}</applicationId>
      <roleName>{$ctx:roleName}</roleName>
      <password>{wso2:vault-lookup('netsuite.password')}</password>
      <roleExternalId>{$ctx:roleExternalId}</roleExternalId>
      <email>johndoe@wso2.com</email>
      <account>TSTDRV1473412</account>
      <roleType>{$ctx:roleType}</roleType>
      <blocking>true</blocking>
   </netsuite.init>
</localEntry>


Scheduled Task 

Scheduled tasks allow us to run scheduled jobs at given time intervals. Here we specify to inject a message to the zuoraNetsuiteIntegration sequence and use cron-style to schedule the task to run every day. Since it is mandatory to provide a value for the message property, we can provide an empty payload as the value.


1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<task xmlns="http://ws.apache.org/ns/synapse" class="org.apache.synapse.startup.tasks.MessageInjector" group="synapse.simple.quartz" name="invoiceSync">
   <trigger cron="0 0 15 * * ?" />
   <property xmlns:task="http://www.wso2.org/products/wso2commons/tasks" name="injectTo" value="sequence" />
   <property xmlns:task="http://www.wso2.org/products/wso2commons/tasks" name="message">
      <request xmlns="" />
   </property>
   <property xmlns:task="http://www.wso2.org/products/wso2commons/tasks" name="sequenceName" value="zuoraNetsuiteIntegration" />
</task>


Running scenario 

Once the configuration is completed, you need to create a Connector Exporter Project and add the above three connectors. Then create a C-App project and build a CAR file out of that project and deploy it in WSO2 ESB.