Tuesday, August 5, 2014

How to deploy and use WSO2 ESB Cloud Connector

In this post I describe steps on how to upload a connector to WSO2 ESB, creating a proxy and sending a request to test the functionality of the connector.


Prerequisite


  • Have a bug free built connector zip file to upload to the ESB.
  • Have an instance of WSO2 ESB server up and running.
  • SOAP UI version 4.5 or above to test the request.


Uploading and enabling the connector in ESB

Assuming you have an up and running instance of the WSO2 ESB server, follow the below steps.
















Click on Choose File button and browse the connector zip file you have.
















Then click on Upload. Note if the upload is successful, the connector file name will be shown in the list and its status will be marked in red as disabled as shown below.









Click on the Status icon to make it enable.










Note:

If you get an error message while uploading the connector zip file saying the upload failed, Don't worry just refresh the page  few times and retry. If that is not caused by an error thrown by ESB server, this should work for you.

Also, you may need to wait for few seconds to enable the connector after it is uploaded. Note that if you cannot enable the connector even after few attempts, your connector may have issues, you can observe the ESB server log to check whether any exceptions are thrown. If so, carefully handle them in your connector, then build and upload again.


Creating a proxy and getting the WSDL 

Now we are done with the connector file and need to create a proxy to map the specific function call that we require to test.












You can observe there are several types of proxies shown as above. You can use Custom Proxy to define your own proxy file.

So, Click on Custom Proxy link and switch to source view from where you can handle the source of the proxy easily.

For the demonstrations purpose I am using the Github connector file and Ill focus on getPullRequest method. An example proxy file is shown below.















Proxy file content:



































Click on Save. If you created the proxy with no errors, the proxy file will be listed as shown below.
















If you face any error while creating the proxy, fix it and save again.

Now, to get the WSDL, you have to simply click on the WSDL1.1 link of the specific proxy.










Making a request through SOAP UI

In the final step, you can use the above WSDL to create a request and make an API call through the WSO2 ESB

Note that I will show how to create a REST request call since I deal with the Github REST API, You can customize your Proxy and the request in any type that suits your requirement (REST(JSON/XML), SOAP etc)

Create a New REST project in SOAP UI using the above WSDL.


















Now build the REST request with the necessary parameter and valid values as shown below. Send the request and observe the output






















Hope it was useful for you. If so, please leave a comment.

Thursday, June 12, 2014

Visual Studio Add-in creation tips : Cannot see the created add-in under Add-in manager in Visual Studio

Problem :


I made an add-in in visual studio and it is visible in any instance of visual studio under Add-in Manager. but if i want to work with the project having a copy of it to another machine, what should be done to make it visible under the add-in manager.

basically, i want be able to let VS of any of my PCs to detect the add-ins that i have created in it or copied from some other machine.

















Solution : 


You need to register the assembly as add-in for VS using an .AddIn file in some of the well-known locations.

The .AddIn file for add-ins that you create are typically in the folder C:\Users\<user>\Documents\Visual Studio <version>\AddIns.















Inside the .AddIn file there is a <Assembly> tag whose value you need to adjust if needed to point to the assembly path. (Open the AddIn file in a text editor)














Note the highlighted line in the above image. The location that mentioned within the Assembly tag should point to the .dll file of the addIn that you have created. Then the next time you open Visual Studio, your addIn will be visible.
























Hope it was a useful tip to you.

Sunday, June 1, 2014

Visual Studio Add-in creation tips : How to change the default icon of an add-in?

Problem :

When you create an add-in Visual Studio, you will see the default set icon as a smiley. May be your requirement needs some other proper icon to be used. The question is how to change the default add-in icon easily.














Solution :

-Open a solution that was created by using the Add-in project type.
-Open the Connect.cs file and navigate to the below shown line in OnConnection() method.











Note the number "59" in the line where the Command object is initialized. This is considered as the index of the current icon of the add-in. You can change this number to a different standard icon to get a new icon.

It is simple as that. Further more you can refer the below shown list to identify which icon stands for which number you specify.







You can see the complete list from the below reference :



