Friday, December 23, 2011

GWT RequestFactoryGenerator Mod: Session timeout handling on client without code refactor- when using Receivers and RequestFactory


Problem:
There's a GWT project that uses RequestFactory-entity-proxy-receiver mechanism to load data from server.(http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html).
It's an alternative to GWT-RPC.
The objective is to make the client session-timeout-aware i.e. It should show a popup and redirect/load to a login endpoint if a data request can't be served due to session-timeout.

Most-intuitive solution:
If there is an entity with a method (eg: MyEntity.myMethod():MyReturnObject) then the GWT client makes a call to the method in a manner similar to following:

myEntityRequest = requestFactory.myEntityRequest();
myEntityRequest.myMethod().fire(
new Receiver<MyReturnObjectProxy>(){

public void onSuccess(MyReturnObjectProxy response)
{
this is success callback
}

@Override
public void onFailure(ServerFailure error)
{
this is failure callback. failure = thrown/unthrown exceptions, connection failures etc.
}

}

If you are wondering, myEntityRequest.myMethod() must be a stub implementation generated by GWT for myEntity.myMethod().

The most intuitive solution is to create a custom Receiver class that implements the session-timeout handling logic in its onFailure() and use it everywhere instead of the inline Receiver implementations as above.

Problem with the intuitive solution:
Well, there's already over 500 places in the code where inline receivers have already been declared.
This would mean a lo....t of refactoring.

Another Solution:
http://stackoverflow.com/questions/3657572/how-to-redirect-to-login-page-after-session-expire-in-gwt-rpc-call - has a smart solution discussed by "Piotr".
The idea is based on the fact that GWT offers deferred binding (http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html)
But the code provided in the post are for those using GWT-RPC.
We will be re-doing the same for RequestFactory.

The code:
It seems that com.google.gwt.requestfactory.rebind.RequestFactoryGenerator is responsible for emitting some intermediate JAVA code for the "requestFactory" that gets converted into JS eventually. And then you use this requestFactory to create *Request objects(eg: myEntityRequest)

However RequestFactoryGenerator is not as generous as MyRpcRemoteProxyGenerator(Refer Piotr's  changes in classes in his post). Most of the code is private. No mechansim to inject some MyProxyCreator.

So we copy the entire code and patch it.

The logic is exactly same as the one in the blog post by "Piotr".

Step1:
Create a com.foo.bar.client.requestfactory.shared.MyReceiver extends Receiver

public class MyReceiver<V> extends Receiver<V> {

private final Receiver<V> receiver;
private final String sessionExpiredExceptionType = MyConstants.SESSION_EXPIRED_EXCEPTION_TYPE;

public MyReceiver(Receiver<V> receiver) {
this.receiver = receiver;
}

@Override
public void onSuccess(V response) {
// Window.alert("Success");
receiver.onSuccess(response);
}

@Override
public void onFailure(ServerFailure error) {

if(null!= error.getExceptionType() && error.getExceptionType().equals(sessionExpiredExceptionType)){
Window.alert("Sorry! Session Expired due to inactivity.");
Window.Location.replace("login");
return;
}
receiver.onFailure(error);
}

@Override
public void onViolation(Set<Violation> errors) {
receiver.onViolation(errors);
}

}

Please note how elegantly this class composes and reuses the callbacks of the Receiver passed to its constructor. Yes, you are right. We won't be touching the existing inline Receivers at all. The Generator takes care of it all. Go through the Generator code to figure it out how it does this.

In short, for every *Request class it generates, it overrides the fire method - wraps the argument receiver into our custom receiver  - and performs super.fire(customReceiver).

Step2:
Add the Generator mod. Uploaded a diff at (http://www.esnips.com/displayimage.php?album=3521675&pid=33041663) Use the diff to patch a copy of com.google.gwt.requestfactory.rebind.RequestFactoryGenerator and rename it as some com.foo.bar.server.gwt.rebind.MyRequestFactoryGenerator.
If you want to DIY manually, look out for the tokens "@TAPOMAY". Compare the area of interest with original code and use the code that has the token as a prefix.

Step3:
Add the following deferred-binding declaration in your <Module>.gwt.xml
<generate-with
class="com.foo.bar.server.gwt.rebind.MyRequestFactoryGenerator">
<when-type-assignable class="com.google.gwt.requestfactory.shared.RequestFactory" />
</generate-with>
This enables GWT to use our custom generator to be used to emit the RequestFactoryGenerator code.

Step4:
Enjoy the modded behaviour

Step5:
The MyReceiver.onFailure() in step1 detects session timeout against other failures by checking the ServerFailure.exceptionType.
Following is a sample servlet that can serve such a JSON to the client. This servlet is used by the server-side security layer as a request-forward destination to serve AJAX(/gwtRequest) requests if there is a session timeout.

/**
 * Servlet for handling request forward on session timeout.
 * Used for customizing what is returned to client.
 *
 * If GET request: redirect to login page
 * If POST request: Assume this was a GWT AJAX request. Uses GWT's mechanism for generating
 * response JSON indicating a SessionAuthenticationException.
 * Sets the serverFailure.exceptionType so that client can differentiate SessionAuthenticationException from other failures.
 * The JSON creation mechanism was taken from
 * com.google.gwt.requestfactory.server.SimpleRequestProcessor.process()
 * and com.google.gwt.requestfactory.server.RequestFactoryServlet
 *
 * @author Tapomay Dey (tapomay.dey@texity.com)
 *
 */
public class SessionExpiredServlet extends HttpServlet {

public static final String exceptionType = MyConstants.SESSION_EXPIRED_EXCEPTION_TYPE;
static final MessageFactory FACTORY = AutoBeanFactoryMagic.create(MessageFactory.class);
private ExceptionHandler exceptionHandler = new DefaultExceptionHandler();

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect(req.getContextPath() + "/login");
}

@SuppressWarnings("deprecation")
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse response)
throws ServletException, IOException {
String servletPath = req.getServletPath();
String requestURI = req.getRequestURI();
StringBuffer requestURL = req.getRequestURL();
PrintWriter writer = response.getWriter();
System.out.println(servletPath);

SessionAuthenticationException e = new SessionAuthenticationException("SessionAuthenticationException. Please login again.");

AutoBean<ResponseMessage> responseBean = FACTORY.response();
AutoBean<ServerFailureMessage> createFailureMessage = createFailureMessage(e);

ServerFailureMessage serverFailureMessage = createFailureMessage.as();
ResponseMessage responseMessage = responseBean.as();
responseMessage.setGeneralFailure(serverFailureMessage);

String payload = AutoBeanCodex.encode(responseBean).getPayload();

writer.print(payload);
writer.flush();
}

 private AutoBean<ServerFailureMessage> createFailureMessage(
     Exception e) {
   ServerFailure failure = exceptionHandler.createServerFailure(e.getCause() == null
       ? e : e.getCause());
   AutoBean<ServerFailureMessage> bean = FACTORY.failure();
   ServerFailureMessage msg = bean.as();
   msg.setExceptionType(exceptionType);
   msg.setMessage(failure.getMessage());
   msg.setStackTrace(failure.getStackTraceString());
   msg.setFatal(failure.isFatal());
   return bean;
 }

}

Friday, November 25, 2011

JSP / javascript escape "$" / EL expression

http://www.velocityreviews.com/forums/t129212-ot-jsp-escape-el-expressions.html

:

The problem:
Using JQuery template,
The javascript when included in the JSP, evaluated fields like "${name}" into JSP EL expressions as obvious. But I wanted them to be included in the templates as is.

Solution:
${'${'}name}

