Sunday, November 25, 2007

Refinement

Zhenhua Guo

Architecture: 1

Job Submission and Execution. 1

Query: 1

Some issues: 1

Class Design. 2

Client-side Classes: 2

Agent side Classes 3

Executor side classes 4

Architecture:

Job Submission and Execution

Query:

Some issues:

(1) Authentication

As we all know, username and password is a fundamental authentication method.

Should we support other types of authentication, especially users’ certificate authentication?

Answer is no. Generally client-side javascript is not allowed to access local file system. Although some systems provide extension to support local file access (e.g. IE ActiveX object: FileSystemObject), this is not portable. As a result, to get user’s certificate, we must provide a text area on the web page where user can paste his/her certificate. You know mostly web pages cope with printable characters. In certificate, there are lots of non-printable characters so that user can not simply copy and paste its content. In a word, lots of tricky work must be done. In the meanwhile, convenience of using out system gets worse because user must do some additional work.

Now let’s rethink over this issue. Why do we need to provide support for certificate authentication? In our system, HTTPS is used as the fundamental transmission protocol. So we don’t worry about eavesdropping attack. By imposing strength constraint on users’ password, we can guarantee desirable security level. So I think username and password authentication is enough for us.

(2) Built-in authentication vs. our own authentication

Tomcat provides built-in support for username and password authentication. However, sometimes it is not flexible to satisfy our requirements.

(3) Work flow support

Do we need to support workflow-level composition? For example, one workflow depends on another workflow or two workflows can be executed parallel.

If answer is yes, does Karajan workflow engine support it?

If not, we must support it in javascript and now we encounter another big issue: javascript does not provide multithread support. I think we can do some workaround here. But the performance and functionality may not satisfy us.

(4) Job manipulation

To manipulate a job (cancel, suspend, resume ...), client should have a valid handle to refer to the job. I am not sure how users can get this handle. I think this handle should be returned when user submits a job. Then when user wants to manipulate the job, he/she needs to send that handle to tell agent which job will be manipulated.

(5) Status checking

Does the user have to be authenticated to do status checking? In other words, do we allow status checking issued by anonymous users?

What mechanisms are used to support status checking?

Ø check on demand

Every time a client sends a status-checking request, status repository sends a similar request to executor... This mechanism guarantees that the client always get accurate and real-time result. However, it may incur unnecessary workload. Even if the status of a certain job does not change, the whole process must be performed still.

In this case, a separate status repository does not benefit us except that it results in a clearer logic representation.

Ø update on demand

Every time status of a job changes, executor will notify status repository. When a user sends a request to get status of his/her jobs, agent server gets result from status repository. However status repository does not need to sends request to executor. By this means, unnecessary communication is eliminated.

I am not sure whether Java CoG provides callback support so that a specified action will be performed if a certain event occurs.

Class Design

Client-side Classes:

Foundation Stones:

1) Workflow

Description:

This class is used to encapsulate functionality related to workflow manipulation. A workflow can contain more than one task.

Now, only Karajan workflow language is supported.

Methods:

addTask(Task); //add a task to workflow description

removeTask(Task) //remove a task from workflow description

setWorkflow(String workflowDescription); //set workflow description directly

toXML() //convert description into a string which can be transferred on the wire.

2) WFStatus

Description:

This class contains status of a workflow.

Methods:

getStatus();

3) Task

Description:

This class represents a detailed task. The task

Methods:

initialize(String description) //For example, initialize(“<transfer source=... destination=...>”);

toXML();

4) WFGraph

Description:

This class contains a list of workflows which will be executed and maintains the relationship among these workflows. The detailed representations maybe vary (queue, stack...).

Methods:

addWorkflow(Workflow);

removeWorkflow(Workflow);

5) Agent

Description:

This class communicates with agent server.

Methods:

getURL(); setURL(); //getter and setter for URL of agent

getPort(); setPort();

Workflow manipulation:

Job manipulation:

6) Submit/cancel/suspend/resume/

Description:

This class submits workflows to remote server.

Methods:

submit(WFGraph, Agent);

submit(Workflow, Agent);

...

Monitor:

7) Monitor

Description:

This class contains functionalities which are needed to monitor status of submitted workflows by a user.

Methods:

getStatus(WFGraph, Workflow, Agent); //get status of a workflow,

getStatus(WFGraph, Agent); //get status of all workflows in a workflow graph

