Monday, February 08, 2010

Passing custom objects with Apache Etch.

While using Apache Etch as the wire protocol of a distributed project, we had a requirement to send our custom Java objects across. This post demonstrates sending custom types and invoking different server methods without changing the idl.

Apache Etch has the concept of an extern, which can be used to define specific types. The IDL needs the definition of the type, and the class with which to serialize/deserialize it. This serializer helps Etch transfer the object across the network. Let us define our pojo - com.etchTrials.Base

package com.etchTrials;

import java.io.Serializable;
import java.util.Map;

public class Base implements Serializable{

private String name;
private int age = 5;

public Base(String values) {
this.name = values;
}

public Base() {

}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String methodA() {
System.out.println("Inside method A");
return "A";
}

public String toString() {
return "Value is " + name + " and int is " + age;
}

}


Next we define the BaseSerializer. This implements Etch's ImportExportHelper to define how Base can be marchalled/unmarshalled.


package com.etchTrials;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import etch.bindings.java.msg.Field;
import etch.bindings.java.msg.ImportExportHelper;
import etch.bindings.java.msg.StructValue;
import etch.bindings.java.msg.Type;
import etch.bindings.java.msg.ValueFactory;
import etch.bindings.java.support.Class2TypeMap;
import etch.bindings.java.support.Validator_byte;
import etch.bindings.java.support.Validator_object;
import etch.bindings.java.util.StrStrHashMap;
import etch.bindings.java.util.StrStrHashMapSerializer;

public class BaseSerializer implements ImportExportHelper {

private final Type type;
private final Field field;

public final static String FIELD_NAME = "base";

public BaseSerializer(Type type, Field field) {
this.type = type;
this.field = field;
}

/**
* Defines custom fields in the value factory so that the importer can find
* them.
*
* @param type
* @param class2type
*/
public static void init(Type type, Class2TypeMap class2type) {
Field field = type.getField(FIELD_NAME);
class2type.put(Base.class, type);
type.setComponentType(Base.class);
type.setImportExportHelper(new BaseSerializer(type, field));
type.putValidator(field, Validator_byte.get(1));
type.lock();
}

@Override
public Object importValue(StructValue struct) {
Base base = new Base();
try {
byte[] bytes = (byte[]) struct.get(field);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(stream);
base = (Base) ois.readObject();
ois.close();
}
catch(Exception e) {
e.printStackTrace();
}
return base;
}

@Override
public StructValue exportValue(ValueFactory vf, Object arg1) {
StructValue struct = new StructValue(type, vf);
Base base = (Base) arg1;
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(stream);
oos.writeObject(base);
oos.close();
byte[] bytes = stream.toByteArray();
struct.put(field, bytes);
}
catch(Exception e) {
e.printStackTrace();
}
return struct;
}

}


We define these two in the IDL:

module com.etchTrials

service Generic {
exception BaseException(string msg);

@Extern( java, "com.etchTrials.Base", "",
"com.etchTrials.BaseSerializer", "" )
extern Base;

object invokeServerMethod(string method, object[] params);

void connect( string host, int port );

void listen();

@Direction(Both)
void close();

}



The above idl has:
1. Definition of our custom type - Base as an extern. It tells Etch that we have a type called Base, which can be marshalled/demamarshalled using the BaseSerializer. Other pojos need to be defined similarly
2. Definition of a generic method invokeServerMethod. This is capable of accepting and returning Etch currently supported java types and Base types. It takes the name of the method to be executed, and its parameters.

We now define EtchClient, our client, The Etch client will be able to execute the following on the server:
a. Invoke method whoIsOnline which returns a String[].
b. Invoke method login which accepts a String and returns a boolean.
c. Invoke a void method with no params
d. Invoke a method which sends a custom pojo com.etchTrials.Base object.
Server alters this object and client receives the changed values

We also define EtchServer, which implements the methods defined in the IDL.


package com.etchTrials;

import java.lang.reflect.Method;

import etch.util.core.io.Transport;

