Tuesday, February 22, 2011

Linux Port forward for debug remote application

Sometime, we need to debug production server code.

Here is approach of doing this:
1) start remote server with Debug flag, ex port 8000
2) in window local host cygwin: ssh -L 8787:localhost:8000 remoteuser@remote.myserver.com
3) start eclipse with port 8787.


ps.
-Xdebug
-Xnoagent
-Djava.compiler=NONE
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787
or:
SET args=%args% -Xdebug -Xnoagent -J-Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n

Monday, February 21, 2011

Binary Web Service - Hessian

Currently, most web services are XML-based due to the advantage of XML self-describing and well support. However, the bandwidth and performance may be the issues for XML based web service.

Binary Web Service, by design, attempts to solve the above issues.
Hessian (http://hessian.caucho.com/) is one of binary web service implementation. We used it and it is proved to be a good approach. Following is the simple code of showing how to use Hessian.


First we create interface with two methods, hello and hiClient
public interface Basic {
public String hello();
public MyOutputResponse hiClient(MyInputRequest input);
}


Server Side:
1. Create implementation of that interface.
public class BasicService implements Basic {
private String _greeting = "My Hello world";

public void setGreeting(String greeting) {
_greeting = greeting;
}

public String hello() {
return _greeting;
}

public MyOutputResponse hiClient(MyInputRequest input) {
System.out.println(" from client: " + input.toString());
MyOutputResponse response = new MyOutputResponse();
response.setMsg("HI there from " + input.getFirstName());
return response;
}
}

2. Standard web.xml for Hessian service
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param>
<param-name>home-class</param-name>
<param-value>example.service.BasicService</param-value>
</init-param>
<init-param>
<param-name>home-api</param-name>
<param-value>example.interfaces.Basic</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Where home-api refers defined interface and home-class is implementation of the interfaces.

Client Side:
public class BasicClient {
public static void main(String []args)
throws Exception
{
String url = "http://localhost/hessian_webapp/hello";

HessianProxyFactory factory = new HessianProxyFactory();
Basic basic = (Basic) factory.create(Basic.class, url);

//test first API hello
System.out.println("Hello from server: " + basic.hello());

//test second API hiClient
MyInputRequest input = new MyInputRequest();
input.setFirstName("Michael");
input.setLastName("W");
MyOutputResponse response = basic.hiClient(input);

System.out.println("hiClient from server: " + response.toString());
}
}

The url of http://localhost/hessian_webapp/hello is the servlet for the service.

HessianProxyFactory factory = new HessianProxyFactory();
Basic basic = (Basic) factory.create(Basic.class, url);

Get reference of the interface

Build/Deploy
I used maven to build Hessian web service and deployed to jboss.
Here is pom file:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>hessian_webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>hessian_webapp Maven Webapp</name>
<url>http://maven.apache.org</url>
<build>
<finalName>hessian_webapp</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>client</id>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>example.client.BasicClient</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>


</profiles>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>


<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>3.1.5</version>
</dependency>
</dependencies>

</project>






Build/Deploy
1. build: mvn clean package
2. deploy: copy target\hessian_webapp.war to your web server
3. start server.
4. test service with following URL: http://localhost/hessian_webapp/hello
You will get "Hessian Requires POST"
5. Run client BasicClient
In command line:
mvn -Pclient

In Eclipse:
Right click BasicClient, and Run As Java Application.



Source code: click here to download source code.

Wednesday, February 10, 2010

GWT - Use Google analytics to find bug

Google analytics provides a way to monitor the user behaviors. It enables us to monitor conversion rate overall, and/or based on browser type.

Few days ago, the Google analytics conversion chart showed that IE8 conversion rate was much less than IE6 and IE7. We doubted IE8 may have some problem for our application.

With extensive research, we found that IE8 more strict on the rule of form.attributes.name.nodeValue.
If no attribute name for the form, IE6/IE7 will ignore it, while IE8 will give exception.

One of our third party Javascript used form.attributes.name.nodeValue for tracking purpose.

The interesting thing is that it only happended if newly install IE8.
If you upgrade IE8 from IE6 or IE7, there is no such problem as IE8 will run in Compatibility mode. That was the reason the problem was skiped from our developers and QA testers.

With the fix, IE8 conversion rate goes up.


GWT - Quick steps to craete ClientBundle for image

GWT 2.0 provides new features to replace original ImageBundle.

Here are the steps to using ClientBundler

Step 1, add following line to .gwt.xml file
< inherits name="com.google.gwt.resources.Resources" / >

Step 2. for the case of using Maven, copy/create images under src\main\resources
ex.
put two images logos.gif and quickResButton.gif under
src\main\resources\com\myapp\resources\images

Step 3. create your image bundle interface to extends ClientBundle
ex.
public interface MichaelImageBundle extends ClientBundle {

@Source("
com/myapp/resources/images/logos.gif")
public ImageResource mylogo();

@Source("
com/myapp/resources/images/quickResButton.gif")
@ImageOptions(flipRtl = true)
public ImageResource mypointer();

public class Util {
private static MichaelImageBundle imgBundle = null;

public static MichaelImageBundle getInstance() {
if (
imgBundle == null) {
imgBundle = (MichaelImageBundle) GWT.create(MichaelImageBundle.class);
}
return imgBundle ;
}
}
}

Step 4. create Image in your GWT code
ex.

MichaelImageBundle michaelImageBundle = MichaelImageBundle.Util.getInstance();
Image imgLogo = new Image(michaelImageBundle.mylogo().getURL());
Image imgMypointer = new Image(michaelImageBundle.mypointer().getURL());

That is.
For more information, refer to http://code.google.com/webtoolkit/doc/latest/DevGuideClientBundle.html#ImageResource


Thursday, January 28, 2010

GWT, Firebug -- lookup meta description, title

In GWT, The page title, meta description and meta keywords are changed dynamically as GWT token changes
So view source will show different values than in DOM.

By using firebug, we can view those information.

We put description before keywords, so the order would be:

For meta.description
document.getElementsByTagName('meta')[0].content;

For meta.keywords
document.getElementsByTagName('meta')[1].content;

For title
document.title

Saturday, January 23, 2010

GWT Create suggestion box

Have got request of how to create GWT suggestion box. Here is the copied version from my post in user group.

what you need to do it to overrite SuggestOracle, for example
YourSuggesOracle extends SuggestOracle
in method of
public void requestSuggestions( Request request, Callback callback ) {
// get query
String query
= request.getQuery();

if (query.length >=3) {
Call your RPC

set your result list to
Collection suggestions = new ArrayList();

Response response = new Response( suggestions );
callback.onSuggestionsReady( request, response );

}
}


Then you can use that orerride class
YourSuggesOracle oracle = new YourSuggesOracle ();
SuggestBox destination = new SuggestBox(oracle);


finally, you can get value of it
destination.getText();

Thursday, December 31, 2009

Java, IO read file

protected ArrayList getKmlFromFile(String filename) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(filename));

ArrayList lineList = new ArrayList();
String line = null;
while ((line = reader.readLine()) != null) {
if (line.startsWith( "#" )) {
continue;
}

if (line.trim().equalsIgnoreCase("")) {
continue;
}

lineList.add( line );
}

reader.close();

return lineList;
}