Thursday, June 19, 2014

WSO2 Task Server - Interfacing tasks from other WSO2 Servers

WSO2 TS (At the moment it's 1.1.0) is released with the following key features
  • Interfacing tasks in Carbon servers.
  • Trigger web tasks remotely
The first feature will be discussed in this blog post. Carbon servers can be configured to use WSO2 Task Server as the dedicated task provider. I will take WSO2 DSS (Here I'm using DSS 3.2.1) as the WSO2 Server for demonstration purposes. These are the steps to follow.

1.  Download TS and DSS product zip files and extract them.
2.  We are going to run 2 carbon servers in the same machine. Therefore, we need to change the port index of DSS in CARBON_HOME/repository/conf/carbon.xml so that the DSS nodes will run without conflicting with other server.
In carbon.xml, change the following element in order to run the DSS in HTTP port 9764 and HTTPS port 9444.

<Offset>1</Offset>

3.  Open the tasks-config.xml file of your carbon server (e,g. DSS Server). You can find this file from the <PRODUCT_HOME>/repository/conf/etc directory. Do the following changes.
4.  Set the task server mode to REMOTE.

 <taskServerMode>REMOTE</taskServerMode>

By setting this mode, we can configure the carbon server to run it's task remotely.

5.  Point the taskclientdispatchaddress to the same DSS server address. 

<taskClientDispatchAddress>https://localhost:9444</taskClientDispatchAddress>

6. Remote address URL and credentials to login to the server should be defined. 

    <remoteServerAddress>https://localhost:9443</remoteServerAddress>
   
    <remoteServerUsername>admin</remoteServerUsername>
   
    <remoteServerPassword>admin</remoteServerPassword>


7. Start the Task Server.

8. Start the DSS Server. You can see it is started in REMOTE mode from the startup logs


9. Now you can add a task from management console of the DSS Server.


 10. You can verify that the task is running on the Task Server by the logs printed in the TS logs


 

Thursday, January 16, 2014

Clustering WSO2 Products with Registry Mounting

In this blog post I'm going to explain how to set up a cluster of WSO2 products using registry mounting. This setup method is applicable to products built using 4.2.0 kernel.

Here I will use WSO2 DSS as the product and WSO2 GREG for registry mounting.

This is what we are going to do!

GREG will be our central repository which uses MySQL as the database. The two DSS servers will use the same repository for their shared resources.

Now it is time to configure these products.

1. Download DSS 3.1.1 from here
2. Download GREG 4.6.0 from here
3. Create a database in MySQL and assign user priviledges with the following commands.

mysql>create database regdb;
mysql>use regdb;
mysql>grant all on regdb.* TO regadmin@localhost identified by "regadmin";

4. Extract the GREG 4.6.0 zip file and change the configured datasource in $GREG_HOME/repository/conf/datasources/master-datasources.xml file in order to tell GREG to run on top of the MySQL datasource instead of default H2 datasource

For that replace 

        <datasource>
            <name>WSO2_CARBON_DB</name>
            <description>The datasource used for registry and user manager</description>
            <jndiConfig>
                <name>jdbc/WSO2CarbonDB</name>
            </jndiConfig>
            <definition type="RDBMS">
                <configuration>
                    <url>jdbc:h2:repository/database/WSO2CARBON_DB;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=60000</url>
                    <username>wso2carbon</username>
                    <password>wso2carbon</password>
                    <driverClassName>org.h2.Driver</driverClassName>
                    <maxActive>50</maxActive>
                    <maxWait>60000</maxWait>
                    <testOnBorrow>true</testOnBorrow>
                    <validationQuery>SELECT 1</validationQuery>
                    <validationInterval>30000</validationInterval>
                </configuration>
            </definition>
        </datasource>

with the following content

        <datasource>
            <name>WSO2_CARBON_DB</name>
            <description>The datasource used for registry and user manager</description>
            <jndiConfig>
                <name>jdbc/WSO2CarbonDB</name>
            </jndiConfig>
            <definition type="RDBMS">
                <configuration>
                    <url>jdbc:mysql://localhost:3306/regdb</url>
                    <username>regadmin</username>
                    <password>regadmin</password>
                    <driverClassName>com.mysql.jdbc.Driver</driverClassName>
                    <maxActive>80</maxActive>
                    <maxWait>60000</maxWait>
                    <minIdle>5</minIdle>
                    <testOnBorrow>true</testOnBorrow>
                    <validationQuery>SELECT 1</validationQuery>
                    <validationInterval>30000</validationInterval>
                </configuration>
            </definition>
        </datasource>

5. Download the MySQL JDBC driver connector JAR from here and place it in the $GREG_HOME/repository/components/lib directory.

6. Start the GREG server with the following command

For Linux : wso2server.sh -Dsetup
For Windows : wso2server.bat -Dsetup

This will start GREG on MySQL  and setup the regdb database. The work by GREG is done now.

7. We have to configure DSS products as well. As we are having two DSS instance we have to make two copies.

8. As we are running two WSO2 product instances in the same machine, we have to change running ports for each products. We can change the port by changing the following value in $DSS_HOME/repository/conf/carbon.xml

<Offset>1</Offset>

Then it will run on HTTP port 9764 and HTTPS port 9444.


9. Put the following content to the $DSS_HOME/repository/conf/registry.xml for registry mounting in both DSS instances

<dbConfig name="mysql-reg">
     <url>jdbc:mysql://localhost:3306/regdb</url>
     <userName>regadmin</userName>
     <password>regadmin</password>
     <driverName>com.mysql.jdbc.Driver</driverName>
     <maxActive>5</maxActive>
     <maxWait>60000</maxWait>
     <minIdle>50</minIdle>
     <validationQuery>SELECT 1</validationQuery>
</dbConfig>

<remoteInstance url="https://localhost:9443/registry">
     <id>conf-gov-registry</id>
     <dbConfig>mysql-reg</dbConfig>
     <readOnly>false</readOnly>
     <enableCache>true</enableCache>
     <registryRoot>/</registryRoot>
</remoteInstance>

<!-- Governance data will be stored in /_system/governance collection of central registry instance -->
     <mount overwrite="true" path="/_system/governance">
     <instanceId>conf-gov-registry</instanceId>
     <targetPath>/_system/governance</targetPath>
</mount>

<!-- Configuration data will be stored in /_system/dssnodes collection of central registry instance --> 
     <mount overwrite="true" path="/_system/config">
     <instanceId>conf-gov-registry</instanceId>
     <targetPath>/_system/esbnodes</targetPath>
</mount>

10. Drop the MySQL driver into $DSS_HOME/repository/components/lib directory which is downloaded in the step5

11. By Default the All WSO2 products starts with STANDALONE mode. We have to tell the DSS product to start in CLUSTERED mode. We can enable it by the setting the following property in $DSS_HOME/repository/conf/axis2/axis2.xml to true

<clustering class="org.wso2.carbon.core.clustering.hazelcast.HazelcastClusteringAgent"
                enable="true">

12. We have to tell the cluster how many servers are running explicitly.This can be configured in the $DSS_HOME/repository/conf/etc/tasks-config.xml

<taskServerCount>2</taskServerCount>

With this configuration the server starts first will be waiting for others. (ie. It knows that there are two servers in the cluster and have to wait for the other one.)

12. Now, we are done with the configurations. You can test the clustering and registry mounting through task scheduling. More info available in docs. Once we schedule a task from one DSS instance, that particular task is shared with the other instance as well.








Wednesday, January 8, 2014

Maven 2 Building error : How to sort it out

Today I tried to build a source using Maven 2. In the pom.xml file it is building build.xml file using ant. Then I got the following error.

An Ant BuildException has occured

Perhaps JAVA_HOME does not point to the JDK. It is currently set to /media/chanika/apps/java/java_1.6/jdk1.6.0_45/jre

So the first thing came to my mind is that the path for java JDK is set to as a wrong one. But when I checked the path it has been set correctly.

So I googled a liitle bit and found out this is because of that Maven2 starts the antrun plugin with the JRE not the JDK.

This can be overcome by doing one of the followings.

1. By editing your pom.xml file in order to add tools.jar dependency.

      <profile>
          <id>tools.jar</id>
          <activation>
              <property>
                  <name>java.vendor</name>
                  <value>Sun Microsystems Inc.</value>
              </property>
          </activation>
          <build>
            <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-antrun-plugin</artifactId>
              <dependencies>
                <dependency>
                  <groupId>com.sun</groupId>
                  <artifactId>tools</artifactId>
                  <version>1.5.0</version>
                  <scope>system</scope>
                  <systemPath>${java.home}/../lib/tools.jar</systemPath>
                </dependency>
              </dependencies>
            </plugin>
            </plugins>
          </build>
      </profile>

2. Or else you can add the following property to your build.xml file

<property name="build.compiler" value="extJavac"/> 




Thursday, September 26, 2013

How to connect to Cassandra using WSO2 DSS

WSO2 Data Service Server supports exporting data as a web service, called a data service. It can connect to various data sources and expose those data to do operations on them. This post will guide you to use a Cassandra data source using WSO2 DSS.

1. Download Cassandra from here and install (You may have to change some configurations. Please refer this).
2. Create a keyspace, table and store some data
Now we will look into how to configure DSS
3.You can download DSS from here
4. Extract the pack and goto $DSS_HOME/bin folder and run sh wso2Server.sh (if you are a Windows user run wso2Server.bat file)
5. Add a data source. This step has been described in details here
6. You can test connection and save it
7. Deploy data service

The important thing that I would like to address in here is the versions compatibility of WSO2DSS and Cassandra jdbc drivers.
  • The WSO2 DSS version older than 3.1.0 compatible with Cassandra JDBC 1.1.1. By default the Cassandra 1.1.x supports CQL (Common Query Language) 2. CQL3 is released with much more functionalities than CQL2 such as schema-free feature. 
  • But you can connect to CQL3 by starting the Cassandra server with the following command ./cqlsh -3
  • From WSO2 DSS (older version starting from 3.0.1) you have to specify the connection url as below. jdbc:cassandra://localhost:9160/keyspace_name?version=3.0.0
  • If you do not specify the version in the URL it will connect to CQL2 by default
  • But from DSS version 3.1.0 onward it supports Cassandra JDBC 1.2.x and because of that, it will connect to CQL3 by default.


Wednesday, September 25, 2013

Escape non printable characters in WSO2 DSS

WSO2 Dss can be used to expose data from different data sources (ex: MYSQL, ORACLE) as a web service. Escaping non printable characters is a feature introduced from WSO2 DSS 3.1.0 onward.

Lets say in your database there are characters which cannot be printed. But you cannot replace or delete them as those are the data you have. But if you want to retrieve those data through a web service it will not allow to do so as they cannot be represented. For an example when you are invoking a data service (using soap-ui or try-it) and do a select query for a data contains characters which are not in printable format it will throw the following exception.

ERROR {org.wso2.carbon.dataservices.core.description.query.SQLQuery} -  DS Fault Message: Error in XML generation at StaticOutputElement.execute
DS Code: UNKNOWN_ERROR
Nested Exception:-
com.ctc.wstx.exc.WstxIOException: Invalid white space character (0x5) in text to output
 {org.wso2.carbon.dataservices.core.description.query.SQLQuery}
DS Fault Message: Error in XML generation at StaticOutputElement.execute
DS Code: UNKNOWN_ERROR
Nested Exception:-
com.ctc.wstx.exc.WstxIOException: Invalid white space character (0x5) in text to output

 at org.wso2.carbon.dataservices.core.engine.StaticOutputElement.execute(StaticOutputElement.java:232)
 at org.wso2.carbon.dataservices.core.engine.OutputElementGroup.execute(OutputElementGroup.java:121)
 at org.wso2.carbon.dataservices.core.description.query.Query.writeResultEntry(Query.java:339)
 at org.wso2.carbon.dataservices.core.description.query.SQLQuery.processNormalQuery(SQLQuery.java:822)
 at org.wso2.carbon.dataservices.core.description.query.SQLQuery.runQuery(SQLQuery.java:2034)
 at org.wso2.carbon.dataservices.core.description.query.Query.execute(Query.java:254)
 at org.wso2.carbon.dataservices.core.engine.CallQuery.execute(CallQuery.java:161)
 at org.wso2.carbon.dataservices.core.engine.CallQueryGroup.execute(CallQueryGroup.java:118)
 at org.wso2.carbon.dataservices.core.description.operation.Operation.execute(Operation.java:73)
 at org.wso2.carbon.dataservices.core.engine.DataService.invoke(DataService.java:598)
 at org.wso2.carbon.dataservices.core.engine.DSOMDataSource.execute(DSOMDataSource.java:135)
 at org.wso2.carbon.dataservices.core.engine.DSOMDataSource.serialize(DSOMDataSource.java:147)
 at org.apache.axiom.om.impl.llom.OMSourcedElementImpl.internalSerialize(OMSourcedElementImpl.java:691)



This happened as those characters cannot be serialized to xml when they are going to be printed. But with this newly added feature you can define to escape the those characters with '?' when you define output mapping in the process of creating the data service. You can select "Escape Non Printable Characters" from the UI.

If it is selected the corresponding characters will be replaced by ? and if it is not, then it will throw the above exception. Find more from here. 



Sunday, June 30, 2013

Analyze your IBM thread dump in Linux

Last week I had to analyze a heap dump taken from IBM VM. That heap dump was in .txt file and therefore it is readable. Part from the heap dump is shown below.


NULL           ------------------------------------------------------------------------
0SECTION       TITLE subcomponent dump routine
NULL           ===============================
1TISIGINFO     Dump Event "user" (00004000) received
1TIDATETIME    Date:                 2004/08/23 at 10:20:50
1TIFILENAME    Javacore filename:    /u/mcculls/test/javacore.20040823.102050.16908401.txt
NULL           ------------------------------------------------------------------------
0SECTION       GPINFO subcomponent dump routine
NULL           ================================
2XHOSLEVEL     OS Level         : z/OS 06.00
2XHCPUS        Processors -
3XHCPUARCH       Architecture   : s390x
3XHNUMCPUS       How Many       : 2

As the format of this heap dump is different from hprof file format this cannot be analyzed using either MAT analyzer (the eclipse plugin) or JProfiler because those prefer binary data to analyze.

There is a heap dump analyzer specially to the IBM VM called 'IBM Thread and Monitor Dump Analyzer for Java'. You can download the jar from here. (Please note that this version works with only JDK 7). Then you can simply run the jar file using this command

chanika@chanika-ThinkPad-T530:/apps/jdk1.7.0/bin$ ./java -jar /home/chanika/Downloads/jca445.jar

Then you will get a window as following




Click on File -> Open Thread Dumps -> Brows the thread dump file and select that.

Then that file will come under thread dump list and the when you select the dump file from the list some information in the header will appear as following screenshot




Then you can analyze the thread dump using options in 'Analyze' tab.  This is a sample thread dump analyze I have done.




Tuesday, May 14, 2013

Simultaneous read and write in Custom TCPMon

TCP Monitors are used to monitor messages passed through a TCP based communication. Apache TCPMon is one of the open source TCP Montor which is developed under Apache Software Licence. You can download TCPMon from here.

But when I used TCPMon to listen two way TCP communication by configuring the listen port and the  target port, I observed there is no simultaneous reading and writing for the two paths (from source to target and target to source).

Therefore a simple custom TCPMon is written to facilitate simultaneous read and write. Here is the approach I followed.

To listen from a port we can create a new Socket connection, configure the port and accept data. Here I have taken the listening port as 2389.

public static void main(String[] args) throws Exception {
        ServerSocket srcSocket = new ServerSocket(2389);
        while (true) {
            new Thread(new TCPServer(srcSocket.accept())).start();
        }
    }

It requires what is the target port that data should be sent to. Here the target port is 3456.

Socket targetSock = new Socket("localhost", 3456);

Then we can have input stream and the output stream from both socket connections.

        srcIn = srcSocket.getInputStream();
        srcOut = srcSocket.getOutputStream();
        targetIn = targetSock.getInputStream();
        targetOut = targetSock.getOutputStream();

Then we should pipe data from the input stream to output stream to have no data loss during communication.

private class Pipe extends Thread {

        private InputStream in;

        private OutputStream out;

        public Pipe(InputStream in, OutputStream out) {
            this.in = in;
            this.out = out;
        }

        public void run() {
            try {
                byte[] buff = new byte[512];
                int i;
                while (true) {
                    i = in.read(buff);
                    if (i > 0) {
                        out.write(buff, 0, i);
                        System.out.print(".");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
In order to have simultaneous data writing and reading operations two threads should be started.

        new Pipe(srcIn, targetOut).start();
        new Pipe(targetIn, srcOut).start();

Now our TCPMon works fine with simultaneous data passing.

The full code is shown below.
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer implements Runnable {

    private InputStream srcIn, targetIn;

    private OutputStream srcOut, targetOut;

    public TCPServer(Socket srcSocket) throws Exception {
        Socket targetSock = new Socket("localhost", 3456);
        srcIn = srcSocket.getInputStream();
        srcOut = srcSocket.getOutputStream();
        targetIn = targetSock.getInputStream();
        targetOut = targetSock.getOutputStream();
    }

    public void run() {
        new Pipe(srcIn, targetOut).start();
        new Pipe(targetIn, srcOut).start();
    }

    private class Pipe extends Thread {

        private InputStream in;

        private OutputStream out;

        public Pipe(InputStream in, OutputStream out) {             this.in = in;             this.out = out;         }         public void run() {             try {                 byte[] buff = new byte[512];                 int i;                 while (true) {                     i = in.read(buff);                     if (i > 0) {                         out.write(buff, 0, i);                         System.out.print(".");                     }                 }             } catch (Exception e) {                 e.printStackTrace();             }         }     }     public static void main(String[] args) throws Exception {         ServerSocket srcSocket = new ServerSocket(2389);         while (true) {             new Thread(new TCPServer(srcSocket.accept())).start();         }     } }