Visual Studio Add-in creation tips : Build Error.Unable to delete dll file



Problem :


I was working on an add-in in visual studio where it gave me the above error from the second time onward while building the add-in project. As I searched about the issue, it seemed some other process is being locking the dll file of my add-in.





I made sure that all other projects which are using the add-in are closed but it didn't fix the issue. I even turned the virus guard off since they too may cause some issues like this.So, I manually went to the bin folder of where the add-in project is created and deleted the dll file. then onward the build was successful. but this is only until I close the add-in project in visual studio. once I restart, make some changes and rebuild, the error pops up again is this a bug or is there a way to fix this issue?

Solution : 

What cause this issue may be your Visual Studio run the add-in when your Visual Studio is started. You can disable Add-ins (e.g. “Tools” | “Add-in Manager”) and run “devenv.exe /safemode”. 

























When I start visual studio the add-in runs automatically.This happens because while creating the add-in using the wizard, I checked 'Microsoft Visual Studio 2010' as an application host and then in the next step i too have checked the option saying that I would like to load the Add-in when the host application starts (see the image below). So, automatically, if another project or a website is running at the moment when I tried to modify the add-in in another instance, the add-in project file is getting locked.  


Monday, April 14, 2014

How to remove custom transport headers in a WSO2 ESB Connector

When u send an HTTP request, as same as you set specific headers for the request, you also will get a set of headers in your response as well no matter the response is successful or an error response.

You may get some custom headers along with the standard HTTP headers. In this post, I will be describing on how you should remove those custom headers if you don't want to send them to your end user.

First off all, you should know what are considered as standard headers. You can have a very useul article and along with the necessary list of headers in the below link.

List of HTTP header fields

The following Screenshot shows you a GET request sent from Postman that's made to Google Calendar REST API. You can see the headers section that there are some headers resulted that are not in the above list of standard HTTP headers.

























You can add the below section as a set of properties in your synapse Sequence to be executed after making the call to the endpoint. So, the custom headers can be removed easily.

<!-- Remove response custom header information --> 
<header name="X-Frame-Options" scope="transport" action="remove" /> 
<header name="X-XSS-Protection" scope="transport" action="remove" /> 
<header name="Alternate-Protocol" scope="transport" action="remove" /> 
<header name="X-Content-Type-Options" scope="transport" action="remove" />

Hope it was useful to you.

How to set HTTP headers in a connector for WSO2 ESB

HTTP header fields are components of the message header of requests and responses in the Hypertext Transfer Protocol (HTTP). They define the operating parameters of an HTTP transaction. Most of the API calls requires to set some headers before making each API calls no matter its GET, POST or any other request type. 

In this post, I am going to focus on the headers that needs to be set for HTTP calls for Google Calendar REST API. 














API:                                   Google Calendar
Reference Link:                    https://developers.google.com/google-apps/calendar/v3/reference/
Headers need to be set :  Authorization , Content-Type

What do those headers mean?

Authorization : Authentication credentials for HTTP authentication
Content-Type: The MIME type of the body of the request

Now, let's see how to set those headers within the synapse template of the connector.It's quiet simple and the below code explain them to you.

<template name="test" xmlns="http://ws.apache.org/ns/synapse">
<!-- Set a parameter to get the access token  -->
<parameter name="accessToken"
description="The access token  of the Google Calendar API" />
<sequence>
<!-- Get the access token from the user  through synapse-->
<property name="uri.var.accessToken" expression="$func:accessToken" />

  <!--Set the access token as the Authorization transport header as below --> 
<property name="Authorization"
expression="fn:concat('Bearer ', get-property('uri.var.accessToken'))"
scope="transport" type="STRING" />

 <!-- Setting the Content-Type transport header as below-->
<property name="Content-Type" value="application/json" scope="transport"
type="STRING" />

<call>
<endpoint>
<!-- you can call the required end point from here  -->
</endpoint>
</call>
</sequence>
</template>

As you see above while setting the Authorization header i have used a concatenation function. That's because the authorization header should be set along with the ''Bearer" field concatenated with the access token. 

