Pages

Sunday, July 15, 2007

Filtering the result in hibernate

The filtering in hibernate can be acheived in two ways.
One, applying the filtering on the session before a finder or any query is hit.
Two, applying the filtering on the collection which is a persistent set after the query is hit.

For the first one,
An entry has to be made in the hbm xml's defing the filter, the parameters it take and the persistent collection on which the filter has to be applied to. Then before hitting the query on the session, we enable the filter on the session. Once the filter is enabled, any query on the session resulting in the persistent collection on which the filtering has been enable will be filtered on the filtering condition specified.

Example:

Example.hbm.xml
-------------------
<hibernate-mapping>
<class>
.
.
<set name="exampleTwo" inverse="true">
<key>
<column name="EXAMPLETWO_ID" precision="12" scale="0" />
</key>
<one-to-many class="ExampleTwo" />
<filter name="CaseOneFilter" condition="ACTIVE_IND = :CaseOneFilterParam"/>
</set>
</class>

<filter-def name="CaseOneFilter">
<filter-param name="CaseOneFilterParam" type="char"/>
</filter-def>

</hibernate-mapping>

In Code,
we enable the filter as:
session.enableFilter("CaseOneFilter").setParameter("CaseOneFilterParam",'Y');


For the second case,
Once we hit a finder and get a hook on a persistent object, we can create a filter on the session. The collection associated with this persistent object on which filtering has to be applied is sent to this newly created filter on the session. This results in getting a collection which is filtered on the conditions specified in the filter.

Example:


public static <T> Collection<T> filterCollection(Collection<T> collection, Session session,String filterCondition) {
Query filterQuery = s.createFilter(collection, filterCondition);
return filterQuery.list();
}

This can be called as:
/**
* Assuming pk to be perisitent object, session to be hibernate session.
*
*/
filterCollection(pk.getChildrens(), session, "select this.attribute where this.id = 23");

Eager fetching in Hibernate using Criteria queries

One of the easiest way of eager fetching is using the setFetchMode function present with Criteria API's. The whole clutter of reflection which i presented below can be removed by using this.
But the criteria queries when doing eager loading gives duplicate resultsets, what i mean is if the parent table has one row and the child table associated with it has say 2 rows then on doing an eager fetch we receive 2 parent Objects representing the parent table. This is because, eager fetching is nothing but putting 'sql join' on the underlying tables. And, as a result of this outer joins we get duplicate results. To get distinct results we have to use resultTransformer. The same code is given below.
.
.
Class Example{//Associated with Table EXAMPLE in Example.hbm.xml
private String attributeOne;
private ExampleTwo exampleTwo; //A foreign one to one relation with ExampleTwo
//Getters and Setters
}
.
Class ExampleTwo{//Associated with Table EXAMPLE_TWO in Example.hbm.xml
private String attributeOne;
//Getters and Setters
}
.
Criteria criteria = session.createCriteria(Example.class); //Create the criteria query
List fetchList=new ArrayList();
fetchList.add(exampleTwo);
initializeFetchList(Criteria criteria, List fetchList); //initialize
List exmpleList = criteria.list() //Executing this gives us List of Example Objects with pre-fetched ExampleTwo Objects in it.
.
.
public void initializeFetchList(Criteria criteria, List fetchList){

for (String entityAttribute : fetchList) {
criteria.setFetchMode(entityAttribute, FetchMode.JOIN);
}

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
}

Sunday, April 08, 2007

Using hibernate and reflection to generate queries on any table with eager fetching of the specified attributes representing the foreign key relations

Below is the code attached with appropriate comments:

package reflection;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;