Note:
Using
<script id="searchFriendTemplate" type="text/x-jquery-tmpl">
for declaring the template.
http://api.jquery.com/template/

:).

Spring security and JPA

Always remember to declare
"Spring OpenEntityManagerInViewFilter" before "springSecurityFilterChain" in web.xml.
Otherwise JPA calls to load entities would return entities successfully but without all properties (null values for entity fields).

Correct:

<filter-mapping>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
        ...
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Thursday, November 24, 2011

Eclipse/IDE build failing - version problems

Here's what the issue was:
Developing on a project having a complex build process:
Spring Roo generating AspectJ sources - GWT - Datanucleus enhancing the outcome etc.

The project was initially built on STS with an older version (lets say V1) with all the required classpath and preferences to compile-build the project using STS. (Later command line build was introduced using maven).
It was checked-in to an SVN repo with all the complex eclipse/STS preferences and classpath.

Downloaded the project from SVN.
Installed a later version of STS-V2.
The project won't build.
Well, actually I won't need the IDE build as the project was building well with maven on command-line, but I guess IDE build would be required for debug to map classes to sources- not sure of that though.

When I looked at the changes in an SVN client, IDE had changed the IDE prefs and classpath to match the STSV2 plugins/mechanisms.

Reverted the changes, project built on IDE with a few errors related to project configurations. No compile errors-that important.