Authentication:

8) User

Description:

This class represents a user in our system. Note: this user account does not necessarily appear in the backend grid service account list.

Methods:

getUsername();

getPassword();

toXML();

9) UPAuth (Username Password authentication)

Description:

This class handles authentication of users.

Methods:

auth(User, Agent); //send authentication request to agent server

Agent side Classes

Agent server sits between client and backend executor. So it communicates with two parties.

Communication with client:

Accept requests from clients. Requests include:

(1) Login

(2) Logout

(3) Register

(4) Job submission

(5) Job status query

(6) Job cancellation

(7) Job suspension

(8) Job resumption

In the meanwhile, agent sends requests to backend executor. Requests include:

(1) Job submission

(2) Job status query

(3) Job cancellation

(4) Job suspension

(5) Job resumption

Note: I assume agent and executor trust each other, which is guaranteed by underlying authentication system.

Executor side classes

Executor receives requests from agent and sends requests to MyProxy server or underlying grid service provider.

Requests from agent:

(1) Job submission

(2) Job status query

(3) Job cancellation

(4) Job suspension

(5) Job resumption

Requests sent to MyProxy (Java CoG is used here):

(1) Fetch a certificate

(2) Renew a certificate?

Requests sent to grid service provider (Java CoG is used here):

(1) Job submission

(2) Job status query

(3) Job cancellation

(4) Job suspension

(5) Job resumption

Monday, November 12, 2007

Design alternatives

Zhenhua Guo

Where should the control logic be located, at service side or client side?

(1) Client side

There will be lots of javascript work.

To use JavaCOG, there two choices:

(a) Support task/taskgraph submission:

In javascript, mirror related classes (Task, Specification, Taskgraph … ) of JavaCoG. Those classes in javascript just send encoded instructions/commands to agent server.

Like this:

In a work submission, a client needs to contact server many times besides status checking.


(b) Support Karajan workflow submission:

The client javascript must support the Karajan workflow language, including parsing it, generating corresponding control logic... This functionality has been implemented at JavaCoG. So, I don't think it is reasonable to reimplement it in Javascript.

One issue:

  • How to submit task to the agent?

  1. Client splits the original workflow description into separate smaller ones.

Client javascript maintains relationship (parallel or sequential …) among these small pieces. When needed, it submits a certain workflow piece to agent.

If so, maybe submitting the whole Karajan workflow is better.

  1. Convert the workflow description to detailed instructions and then send these instructions in the way described above in (a).

(2) Server side

Client side composes the Karajan workflow document based on the users' requirement and then sends it to server.


Summary:

Method (2) is preferred.

Notification:

(1) Pull

Client side javascript program periodically sends messages to server to check the status of submitted task. The interval of polling is difficult to choose.

One solution is that the pull action is driven by users. We can put a button on the webpage. If the user wants to update the status report, just click the button. Obviously, this is not user-friendly.

(2) Push

In javascript, a client program can not listen to a specified port like regular socket programming. However, we can make use of the request-reply communication style to indirectly simulate that functionality. Every time the client sends a job status checking request to the server, server does not return immediately the response message until some conditions(job is completed, job fails or time out) are satisfied.



Complex workflow support

I am not very clear about support provided by Karajan for complex workflow. Can a workflow be part of another larger workflow?

If so, we don’t bother to do it.

If not, we need to complete simple control logic in client side javascript. Support sequential execution, parallel execution...

UI consideration

Do we need to provide client side UI components to help users build workflow more quickly? Are the UI components workflow language specific?


Server side components:

  1. User management

    1. write our own management system

    2. use existing system

How to integrate it into our system?

Where to store user related data, including users’ identity information, submitted tasks...? In database, or just regular files?

  1. Job management

queue...


How to check status of submitted jobs by using CogKit?

Wednesday, October 31, 2007

Install JDK, Tomcat and Axis2 on Ubuntu