/**
* @author SacrosanctBlood
*
*
* <p>
* This utility class is used to execute an hibernate query on a single entity class, with any number of conditions
* (equals conditions only, but can be extended)on the attributes of the class. It also fetches the Objects given in the
* list which would otherwise be fetched lazily.
* </p>
*/
public class HibernateQueryUtil {
/**
* This method returns the result of the find query on the given input class.
*
* @param session
* The hibernate session in which the query will be executed. This can not be null.
* @param clazz
* The entity class which is mapped to a table in database, on which the query is executed. This can not
* be null.
* @param conditions
* A map of attributeName = attributeValue for the attributes in the class. These represents the
* conditions for the fetch query. This can be null.
* @param fetchList
* A list of attributes in the class representing a foreign relationship that needs to be fetched
* eagerly. This can be null.
* @return List A list of the resultant Objects of the type clazz which have been eagerly initialized according to
* the fetchList. The List can be empty dependent on the query executed.
* @throws IllegalArgumentException
* Thrown when
* <li>Clazz is not valid</li>
* <li>Attributes are not present in clazz</li>
* <li>Attributes in fetchList is not valid.</li>
*/
public static List find(Session session, Class clazz, Map<String, Object> conditions, List<String> fetchList)
throws IllegalArgumentException {
Set<String> attributes = null;
attributes = initializeAttributes(conditions);
String entityName = clazz.getSimpleName();
List result = null;
if (entityName != null) {
Criteria criteria = session.createCriteria(clazz);
if (conditions != null) {
checkIfAttributesExistInClass(clazz, attributes);
addCriterions(criteria, conditions, attributes);
}
result = executeQuery(criteria);
if (fetchList != null && result != null) {
checkIfAttributesExistInClass(clazz, fetchList);
List<String> methodsToInvoke = convertFetchListToMethodToInvokeList(fetchList);
checkIfMethodsExistInClass(clazz, methodsToInvoke);
initializeFetchList(clazz, methodsToInvoke, result);
}
} else {
throw new IllegalArgumentException("Class " + clazz.getName() + " is not valid");
}

return result;
}

/**
* This method eagerly initializes each of the attributes for each Object in the resultList.
*
* @param clazz
* @param methodsToInvoke
* @param resultlist
* @throws IllegalArgumentException
*/
private static void initializeFetchList(Class clazz, List<String> methodsToInvoke, List resultlist)
throws IllegalArgumentException {
// called methods have no argument(They are just getter methods)
Class params[] = {};
Object paramsObj[] = {};
for (Object resultObject : resultlist) {
if (clazz.isInstance(resultObject)) {
for (String aMethod : methodsToInvoke) {
try {
// get the method
Method thisMethod = clazz.getDeclaredMethod(aMethod, params);
// invoke the method on the object and initiliaze in Hibernate
Hibernate.initialize(thisMethod.invoke(resultObject, paramsObj).toString());
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException(
"Error while invoking method to initiliaze in HibernateQueryUtil:initilizeFetchList");
}
}

} else {
throw new IllegalArgumentException(
"The resultant Objects of the hibernate query are not the same as the Class "
+ clazz.getSimpleName());
}
}

}

/**
* This method checks if the methodToInvoke is present in the given Class.
*
* @param clazz
* @param methodsToInvoke
* @throws IllegalArgumentException
*/
private static void checkIfMethodsExistInClass(Class clazz, Collection<String> methodsToInvoke)
throws IllegalArgumentException {

for (String thisMethod : methodsToInvoke) {

try {
clazz.getDeclaredMethod(thisMethod);
} catch (SecurityException e) {
throw new IllegalArgumentException("Method with name " + thisMethod + " is not accessible");
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Method with name " + thisMethod + " does not exist");
}

}

}

/**
* This method converts the fetchList which is just a list of attributes in class, to the corresponding getter
* method on the attribute. This method is later invoked in <i>initializeFetchList</i>.
*
* @param fetchList
* @return List A list containing methods to be invoked.
*/
private static List<String> convertFetchListToMethodToInvokeList(List<String> fetchList) {
List<String> convertedList = new ArrayList<String>();
for (String thisAttribute : fetchList) {
String firstLetterInUpperCase = String.valueOf(thisAttribute.charAt(0)).toUpperCase();
String getterMethodString = "get" + firstLetterInUpperCase + thisAttribute.substring(1);
convertedList.add(getterMethodString);
}
return convertedList;
}

/**
* This method returns a Set of the attributes present in the Class given as an input to <i>find</i> method.
*
* @param attributes
* @return Set All the attributes.
*/
private static Set<String> initializeAttributes(Map<String, Object> attributes) {
Set<String> keys = null;
if (attributes != null)
keys = attributes.keySet();
return keys;
}

/**
*
* @param clazz
* @param attributes
* @throws IllegalArgumentException
*/

private static void checkIfAttributesExistInClass(Class clazz, Collection<String> attributes)
throws IllegalArgumentException {

for (String thisAttribute : attributes) {
try {
clazz.getDeclaredField(thisAttribute);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Column with name " + thisAttribute + " does not exist");
}
}
}

/**
* This method add new criterions for the criteria object.
*
* @param criteria
* @param columns
* @param keys
*/
private static void addCriterions(Criteria criteria, Map<String, Object> columns, Collection<String> keys) {
for (String thisAttribute : keys) {
Object thisAttributValue = columns.get(thisAttribute);
// equals operator by default
criteria.add(Expression.eq(thisAttribute, thisAttributValue));
}
}

/**
*
* @param criteria
* @return List Result of executing the query
*/
private static List executeQuery(Criteria criteria) {
List result = null;
if (criteria != null) {
result = criteria.list();
}
return result;
}
}

Below is a client that uses this utility class:

package client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import entity.data.Data;
import entity.datachildren.DataChildren;

import reflection.HibernateQueryUtil;