Started debug from command line- connected to the debug from IDE by debugging the app as "External app". All well.
:)

Wednesday, November 23, 2011

Clean URLs with Drupal-UrlRewriteFilter-Quercus-Jboss


http://www.brianshowalter.com/blog/running_drupal_on_quercus - There's a nice RewriteRule-RewriteMatch combo classes for UrlRewriteFilter posted at this blog.
But it's designed  for tomcat and didn't work on following JBoss configuration right away.
The JBoss config:
1. JBoss-4.2.2
2. Deploying the Quercus web-app(with Drupal inside) as exploded war (Folder name= "myapp.war").
3. Quercus 403
4. Drupal-6.17.
5. UrlRewriteFilter-320
Steps that worked for me:
1. Follow  the above blog at brianshowalter.com.
2. Download UrlRewriteFilter source code from http://code.google.com/p/urlrewritefilter/
(http://code.google.com/p/urlrewritefilter/downloads/detail?name=urlrewritefilter-3.2.0-src.zip&can=2&q=)
3. You must have already downloaded drupalrewrite_0.1 in step1.
4. Couldn't find a link for posting comments on above blog. Hence posting the modified source code here. Kindly setup UrlRewriteFilter and drupalrewrite_0.1 sources with all required libs in eclipse etc. and copy the compiled classes to your myapp.war/WEB-INF/classes.
5. Checkout updated sources for drupalrewrite fromhttp://drupalrewritefilter.googlecode.com (http://code.google.com/p/drupalrewritefilter/source/checkout) and compile/jar and copy to WEB-INF/lib(jar) or WEB-INF/classes(class) as you wish.
6. Good to go.

Thank you.

Sunday, November 13, 2011

Spring intercept-url patterns "/** Vz /*"

http://stackoverflow.com/questions/5240794/spring-intercept-url-patterns : "Melv" says that  the difference between /* and /** is as follows
Eg:

Main.java
directory/Main.java
/*: Files only at the / directory level are matched. Contents of directories are not processed. Thus only Main.java is returned.
/**: Pattern matcher recurses into directories also. Thus /**/*.java returns the directory/Main.java too along with /Main.java.

Thursday, November 10, 2011

Bash script to build and deploy GWT-SpringRoo-MVN app to tomcat


Following is a bash script that I wrote to perform following batch of tasks:
1. Invoke ROO shell to perform a startup scan to update generated sources. Optional(--rooscan option)
2. Somehow ROO updated the project POM to use GWT-2.3.0. Hence after scan is complete, using "sed" to update the POM(--modpom).
3. There is an option to do an "mvn gwt:run" or
to do an "mvn package" and deploy it to tomcat installation(--deploy) and copy some extra libs into the deployed app(--cpextjars)



#!/bin/sh
####################################################
#
# Author: Tapomay Dey
# Start Date: 9th November 2011
#
####################################################
# Please change the following variables to match your environment

project_home=
roo_home=
maven_home=
tomcat_deploydir=/var/lib/tomcat6/webapps
version=0.1.0.BUILD-SNAPSHOT

CLEAN=clean
ROOSCAN=false
DEPLOY=false
MODPOM=false
CPEXTJARS=false
GWTVERSION=2.2.0

usage() {
  echo "Usage: argument descriptions"
  echo "${0} [--rooscan] [--deploy] [--noclean] [--modpom] [--extjars]"
  echo "--rooscan: invokes roo shell for auto scan before proceeding"
  echo "--deploy: deploys app to tomcat. If not set, the app is run using gwt:run"
  echo "--noclean: mvn clean is not performed"
  echo "--modpom: Modifies project POM to reset GWT version to 2.2.0 and sets datanucleus fork=true."
  echo "--extjars: After deploying app to tomcat, copies external jars to deployment and restarts tomcat."
}

rooscan() {
  cd $project_home
  echo "Running ROO shell in $project_home ....."

  TEMP_FILE=`mktemp -t input.XXXXXX.tmp`
  echo 'quit' >> $TEMP_FILE
  $roo_home/bin/roo.sh < $TEMP_FILE
}

maven_run() {
  echo "Running APP....."
  cd $project_home
  pwd
  echo "$maven_home/bin/mvn ${CLEAN} ..... gwt:run -e";
  $maven_home/bin/mvn ${CLEAN}..... gwt:run -e

}

maven_deploy() {
  echo "Deploying to tomcat....."
  cd $project_home
  pwd
  echo "$maven_home/bin/mvn ${CLEAN} ..... package -e"
  $maven_home/bin/mvn ${CLEAN} ..... package -e

  cd target
  cp project-${version}.war project.war
  sudo cp project.war ${tomcat_deploydir}
  sudo /etc/init.d/tomcat6 restart
  echo 'Deployed to tomcat.....Press Enter'
  read s
}

modpom() {
  file=pom.xml
  temp_file=pOmTeMp.tmp
sed "
  # Change fork value for datanucleus to true
  /<groupId>org.datanucleus<\/groupId>/,/<\/plugin>/ {
  s/<fork>false<\/fork>/<fork>true<\/fork>/
  }
  # Set GWT versions to 2.2.0
  /<artifactId>gwt-maven-plugin<\/artifactId>/,/<\/plugin>/ {
  s/<version>.*<\/version>/<version>${GWTVERSION}<\/version>/
  }
  " <${file} > ${temp_file}
 
  mv ${temp_file} ${file}
}

cpextjars() {
  echo "Copying external jars to tomcat deployment....."
  cd $project_home
  sudo cp externaljars/extralib1.jar ${tomcat_deploydir}/project/WEB-INF/lib
  sudo cp externaljars/extralib2.jar ${tomcat_deploydir}/project/WEB-INF/lib
  sudo /etc/init.d/tomcat6 restart
  echo 'Deployed External JARs to tomcat.....Press Enter'
  read s
}

echo "WELCOME ${USER}"
cd $project_home
pwd

echo "Options Selected: $*"
for i in $*
do
case $i in
    --help)
