Tuesday, March 17, 2015

How to monitor the created tcp connections for a particular proxy service in WSO2 ESB


As an example if we want to monitor the number of tcp connections created during a proxy invocation, the following steps can be performed.

1. Assume you need to monitor the number of tcp connections created for the following proxy service :


 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="Proxy1"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <inSequence>  
      <property name="NO_KEEPALIVE" value="true" scope="axis2"/>  
      <clone>  
       <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
        <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
       <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
      </clone>  
    </inSequence>  
    <outSequence>  
      <aggregate>  
       <completeCondition>  
         <messageCount/>  
       </completeCondition>  
       <onComplete xmlns:m0="http://services.samples" expression="//m0:getQuoteResponse">  
         <send/>  
       </onComplete>  
      </aggregate>  
    </outSequence>  
   </target>  
   <description/>  
 </proxy>  


You will see there are 5 clones. Therefore it should create only 5 tcp connections.

2. We have used SimpleStockQuoteService service as the backend.
3. Since you need to monitor the connections created, we should delay the response coming from the backend. Therefore we need to change the code slightly in the SimpleStockQuoteService.


We have include a Thread.sleep() for 10 seconds until we monitor the number of connections.
Therefore go to <ESB_HOME>/samples/axis2Server/src/SimpleStockQuoteService/src/samples/services/SimpleStockQuoteService.java

and add the Thread.sleep(10000); as below to hold the response for sometime.

 public GetQuoteResponse getQuote(GetQuote request) throws Exception {  
 Thread.sleep(10000);  
 if ("ERR".equals(request.getSymbol())) {  
 throw new Exception("Invalid stock symbol : ERR");  
 }  
 System.out.println(new Date() + " " + this.getClass().getName() +  
 " :: Generating quote for : " + request.getSymbol());  
 return new GetQuoteResponse(request.getSymbol());  
 }   


4. Build the SimpleStockQuoteService once again by “ant” in here, <ESB_HOME>/samples/axis2Server/src/SimpleStockQuoteService

5. Now start the axis2server
6. Now you have to open a terminal and provide the following netstat command to get the process id.

sudo netstat --tcp --listening --programs
 

You will see the relevant SimpleStockQuoteService which is up in port 9000 like below.

tcp6 0 0 [::]:9000 [::]:* LISTEN 20664/java

So your process ID will be 20664.


7. Then open a terminal and provide the below command to view the tcp connections for the particular process id.

watch -n1 -d "netstat -n -tap | grep 20664"

8. Now open your soapui and send the following request to Proxy1
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.samples" xmlns:xsd="http://services.samples/xsd">  
   <soapenv:Header/>  
   <soapenv:Body>  
    <ser:getQuote>  
      <!--Optional:-->  
      <ser:request>  
       <!--Optional:-->  
       <xsd:symbol>IBM</xsd:symbol>  
      </ser:request>  
    </ser:getQuote>  
   </soapenv:Body>  
 </soapenv:Envelope>  

9. View the tcp connections created in the terminal which you have been monitoring as soon as you send the request. You should be able to view only 3 connections since we have configured like that in proxy using clone mediator.

tcp6 0 0 127.0.0.1:9000 127.0.0.1:44218 ESTABLISHED 20664/java
tcp6 0 0 127.0.0.1:9000 127.0.0.1:44219 ESTABLISHED 20664/java
tcp6 0 0 127.0.0.1:9000 127.0.0.1:44217 ESTABLISHED 20664/java




Tuesday, February 17, 2015

A sample on a WSO2 ESB proxy with a DBLookup mediator and a dedicated faultSequence to excute during an error

Databases :

DB customer should be created with the required tables.

DB : customerDetails
table :  customers


Proxy :


<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="TestProxyUsh"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence onError="testError">
         <dblookup>
            <connection>
               <pool>
                  <password>root</password>
                  <user>root</user>
                  <url>jdbc:mysql://host:3306/customerDetails</url>
                  <driver>com.mysql.jdbc.Driver</driver>
               </pool>
            </connection>
            <statement>
               <sql>SELECT * FROM customers WHERE name =?</sql>
               <parameter value="WSO2" type="INTEGER"/>
               <result name="company_id" column="id"/>
            </statement>
         </dblookup>
      </inSequence>
      <faultSequence>
         <log level="custom">
            <property name="text" value="An unexpected error occurred for the service"/>
         </log>
      </faultSequence>
   </target>
   <description/>
</proxy>
                               

onError targeting sequence :


<sequence xmlns="http://ws.apache.org/ns/synapse" name="testError">
   <log>
      <property name="error" value="Error Occurred"/>
   </log>
</sequence>


Invoke :

curl -v http://host:8280/services/TestProxyUsh









One possible reason and solution for getting Access denied for user 'username'@'host' in mysql when accessing from outside

Sometimes we might get the below exception when creating a DB connection.

 {org.apache.synapse.mediators.db.DBLookupMediator}
org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Access denied for user 'username'@'203.94.95.133'


Reasons :

The particular IP might not be accessible from outside.

Therefore you need to grant priviledges by the below command in mysql :

GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' IDENTIFIED BY 'password';


FLUSH PRIVILEGES;


Sometimes you might try out below :

GRANT ALL PRIVILEGES ON *.* TO 'password'@'%' WITH GRANT OPTION;

