Monday, November 25, 2013

How to add sleep interval or delay between 2 mediators -WSO2 ESB

You can add thread.sleep by using script mediator. See following synapse configuration block. You can add it to between your operations.

<script language="js">java.lang.Thread.sleep(5000);</script>


However having Thread.sleep() has an impact when the ESB is working in very high concurrency levels. In ESB a thread pool is used to do the processing, if all the threads in this thread pool get blocked at the same time due to Thread.sleep() calls, then we have a problem. 

Wednesday, November 20, 2013

How to create multipart file upload API in WSO2 API Manager

I tried this scenario in my local machine with multi part file upload sample[1]. Please refer my instructions below.

01. Deployed file uploading war file into webserver(for this example i used WSO2  Application server 5.2.0).
02. Create API from publisher UI in API manager by pointing to file upload web service, and then publish API. Here you don't have to add any other parameter to synapse configuration.
03. Create SoapUI project to send requests(attached here).
04. Then added file attachment and oauth authentication header and send request to API manager's API.

I was able to send large(4.0 MB) files without any issue. I have attached fileupload-sample.zip file to this JIRA and it contains all artefacts i used for this test(file upload war file, SoapUI project and API definition).


[1]https://svn.wso2.org/repos/wso2/trunk/commons/qa/qa-artifacts/app-server/as-5.1.0/content_type/

fileupload-sample.zip

Tuesday, November 19, 2013

How Clustering and caching effect for WSO2 API Manager 1.2.0 distributed deployment

So here is a small description about caching and clustering configurations and parameters we used in WSO2 API manager. Lets see how clustering and caching effects for API manager.  1.2.0.

Gateway
=======
Effect of tribes clustering := Clustering must be enabled for gateways and all should clustered to single clustering domain, otherwise throttling replication will not happen.
Effect of cache enable:= There is no effect on caching if we don't use validation information cache at gateway.
Effect of synchronizeAll parameter in axis2.xml:= This doesn't have any effect on throttling information replication. Throttling information replication happens through axis2 context(according to throttle code) and there is no effect on this parameter. So we can set this as false for gateway nodes.

Key manager
===========
For key manager clustering should be enabled as we send cluster messages to invalidate cache. And we need to enable replicate cache for API key manager nodes as oauth2 cache is a replicated cache. Also we checked synch or asynch mode of replicate cache and didn't noticed any issues in the system.
SynchronizeAll parameter in axis2.xml doesn't have any effect for key manager nodes.

Enable async replicated cache mode can be done by setting sync property in cache.xml as false. According to infinity span documents, if Infinispan is configured in async mode, the cache will become inconsistent when the same key is modified by two peers at the same time. But inside our code we do not update cache elements ,instead of that we will invalidate old objects. So both asynch and synch should work fine with API manager.

In addition to that we have introduced complete new caching mechanism from API manager 1.5.0 onwards. Now we have JSR 107 (JCache) based caching implementation which has been implemented on top of Hazelcast. All components which were using the older infinispan & ehcache based implementations now changed to this new implementation.

Monday, November 11, 2013

How to fix issue in subscription page of the WSO2 API Manager due to missed API( ERROR - UserAwareAPIConsumer Failed to get API from : /apimgt/applicationdata/provider/)