That's all about it. You can set any HTTP header by following the similar approach. Hope it was useful to you...

Tuesday, April 8, 2014

Using Script mediators to build a Json payoad with optional parameters in a connector for WSO2 ESB

When making requests to an API, it's very important to identify the parameters that are required (mandatory) and that are optional. It's also essential to know the type of those parameters and the proper way of sending them to the API such as if the api supports REST and we are making a REST/json request, we must ensure that the request that we are sending is a valid json string.

In this post, I wanted to focus bit more on how to handle body parameters that are optional. The concept beind using optional parameters are, it says, a user need not mandatory send those values to call that function but if they wish to set those values as well, then the function should support them. 

As in my other similar posts, let me take a real word example to demonstrate this.

API:                     Google Calendar
Function:             CalendarList: insert
Reference Link: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/insert

The above mentioned request is an HTTP POST request to create a new Calendar List Entry.According to the API documentation, it expects a list of values to be sent through the request body and the request body consists of both required and optional parameters. 

So, these should be handled carefully within the synapse template of the connector. The concept is clear. We are going to set a payload factory to send the request body parameters and the required parameters can be directly hard coded. Also, the optional parameters will be added to the request body checking the condition that the parameter holds a value (it should be not null and not empty to be added to the payload).

The below shown code from the synapse template will clearly explain you how this task is handled.

Note that this function has id as the only request body parameter that is considered to be required and all the rest of the parameters are optional.

The request body parameters should be declared as below;

<!-- Required parameters -->
<parameter name="id" description="Identifier of the calendar." />

<!-- Optional parameters -->
<parameter name="defaultReminders" description="A list of authenticated users for this calendar. Each item has method and minutes." />
<parameter name="foregroundColor" description="The foreground color of the calendar in the format '#ffffff'." />
<parameter name="isHidden" description="Whether the calendar has been hidden from the list." />
<parameter name="notificationSettings" description="The method used to deliver the notification. " />
<parameter name="summaryOverride" description="The summary that the authenticated user has set for this calendar." />

Property mediators should be set to the above parameters to map with the proxy as below within the <sequence>.

<property name="uri.var.defaultReminders" expression="$func:defaultReminders" /> 
<property name="uri.var.foregroundColor" expression="$func:foregroundColor" /> 
<property name="uri.var.isHidden" expression="$func:isHidden" /> 
<property name="uri.var.notificationSettings" expression="$func:notificationSettings" /> 
<property name="uri.var.summaryOverride" expression="$func:summaryOverride" />

Then the payload factory can be added with the required (mandatory) parameters as shown below.

<!-- Building request with mandatory params -->
<payloadFactory media-type="json">
<format>
{
"id":"$1"
}
</format>
<args>
<arg expression="get-property('uri.var.id')" />
</args>
</payloadFactory>

Finally, the script mediator can be used to add the optional request body parameters on checking the conditions as below.

<script language="js">
<![CDATA[        
//request body param variables
var defaultReminders = mc.getProperty('uri.var.defaultReminders');
var foregroundColor = mc.getProperty('uri.var.foregroundColor');
var isHidden = mc.getProperty('uri.var.isHidden');
var notificationSettings = mc.getProperty('uri.var.notificationSettings');
var summaryOverride = mc.getProperty('uri.var.summaryOverride');                                    
//getting the json payload of the message context.
var payload = mc.getPayloadJSON();
//if values set for defaultReminders Array, then add it to the payload
if ( defaultReminders != null && defaultReminders != "") { 
payload.defaultReminders = eval("("+defaultReminders+")");
}
//if a value is set for foregroundColor , then add it to the payload
if (foregroundColor != null && foregroundColor != "") {
payload.foregroundColor = foregroundColor;
}
//if isHidden parameter is set, add it to the payload
if (isHidden != null && isHidden != "") {
payload.hidden = isHidden;
}
//if values set for notificationSettings Object, then add it to the payload
if ( notificationSettings != null && notificationSettings != "") { 
payload.notificationSettings = eval("("+notificationSettings+")");
}
//if values set for summaryOverride , then add it to the payload
if (summaryOverride != null && summaryOverride != "") {
payload.summaryOverride = summaryOverride;
}
//add the payload to the message context
mc.setPayloadJSON(payload);
]]>
</script>