public class Client {
public static void main(String[] args) throws Exception{
SessionFactory factory = new Configuration().configure().buildSessionFactory();
Session session = factory.openSession();
//case 1: get all the Data.
List list = HibernateQueryUtil.find(session, Data.class, null,null);
Iterator iter = list.iterator();
while(iter.hasNext()){
Data data = (Data)iter.next();
}
//case 2: get Data with dataId = 3 and dataBy = "ABC"
Map<String, Object> conditions = new HashMap<String, Object>();
map.put("dataId", new Integer(3));
conditions.put("dataBy", "ABC");

// also fetch Data Childrens
List<String> fetchList = new ArrayList<String>();
fetchList.add("dataChildrens");
// list = HibernateQueryUtil.find(session, Data.class, map,null); throws LazyInitializeException
list = HibernateQueryUtil.find(session, Data.class, conditions,fetchList);//initializes so no problem

session.close();
Set ds = null;
iter = list.iterator();
while(iter.hasNext()){
Data data = (Data)iter.next();
System.out.println(data.getDataId() + " " + data.getDataBy());
ds = data.getDataChildrens();
Iterator dIter = ds.iterator();
while(dIter.hasNext()){
System.out.println("LP: " + ((DataChildren)dIter.next()).getDataChildrenName());
}
}



}

}

Hope this was helpful..

Wednesday, March 28, 2007

Step by step tutorial to use Rampart with axis2 web service for implementing security.

Given below is a tutorial to use axis2 in implementing web services with security(This shows sync/Blocking call client along with Rampart security). This tutorial extends the previous tutorials to add security features to the web services using rampart module. For more details regarding any aspect of the tutorial, the axis2 or rampart documents will assist you.

My Configuration:(same as previous)
a) AXIS2 1.1.1
b) JDK 1.5
c) ANT 1.7.0
d) TOMCAT 5.5

Before proceeding, please read the installation doc of axis2 and rampart to do a proper installation.

Step 0: Set the following paths in your system.(This step is very important)
a) AXIS2_HOME = "your axis2 installation(unzipped) directory"
b) JAVA_HOME = "your jdk installation path"
c) PATH = "add ant, axis2/bin to this"

Step 1: Extract the rampart-1.1.zip. Before doing anything more copy the %AXIS2_HOME%/lib to %AXIS2_HOME%/lib.1. Run the ant task on build.xml present in extracted folder. Now rebuild the whole axis2(i.e run the ant task in %AXIS2_HOME%/webapp). Deploy this in your server. Rename the lib to lib.2, and lib.1 to lib.[This is to run WSDL2JAVA and JAVA2WSDL tool, other wise the tools doesn't run and the reason is that the path AXIS2_CLASS_PATH becomes too long(I am running on Win 2000)]

Step 2: Create your service interface and impl class. Generate the WSDL using java2wsdl, generate the skeleton and stubs using wsdl2java, code the skeleton. Build the "MyRampartService.aar" and deploy on the server. Test the service. Use the client service stub to code a basic client, run the client to see its working. This step has set up a web service and a client in a usable state. Next, step goes through the rampart part.
The service and skeleton are given below for reference.
--------------Interface-------------------
package axis2.adb.sync.rampart;
public interface MyRampartService {
public String getSecretText(String codeword);
}

-------------Impl class-------------------
package axis2.adb.sync.rampart;
public class MyRampartServiceImpl implements MyRampartService {
public String getSecretText(String codeword) {
if(codeword.equalsIgnoreCase("apache"))
return "You have done a good choice to build an application";
return "You have done a bad choice to build application";
}
}
-------------Skeleton Class----------------
/**
* MyRampartServiceSkeleton.java
*
* This file was auto-generated from WSDL
* by the Apache Axis2 version: 1.1.1 Jan 09, 2007 (06:20:51 LKT)
*/
package axis2.adb.sync.rampart;
import axis2.adb.sync.rampart.MyRampartService;
import axis2.adb.sync.rampart.MyRampartServiceImpl;
import axis2.adb.sync.rampart.xsd.GetSecretTextResponse;
public class MyRampartServiceSkeleton implements MyRampartServiceSkeletonInterface {
MyRampartService myService = new MyRampartServiceImpl();
public axis2.adb.sync.rampart.xsd.GetSecretTextResponse getSecretText(axis2.adb.sync.rampart.xsd.GetSecretText param2){
GetSecretTextResponse res = new GetSecretTextResponse();
res.set_return(myService.getSecretText(param2.getParam0()));
return res;
}
}

Step 3: This step uses the example from the rampart sample05. The intention is to encrypt the data in XML's which are exchanged between the client and the server. Copy %AXIS2_HOME%/repository to a convenient location. Copy %AXIS2_HOME%/conf/axis2.xml to %COPIED_LOCATION%/repository/modules/client.axis2.xml. Copy the rampart-1.1/samples/Keys to "resources" directory created on running the WSDL2JAVA on previous step. We will be using the same keystore which rampart has provided for encrypting the message. you use the "keytool" that is a part of JDK to create your own keystore. Add the rampart lib also to your classpath to compile and run the client. Copy from the sample05 directory org/apache/rampart/samples/sample05/PWCBHandler.java into your source directory(remember to change the package in PWCBHandler.java, if you put it in some other package). This is the callback handler that is called on the client and the server side for verifying the password.

Step 4: Modify the resources/services.xml and %COPIED_LOCATION%/repository/modules/client.axis2.xml to enter Rampart configuration.
Add the below into the services.xml.
<serviceGroup>
<service name="MyRampartService">
......
......
<module ref="rampart" />
<parameter name="InflowSecurity">
<action>
<items>Encrypt</items>
<passwordCallbackClass>axis2.adb.sync.rampart.callbackhandler.PWCBHandler</passwordCallbackClass>
<decryptionPropFile>service.properties</decryptionPropFile>
</action>
</parameter>

<parameter name="OutflowSecurity">
<action>
<items>Encrypt</items>
<encryptionUser>client</encryptionUser>
<encryptionPropFile>service.properties</encryptionPropFile>
</action>
</parameter>
</service>
</serviceGroup>

Add the below into the client.axis2.xml just before the "phases" definitions.
<module ref="rampart" />

<parameter name="OutflowSecurity">
<action>
<items>Encrypt</items>
<encryptionUser>service</encryptionUser>
<encryptionPropFile>client.properties</encryptionPropFile>
</action>
</parameter>

<parameter name="InflowSecurity">
<action>
<items>Encrypt</items>
<passwordCallbackClass>axis2.adb.sync.rampart.callbackhandler.PWCBHandler</passwordCallbackClass>
<decryptionPropFile>client.properties</decryptionPropFile>
</action>
</parameter>

Now, parameter OutFlowSecurity represents the action to be taken on the outgoing XML's. In our case it is to encrypt. The encryption property file client.properties is present in keys directory. It gives the details of the keystore file, the password to that keystore, the keystore type and the provider.

The parameter InFlowSecurity represents the action to be taken on the incoming XML's. It provides with the decryption property file which is same as the encryption property file in client.axis2.xml, the action item is same as the OutFlowSecurity action item and the password callbackhandler class. I am using the one which came with samples provided with apache rampart.Its given below.

import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
public class PWCBHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
String id = pwcb.getIdentifer();
if("client".equals(id)) {
pwcb.setPassword("apache");
} else if("service".equals(id)) {
pwcb.setPassword("apache");
}
}
}
}