Sometimes you may not able to view subscriptions in the Store of the WSO2 API Manager due to missing API from registry. When you visit subscription page
(https://192.168.1.4:9443/store/site/pages/subscriptions.jag) you might get following error.

[2013-11-11 21:14:58,904] ERROR - UserAwareAPIConsumer Failed to get API from : /apimgt/applicationdata/provider/admin/ddd/1.0.0/api
org.wso2.carbon.registry.core.exceptions.ResourceNotFoundException: Resource does not exist at path /_system/governance/apimgt/applicationdata/provider/admin/ddd/1.0.0/api
    at org.wso2.carbon.registry.core.jdbc.EmbeddedRegistry.get(EmbeddedRegistry.java:532)
    at org.wso2.carbon.registry.core.caching.CacheBackedRegistry.get(CacheBackedRegistry.java:166)
    at org.wso2.carbon.registry.core.session.UserRegistry.get(UserRegistry.java:524)
    at org.wso2.carbon.apimgt.impl.AbstractAPIManager.getAPI(AbstractAPIManager.java:292)
    at org.wso2.carbon.apimgt.hostobjects.APIStoreHostObject.addAPIObj(APIStoreHostObject.java:1289)
    at org.wso2.carbon.apimgt.hostobjects.APIStoreHostObject.jsFunction_getAllSubscriptions(APIStoreHostObject.java:1278)


The reason for this issue is api resource is not there in provided path(/_system/governance/apimgt/applicationdata/provider/admin/ddd/1.0.0/api ). Here, subscriptions are run time data that stored in api manager db and API are meta data stored in registry. This error log says application is having API which is not there in registry.

This can happen due to multiple reasons.
01. Deleting registry API resource without deleting it from publisher UI(then it will delete registry data and entries in API manager tables).
02. change governance space after create subscriptions().

For this issue you can do followings.
If governance space changed you can mount to old space again. Then missed API will appear in given path.
You can create missed (API ddd/1.0.0) again in the system. for this delete API from api manager tables and create API from publisher UI.
You can delete subscriptions associated with missed API(ddd/1.0.0). For this you need to delete all associated entries from api manager tables carefully.

To fix this issue please run following db queries against you API manager database. Its always recommend to run these queries on test environment and then apply to production servers.

Here first we need to get API_ID associated with problematic API. To get that please run following command
SELECT API_ID FROM AM_API where API_NAME = 'ddd' and API_VERSION = '1.0.0'

Then we need to delete all subscriptions associated with that API. Let say we got 3 as the result of above query. Run following query to delete all associated subscriptions.
DELETE FROM AM_SUBSCRIPTION where API_ID = '3'

Then you are done  :)

Tuesday, November 5, 2013

How to use AuthenticationAdmin service to authenticate user against WSO2 carbon server

In WSO2 products we use client server architecture within our servers. Any functionality available to you via WSO2 Carbon management console can also be invoked via a web service call. To invoke an admin service you have to authenticate user first, then get the session cookie and invoke the services you want. For this you need to invoke AuthenticationAdmin service. Here is a sample java code to invoke AuthenticationAdmin service and get session cookie. While running sample you can change username and password and see how authentication works.


package wso2.test.com;

import org.apache.axis2.AxisFault;
import org.apache.axis2.transport.http.HTTPConstants;
import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub;
import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;
import org.wso2.carbon.authenticator.stub.LogoutAuthenticationExceptionException;
import org.apache.axis2.context.ServiceContext;

import java.rmi.RemoteException;

public class AdminServiceClient {

    public static void main(String[] args)
            throws RemoteException, LoginAuthenticationExceptionException,
            LogoutAuthenticationExceptionException {
        System.setProperty("javax.net.ssl.trustStore", "/repository/resources/security/wso2carbon.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
        System.setProperty("javax.net.ssl.trustStoreType", "JKS");
        String backEndUrl = "https://localhost:9443";
        LoginAdminServiceClient login = new LoginAdminServiceClient(backEndUrl);
        String session = login.authenticate("admin", "admin");
    }
}

class LoginAdminServiceClient {
    private final String serviceName = "AuthenticationAdmin";
    private AuthenticationAdminStub authenticationAdminStub;
    private String endPoint;

    public LoginAdminServiceClient(String backEndUrl) throws AxisFault {
        this.endPoint = backEndUrl + "/services/" + serviceName;
        authenticationAdminStub = new AuthenticationAdminStub(endPoint);
    }

    public String authenticate(String userName, String password) throws RemoteException,
            LoginAuthenticationExceptionException {

        String sessionCookie = null;

        if (authenticationAdminStub.login(userName, password, "localhost")) {
            System.out.println("Login Successful");

            ServiceContext serviceContext = authenticationAdminStub.
                    _getServiceClient().getLastOperationContext().getServiceContext();
            sessionCookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);
            System.out.println(sessionCookie);
        }
        System.out.println("Login Unsuccessful");
        return sessionCookie;
    }