usage
exit
;;
    --rooscan)
echo 'Rooscan option detected.'
ROOSCAN=true
;;
    --noclean)
echo 'No-clean option detected.'
CLEAN=''
;;
--deploy)
echo 'Deploy option detected'
DEPLOY=true
;;
--modpom=*)
echo 'modpom with value option detected'
MODPOM=true
GWTVERSION=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
--modpom)
echo 'modpom option detected'
MODPOM=true
;;
--cpextjars)
echo 'cpextjars option detected'
CPEXTJARS=true
;;
    *)
                # unknown option
;;
  esac
done

echo "ROOSCAN=${ROOSCAN}"
echo "DEPLOY=${DEPLOY}"
echo "MODPOM=${MODPOM}"
echo "GWTVERSION=${GWTVERSION}"
echo "CPEXTJARS=${CPEXTJARS}"

if ${ROOSCAN};
then
rooscan
fi

if ${MODPOM};
then
modpom
fi

if ! ${DEPLOY};
then
echo 'RUN GWT'
maven_run
else
echo 'DEPLOY TO TOMCAT'
maven_deploy
fi

if ${CPEXTJARS};
then
cpextjars
fi

sudo -k
echo 'Exiting.....'

Wednesday, November 9, 2011

Parsing Bash Script Command Line Arguments

http://www.digitalpeer.com/id/parsing

for i in $*
do
 case $i in
     --prefix=*)
  PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
  ;;
     --searchpath=*)
  SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
  ;;
     --lib=*)
  DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
  ;;
     --default)
  DEFAULT=YES
  ;;
     *)
                # unknown option
  ;;
   esac
done

Tuesday, November 8, 2011

Maven - mavenize project and recipes

Links and commands used by the authors:
http://i-proving.com/2007/03/29/Maven-Recipes/

http://i-proving.com/2007/04/27/How-to-Mavenize-an-Existing-Eclipse-Project/ :
Insure that your M2_REPO variable is properly defined
mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo
mvn eclipse:eclipse -DdownloadSources=true

http://i-proving.com/2009/11/03/creating-a-maven-project-and-adding-it-to-subversion/ :
mvn archetype:create -DgroupId=[packageName] -DartifactId=[projectName]
mvn eclipse:eclipse -DdownloadSources.
For integration with Hudson, some nodes should be added to the pom.xml
 1. parent 
 2. distributionManagement 
 3. scm