public class EtchClient extends BaseGenericClient {

private RemoteGenericServer server;

public EtchClient() {
}

protected void setUp() {
try {
String uri = "tcp://0.0.0.0:4005?TcpTransport.reconnectDelay=4000";
System.out.println("URI " + uri);
final EtchClient client = this;
server = GenericHelper.newServer(uri, null,
new GenericHelper.GenericClientFactory() {
public GenericClient newGenericClient(
RemoteGenericServer server) throws Exception {
return client;
}
});

server._startAndWaitUp(4000);
System.out.println("Client server started");
} catch (Exception e) {
e.printStackTrace();
}

}

public void close() {
try {
System.out.println("Closing time");
server._transportControl(Transport.STOP, null);
} catch (Exception e) {
e.printStackTrace();
}
}

//test method which invokes some methods on Base object
public void testInvokeServer() {
String[] whoIsOnline = (String[]) server.invokeServerMethod("whoIsOnline", null);
for (String who: whoIsOnline) {
System.out.println("whoIsOnline returns " + who) ;
}
System.out.println("Login returns " + server.invokeServerMethod("login", new String[] {"Browser1"}));
System.out.println("Invoking voidMethod ");
server.invokeServerMethod("voidMethod", null);
System.out.println("Invoked voidMethod ");
//String user = "User";
Base base = new Base();
base.setAge(25);
base.setName("Any value");
String name = "Change from server";
Object[] params = new Object[] {base, name};
System.out.println("Invoking withParams");
Base returnBase = (Base) server.invokeServerMethod("withParams", params);
System.out.println("Base returned is " + returnBase);

}

public static void main(String[] args) {
EtchClient client = new EtchClient();
client.setUp();
client.testInvokeServer();
client.close();
}

}


The Etch client will be able to execute the following on the server:
a. Invoke method whoIsOnline which returns a String[].
b. Invoke method login which accepts a String and returns a boolean.
c. Invoke a void method with no params
d. Invoke a method which sends a custom pojo com.etchTrials.Base object.
Server alters this object and client receives the changed values

Finally, we have the EtchServer:

package com.etchTrials;

import etch.bindings.java.support.ServerFactory;
import etch.util.core.io.Transport;

public class EtchServer extends BaseGenericServer implements
GenericHelper.GenericServerFactory {

public EtchServer(RemoteGenericClient client) {
System.out.println("Client " + client);
this.client = client;
}

public EtchServer() {
System.out.println("Server constructor");
}

public Object invokeServerMethod(String method, Object[] params) {
//System.out.println("Inside invoking the method");
if (method.equals("whoIsOnline")) {
return whoIsOnline(params);
}
else if (method.equals("login")) {
return login(params);
}
else if (method.equals("voidMethod")) {
voidMethod();
return null;
}
else if (method.equals("withParams")) {
return withParams(params);
}
return null;
}

private Boolean login(Object[] params) {
String userName = (String) params[0];
System.out.println("login: User is logged in now " + userName);
return new Boolean(true);
}

private String[] whoIsOnline(Object[] params) {
String[] names = new String[] { "ChatterBoxA", "ChatterBoxB" };
return names;
}

private void voidMethod() {
System.out.println("voidMethod: Inside Void method");
}

private Base withParams(Object[] params) {
System.out.println("withParams: With params method");
//String clientName = (String) params[0];
//System.out.println(params[1].getClass().toString());
Base base = (Base) params[0];
//do some calculations
//return clientName +
System.out.println("withParams: Received base object from client" + base);
String name = (String) params[1];
base.setAge(base.getAge() * 2);
base.setName(name);
return base;
}

private RemoteGenericClient client;

public void connect(String host, String port) {
try {
String uri = "tcp://" + host + ":" + port;
System.out.println("URI " + uri);
Transport listener = GenericHelper.newListener(uri,
null, this);

listener.transportControl(Transport.START_AND_WAIT_UP, 4000);
System.out.println("Started");
} catch (Exception e) {
e.printStackTrace();
}
}

public void listen() {
System.out.println("listen");
}

public void close() {
System.out.println("close");
}

public GenericServer newGenericServer(RemoteGenericClient client)
throws Exception {
return new EtchServer(client);
}

public static void main(String[] args) {
EtchServer server = new EtchServer();
System.out.println("New Server");
server.connect("0.0.0.0", "4005");
System.out.println("Up and running");
}

}

