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.