    public void logOut() throws RemoteException, LogoutAuthenticationExceptionException {
        authenticationAdminStub.logout();
    }
}

Recommended system requirement for WSO2 carbon 4.2.0 based products

Here are list of recommended hardware configurations for WSO2 carbon 4.2.0 based products. With following specifications we can get maximum output of servers.

Physical : 3GHz Dual-core Xeon/Opteron (or latest), 4 GB RAM 
(minimum : 2 GB for JVM and 2GB for the OS, 10GB free disk space 
(minimum) disk based on the expected storage requirements 
(calculate by considering the file uploads and the backup policies) . 

Virtual Machine : 2 compute units minimum (each unit having 1.0-1.2 
GHz Opteron/Xeon processor) 4 GB RAM 10GB free disk space. 
One cpu unit for OS and one for JVM. (e.g if 3 Carbon instances 
running require VM of 4 compute units 8 GB RAM 30 GB free space) 

EC2 : M1-Medium instance to run one Carbon instance. (e.g if 3 Carbon 
instances EC2 Large instance)

Friday, November 1, 2013

How to limit number of connections to cassandra server - WSO2 BAM2

We might need to limit number of connections to cassandra server due to some fine tuning purposes. Here we will see how we can do that.

For this we can use rpc_max_threads parameter. Description about rpc_max_threads as follows.
"Cassandra uses one thread-per-client for remote procedure calls. For a large number of client connections, this can cause excessive memory usage for the thread stack. Connection pooling on the client side is highly recommended. Setting a maximum thread pool size acts as a safeguard against misbehaved clients. If the maximum is reached, Cassandra will block additional connections until a client disconnects."


So we can use this parameter to limit number of active connections.

So you need to edit repository/conf/etc/cassandra.yaml file and edit  rpc_max_threads property with desired value.

Wednesday, October 30, 2013

WSO2 ESB - How to secure API with Basic Auth

01. You can download basicAuth JAR file from the following location[1], copy it to the repository/component/lib directory, and restart the ESB. 
02. Please copy this configuration to your synapse configuration 
03. Invoke it with following curl command or any client(please note you must send basic auth header with request and invoke through https ports). 
      curl -v -k -H "Authorization: Basic YWRtaW46YWRtaW4=" https://localhost:8243/RESTWebService/dept/1

[1]https://svn.wso2.org/repos/wso2/carbon/platform/branches/4.1.0/products/esb/4.7.0/modules/samples/integration-scenarios/starbucks_sample/bin/WSO2-REST-BasicAuth-Handler-1.0-SNAPSHOT.jar

configuration 
========== 
   <api name="test-api" context="/RESTWebService"> 
      <resource methods="GET" protocol="https" uri-template="/dept/{id}"> 
         <inSequence> 
            <log level="full"/> 
            <log> 
               <property name="REST_URL_POSTFIX" expression="get-property('uri.var.id')"/> 
            </log> 
            <property name="POST_TO_URI" value="true" scope="axis2"/> 
            <send> 
               <endpoint name="test-api_APIEndpoint_0"> 
                  <address uri="http://service_host:port/RESTWebService/rest/departments/"/> 
               </endpoint> 
            </send> 
         </inSequence> 
         <outSequence> 
            <send/> 
         </outSequence> 
      </resource> 
      <handlers> 
         <handler class="org.wso2.rest.BasicAuthHandler"/> 
      </handlers> 
   </api>

Thursday, October 24, 2013

How to get client IP from out going requests of WSO2 Elastic load balancer (Avoid masking client IP)

Normally when requests pass through load balancers client IP for actual back end server would be load balancers IP. But sometimes actual back end server may need actual client and load balancers (all  load balancers message passed) IPs to tracing message flows. In such cases normally we use  X-Forwarded-For[1]  header. If we need to achieve same using WSO2  elastic load balancer we need to add following configuration to main sequence. Also if header is already present we should append ip by separating ",". We can use this to avoid masking client IP from WSO2 ELB


[1]http://en.wikipedia.org/wiki/X-Forwarded-For 

Add following configuration to main sequence in flow

<filter source="get-property('transport','X-Forwarded-For')" regex=".*">
<then>
<property name="coming-X-Forwarded-For" expression="fn:concat(get-property('transport','X-Forwarded-For'),
', ')" scope="axis2" type="STRING"/>
<property name="clientIP" expression="get-property('axis2','REMOTE_ADDR')"/>
<property name="X-Forwarded-For" expression="fn:concat(get-property('axis2','coming-X-Forwarded-For'),
get-property('clientIP'))" scope="transport" type="STRING"/>
</then>
<else>
<property name="X-Forwarded-For" expression="get-property('axis2','REMOTE_ADDR')" scope="transport" type="STRING"/>
</else>
</filter>