Finally you can use the call mediator by setting required or optional URL parameters to call the function appropriately.

Hope it was useful to you.

How to parse Complex data types or arrays through payload in a synapse template of a connector for WSO2 ESB?

Here I am going to focus on a REST API where we should be able to pass objects or arrays as a rest request in json. Let me start with a real word example as shown below.

API:                     Google Calendar
Function:             CalendarList: insert
Reference Link: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/insert
Sample REST Request:

{
    "id": "836g6ropqm741sqsjl7abcde@group.calendar.google.com",
    "defaultReminders": [
        {
            "method": "email",
            "minutes": 60
        }
    ],
    "notificationSettings": {
        "notifications": [
            {
                "type": "eventCreation",
                "method": "email"
            },
            {
                "type": "eventResponse",
                "method": "email"
            }
        ]
    }
}

Note that the above highlighted values are complex types such as defaultReminders being a list and notificationSettings being an object. The proxy will accept only the first level parameters. So that the objects and arrays will be accepted in the proxy as one single parameter as shown below.

<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="googlecalendar_createCalendarEntry"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>        
         <property name="id" expression="json-eval($.id)"/>       
         <property name="defaultReminders" expression="json-eval($.defaultReminders)"/>
         <property name="notificationSettings" expression="json-eval($.notificationSettings)"/>         
         <googlecalendar.createCalendarEntry>
            <id>{$ctx:id}</id>         
            <defaultReminders>{$ctx:defaultReminders}</defaultReminders>           
            <notificationSettings>{$ctx:notificationSettings}</notificationSettings>           
         </googlecalendar.createCalendarEntry>
         <respond/>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </target>
   <description/>
</proxy>
              
Now the challenge comes on how we are going to add them to the payload factory inside the synapse template. Of course we have to use a script mediator because the above highlighted parameters are considered as optional parameters according to the API. Unlike handling string values, integers or even booleans, a valid json string does not accept "" surrounded within the values of complex types like arrays and objects but they should be sent within {} or []. 

To achieve the task, we must use eval function in JavaScript.

The eval() function evaluates or executes an argument.If the argument is an expression, eval() evaluates the expression. If the argument is one or more JavaScript statements, eval() executes the statements.
.
Note how it should be handled within a script mediator as shown below.

<script language="js">
        <![CDATA[      
               var defaultReminders = mc.getProperty('uri.var.defaultReminders');   
               var notificationSettings = mc.getProperty('uri.var.notificationSettings');
                            
var payload = mc.getPayloadJSON();
if ( defaultReminders != null && defaultReminders != "") { 
                 // if not null, add optional defaultReminders Array 
payload.defaultReminders = eval("("+defaultReminders+")");
}
if (notificationSettings != null  && notificationSettings != "") { 
                 // if not null , add optional notificationSettings JSON Obj
payload.notificationSettings = eval("("+notificationSettings+")");
}
mc.setPayloadJSON(payload);
]]>
</script>

Hope it was useful to you...

Sunday, April 6, 2014

Using Script mediators to build a url with optional parameters in a connector for WSO2 ESB

I thought to write another useful post that is related to connector development of WSO2 ESB. You may have seen many request URLs in APIs that mention a set of parameters. It's very important to identify the required and the optional parameters. In such cases we should know some efficient techniques on how to handle them inside the synapse template mediator.

Let me focus some real world REST API calls to explain these to you in this post. I use Linkedin API Reference for this post.

Handling request of a GET request with no URL parameters


Reference Link: 
https://developer.linkedin.com/documents/connections-api

Task:
Returns a list of 1st degree connections for a user who has granted access to his/her account.

E.g:
http://api.linkedin.com/v1/people/~/connections

If the request URL is as above where you see no any parameters mentioned but it  returns the authenticated user's list of first degree connection details, you can simply hard code the URL in the call mediator as below.