Step 5: Edit build.xml.
Search for target "jar.all" and add the following beneath the first copy element.
<copy toDir="${classes}" failonerror="false">
<fileset dir="${resources}/keys">
<include name="*.jks"/>
<include name="*.properties"/>
</fileset>
</copy>

Step 6: Build and deploy service.

Run ant command on this build.xml and deploy the service on axis2 in tomcat. Do not forget to restart the tomcat server if hotupdate is off.

Step 7: Edit the client and run. The client code is given below with appropriate comments. We do not have to configure the client using the XML, it can be done through code also. The below client uses the code when useRampartThroughCode is set to true. Please note that when this is used you do not have to configure the inflowsecurity and outflow security in the client.axis2.xml. Add the "resource/keys" on to the classpath before you run the client.

package axis2.adb.sync.rampart.client;
import java.rmi.RemoteException;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.description.Parameter;
import org.apache.rampart.handler.WSSHandlerConstants;
import org.apache.rampart.handler.config.InflowConfiguration;
import org.apache.rampart.handler.config.OutflowConfiguration;
import axis2.adb.sync.rampart.MyRampartServiceStub;
import axis2.adb.sync.rampart.xsd.GetSecretText;
import axis2.adb.sync.rampart.xsd.GetSecretTextResponse;

public class MyRampartServiceServiceClient {
private static boolean useRampartThroughCode = false; // set this to true if you do not want to configure client using client.axis2.xml for using rampart.

public static void main(String[] args) {
MyRampartServiceStub stub = null;
ConfigurationContext configContext = null;
try {
// put your appropriate repository path in first arg, and path to client.axis2.xml in second arg.
configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("Axis2WithRampart/repository", "Axis2WithRampart/repository/modules/client.axis2.xml");
//create the stub
stub = new MyRampartServiceStub(configContext,"http://localhost:8080/axis2/services/MyRampartService");
if(useRampartThroughCode){
//set the outflow security through code
stub._getServiceClient().getOptions().setProperty(WSSHandlerConstants.OUTFLOW_SECURITY, getOutflowConfiguration());
//set the inflow security through code
stub._getServiceClient().getOptions().setProperty(WSSHandlerConstants.INFLOW_SECURITY, getInflowConfiguration());
}
// invoke the service
String returnText = getSecretTextFromRampartService(stub,"apache");
// print it out
System.out.println("Return Text: " + returnText);
} catch (AxisFault e) {
e.printStackTrace();
} catch (RemoteException re){
re.printStackTrace();
}

}

private static String getSecretTextFromRampartService(MyRampartServiceStub stub, String string) throws RemoteException {
//create the request payload
GetSecretText req = new GetSecretText();
//set the parameter in the payload
req.setParam0(string);
//invoke service and get response
GetSecretTextResponse res = stub.getSecretText(req);
//return the response string.
return res.get_return();
}

private static Parameter getOutflowConfiguration() {

OutflowConfiguration ofc = new OutflowConfiguration();
//set the action item
ofc.setActionItems("Encrypt");
//set the encryption user
ofc.setEncryptionUser("service");
//set the property file; remember if the properties is not in classpath then it will not find this.
ofc.setEncryptionPropFile("client.properties");
// return the Parameter
return ofc.getProperty();
}

private static Parameter getInflowConfiguration() {
InflowConfiguration ifc = new InflowConfiguration();
//set the action item
ifc.setActionItems("Encrypt");
//set the password callback class
ifc.setPasswordCallbackClass("axis2.adb.sync.rampart.callbackhandler.PWCBHandler");
//set the property file; remember if the properties is not in classpath then it will not find this.
ifc.setDecryptionPropFile("client.properties");
//return the parameter
return ifc.getProperty();
}

}