Wednesday, October 16, 2013

How to increase maximum number of Proxies using JMS Listeners - WSO2 ESB

Here we will see how we can increase maximum number of Proxies using JMS Listeners. When you create JMS proxy services in WSO2 ESB you might see something like below(if you created at-least 20 JMS proxies).

[2013-11-07 20:25:41,875]  WARN - JMSListener Polling tasks on destination : JMStoHTTPStockQuoteProxy18 of type queue for service JMStoHTTPStockQuoteProxy18 have not yet started after 3 seconds ..

So lets see how we can avoid this issue. For this we need to increase number of threads which consume messages from jms queues. So we need to edit wso2Server.sh file and add following 2 parameters as system properties.

    -Dsnd_t_core=200 \
    -Dsnd_t_max=250 \


Then restart server.Or you can create new folder named /conf inside server root and add file named jms.properties. Contents of jms.properties should be as follows.

snd_t_core=200
snd_t_max=250


Add that file and restart server.

WSO2 ESB JSON to XML transformation sample


1. Deploy the SimpleStockQuoteService in sample Axis2 server and start it on port 9000.
  goto wso2esb-4.7.0/samples/axis2Client/SimpleStockQuoteService/
  Then run ant command to build sample(type ant)
   Start axis2 server by using command sh axis2server.sh      
   (wso2esb-4.7.0/samples/axis2Server)

2. Start WSO2 ESB and add following proxy service configuration from source view.


 <proxy name="JSONProxy" transports="http https">
        <target>
            <endpoint>
                <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
            </endpoint>
            <inSequence>
                <log level="full"/>
                <xslt key="in_transform"/>
                <property name="messageType" scope="axis2" value="text/xml"/>
            </inSequence>
            <outSequence>
                <log level="full"/>
                <xslt key="out_transform"/>
                <property name="messageType" scope="axis2" value="application/json"/>
                <send/>
            </outSequence>
        </target>
    </proxy>
 
    <localEntry key="in_transform">
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                        xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
                        xmlns:m0="http://services.samples" version="2.0" exclude-result-prefixes="m0 fn">
            <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
            <xsl:template match="*">
                <xsl:element name="{local-name()}" namespace="http://services.samples">
                    <xsl:copy-of select="attribute::*"/>
                    <xsl:apply-templates/>
                </xsl:element>
            </xsl:template>
        </xsl:stylesheet>
    </localEntry>
 
    <localEntry key="out_transform">
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
            <xsl:output method="xml" version="1.0" encoding="UTF-8"/>
            <xsl:template match="*">
                <xsl:element name="{local-name()}">
                    <xsl:apply-templates/>
                </xsl:element>
            </xsl:template>
        </xsl:stylesheet>
    </localEntry>


3. Invoke created JSON proxy by using following request
payload> {"getQuote":{"request":{"symbol":"IBM"}}}
Header> Content-Type: application/json


Sample curl request

curl -v -H "Content-Type: application/json" POST -d '{"getQuote":{"request":{"symbol":"IBM"}}}' http://localhost:8280/services/JSONProxy