<template xmlns="http://ws.apache.org/ns/synapse" name="getConnections">
   <sequence>
      <call>
         <endpoint>
            <http method="get" uri-template="http://api.linkedin.com/v1/people/~/connections" />
         </endpoint>
      </call>
   </sequence>
</template>


Handling request of a GET method with required URL parameters


Reference Link: 
https://developer.linkedin.com/documents/connections-api

Task:
Returns the 1st degree connection's details with the specified id  for a user who has granted access to his/her account.

E.g:
http://api.linkedin.com/v1/people/id=12345/connections

Now we have a URL parameter that should be expected from the user through the proxy. It can be handled as below.

<template xmlns="http://ws.apache.org/ns/synapse" name="getConnections">
   <parameter name="id" description="Id of the member of whose connections are requested to be retrieved." />
   <sequence>
      <property name="uri.var.id" expression="$func:id" />
      <call>
         <endpoint>
            <http method="get" uri-template="http://api.linkedin.com/v1/people/id={uri.var.id}/connections" />
         </endpoint>
      </call>
   </sequence>
</template>


Handling request of a GET method with set of optional URL parameters


Reference Link: 

Task:
Returns the 1st degree connection's mentioned field details with the specified id  for a user who has granted access to his/her account.

E.g: 
http://api.linkedin.com/v1/people/~/connections:(headline,first-name,last-name)

This request is similar to retrieving  a list of 1st degree connections for a user who has granted access to his/her account. But this returns only the fields that are mentioned within the braces separated with commas.request will display only the headline,first-name and the last-name of the connections that are of 1st degree connections for the user who has granted access to his/her account. For an instance the above shown.

Let's assume the end users send the comma separated values to the above request as shown below through the proxy (assume it's an XML request),

<fieldSelectors>headline,first-name,last-name,id</fieldSelectors>

then the given URL can be constructed from the synapse template as shown below using a script mediator. Note that, I have mentioned how to construct it using javascript.

<template xmlns="http://ws.apache.org/ns/synapse" name="getConnections">
   <parameter name="fieldSelectors" description="Fields that are required tobe retrieved from the search result." />
   <sequence>
      <property name="uri.var.fieldSelectors" expression="$func:fieldSelectors" />
      <property name="uri.var.query" value="" />

      <script language="js"><![CDATA[
         //getting the comma separated values to a string variable
         var fieldSelectors = mc.getProperty('uri.var.fieldSelectors');

         //query variable is initially empty
         var query =mc.getProperty('uri.var.query');
   
         //if user has given some values to fieldSelectors variable through the proxy, then condition becomes true

         if (fieldSelectors != null && fieldSelectors != "") 
         {

          query=':'+'('+ mc.getProperty('uri.var.fieldSelectors')+')';

         }        
         mc.setProperty('uri.var.query', query);]]></script>

      <call>
         <endpoint>

            <!--since the fieldSelectors part of the URL is optional, it will  be set if an only f the user passes values to it. Else {uri.var.query} will be empty  -->
            <http method="get" uri-template="http://api.linkedin.com/v1/people/~/connections{uri.var.query}" />

         </endpoint>
      </call>
   </sequence>
</template>

Note: 

CDATA block within the script mediator must be used to avoid special characters to be encoded within the script mediator.

If you have any number of optional URL parameters in the request links, you can easily use script mediators as above in order to construct them as you wish. For better understanding see the below example as well where there are more number of parameters, how they should be concatenated with "&" symbol within the script mediator.

Reference Link: 

Task:
Covers all the URL GET requests of below shown calls of the connections API calls of Linkedin.

E.g: 

http://api.linkedin.com/v1/people/~/connections
http://api.linkedin.com/v1/people/id=12345/connections
http://api.linkedin.com/v1/people/~/connections:(headline,first-name,last-name)
http://api.linkedin.com/v1/people/url=http%3A%2F%2Fwww.linkedin.com%2Fin%2Flbeebe/connections