Step 8: The output.
You will see the output:

Return Text: You have done a good choice to build an application

You can use the tcpmon tool to capture the XML exchanges. Then, you can observe the encrypted contents of the request and response messages.

NOTE: I am using the keystore's and the password callback handlers provided with rampart distribution for explaining this tutorial.

Monday, March 26, 2007

Step by step tutorial of web service with axis2 and tomcat in java - part2

Given below is a tutorial to use axis2 in implementing web services(This shows Async/Non-Blocking call client). This tutorial extends the previous tutorial of blocking client call of web service. For more details regarding any aspect of the tutorial, the axis2 documents will assist you.
(Just for Information: The web service gives the Lucky number of a person based on date of birth, and lucky color based on lucky number of user.)

My Configuration:(same as previous)
a) AXIS2 1.1.1
b) JDK 1.5
c) ANT 1.7.0
d) TOMCAT 5.5

Before proceeding, please read the installation doc of axis2 to do a proper installation.

Step 0: Set the following paths in your system.(This step is very important)
a) AXIS2_HOME = "your axis2 installation(unzipped) directory"
b) JAVA_HOME = "your jdk installation path"
c) PATH = "add ant, axis2/bin to this"

Step 1: Create your service interface and class.

In my case:
--------------Interface-------------------
package axis2.adb.async;
import java.util.Date;
public interface MyNewService {
public String getLuckyColor(int luckNumber);
public int getLuckyNumber(Date birthDate);
}
--------------Implementation--------------
package axis2.adb.async;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class MyNewServiceImpl implements MyNewService {
static Map luckyColor = null;
static{
luckyColor = new HashMap();
luckyColor.put(new Integer(0), "Red");
luckyColor.put(new Integer(1), "Blue");
luckyColor.put(new Integer(2), "Yellow");
luckyColor.put(new Integer(3), "Pink");
luckyColor.put(new Integer(4), "Orange");
luckyColor.put(new Integer(5), "Black");
luckyColor.put(new Integer(6), "Green");
luckyColor.put(new Integer(7), "Brown");
luckyColor.put(new Integer(8), "White");
luckyColor.put(new Integer(9), "Grey");
}
public String getLuckyColor(int luckNumber) {
if(luckNumber < number =" birthDate.getDate()" lucknumber =" 0;"> 0){
luckNumber += number % 10;
number /= 10;
if(number == 0)
if(luckNumber > 9){
number = luckNumber;
luckNumber = 0;
}

}
return luckNumber;
}
}

Step 2: Generate the WSDL file using the command:
java2wsdl -cp ./bin -cn axis2.adb.async.MyNewService -of ./resource/MyNewService.wsdl
See the previous tutorial for more explanation.

Step 3: Generate the Skeleton and stub using the below command. I will be using the ADB(Axis data binding). You can use XMLBean or JiBx or AXIOM also.

wsdl2java -uri ./resource/MyNewService.wsdl -p axis2.adb.async -d adb -a -ss -sd -ssi -g -o . -S axis2ADBAsync
Here, the changes from the previous tutorial include:
a)-a switch instead of -s. -a is used for Async web Service.
b)-g switch generates the Client side stub along with the Skeleton.
c)-S switch allows you to provide the output folder

Step 4: Put the business logic inside the skeleton. The code is explained with appropriate comments.