Project under an existing project:
Using the command line, enter the following in the root of the parent project
mvn archetype:create -DgroupId=[packageName] -DartifactId=[projectName]
svn add 'projectName'
svn commit [projectName] pom.xml
mvn eclipse:eclipse -DdownloadSources

http://i-proving.com/2007/05/10/How-to-Determine-the-Maven-dependency-to-use-for-a-jar/ :
$ md5sum commons-collections.jar
$ openssl dgst -md5 commons-collections.jar
$ openssl dgst -sha commons-collections.jar
mvn deploy:deploy-file -Dfile=<the file to deploy> \
   -Durl=<url to your repository> \
   -Dpackaging=jar \
   -DrepositoryId=<the repositoryID> \
   -DpomFile=<path to your pom.xml file>

http://i-proving.com/2007/03/29/Split-Your-Project-Into-Sub-Projects/ :
+-- workspace/
    +-- myproject/
    |    +-- pom.xml    --IMP: please refer link for contents. Note <packaging>pom</packaging>
    +-- subproject-1/
    |    +-- pom.xml
    +-- subproject-2/
        +-- pom.xml
The  myproject pom makes myproject your "one stop shopping" location for running mvn goals such as install or release or eclipse:eclipse
If subproject-1 pom has
<groupId>ca.intelliware</groupId>
  <artifactId>subproject-1</artifactId>
  <version>1.0-SNAPSHOT</version>
and if subproject-2 consumes subproject-1 as a dependency
then
<dependencies>
    <dependency>
        <groupId>ca.intelliware</groupId>
        <artifactId>subproject-1</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
eclipse:eclipse goal behaviour:
If dependency.SNAPSHOT: subproject-2 should reference the Eclipse project for subproject-1 as a project dependency in its Java build path
else if dependency.RELEASE: Eclipse project that gets generated by the eclipse:eclipse will simply refer to the released version of the JAR in your M2_REPO repository
1. mvn archetype:create -DartifactId=myNewProject -DgroupId=ca.intelliware
2. cd myNewProject 
3. mvn archetype:create -DartifactId=myNewSubProject-i -DgroupId=ca.intelliware
4. cd ..
5. mv myNewProject/myNewSubProject-i ./myNewSubProject-i
6. Edit myNewProject.POM
<modules>
        <module>../myNewSubProject-1</module>
        <module>../myNewSubProject-2</module>
</modules>
7. mvn -DdownloadSources=true eclipse:eclipse
SPLITTING PROJECT: foobar->{foo,bar}
1. Rename foobar as foo
2. mvn archetype:create -DartifactId=foobar -DgroupId=ca.intelliware

Edit foobar.POM.packaging to "pom"
3. cd foobar
4. mvn archetype:create -DartifactId=bar -DgroupId=ca.intelliware
5. cd ..
6. mv foobar/foo ./foo
7. Edit foo.POM.artifactId to foo
8. Copy bar.POM.parent to foo.POM.parent
9. Edit foobar.POM

<modules>
    <module>../foo</module>
    <module>../bar</module>
</modules>
10. Move code you want to split from foo to bar
11. mvn eclipse:eclipse
Thats it for now!!!

C:\>mvn install:install-file -Dfile=utils.jar -DgroupId=com.zparacha.example -DartifactId=utils -Dversion=1.0 -Dpackaging=jar

Monday, September 19, 2011

Ubuntu 10.04 lucid lynx : netcat -e option not present

Install netcat-traditional from Ubuntu Software center and run following:
$ nc.traditional -lvp {port} -e /bin/bash

Wednesday, August 24, 2011

Parametrized fmt tag in JSTL

http://www.xinotes.org/notes/note/452/


<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

<fmt:message key="my.message.key">
      <fmt:param value="${the.first.place.holder}"/>
      <fmt:param value="${the.second.place.holder}"/>
</fmt:message>

Monday, July 25, 2011

Android x,y =0 plotted view at top-center instead of top-left


WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mDragView.getLayoutParams();
layoutParams.x = 0;
layoutParams.y = 0;
WindowManager mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
mWindowManager.updateViewLayout(mDragView, layoutParams);

The gravity for this LayoutParams was set as Gravity.TOP.
Instead use:
        mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