Then you will recieve JSON response similar to
{"getQuoteResponse":{"return":{"change":"4.037527807194175","earnings":"-8.090117195350409","high":"70.45626821525283","last":
"67.1998913871881","lastTradeTimestamp":"Wed Oct 16 14:39:16 IST 2013","low":"68.94581289774287","marketCap":"-5387372.221669148","name":"IBM Company","open":"-66.52524061422466","peRatio":"23.47679801684674","percentageChange":
"5.438572840664724","prevClose":"74.23873735780825","symbol":"IBM","volume":"18254"}}}


Here what happen is
Client > sending json request > JSON proxy in sequence -convert message to xml  > send to actual back end server > JSON proxy in sequence -convert xml response to JSON > Client will receive JSON response

JSON client will send a stockquote request to ESB using the JSON content interchange format. Synapse will transform it into a SOAP request and forward to the Axis2 server. The SOAP response from the Axis2 server will be converted into a JSON message and sent back to the JSON client.

Tuesday, October 15, 2013

How to convert xml formatted authentication faliure error into JSON errors in WSO2 API manager

For this we need to add additional sequence which convert message into JSON. Then we need to add that sequence to auth failure sequence so authentication faliure message will be convert and sent to client.

Add convert sequence to _auth_failure_handler_
 

<sequence name="_auth_failure_handler_" xmlns="http://ws.apache.org/ns/synapse">
    <sequence key="convert"/>
</sequence>

convert sequence

<sequence xmlns="http://ws.apache.org/ns/synapse" name="convert">
<sequence key="_build_"/>
<filter source="get-property('MESSAGE_FORMAT')" regex="soap1[1-2]">
<then>
<property name="SOAP_FAULT_CODE" value="Server"/>
<makefault>
<code expression="$ctx:SOAP_FAULT_CODE"/>
<reason expression="$ctx:ERROR_MESSAGE"/>
</makefault>
</then>
<else>
<payloadFactory>
<format>
<am:fault xmlns:am="http://wso2.org/apimanager">
<am:code>$1</am:code>
<am:type>Status report</am:type>
<am:message>Runtime Error</am:message>
<am:description>$2</am:description>
</am:fault>
</format>
<args>
<arg expression="$ctx:ERROR_CODE"/>
<arg expression="$ctx:ERROR_MESSAGE"/>
</args>
</payloadFactory>
<filter source="$axis2:HTTP_METHOD" regex="^(?!.*(POST|PUT)).*$"></filter>
</else>
</filter>
<filter xpath="$ctx:CUSTOM_HTTP_SC">
<then>
<property name="HTTP_SC" expression="$ctx:CUSTOM_HTTP_SC" scope="axis2"/>
</then>
<else>
<property name="HTTP_SC" value="500" scope="axis2"/>
</else>
</filter>
<class name="org.wso2.carbon.apimgt.usage.publisher.APIMgtFaultHandler"/>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<property name="NO_ENTITY_BODY" scope="axis2" action="remove"/>
<property name="ContentType" scope="axis2" action="remove"/>
<property name="Authorization" scope="transport" action="remove"/>
<property name="Host" scope="transport" action="remove"/>
<property name="Accept" scope="transport" action="remove"/>
<property name="X-JWT-Assertion" scope="transport" action="remove"/>
<property name="messageType" value="application/json" scope="axis2"/>
<send/>
</sequence>

Wednesday, October 2, 2013

How to convert token API response into xml format WSO2 API manager - json to soap conversion


Here in this post i have described how to convert token/login API response into xml format WSO2 API manager. This is similar to json to soap conversion in WSO2 ESB. Here is the updated token API. Please copy this and replace with current token api synapse configuration.



<api name="_WSO2AMLoginAPI_" context="/login" xmlns="http://ws.apache.org/ns/synapse"> 
    <resource methods="POST" url-mapping="/*"> 
        <inSequence> 
