Implementing a connector for WSO2 ESB mainly consists of 3 main sub tasks as explained below.
- Research on the APIs provided by the specific third-party company.
- Decide on which API you are going to use to write the connector. This can be one of the following.
- REST-based connectors
- SOAP-based connectors
- Java API-based connectors
- Start writing the connector by using the connector core available with WSO2 ESB.
The rest of the document shows how to write connectors using each of those APIs. The following standard folder structure should be followed.
1 | connector.xml | This defines the connector name and dependant modules. (Metadata of the connector) |
2 | component.xml | This is included in each module. This defines the available methods in the module. |
3 | init.xml | For a connector, this is mandatory. By using this, users can initialize the connector environment, e.g. when writing the Salesforce connector login call can be included here. Sessiontoken and API URL returned as the response can be stored in a property and used with other operations. |
4 | assemble-connector.xml/filter.properties | These files are used at the build time of the connector. You barely need to modify this file. So, in this article, we will not provide a detailed explanation. |
5 | pom.xml | Contains the required dependencies for connector core libraries and relevant synapse libraries as well as maven repositories for a specific connector. |
6 | <operation-name>.xml | This is the actual API operation calling configuration. It contains the steps necessary to call the API that is exposed by the third party. Similar to init.xml, each method of the API can be written. If there are any Java codes those can be included under Java and relevant dependants needs to be added to pom.xml |
Required template can be created using the maven archetype found with following and using the mentioned command.
https://github.com/wso2/esb-connectors/tree/master/connector-archetype
mvn archetype:generate -DarchetypeGroupId=org.wso2.carbon -DarchetypeArtifactId=org.wso2.carbon.mediation.library.connectors.connector-archetype -DarchetypeVersion=4.4.0 -DgroupId=org.wso2.carbon.connector -DartifactId=org.wso2.carbon.connector -Dversion=1.0.0
Now you have the knowledge about basic structure of a connector. The next sections of the article describes in detail the different types of connectors.
SOAP-based connectors
Since we are writing a connector for SOAP API, we can write the entire connector with Synapse configurations. You can create a maven project from your preferred IDE and the folder structure should be similar to the above.
Following is an example of a SOAP-based connector that is written for Salesforce in order to execute the query method of the API.
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 | < parameter name = "sessionId" /> < parameter name = "url" /> < parameter name = "queryString" /> < sequence > < payloadFactory > < format > < soapenv:Envelope xmlns:soapenv = "http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn = "urn:partner.soap.sforce.com" > < soapenv:Header > < urn:SessionHeader > </ urn:SessionHeader > </ soapenv:Header > < soapenv:Body > </ soapenv:Body > </ soapenv:Envelope > </ format > < args > </ args > </ payloadFactory > < property name = "messageType" scope = "axis2" value = "text/xml" /> < property value = "true" name = "FORCE_ERROR_ON_SOAP_FAULT" /> < property name = "HTTP_METHOD" scope = "axis2" value = "POST" /> < call > < endpoint > < default format = "soap11" > < timeout > < duration >60000</ duration > < responseAction >fault</ responseAction > </ timeout > < suspendOnFailure > < initialDuration >2000</ initialDuration > < progressionFactor >1.0</ progressionFactor > < maximumDuration >3000</ maximumDuration > </ suspendOnFailure > </ default > </ endpoint > </ call > </ sequence > </ template > |
In the above example, we are creating the required payload using payload factory mediator and we send the request using call mediator.
REST-based connectors
Writing a REST-based connector is no different from writing a SOAP connector. The only difference is the underlying communication mechanism. Other than that, you can basically write a REST-based connector just by using synapse configuration similar to SOAP connectors.
Following is an example of a connector calling Twitter rest API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | < parameter name = "search" /> < parameter name = "accessToken" /> < sequence > < property name = "messageType" value = "application/x-www-form-urlencoded" scope = "axis2" /> < payloadFactory media-type = "xml" > < format > < soapenv:Header /> < soapenv:Body /> </ soapenv:Envelope > </ format > < args /> </ payloadFactory > < call > < endpoint > < http method = "GET" uri-template = "https://api.twitter.com/1.1/search/tweets.json?q={uri.var.twitter.search}" /> </ endpoint > </ call > </ sequence > </ template > |
Java API-based connectors
When you are writing Java API-based connectors, you have to use custom class mediators to implement it. You need to extend the AbstractConnector class and implement its connect method. All the required logic must go within this method. Once you have implemented this method, it can be called using the synapse configuration, which is in the .xml
Following in an example of a connector Java class that is written for Twilio in order to send an SMS.
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 | import java.util.HashMap; import java.util.Map; import org.apache.axiom.om.OMElement; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseException; import org.apache.synapse.SynapseLog; import org.wso2.carbon.connector.core.AbstractConnector; import org.wso2.carbon.connector.core.util.ConnectorUtils; import org.wso2.carbon.connector.twilio.util.TwilioUtil; import com.twilio.sdk.TwilioRestClient; import com.twilio.sdk.resource.factory.SmsFactory; import com.twilio.sdk.resource.instance.Sms; public class SendSms extends AbstractConnector { public void connect(MessageContext messageContext) { SynapseLog log = getLog(messageContext); log.auditLog("Start: send SMS"); String to = (String) ConnectorUtils.lookupTemplateParamater(messageContext, TwilioUtil.PARAM_TO); String from = (String) ConnectorUtils.lookupTemplateParamater(messageContext, TwilioUtil.PARAM_FROM); String body = (String) ConnectorUtils.lookupTemplateParamater(messageContext, TwilioUtil.PARAM_BODY); String statusCallBackUrl = (String) ConnectorUtils.lookupTemplateParamater(messageContext, TwilioUtil.PARAM_STATUS_CALLBACK_URL); String applicationSid = (String) ConnectorUtils.lookupTemplateParamater(messageContext, TwilioUtil.PARAM_APPLICATION_SID); Map< string , string = "" > params = new HashMap< string , string = "" >(); params.put(TwilioUtil.TWILIO_TO, to); params.put(TwilioUtil.TWILIO_FROM, from); params.put(TwilioUtil.TWILIO_BODY, body); if (applicationSid != null) { params.put(TwilioUtil.TWILIO_APPLICATION_SID, applicationSid); } if (statusCallBackUrl != null) { params.put(TwilioUtil.TWILIO_STATUS_CALLBACK, statusCallBackUrl); } try { TwilioRestClient twilioRestClient = TwilioUtil.getTwilioRestClient(messageContext); SmsFactory messageFactory = twilioRestClient.getAccount().getSmsFactory(); Sms message = messageFactory.create(params); OMElement omResponse = TwilioUtil.parseResponse("sms.create.success"); TwilioUtil.addElement(omResponse, TwilioUtil.PARAM_MESSAGE_SID, message.getSid()); TwilioUtil.addElement(omResponse, TwilioUtil.PARAM_STATUS, message.getStatus()); TwilioUtil.preparePayload(messageContext, omResponse); } catch (Exception e) { log.error(e.getMessage()); messageContext.setProperty(SynapseConstants.ERROR_EXCEPTION, e); messageContext.setProperty(SynapseConstants.ERROR_MESSAGE, e.getMessage()); messageContext.setProperty(SynapseConstants.ERROR_CODE, "0007"); throw new SynapseException(e); } log.auditLog("End: send SMS"); } } </ string ,></ string ,> |
Following is the associated sendSms.xml that calls the class mediator.
1 2 3 4 5 6 7 8 9 10 | < parameter name = "body" /> < parameter name = "to" /> < parameter name = "from" /> < parameter name = "statusCallBackUrl" /> < parameter name = "applicationSid" /> < sequence > < class name = "org.wso2.carbon.connector.twilio.sms.SendSms" /> </ sequence > </ template > |
So these are the currently available approaches. You should be able to write any connector using one of these approaches.