Previously, I deployed all java related stuff on my windows machine. Now, I would like to deploy on linux.
My environment:
Operating System: Ubuntu 6.06.1 LTS f
JDK 6 installation
In Ubuntu, an open source Java environment has been included. It is Gcj(http://gcc.gnu.org/java/). It is a GNU project. However, I prefer Sun JDK.
(1) download and install Sun JDK 1.6
Ubuntu is a branch of Debian, so it naturally inherits the great package management tool -- apt-get. It is an easy job to install packages on Ubuntu.
First, you should add "universe" and "multiverse" repositories to your /etc/apt/sources.list file. Then, execute following command:
   sudo apt-get install sun-java6-jdkBy default, it will be installed to /usr/lib/jvm/.
(2) configure it
Because now we have two Java compilers/interpreters installed, to make it work in the way I expect configuration is a must. In directory /usr/lib/jvm/, there are several *.jinfo files which contains information about installed jdk/jre packages. You can change jdk/jre alternatives by using command:update-java-alternatives.   
   sudo update-java-alternatives -l
  //list all available jre/jdk installations
   sudo update-java-alternatives -s java-6-sun  //set sun's jdk to be used
Or, you can use:
   sudo update-alternatives --config java
Then a list of available jdk/jre installations is displayed. In my case, it is:
There are 3 alternatives which provide `java'.

  Selection    Alternative
-----------------------------------------------
          1    /usr/bin/gij-wrapper-4.1
 +        2    /usr/lib/jvm/java-gcj/jre/bin/java
*         3    /usr/lib/jvm/java-6-sun/jre/bin/java

Press enter to keep the default[*], or type selection number: 
Then, set environment vaiable. Add following two lines:  
   JAVA_HOME="/usr/lib/jvm/java-6-sun"
to file /etc/environment.
(3) test
Type:
javac -version
java -version
to see whether your configuration works.
Install Tomcat 5.5
(1) Download and install
sudo apt-get install tomcat5.5 tomcat5.5-admin tomcat5.5-webapps
Note: here I installed three packages. Tomcat 5.5 contains basic implementation of Servlet and JSP specifications. Tomcat 5.5-admin contains two web-based management interface. Tomcat 5.5-webapps contains documents and some sample web applications.
(2)Configure
I installed webapps and admin.
Set CATALINA_HOME environmen variable. In my case, CATALINA_HOME=/usr/share/tomcat5.5.
The example apps are installed to "/usr/share/tomcat5.5/webapps/".
Global configuration files (server.xml and web.xml) are located in "/etc/tomcat5.5".
To make use of the web-based management tool, you need an account. You can set up your account by modifying file /usr/share/tomcat5.5/conf/tomcat-users.xml. Add the following line:
   <user username="username"  password="password" roles="manager,admin" />
Then, restart tomcat
   sudo /etc/init.d/tomcat5.5 restart
Note: "admin" and "manger" are two different roles.
(3)Start/Stop server
Script used to start/stop tomcat server is /etc/init.d/tomcat5.5.
sudo /etc/init.d/tomcat5.5 start
sudo /etc/init.d/tomcat5.5 stop
sudo /etc/init.d/tomcat5.5 restart
sudo /etc/init.d/tomcat5.5 force-reload
sudo /etc/init.d/tomcat5.5 status
However, you had better use script in directory /usr/share/tomcat5.5/bin/. I guess /etc/init.d/tomcat5.5 is intended to be used internally.
      /usr/shar/share/tomcat5.5/bin/startup.sh
      /usr/shar/share/tomcat5.5/bin/shutdown.sh
(4)Test
Tomcat by default listens to port 8180. In windows, it listens to 8080. Strange...
You can visit http://localhost:8180 to check whether your installation succeeds.
(5) Deploy your own web app
Your application should be put into directory "/usr/share/tomcat5.5/webapps/". You can use a .war file or just regular file system tree.

Problem:

   After installing Tomcat 5.5, I typed http://localhost:8180 to do test. Everything seemed to work well -- management, administration ... However, when I tried the JSP example at http://156.56.104.196:8180/jsp-examples/, error occurred!
Error message is:

HTTP Status 500 -


type Exception

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException: Unable to load class for JSP
 org.apache.jasper.JspCompilationContext.load(JspCompilationContext.java:598)
 org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:147)
 org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:315)
 org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
 org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
 javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

root cause
......

I made sure that all related .jar files were positioned correctly. What was weird was that servlet example could run correctly while JSP example always incurred error. I wrote a simple JSP file:
   <% out.println("Hello,world"); %>
After deploying it, I found that it worked!!!

Solution
After search by Google, finally I found this page http://forum.java.sun.com/thread.jspa?threadID=693082&messageID=4028997 which gave solution. The reason is incorrect configuration in Tomcat 5.5 distribution!!! I repeat the solution simply here:
Edit /usr/share/tomcat5.5/webapps/jsp-example/WEB-INF/tagPlugins.xml.
Original one is:

<tag-plugins>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.If</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.Choose</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.When</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.Otherwise</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.ForEach</plugin-class>
  </tag-plugin>
</tag-plugins>
Note, those orange lines are not correct!! Altered copy is:
<tag-plugins>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.core.If</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Choose</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.core.When</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Otherwise</plugin-class>
  </tag-plugin>
  <tag-plugin>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
    <plugin-class>org.apache.jasper.tagplugins.jstl.core.ForEach</plugin-class>
  </tag-plugin>
</tag-plugins>
Install Axis2 1.3 in Tomcat 5.5
(1) Download Axis2 1.3 Release
I chose to download .war file which would be deployed in tomcat 5.5
Command:
   wget http://www.eng.lsu.edu/mirrors/apache/ws/axis2/1_3/axis2-1.3-war.zip
(2) Deploy axis2.
Copy the downloaded axis2.war to /usr/share/tomcat5.5/webapps/. Then restart Tomcat. Tomcat automatically extracts and deploys the .war file.
(3) Test
Go to http://localhost:8180/axis2/. You should see the welcome page of Axis2.
Axis2 provides a user-friendly web-based interface to view all available services, validate the installation, upload new service (actually what are uploaded are .aar files)...
Standard binary distribution of Axis2 1.3
In fact, if you want to develop web service by using Axis2, you should download standard binary distribution which contains complete version of Axis2.
The most important part of Axis2 are those tools under directory bin. These tools include axis2.sh/axis2.bat, axis2server.bat/axis2server.sh, java2wsdl.bat/java2wsdl.sh, wsdl2java.sh/wsdl2.bat.  I described usage of these tools in my last post.

Tuesday, October 30, 2007

Web Service Development and Deployment using Axis2

Goal
Develop and deploy web service in Apache Tomcat by using Axis2 1.2/1.3.
Prerequisite:
(1) Install JDK, Tomcat and Axis2.
      Keys:
         (a) Versions of these packages must match.
         (b) JDK is recommended. Though JRE works most of the time, some features of the additional libraries/packages may not work well.
(2) Configure JDK. I think the most important part is to set the environment.
     There are already lots of tutorials around the internet. Typically, you should set environment variables : JAVA_HOME and CLASSPATH.
(3) Configure Tomcat
     Tomcat must be run on JVM. So path of JVM needs to be configured correctly.
(4) Deploy Axis2
     Axis2 is deployed in Tomcat. You can put the axis2.war file to webapps directory of Tomcat. Tomcat automatically unextracts and deploys it.
     In addition, you should set AXIS2_HOME environment variable to point to the location of axis2.
Procedure
Now, let's start to write our service prototype.
(1) Define interface in Java.
My sample interface:
File Add.java
package test;
interface Add{
   int addoperation( int op1, int op2 ) ;
}
(2) Now, compile Add.java to .class file. Command:
     javac Add.java
(3) Then, we will generate WSDL document based on the interface defined above.
     The tool is Java2WSDL which is included in Axis2 package.  My command used to generate WSDL document is:
          Java2WSDL -cn test.Add
     The newly generated WSDL document is Add.wsdl.
     Note: (1) Java2WSDL generates WSDL document based on .class file, not .java source file. So step (2) is necessary.
              (2) Java2WSDL command must be invoked in right directory. You must obey that package name must match
                   the directory hierarchy. In my case,directory tree is: D:/apps/demo/test/Add.java. When I invoke Java2WSDL,
                   current working directory is D:/apps/demo/.
(4) Use WSDL2Java (included in Axis2 package) to generate stub Java functions based on WSDL document.
There are two parts: client side and server side.
Detailed information about WSDL2Java/Java2WSDL is here: http://ws.apache.org/axis/java/user-guide.html#UsingWSDLWithAxis
(4.1) Server side
First you need to copy the generated Add.wsdl to the machine where service is to be located. In my case, the Add.wsdl is stored at D:/apps/demo/service.
(4.1.1) Generate stub functions
Again, WSDL2Java is used. Command is:    WSDL2Java -uri C:/apps/demo/test/Add.wsdl -p test -d adb -s -ss -sd -ssi
After excution of this command, directory tree looks like:
D:/apps/demo/service/
   Add.wsdl 
   resource
      Add.wsdl
      services.xml
   src
      test
         AddMessageReceiverInOut.java
         Addoperation.java
         AddoperationResponse.java
         AddSkeleton.java
         AddSkeletonInterface.java
         ExtensionMapper.java
   build.xml
(4.1.2) Add functionality of your service to generated methods
File AddSkeleton.java contains code directly related to your web service implementation. Initial content of AddSkeleton.java is:
/**
 * AddSkeleton.java
 *
 * This file was auto-generated from WSDL
 * by the Apache Axis2 version: 1.3  Built on : Aug 10, 2007 (04:45:47 LKT)
 */
package test;

/**
 *  AddSkeleton java skeleton for the axisService
 */
public class AddSkeleton implements AddSkeletonInterface {
    /**
     * Auto generated method signature
     * @param addoperation0
     */
    public test.AddoperationResponse addoperation(
        test.Addoperation addoperation0) {
        //TODO : fill this with the necessary business logic
        throw new java.lang.UnsupportedOperationException("Please implement " +
            this.getClass().getName() + "#addoperation");
    }
}

I modify AddSkeleton.java to add my web service implementation. New content is:
package test;

public class AddSkeleton implements AddSkeletonInterface {
    public test.AddoperationResponse addoperation(
        test.Addoperation addoperation0) {
         //first, get two parameters
         int op1 = addoperation0.getParam0();
         int op2 = addoperation0.getParam1();
         int sum = op1 + op2; //calculate summation
         AddoperationResponse resp = new AddoperationResponse();//construct response object
         resp.set_return( sum );//set the return value
         return resp;
    }
}
(4.1.3) Build a service
Change directory to D:/apps/demo/service/, then execute the following command:
ant jar.server
After execution, directory tree looks like:
D:/apps/demo/service/
   Add.wsdl 
   resource
      Add.wsdl
      services.xml
   src
      test
         AddMessageReceiverInOut.java
         Addoperation.java
         AddoperationResponse.java
         AddSkeleton.java
         AddSkeletonInterface.java
         ExtensionMapper.java
   build.xml
   build
      classes
         META-INF
            Add.wsdl
            services.xml
         test
            some .class files
      lib
         Add.aar
Note: Add.aar is the the archive.
(4.1.4) Deploy the service
Copy Add.arr to the "services" directory (Tomcat_directory/webapps/axis2/WEB-INF/services) of deployed axis2. Axis2 provides a web-based interface to manage the deployed services. You can use that interface to upload your .arr file.
(4.2) Client side
(4.2.1) Generate stub functions
My command used to generate client-side Web service stub functions is:
    WSDL2Java -uri Add.wsdl -p test.axis2.add -d adb -s
After execution of this command, directory tree should look like:
D:/apps/demo/ 
   Add.wsdl 
   test
      Add.java 
      Add.class
   src
      test
         AddStub.java
   build.xml
The file AddStub.java contains the newly generated client-side stub functions.
(4.2.2) develop your code to use web service
(4.2.2.1) Write source code to invoke remote web service
Create a new file called Client.java (Actually, you can use any name you like) in the directory D:/apps/demo/src/test/.
Content of the file:
package test;

import java.io.*;
import test.AddStub.Addoperation;
import test.AddStub.AddoperationResponse;

public class Client {
 public static int op1 = 0;
 public static int op2 = 0;
    public static void main(java.lang.String[] args) {
        try {
            AddStub stub = new AddStub("http://localhost:8080/axis2/services/Add");
            BufferedReader   in=new   BufferedReader(new  InputStreamReader System.in));  
            System.out.println("Please input the first operand:");
            String input = in.readLine();
            op1 = Integer.parseInt( input );
            System.out.println("Please input the second operand:");
            input = in.readLine();
            op2 = Integer.parseInt( input );
            add(stub);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
    }

    /* invoke the 'add' web service */
    public static int add(AddStub stub) {
        try {
            Addoperation req = new Addoperation();
            req.setParam0(op1);
            req.setParam1(op2);
            AddoperationResponse resp = new AddoperationResponse();
            resp = stub.addoperation(req);//invoke the web service
            System.out.println("done");
            System.out.println(op1 + "+"+ op2 + " is " + resp.get_return());
            return resp.get_return();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("\n\n\n");
        }
        return 0;
    }
}
Note: In axis2 1.4, the generated code is different from code generated by axis2 1.3.
In axis2 1.3, parameters of a request are set using setParam0, setParam1,...
In axis2 1.4, parameters of a request are set using setter functions of those properties, e.g. setName, setId.
Also the method to get return value is different. There may be some other changes I don't know, so I encourage to consult official Axis2 document.
(4.2.2.2) compile the source file and execute it.
Change your current working directory to: C:/apps/demo/, then execute following command:
    ant jar.client
Then, a new directory "build" is created. Now the directory looks like:
D:/apps/demo/ 
   Add.wsdl 
   test
      Add.java 
      Add.class
   src
      test
         AddStub.java
   build.xml
   build
      classes
         test
            some .class files
      lib
         Add-test-client.jar
Now, you can use java command to execute the program.
Remeber: first you must set CLASSPATH to include axis2 .jar libraries and newly created Add-test-client.jar. One alternative way is to use option -cp of command java. Command to execute your program is:
    java test.Client      #with CLASSPATH being set
or
  java -cp <axis2_jars>:./Add-test-client.jar test.Client      #without CLASSPATH being set
To relieve programmers from these fussy stuff, axis2 provides a tool axis2.bat/axis2.sh. This script automatically set CLASSPATH to include all the .jar files of axis2. How can the script know where your axis2 is installed? Ha, you must create a new environment variable called AXIS2_HOME which contains the path where axis2 is installed. However, the newly created Add-test-client.jar is not included in the classpath by the axis2.bat/axis2.sh script. So you still need to add it to CLASSPATH. Execute your program using command:
    axis2.sh -cp ./Add-test-client.jar test.Client
In fact, I wrote my own script to ease invocation of that program. Now, I don't need to set long CLASSPATH or input long command line with -cp option.

Tuesday, October 23, 2007

A problem of JavaCOG

I submit an execution task. The COG program seems to wait forever. But the task actually is executed by the remote server.
The reason seems to be that: COG program expects response from remote server (Globus server or others), but the remote server does not return any response even if the task is completed successfully.
I don't know whether my understanding is correct. I tried different ways to submit a task.
(1) by using command line tool
    task 1: transfer a local file to remote machine using gridftp.
    cog-file-transfer.bat -s file:///E:/my_program/web_app/CogTest/bin/testkarajan.xml -d gsiftp://gf1.ucs.indiana.edu/home/zhguo/testkarajan.xml
    This can be completed successfully.
    task 2: execute a command on remote machine
    cog-job-submit.bat -s gf1.ucs.indiana.edu -e /bin/ls -stdout list.txt -d /home/zhguo -provider gt2
    This command hangs up forever and does not return control to user until it is terminated forcibly. But the corresponding command ( in this case, it is /bin/ls ") can be executed on remote machine and the result is written into the specified file.
    cog-job-submit.bat -s gf1.ucs.indiana.edu -e /bin/ls -stdout list.txt -d /home/zhguo -provider gt2 -b
    This works well.
    So, what is difference between batch mode and regular mode?
(2) by using GUI tool
     The same results as above.
(3) by using API
    I wrote a program which utilized the karajan engine to handle the karajan workflow related stuff.
    All kinds of invocation do not work well.

How to solve it? Is there anything I missed ?

XML-RPC Usage

Currently, I am focusing on building client and server programs which communicate with each other by using XML-RPC.
Client
To support XML-RPC at client side, there are two choices. I write javascript functions that handle XML-RPC related stuff --encoding, decoding, escape ... I read the XML-RPC specification. It is not long, just a few pages. However, to implement a robust and steady xml-rpc javascript library is not so easy as it looks. I don't have so much time to do this. So, I chose to make use of existing library. I surveyed many XML-RPC javascript libraries. Shortly afterwards, I found that most of the libraries were not satisfying. For example, some libraries even don't escape the parameters passed to a method. If a parameter is a string and it contains '<' characters, those '<' characters must be escaped in order not to confuse the server because '<' marks start of a tag!! After trying lots of times, I found two good libraries. One is mozilla xml-rpc javascript library which is used by Firefox. However, it requires additional javascript libraries which are basis of Firefox javascript libraries. To use it, lots of libraries are needed and obviously this is cumbersome.  The other good library is Javascript O Lait which builds generic architecture to allow users to create and import module. In addition to support of modularity, it provides many useful modules, such as Codec, JSON-RPC, XML-RPC, String extension ... At last I decided to use Jsolait. Key code is:
var url = "http://127.0.0.1:8080/sample/xmlrpc";//The path must comply with configuration at server side
var methods = ["zhguo.handler.inBound"];//This is the full qualified name of the method you want to invoke. 
     //Note: this must comply with the configuration at service side
var xmlrpc=null;
try{
    xmlrpc = imprt("xmlrpc"); //import the needed module
}catch(e){
    throw "importing of xmlrpc module failed.";
}
 
try{
 var service = new xmlrpc.ServiceProxy( url, methods );
 var from = "home", to = "rpc";
 service.zhguo.handler.inBound( from, to );//directly call the method by using service object
}catch(e){
 alert( e );
} 
Server

I make use of Apache XML-RPC Java library. There is no detailed document on the web. Official website has some description on how to quickly build application based on XML-RPC. There are several ways you can use the XML-RPC service. I chose to embed it in Tomcat container. Key procedure is:
(1) Edit the web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">
  <display-name>Test for XML-RPC</display-name>
  <description>This is a test for XML-RPC</description>
 <servlet>
  <servlet-name>XmlRpcServlet</servlet-name>
  <servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class>
  <init-param>
   <param-name>enabledForExtensions</param-name>
   <param-value>true</param-value>
   <description>Sets, whether the servlet supports vendor extensions.</description>
  </init-param>
 </servlet> 
 <servlet-mapping>
  <servlet-name>XmlRpcServlet</servlet-name>
  <url-pattern>/xmlrpc</url-pattern>
 </servlet-mapping>
</web-app>
(2) Create your service. My sample class is:
package zhguo.test;
public class SimpleHandler{
 public SimpleHandler(){}
 public String inBound( String from, String to ){
  return "thank you, " + from +", for calling " + to;
 }
}
And put the corresponding .class file in the directory WEB-INF/classes/zhguo/test/.
(3) Add a file called XmlRpcServlet.properties under directory WEB-INF/classes/org/apache/xmlrpc/webserver/. Content of the file is
zhguo.handler=zhguo.test.SimpleHandler
Note: zhguo.test.SimpleHandler is the class which provides service to XML-RPC client. The public functions in this class are exposed by Apache XML-RPC framework to clients. In other words, clients can invoke public functions defined in class zhguo.test.SimpleHandler. The property name is an arbitrary string. It represents the corresponding service class (In this case it is zhguo.test.SimpleHandler). Clients use this name to access the service. So, in javascript above, one statement is 'var methods = ["zhguo.handler.inBound"]'. Upon receiving the request, the server looks up the class corresponding to "zhguo.handler", invokes inBound function of that class and returns the result.
(4) Put the necessary libraries(XML-RPC .jar files) in the lib directory
(5) Starts the tomcat.
Finally, the directory layout is:
WEB-INF/lib/
WEB-INF/classes/org/apache/xmlrpc/webserver/XmlRpcServlet.properties
WEB-INF/classes/zhguo/test/SimpleHandler.class
WEB-INF/web.xml

Tuesday, October 16, 2007

JSON-RPC-Java

Site: http://oss.metaparadigm.com/jsonrpc
It is a piece of middleware which allows client-side JavaScript to invoke server-side Java method. It uses xmlhttprequest to send requests to server.

Example
function onLoad()
{
    jsonrpc = new JSONRpcClient("JSON-RPC");
}

function clickHello()
{
    var whoNode = document.getElementById("who");
    var result = jsonrpc.hello.sayHello(whoNode.value);
    alert("The server replied: " + result);
}
Procedure
Every time a new JSONRpcClient object is created, the system automatically asks the server for the method list. Then all these methods are added to this newly created instance. When the user program invokes a certain method, the system marshalls the parameters and method names and then send a message to server. The server unmarshalls the received message and invokes the corresponding function at server side. After the function is executed, the result is marshalled and sent to client. At server side, the library provides a bridge which can be used by a class to expose its methods to clients.
Improvement
To improve performance, that Javascript library maintains a pool of xmlhttprequest instances. Every time a new xmlhttprequest object is required, the pool is searched at first. If there is available xmlhttprequest instance, it is used. Or else, new xmlhttprequest instance is created.