<property name="inSeqFORMAT" expression="$trp:Accept"/> 
<property name="Accept" action="remove" scope="transport"/> 
            <send> 
                <endpoint> 
                    <address uri="https://localhost:9443/oauth2endpoints/token"/> 
                </endpoint> 
            </send> 
        </inSequence> 
        <outSequence> 
<filter source="get-property('inSeqFORMAT')" regex="application/xml"> 
<then> 
<builder> 
<messageBuilder contentType="application/json" class="org.apache.axis2.json.JSONBuilder" 
formatterClass="org.apache.axis2.json.JSONMessageFormatter"/> 
<messageFormatter contentType="application/xml" 
class="org.apache.axis2.transport.http.ApplicationXMLFormatter"/> 
</builder> 
<property name="messageType" value="application/xml" scope="axis2"/> 
<property name="ContentType" value="application/xml" scope="axis2"/> 
<payloadFactory> 
<format> 
<m:root xmlns:m="http://services.samples"> 
<token_type>$1</token_type> 
<expires_in>$2</expires_in> 
<refresh_token>$3</refresh_token> 
<access_token>$4</access_token> 
</m:root> 
</format> 
<args> 
<arg expression="//token_type"/> 
<arg expression="//expires_in"/> 
<arg expression="//refresh_token"/> 
<arg expression="//access_token"/> 
</args> 
</payloadFactory> 
</then> 
<else> 
</else> 
</filter> 
            <send/> 
        </outSequence> 
    </resource> 
</api>

Tuesday, September 3, 2013

Throttling Support at API Resource Level and http verb level in WSO2 API manager

We will add Throttling Support at API Resource Level in API manager 1.5.0 and onwards. Here is a brief description on what we have done here.In WSO2 API manager we have API level throttling support and application level throttling support. API level throttling can be defined when API creator creates the API and subscribers can select one of throttling tiers when they subscribe API under an Application. Application level throttling tier can be defined when you create applications. So all the APIs available in given application will be allowed up to application level throttling limit. With this new feature, Throttling Tier can be engaged to each resource at HTTP verb level. When adding an API, you can configure the Throttle Tier for each HTTP verb under each API resource. By default every HTTP verb will be assigned to Unlimited Tier.


Current functionality:
Now we do have throttling support at API level and application level. Consumer can select throttling tier for API when they subscribe to API, also they can define throttling tier when they create application(application is bundle of APIs). 

New Addition:
Support for providing throttling tier support for resource level and HTTP verb level.

Throttling tiers per resource and http verb level can be define when we create API like we add throttling tiers per API. So when subscribers going to subscribe to API they will notify throttling limits at resource level. see following sample.


API - testAPI (allow subscribers to select gold and unlimited).
/testAPI/1.0.0/. Subscribers can select this when they subscribe to API
    |---Resource - student/ 
         |--get - Bronze (define when we create api and subscribers cannot change this. But they will notify limits). 
         |--put -Silver (define when we create api and subscribers cannot change this.But they will notify limits). 
         |--delete - Bronze(define when we create api and subscribers cannot change this.But they will notify limits).
         
         
Our plan is to add this resource section of API create UI. 

So API publishers can select throttling tier when they create API and add resource level permissions to API.

Implementation:
Throttling key for this scenario will contain access_token + api +resource + http_verb combination. Throttling values once loaded will be cached for performance.
 
 
Below you can see the default Throttle tier selection. Using the drop down menu, Tiers can be changed.

 
 
 
 
 
 View Tiers from the Store
The Resource level throttling Tiers can be viewed by the API subscribers through the new available Tab
'Throttle Tiers'. It displays the throttle information for each HTTP verb, under each resource.
 
 
 
 
When an API is invoked, first it checks whether request is allowed by API level throttling limit. If it has
exceeded request will be terminated.
If it is allowed then it checks whether request is allowed by Application level throttling limit. If it has
exceeded request will be terminated.
If it is also allowed it checks whether request is allowed by Resource level throttling limit.
So if the request was allowed by API and Application level throttling limits, API can be invoked up to
the resource level throttling limit.