This would plot (0,0) at left top.

Regards.

Thursday, July 21, 2011

Programming Songs


Programming Songs

1.      Local variable
Jeena Yahan Marna Yahan,
Iske siva Jana kaahan.

2. Global variable 
Musafir hoon yaaron,
na ghar hai na thikana

3.
Null pointers 
Mera jeevan kora kagaz kora hi reh gaya ..

4. Dangling pointers
Maut bhi aati nahi jaan bhi jati nahin.

5. The debugger
Jab koi baat bigad jaye
Jab koi mushkil pad jaye
Tum dena saath mera hamnawaz

6. From VC++ to VB
Yeh haseen vaadiyan
Yeh khula asmaan
Aa gaye hum kahan

7. Untrackable bug --
aye ajnabi, tu bhi kabhi,
awaaz de kahin se

8. Unexpected bug (esp. during presentation to client)
Ye kya hua, Kaise hua, Kab hua, Kyon hua

9. And then to the client
Jab hua, Tab hua, O chhodo, ye na socho

10. Load Balancing
Saathi haath badhana
ek akela thak jayega
mil kar bojh uthana

11. Modem - talk on a busy connection
suno - kaho,
kaha - suna,
kuch huwa kya?
Abhee to nahin...
kuch bi nahin

12. Windows getting open sourced
Parde mein rahne do
parda na uthao
parda jo uth gaya to bhed khul jayega
allah meri tauba, allah meri tauba

1
3. Two Recursive functions calling each other 

Mujhe kuchh kehna hein
mujhe bhi kuchh kehna hein
pehle tum, pehle tum

14. GOTO
Ajeeb dastan hai yeh
Kahan shuru kahan khatam
Ye manzilen hain kaun si
Na woh samajh sake na hum

15. Hidden or Private scope Variable/value
Jaanejan .. dhoondta phir raha,
Hoon tujhe raat din, main yahan se wahan

NOT ME

Wednesday, July 20, 2011

Thursday, June 9, 2011

Modified GWT sample module code- Successfully using Google transliteration JS API


package org.bvp.be.client;

import java.util.List;

import org.bvp.be.shared.FieldVerifier;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 * Working Version 1.0
 */
public class JSTransliterate implements EntryPoint {

public void handleResult(JsArrayString outputWordsArg){
String printStr = new String();
int i =0;
for(i=0; i<outputWordsArg.length() - 1; i++){
printStr += outputWordsArg.get(i);
printStr += " ";
}
printStr += outputWordsArg.get(i);
serverResponseLabel.setHTML(printStr);
}

public static native void alert(String msg) /*-{
 $wnd.alert(msg);
}-*/;

public native void transliterate(JsArrayString inputWords, JSTransliterate jSTransliterateObjArg) /*-{

 //Call google.language.transliterate()
 $wnd.google.language.transliterate(inputWords, "en", "sa", function(result) {
   if (!result.error) {
   if (result.transliterations && result.transliterations.length > 0 &&
       result.transliterations[0].transliteratedWords.length > 0) {
      var trans = result.transliterations[0].transliteratedWords[0];
 
  var outputWords = new Array();

for(var i =0; i<result.transliterations.length; i++)
{
var transliteration = result.transliterations[i];
outputWords[i] = transliteration.transliteratedWords[0];
}
  jSTransliterateObjArg.@org.bvp.be.client.JSTransliterate::handleResult(Lcom/google/gwt/core/client/JsArrayString;)(outputWords);
       }
   }
 });//ends transliterate call

}-*/;

/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);


final HTML serverResponseLabel = new HTML();

/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final Label errorLabel = new Label();

// We can add style names to widgets
sendButton.addStyleName("sendButton");

// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);

// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();

// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);

// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
sendButton.setEnabled(true);
sendButton.setFocus(true);
}
});

final JSTransliterate jsTransliterateObj = this;

// Create a handler for the sendButton and nameField
class MyHandler implements ClickHandler, KeyUpHandler {
/**
* Fired when the user clicks on the sendButton.
*/
public void onClick(ClickEvent event) {
sendNameToServer();
}

/**
* Fired when the user types in the nameField.
*/
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendNameToServer();
}
}