package axis2.adb.async;
import java.util.Calendar;
import axis2.adb.async.MyNewService;
import axis2.adb.async.MyNewServiceImpl;
import axis2.adb.async.xsd.GetLuckyColorResponse;
import axis2.adb.async.xsd.GetLuckyNumberResponse;
/**
* MyNewServiceSkeleton java skeleton for the axisService
*/
public class MyNewServiceSkeleton implements MyNewServiceSkeletonInterface {
MyNewService myService = new MyNewServiceImpl();
/**
* Auto generated method signature
*
* @param param4
*
*/
public axis2.adb.async.xsd.GetLuckyColorResponse getLuckyColor(
axis2.adb.async.xsd.GetLuckyColor param4)
{
//create the response payload
GetLuckyColorResponse res = new GetLuckyColorResponse();
//get the parameter
int luckyNumber = param4.getParam0();
//businesslogic
String luckyColor = myService.getLuckyColor(luckyNumber);
//put result in payload
res.set_return(luckyColor);
//return payload
return res;
}

/**
* Auto generated method signature
*
* @param param6
*
*/
public axis2.adb.async.xsd.GetLuckyNumberResponse getLuckyNumber(
axis2.adb.async.xsd.GetLuckyNumber param6)

{
//create the response payload
GetLuckyNumberResponse res = new GetLuckyNumberResponse();
//get parameter
Calendar dOfB = param6.getParam0();
//businesslogic
int luckyNumber = myService.getLuckyNumber(dOfB.getTime());
//put result in response payload
res.set_return(luckyNumber);
//return the payload
return res;
}

}
Step 5: Create ".aar" file which has to be deployed inside axis2 using the below command.
The build.xml file is created in Step 3.

ant build.xml

Step 6: Deploy.

A new folder build is created inside the current directory. The MyNewService.aar file is present in \build\lib. Upload this using the axis2 admin page. Refer previous tutorial for more details.

Step 7: Test the service.

type http://localhost:8080/axis2/services/MyNewService?wsdl in address bar. you should get the WSDL file.

Step 8: Code the Client using the generated Stub. The code is explained with appropriate comments.

package axis2.adb.async.client;
import java.rmi.RemoteException;
import java.util.Calendar;
import java.util.Date;
import javax.xml.namespace.QName;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import axis2.adb.async.MyNewServiceStub;
import axis2.adb.async.MyNewServiceCallbackHandler;
import axis2.adb.async.xsd.GetLuckyColor;
import axis2.adb.async.xsd.GetLuckyNumber;

public class MyNewServiceClient {
private static int luckyNumber = 100; //assume some large number
private static String luckyColor = null;
private static boolean twoWayListnerEnabled = false; //When true a asynchronous dual channel non-blocking service will be used

public static void main(String[] args) {
MyNewServiceStub stub = null;
ConfigurationContext configContext = null;
try {
if(twoWayListnerEnabled){
//Since this is the client, addressing module has to be engaged. Copy the "repository" directory, present in %AXIS2_HOME%, to a convenient place and give its path as first argument to the below method. Copy the axis2.xml from %AXIS2_HOME%/conf into convenient location, and give its path as second argument. Edit the axis2.xml to change the port to say, 8082.
configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repository", "repository/modules/axis2.xml");
stub = new MyNewServiceStub(configContext,"http://localhost:8080/axis2/services/MyNewService");
}else{
stub = new MyNewServiceStub(null,"http://localhost:8080/axis2/services/MyNewService");
}
// set the call back handler. Note that call back methods given override the ones in CallBackhandler abstract class.
MyNewServiceCallbackHandler myNewServiceCallBackHandle = new MyNewServiceCallbackHandler(){
public void receiveResultgetLuckyNumber(
axis2.adb.async.xsd.GetLuckyNumberResponse param43) {
luckyNumber = param43.get_return();
}
public void receiveResultgetLuckyColor(
axis2.adb.async.xsd.GetLuckyColorResponse param41) {
luckyColor = param41.get_return();
}
};
if(twoWayListnerEnabled){
//engage the module, and setUseSeparateListner to true.
stub._getServiceClient().engageModule(new QName("addressing"));
stub._getServiceClient().getOptions().setTimeOutInMilliSeconds(1000);
stub._getServiceClient().getOptions().setUseSeparateListener(true);
}
//call the service
getLuckyNumberFromService(stub,myNewServiceCallBackHandle,new Date(1987,12,21));
// Since async call, poll the luckyNumber to see if a value is populated. This is just an example, in practice, should not poll this way. Here it is required cas' the number is an input to the next service all.
do{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
if(luckyNumber != 100){
break;
}
}
}while(luckyNumber == 100);
//call the next service
getLuckyColorFromService(stub,myNewServiceCallBackHandle,luckyNumber);
// again poll to see if lucky color has been populated.
do{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
if(luckyColor != null){
break;
}
}
}while(luckyColor == null);
//print them
System.out.println("Lucky Number: " + luckyNumber);
System.out.println("Lucky Color: " + luckyColor);

} catch (AxisFault e) {
e.printStackTrace();
} catch (RemoteException re){
re.printStackTrace();
}finally{
//do the clean up.
try {
if(twoWayListnerEnabled){
stub._getServiceClient().disengageModule(new QName("addressing"));
stub._getServiceClient().cleanup();
}
stub.cleanup();
if(twoWayListnerEnabled){
System.exit(0);
}
} catch (AxisFault e) {
//ignore this
}
}

}
private static void getLuckyColorFromService(MyNewServiceStub stub, MyNewServiceCallbackHandler myNewServiceCallBackHandle, int luckyNumber) throws RemoteException {
//create request payload
GetLuckyColor req = new GetLuckyColor();
//set the parameter
req.setParam0(luckyNumber);
// do an async call
stub.startgetLuckyColor(req, myNewServiceCallBackHandle);
}
private static void getLuckyNumberFromService(MyNewServiceStub stub, MyNewServiceCallbackHandler callBackForGetLuckyNumber, Date date) throws RemoteException {
//create request payload
GetLuckyNumber req = new GetLuckyNumber();

Calendar dOb = Calendar.getInstance();
dOb.setTime(date);
//set the parameter
req.setParam0(dOb);
//do an async call
stub.startgetLuckyNumber(req, callBackForGetLuckyNumber);

}

}