Labels: , ,

Saturday, July 25, 2009

Unknown Entity with Hibernate 3

While using Hibernate 3 and JPA, remember to place persistence.xml in the classes/META-INF folder. Otherwise, you will get Exception in thread "main" org.hibernate.MappingException: Unknown entity

Labels: , ,

Sunday, August 31, 2008

YouTube API does not work through Resin

I have run into a strange issue with the youtube api. I am able to upload videos through the browser and verify them in my youtube acocunt. However, when I try to retrieve the videos, I do not get them. I am able to retrieve correctly through a junit test case.

After a lot of digging on the forum, I found this post:
Different behaviour under Tomcat and Resin

The client api documentation does not suggest any supported environments or versions. GData Doc

Labels: , , ,

Tuesday, February 26, 2008

Good site for Struts2

Sunday, October 14, 2007

JSF immediate attribute

Usage of JSF immediate attribute can lead to a variety of issues, so it is a handle with care piece will one learns the JSF life cycle, different phases and the bypassing through immediate. For more, check:

ClearInputComponents - Myfaces Wiki

Labels: , ,

Tuesday, October 09, 2007

Enterprise Java Community: Building Custom JSF UI Components

Fixing Required messages in JSF

Another interesting phase listener for required messages Fixing Required messages in JSF

JSF 1.2 components already support requiredMessage attribute, so this may not be handy there.

Customizing JSF Required Field Messages per Component Instance is another flavour of the same.

Labels: , ,

Designing and Implementing Web Application Interfaces

Wonderful use of phase listeners in JSF : Designing and Implementing Web Application Interfaces

It outlines how JSF can be enhanced to define custom error messages per component. Mst read for all those who are on JSF 1.1

Labels: , ,

Friday, October 05, 2007

JSF dropdown with BigInteger keys

We wanted to create a drop down with JSF which had keys as java.math.BigInteger and labels as strings. The drop down was to be pre selected with a value. If everything is string, string, thinds work well. However, the drop down value is not prepopulated if it is bound to a BigInteger. Eventually, we were able to solve this with the following code:

JSP




<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"
\"http://www.w3.org/TR/html4/loose.dtd\">
<%@ page contentType=\"text/html;charset=windows-1252\"%>
<%@ taglib uri=\"http://java.sun.com/jsf/html\" prefix=\"h\"%>
<%@ taglib uri=\"http://java.sun.com/jsf/core\" prefix=\"f\"%>
<f:view>
<html>
<head>
<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=windows-1252\"/>
<title>ConversionTrial</title>
</head>
<body><h:form>
<h:selectOneMenu id=\"menu\" value=\"#{ConversionBean.dto.code}\">
<f:selectItems value=\"#{ConversionBean.valueList}\"/>
</h:selectOneMenu>
</h:form></body>
</html>
</f:view>



Managed Bean



package view;



import java.math.BigInteger;



import java.util.ArrayList;



import javax.faces.model.SelectItem;



public class ConversionBean {

    private DTO dto;

    private ArrayList valueList;

    