Eventhough it says Query OK, still the issue can be there since you have not used the password.

Also you must do a Flush privileges to update it.

Hope this might help sometimes.

Monday, February 16, 2015

A possible reason and solution for getting 400 Bad Request even when the synapse configuration in WSO2 ESB is correct

Sometimes you might spend lot of time in analyzing the reason for getting 400 bad request when you invoke an up and running backend service through WSO2 ESB.

When you configure and save the synapse configuration of your proxy, you will not see any issue. But sometimes there can a possible reason for this issue.

One good example is explained below :

Look at the below synapse configuration of WSO2 ESB proxy service.


 <proxy name="statuscodeProxy"
          transports="https http"
          startOnLoad="true"
          trace="disable">
      <description/>
      <target>
         <inSequence>
            <log level="full"/>
            <send>
               <endpoint>
                  <address uri="http://10.100.0.31:8090"/>
               </endpoint>
            </send>
         </inSequence>
         <outSequence>
            <log level="full"/>
            <send/>
         </outSequence>
      </target>
   </proxy>



By the look of it, this is alright and you are good to configure it in WSO2 ESB. But the endpoint defined as : http://10.100.0.31:8090 is not exactly the endpoint the backend service expects.

Sometimes there can be missing parameters etc. But if you exactly know your backend service does not expect any parameters and still it throws a 400 bad reques, can you imagine the reason for this?

After spending hours, I accidently found a possible reason :

 it was due to the backend expects a / at the end of the endpoint. So it expects :

http://10.100.0.31:8090/ except http://10.100.0.31:8090


If you configure a tcpmon in between ESB and the backend, you will see the difference as below :

http://10.100.0.31:8090 :  GET  HTTP/1.1  - 400 bad Request

http://10.100.0.31:8090/ : GET / HTTP/1.1  - 200 OK

So if you too come across this situation, please try out this option. Sometimes this might save your time! :)


One Possible Reason and solution for dropping the client's custom headers when sending through nginx

Problem :

Sometimes you may have experienced that the custom header values defined and sent through client has been dropped off when it goes via the nginx in a setup fronted by nginx.


Solution :

1. First you should check whether the custom headers  contain underscores (_)

2. If so you need to check whether you have configured underscores_in_headers in your nginx.conf under each server.

3. By default, underscores_in_headers is off.

4. Therefore you need to configure it to on.


Reason :


By this property,

It enables or disables the use of underscores in client request header fields. When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.

Ref: http://nginx.org/en/docs /http/ngx_http_core_module.html


Example :

Sample configuration would be as below :



server{
      listen 8280;
      server_name wrk.esb.com;
      underscores_in_headers on;

location / {
       proxy_set_header X-Forwarded-Host $host;
       proxy_set_header X-Forwarded-Server $host;.
.
.
.
.
                }
         }

Wednesday, February 11, 2015

Reason and solution for not loading WSDL in a clustered setup fronted by NGINX





For more information about nginx http proxy module please refer : http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version



Issue :
Sometimes a WSDL in a clustered setup fronted by NGINX might not be loaded.



Reason :

By default, http version 1.0 is used in nginx. Version 1.1 is recommended for use with keepalive connections. Therefore sometimes the wsdl will not be loaded.

You can confirm it by doing a curl command to the wsdl ngingx url.

E.g.,  curl http://wrk.test.com:8280/services/test?wsdl
Then you will get half of the wsdl.


Solution :

To avoid this, you will have to configure the nginx configuration file to set it's http version.


       proxy_http_version 1.1;
 

Example :

As an example,

server{
      listen 8280;
      server_name wrk.test.com;

location / {
       proxy_set_header X-Forwarded-Host $host;
       proxy_set_header X-Forwarded-Server $host;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

       proxy_http_version 1.1;

        proxy_pass http://esbworkers;
        proxy_redirect http://esbworkers http://wrk.esb.com:8280/;


        }
}

This configuration is applicable for nginx versions above 1.1.4

Monday, December 1, 2014

WSO2 ESB Script Mediator Using JavaScript with a Json payload

Synapse supports Mediators implemented in a variety of scripting languages such as JavaScript, Groovy, or Ruby. For More information on script mediator please refer this link.

This blog post will explain a scenario of using script mediator with a Json payload.


Configure back-end
==============

1. Deploy this webapp in an appserver.
https://svn.wso2.org/repos/wso2/trunk/commons/qa/qa-artifacts/esb/esb481/JSONscenarios/withScriptMediator/pizzashop-rs_1.0.zip

Configure ESB
=============

2. Provide the following api synapse configuration.


<api name="pizzashop" context="/pizzashop">
 <resource methods="GET" uri-template="/api/menu/pizza*">
  <inSequence>
   <send>
    <endpoint>
     <http method="get"
uri-template="http://localhost:9765/pizzashop-rs_1.0/services/menu/pizza/all"/>
    </endpoint>
   </send>
  </inSequence>
  <outSequence>
   <log level="full"/>
    <script language="js">var payload = mc.getPayloadJSON();mc.setPayloadJSON(payload);    </script>
     <send/>
  </outSequence>
 </resource>
</api>


Invoking the service
==============

3. Invoke the service

curl -v "http://localhost:8280/pizzashop/api/menu/pizza/all"


You will get all the available pizza list.