Step 9: Execute the client.

java MyNewServiceClient

output :
Lucky Number: 2
Lucky Color: Yellow


Hope, this tutorial was use full enough. Here, ADB databinding was used and no security implemented. Next will try to get an Webservice up with security implementation.
Adios!!

using tcpmon with axis2 webservices and tomcat

Using tcpMon utility with web services is very easy. Download the jar file from h**p://ws.apache.org/commons/tcpmon/download.cgi. Extract it. Run the tcpmon.bat. This will launch the tcpmon UI. Give the host name (localhost) and the target port# (8080). Give the listener port# to 8081 and say add. This will create a new tab. On this tab, there are two text frames. The top one shows the request, and the bottom one shows the response.
In the client, use the target end point uri with port 8081 instead of 8080(my tomcat server listens to this). This will allow you to see the request and response messages in this small and powerful utility. There is more to this tool, which you can read from the user guide.

Sunday, March 25, 2007

Step by step Web Services with Axis2 Tutorial in Java

It was very hard for me to get a good tutorial on developing web services with axis2 on the internet. After some effort I was able to deploy a axis2 web service. I hope this tutorial below will help you for bringing up the web service using axis2 a lot easier.(This shows sync/blocking call client).
The tutorial shows how to get your web service up as quickly as possible, with out giving intrinsic details. For more details regarding any aspect of the tutorial, the axis2 documents will assist you.

My Configuration:

a) AXIS2 1.1.1

b) JDK 1.5

c) ANT 1.7.0

d) TOMCAT 5.5


Before proceeding, please read the installation doc of axis2 so that it will work with tomcat with no problems. The below steps assumes that the axis2 is configured with tomcat and is running in the tomcat container. You can test the same by visiting http://localhost:8080/axis2/ url, and then clicking on the validate link.


Step 0: Set the following paths in your system.(This step is very important)
a) AXIS2_HOME = "your axis2 installation(unzipped) directory"
b) JAVA_HOME = "your jdk installation path"
c) PATH = "add ant, axis2/bin to this"

Step 1: Create your service class.

In my case:

package axis2.adb;
public class MyService {
public String sayWelcomeToAxis2(String userName){
return "Hi " + userName + "\nWelcome to the world of Axis2";
}
}

You can actually use an interface to define the service contracts, which your service will implement. But, as i said, the goal is to set the webservice up as fast and in as simple way as possible.

Step 2: Generate the WSDL file using the command:
java2wsdl -cp ./bin -cn axis2.adb.MyService -of ./META-INF/MyService.wsdl

here -cp gives the classpath, in my case the class files are present in 'bin' folder. -cn is the class name with package and -of is the output file.

Step 3: Generate the Skeleton using the below command. I will be using the ADB(Axis data binding). You can use XMLBean or JiBx or AXIOM also.

wsdl2java -uri ./META-INF/MyService.wsdl -p axis2.adb -d adb -s -ss -sd -ssi -o .

here uri provides you with the WSDL file path, -p specifies the package, -d gives the data binding(ADB in my case), -s sync call, -ss creates the server side code (skeleton and related files), -sd creates a service descriptor (services.xml file), -ssi switch creates an interface for the service skeleton.

Step 4: Put the business logic inside the skeleton.

package axis2.adb;
import axis2.adb.MyService;
import axis2.xsd.SayWelcomeToAxis2Response;
/**
* MyServiceSkeleton java skeleton for the axisService
*/
public class MyServiceSkeleton implements MyServiceSkeletonInterface {
MyService myService = new MyService();
/**
* Auto generated method signature
*
* @param param2
*
*/
public axis2.xsd.SayWelcomeToAxis2Response sayWelcomeToAxis2(
axis2.xsd.SayWelcomeToAxis2 param2)
{
//create the response obj
SayWelcomeToAxis2Response res = new SayWelcomeToAxis2Response();
//set the response payload
res.set_return(myService.sayWelcomeToAxis2(param2.getUserName()));
// return the response
return res;
}
}