/**
* Send the name from the nameField to the server and wait for a response.
*/
private void sendNameToServer() {
// First, we validate the input.
errorLabel.setText("");
String textToServer = nameField.getText();
if (!FieldVerifier.isValidName(textToServer)) {
errorLabel.setText("Please enter at least four characters");
return;
}

// Then, we send the input to the server.
sendButton.setEnabled(false);
textToServerLabel.setText(textToServer);
serverResponseLabel.setText("");
greetingService.greetServer(textToServer,
new AsyncCallback<List<String>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox
.setText("Remote Procedure Call - Failure");
serverResponseLabel
.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR);
dialogBox.center();
closeButton.setFocus(true);
}

public void onSuccess(List<String> wordsArray) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel
.removeStyleName("serverResponseLabelError");
//serverResponseLabel.setHTML(result);
dialogBox.center();
closeButton.setFocus(true);
// alert("Success");

JsArrayString jsArrayStr = (JsArrayString) JsArrayString.createArray();
 
for (int i = 0; i < wordsArray.size(); ++i) {
       jsArrayStr.set(i, wordsArray.get(i));
     }

transliterate(jsArrayStr, jsTransliterateObj);
}
});
}
}

// Add a handler to send the name to the server
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}
}

Modified GWT sample module code - using JSNI - call JS method from JAVA - call JAVA method from JS


/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class JSTransliterate implements EntryPoint {

public void handleResult(JsArrayString list){
serverResponseLabel.setHTML(list.get(0) + ":" + list.get(1));
}
public static native void alert(String msg) /*-{
 $wnd.alert(msg);
}-*/;

public native void transliterate(JsArrayString words) /*-{
 $wnd.alert(words[1]);
 var ret = ["ret1", "ret2", "ret3"];
 this.@org.bvp.be.client.JSTransliterate::handleResult(Lcom/google/gwt/core/client/JsArrayString;)(ret);
}-*/;

/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);


final HTML serverResponseLabel = new HTML();

/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
nameField.setText("GWT User");
final Label errorLabel = new Label();

// We can add style names to widgets
sendButton.addStyleName("sendButton");

// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("errorLabelContainer").add(errorLabel);

// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();

// Create the popup dialog box
final DialogBox dialogBox = new DialogBox();
dialogBox.setText("Remote Procedure Call");
dialogBox.setAnimationEnabled(true);
final Button closeButton = new Button("Close");
// We can set the id of a widget by accessing its Element
closeButton.getElement().setId("closeButton");
final Label textToServerLabel = new Label();
VerticalPanel dialogVPanel = new VerticalPanel();
dialogVPanel.addStyleName("dialogVPanel");
dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
dialogVPanel.add(textToServerLabel);
dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
dialogVPanel.add(serverResponseLabel);
dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
dialogVPanel.add(closeButton);
dialogBox.setWidget(dialogVPanel);

// Add a handler to close the DialogBox
closeButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
sendButton.setEnabled(true);
sendButton.setFocus(true);
}
});

// Create a handler for the sendButton and nameField
class MyHandler implements ClickHandler, KeyUpHandler {
/**
* Fired when the user clicks on the sendButton.
*/
public void onClick(ClickEvent event) {
sendNameToServer();
}

/**
* Fired when the user types in the nameField.
*/
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendNameToServer();
}
}

/**
* Send the name from the nameField to the server and wait for a response.
*/
private void sendNameToServer() {
// First, we validate the input.
errorLabel.setText("");
String textToServer = nameField.getText();
if (!FieldVerifier.isValidName(textToServer)) {
errorLabel.setText("Please enter at least four characters");
return;
}

// Then, we send the input to the server.
sendButton.setEnabled(false);
textToServerLabel.setText(textToServer);
serverResponseLabel.setText("");
greetingService.greetServer(textToServer,
new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
dialogBox
.setText("Remote Procedure Call - Failure");
serverResponseLabel
.addStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(SERVER_ERROR);
dialogBox.center();
closeButton.setFocus(true);
}

public void onSuccess(String result) {
dialogBox.setText("Remote Procedure Call");
serverResponseLabel
.removeStyleName("serverResponseLabelError");
serverResponseLabel.setHTML(result);
dialogBox.center();
closeButton.setFocus(true);
// alert("Success");
JsArrayString list = (JsArrayString) JsArrayString.createArray();
list.push("str1");
list.push("str2");
list.push("str3");
transliterate(list);
}
});
}
}

// Add a handler to send the name to the server
MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);
}
}