<template xmlns="http://ws.apache.org/ns/synapse" name="getConnections">

   <!--declarations of parameters -->
   <parameter name="id" description="Id of the member of whose connections are requested to be retrived." />
   <parameter name="publicProfileUrl" description="public url of the requested profile." />
   <parameter name="fieldSelectors" description="Fields that are required to be retrieved from the search result." />
   <parameter name="start" description="Start location within the result set for paginated returns." />
   <parameter name="count" description="The number of profiles to return.Values can range between 0 and 25." />
   <parameter name="modified" description="Values are updated or new." />
   <parameter name="modifiedSince" description="Value as a Unix time stamp of milliseconds since epoch." />

   <sequence>

      <!-- Setting the properties accepting the values passed through the proxy -->

      <property name="uri.var.id" expression="$func:id" />
      <property name="uri.var.publicProfileUrl" expression="$func:publicProfileUrl" />
      <property name="uri.var.fieldSelectors" expression="$func:fieldSelectors" />
      <property name="uri.var.start" expression="$func:start" />
      <property name="uri.var.count" expression="$func:count" />
      <property name="uri.var.modified" expression="$func:modified" />
      <property name="uri.var.modifiedSince" expression="$func:modifiedSince" />
      <property name="uri.var.query" value="" />

      <!-- Script Mediator block -->

      <script language="js"><![CDATA[//retrieving the values from the message context

         var apiUrl = 'http://api.linkedin.com'+'/v1/people/';
         var id = mc.getProperty('uri.var.id');
         var publicProfileUrl = 
                    mc.getProperty('uri.var.publicProfileUrl');               
         var fieldSelectors = mc.getProperty('uri.var.fieldSelectors');
         var query ='';
         var start = mc.getProperty('uri.var.start');
         var count = mc.getProperty('uri.var.count');
         var modified = mc.getProperty('uri.var.modified');
         var modifiedSince = mc.getProperty('uri.var.modifiedSince');

         if (id != null && id != "") 
         {
          query = apiUrl + 'id=' + mc.getProperty('uri.var.id') + '/connections';
         } 
         else if(publicProfileUrl != null && publicProfileUrl != "") 
         {
            //public profile url should be sent as a URL encoded string
            var encoded_publicProfileUrl =
                  encodeURIComponent(mc.getProperty('uri.var.publicProfileUrl'));                                               
            query = apiUrl + 'url=' + encoded_publicProfileUrl + '/connections';
         } 
          else 
          {
            query = apiUrl + '~/connections';
          }
      
          if (fieldSelectors != null && fieldSelectors != "") 
          {
            query = query + ':' + '(' + 
                          mc.getProperty('uri.var.fieldSelectors') + ')';        
          } 
  
          //since oauth2 access token should also be passed in every request url of Linkedin  
            query = query + '?oauth2_access_token=' + 
                          mc.getProperty('uri.var.accessToken');      
          //if 'start' optional param is provided append it to the URL with a '&' symbol
            if (start != null && start != "") 
            {
              query = query + '&start=' + mc.getProperty('uri.var.start');
            }
          //if 'count' optional param is provided append it to the URL with a '&' symbol
            if (count != null && count != "") 
            {
              query = query + '&count=' + mc.getProperty('uri.var.count');
            }
         //if 'modified' optional param is provided append it to the URL with a '&' symbol
            if (modified != null && modified != "") 
            {
              query = query + '&modified=' + 
                          mc.getProperty('uri.var.modified');      
            }
         //if 'modifiedSince' optional param is provided append it to the URL with a '&' symbol
            if (modifiedSince != null && modifiedSince != "") 
            {
              query = query + '&modified-since=' + 
                          mc.getProperty('uri.var.modifiedSince');
            }
  
         //set the query to message context's uri.var.query property 
              mc.setProperty('uri.var.query', query);]]></script>
      <call>
         <endpoint>
            <!--Since the entire URL is constructed above,it's just a matter of calling the endpoint as below. -->

            <http method="get" uri-template="{uri.var.query}" />

         </endpoint>
      </call>
   </sequence>
</template>



Hope it was useful to you. If so, please leave a comment.