Step 5: Create the Client Stub using the command below.

wsdl2java -uri ./resources/MyService.wsdl -p axis2.adb.client -d adb -s -o .

Step 6: Code the Client using the generated Stub.

package axis2.adb.client;
import java.rmi.RemoteException;
import org.apache.axis2.AxisFault;
public class MyServiceClient {
public static void main(String[] args) {
try {
//create the stub
MyServiceStub stub = new MyServiceStub("http://localhost:8080/axis2/services/MyService");
// webservice call happens inside this method
sayWelcome(stub);
} catch (AxisFault e) {
e.printStackTrace();
}
}
private static void sayWelcome(MyServiceStub stub) {
//create the request payload
MyServiceStub.SayWelcomeToAxis2 req = new MyServiceStub.SayWelcomeToAxis2();
//set the parameter
req.setUserName("SacroSanctBlood");
MyServiceStub.SayWelcomeToAxis2Response res = null;
try {
//get the response(This example shows a blocking call)
res = stub.sayWelcomeToAxis2(req);
//show the output
System.out.println(res.get_return());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}


Step 7: Create ".aar" file which has to be deployed inside axis2 using the below command.
The build.xml file is created in Step 3.

ant build.xml

Step 8: Deploy.

A new folder build is created inside the current directory. The MyService.aar file is present in \build\lib. Upload this using the axis2 admin page.
Type, http://localhost:8080/axis2/. Click on Administration. Login using the username/password, by default it is admin/axis2. (present in %AXIS2_HOME%/conf/axis2.xml) Use the Upload Service tool present in the left side of page. Upload the MyService.aar.

Step 9: Test the service.

type http://localhost:8080/axis2/services/MyService?wsdl in addressbarr. you should get the WSDL file.

Step 10: Execute the client.

java MyServiceClient


output :

Hi SacroSanctBlood

Welcome to the world of Axis2

Hope, this tutorial was use full enough.
Next time, will try to put up the async/non-blocking version of the web service.

Thursday, January 04, 2007

Java : Sorting the table rows on a particular column

Assumption:
1. A table with a already sorted order is getting displayed on the screen.
2. you know the ID of each of the in the table.
3. The each row of the table is an object in an array.

I am not writing the code as such, but just presenting the idea of sorting the table based on the column header clicked. One way is using common controls, which i rather not use. I am trying to present the most simplest idea of sorting.

Firstly, write the scriplets in which we write a comparator for each column we want to sort and sort the collection using the same.
Next write the javascript function for each of the sorting required which sets the corresponding to the value required from the sorted collection.
Lastly, call the function on click event of the column header.

I briefly write code snippets to make the idea more clear.

[%//scriplets
ExampleForm exampleForm = (ExampleForm)request.getAttribute("exampleForm");
List rowObjects = exampleForm.getRowObjects();

Collection.sort(rowObjects, new Comparator(){
public int compare(Object a, Object b) {
RealObject objectOne = (RealObject)a;
RealObject objectTwo = (RealObject)b;

[On Condiditions] return 1 or -1 or 0

}
});
%]

function sortTypeOne(){//javascript
document.getElementById('td00') = [%= rowObjects.get(0).getRowData() %]
document.getElementById('td10') = [%= rowObjects.get(1).getRowData() %]
.
.
[continue from here as many td's you want; You can also use struts to iterate over the collection here and setting the corresponding to the value required. The data inside the getElementById() can also be filled when you iterate using struts.{logic:iterate tag}]
}

[%// scriplets
Collection.sort(rowObjects, new Comparator(){
public int compare(Object a, Object b) {
RealObject objectOne = (NewRealObject)a;
RealObject objectTwo = (NewRealObject)b;

[On New Condiditions] return 1 or -1 or 0

}
});

%]

function sortTypeTwo(){//javascript
document.getElementById('td00') = [%= rowObjects.get(0).getRowData() %]
document.getElementById('td01') = [%= rowObjects.get(1).getRowData() %]
.
.
[continue from here as many td's you want; You can also use struts to iterate over the collection here and setting the corresponding to the value required. The data inside the getElementById() can also be filled when you iterate using struts.{logic:iterate tag}]
}

Table structure approximately is shown below.

[table]
[tr]
[th onclick="sortTypeOne()"/]
[th onclick="sortTypeTwo()"/]
.
.
.
[/tr]
[tr]
[td id='td00'/]
[td id='td01'/]
.
.
.
[/tr]
[/table]

replace '[' or ']' respectively with '<' or '>'