    public ConversionBean() {

        dto = new DTO(new BigInteger(\"10\"), \"Large\");

    }

    

    public ArrayList getValueList(){

        valueList = new ArrayList();

        valueList.add(new SelectItem(new BigInteger(\"0\"), \"Small\"));

        valueList.add(new SelectItem(new BigInteger(\"5\"), \"Medium\"));

        valueList.add(new SelectItem(new BigInteger(\"10\"), \"Large\"));

        

        return valueList;

    }

    

    public DTO getDto(){

        return this.dto;

    }

}



DTO




package view;



import java.math.BigInteger;



public class DTO {

    private BigInteger code;

    private String val;

    

    public DTO(BigInteger code, String val) {

        this.code = code;

        this.val = val;

    }

    

    public void setCode(BigInteger s){

        System.out.println(\"setCode to \" + s);

        this.code = s;

    }

    

    public BigInteger getCode(){

        System.out.println(\"getCode returns \" + code);

        return this.code;

    }

}

Labels: , ,

Thursday, September 20, 2007

Surprising tip

I was taken aback by the tip A Very Simple Way to Skip Part of Code Without Using Comment Symbols duly linked from http://java.sun.com. It is a surprise way of inserting return statements in the middle of the code to test only the functionality upto the point of return.

Commenting out code and testing, or creating appropriate test harnesses so that all cases can be covered is surprisingly not advocated. Nor is the need for modular methods and further breakdown of code logically.

What is next, Goto ?

Labels: ,

Tuesday, September 18, 2007

Sortable table using JSF and AJAX4JSF

I have written about AJAX and JSF in my previous post. Let us now look at a way to implement sortable tables using JSF and AJAX. We want to build a table which has the header as links. If a particular link is clicked, the table entries are sorted based on the header clicked. We want the entire functionality to be AJAX based, so that only part of the page is refreshed.

A normal JSF table looks like this:



<h:datatable id="addressTableHeader" border="0" cellpadding="0" cellspacing="0">
<h:column>
<f:facet name="header">
<h:outputtext value="Post Code">
</f:facet>
</h:column>
<h:column>
<f:facet name="header">
<h:outputtext value="Street">
</f:facet>
</h:column>
</h:dataTable>
<h:datatable id="addressTableBody" var="tableData" value="#{Bean.addressList}">
<h:column>
<h:outputtext value="#{tabledata.postcode}">
</h:column>
<h:column>
<h:outputtext value="#{tabledata.street}">
</h:column>
</h:dataTable>





The backing bean Bean.java has a method
getAddressList()
which wraps an ArrayList inside a ListDataModel and returns it.

We modify the table header from plain text to links which fire AJAX requests, using Ajax4JSF. We want the table body to be refreshed when the header is pressed, so we specify that in the reRender property of the commandLink.


<h:datatable id="addressTableHeader" border="0" cellpadding="0" cellspacing="0">
<h:column>
<f:facet name="header">
<a4j:commandlink action="#{Bean.postcodeSort}" ajaxsingle="true" rerender="addressTableBody" immediate="true">
<h:outputtext value="Post Code" styleclass="tariffpopupsearchheading">
</a4j:commandLink>
</f:facet>

</h:column>
<h:column>
<f:facet name="header">
<a4j:commandlink action="#{Bean.streetSort}" ajaxsingle="true" rerender="addressTableBody" immediate="true">
<h:outputtext value="Street" styleclass="tariffpopupsearchheading">
</a4j:commandLink>
</f:facet>
</h:column>
</h:dataTable>


We now add a Comparator to the back end code, which can help to sort the ArrayList of data to be presented in the table. The Comparator has different sorting criteria. New methods
postcodeSort()
and
streetSort()
are added to the Bean, which help to set the sorting criteria on click . The Bean's
getAddresslist()
method is modified to pass the appropriate Comparator.

Labels: , , ,

Monday, August 14, 2006

FLWOR with Berkeley DB XML

FLWOR (pronounced Flower) stands for "for let while order by return" and is and XQuery expression. FLWOR enables advanced querying. More details about
FLWOR can be found at http://www.w3schools.com/xquery/xquery_flwor.asp

Sleepycat's Berkeley's XML Database, DB XML the native XML database supports XQuery. I have tried to create a small example here to demonstrate how to read XQuery with FLWOR expressions from a file, and run them against the database of Berkeley DBs dbxml container.(the one built in the 'gettingStarted' section) It is assumed that the xml sample data from the getting started kit has been loaded.

Set your classpath to include the Berkley DB jars under jar folder
(db.jar, dbxml.jar, dbexamples.jar)

The code can be found here.

1. query.txt file, which holds the query.



for $doc in collection(\'simpleExampleData.dbxml\')

where $doc/product/item[text()=\"Lemon Grass\"]

return $doc/product



2. FLWOR.java file, which holds the code.



import java.io.*;

import com.sleepycat.dbxml.*;

import com.sleepycat.db.*;

import dbxml.gettingStarted.*;



public class FLWOR {

 private static void usage() {

String usageMessage = \"\\nThis program performs queries against a DBXML container.\\n\";

usageMessage += \"You should run exampleLoadContainer before running this example.\\n\";

usageMessage += \"You are only required to pass this command the path location of the database\\n\";

usageMessage += \"environment that you specified when you loaded the examples data:\\n\";

usageMessage += \" and the query file which holds the query\\n\";

usageMessage += \"\\t-h <dbenv directory> -q <queryFile>\\n\";



usageMessage += \"For example:\\n\";

usageMessage += \"\\tjava ch.inform.bdb.FLWOR -h examplesEnvironment -q query.txt\\n\";



System.out.println(usageMessage);

System.exit( -1 );

 }



 

 //Utility function to clean up objects, exceptions or not,

 // containers and environments must be closed.

 private static void cleanup(myDbEnv env, XmlContainer openedContainer) {

try {

    if (openedContainer != null)

openedContainer.close();

    if (env != null)

env.cleanup();

} catch (Exception e) {

    // ignore exceptions on close

}

 }



 public static void main(String args[])

throws Throwable {

String theContainer = null;

File path2DbEnv = null;

File queryFile = null;

for(int i = 0; i < args.length; ++i) {

         if (args[i].startsWith(\"-\")) {

          switch(args[i].charAt(1)) {

           case \'h\':

           path2DbEnv = new File(args[++i]);

           break;

           case \'q\':

           queryFile = new File(args[++i]);

           break;

           default:

           usage();

           }//switch

         }//if

}//for



if (path2DbEnv == null || ! path2DbEnv.isDirectory()) {

         usage();

}



if (queryFile == null || queryFile.isDirectory()) {

System.out.println(\"queryFile is \" + queryFile);

usage();

}



//Stream to read file

BufferedReader fin;

String query = \"\";

try

{

fin = 

            new BufferedReader(new FileReader(queryFile));

String line;

    while ((line = fin.readLine()) != null ) {

     query += \"\\n\" + line;

    }



    // Close our input stream

    fin.close();

}

// Catches any error conditions

catch (IOException e)

{

System.err.println (\"Unable to read from file\");

System.exit(-1);

}



System.out.println(\"Query is \" + query);



myDbEnv env = null;

XmlTransaction txn = null;

XmlContainer openedContainer = null;

try {

    env = new myDbEnv(path2DbEnv);

    XmlManager theMgr = env.getManager();

    String containerMark = \"\\\'\";

    theContainer = query.substring(

     query.indexOf(containerMark)+1, 

     query.lastIndexOf(containerMark));

    System.out.println(\"Container is \" + theContainer);

    //Open a non-transactional container

    openedContainer =

     theMgr.openContainer(theContainer);

    XmlQueryContext resultsContext = theMgr.createQueryContext();



        XmlResults results = theMgr.query(query.trim(),

      resultsContext);

    XmlValue value = results.next();

    while (value != null) {

    //Pull the value out of the document query result set.

    System.out.println(value.asString());

    }



} catch (Exception e) {

         System.err.println(\"Error performing query against \" + theContainer);

         System.err.println(\"   Message: \" + e.getMessage());

         throw e;

    }

    finally {

   cleanup(env, openedContainer);

    }

 } //End main

}



I am assuming you have already run the examples. So after that, please compile and
say the following at the command line at test folder:
java FLWOR -h -q query.txt

Labels: , ,