Redoing Guestbook example with Stripes

Google has created an example on how to use google app engine with java. In this example they demonstrate the basic usage of Servlet API and JDO, it’s a simple example that stores, retrieves and renders entities in google app engine.
After the first tutorial on how to deploy Stripes in google app engine I decided to re-write this example using the Stripes framework of course.

Download the source code!

Steps:

1. Create a project and name it Guestbook

2. Follow the Getting started with Stripes and google app engine to configure Stripes

3. Add the JSTL jars (standard.jar and jstl.jar) in the lib directory

4. Create an ActionBean that will handle the greeting requests


package com.guestbook.action;

import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.guestbook.manager.PMF;
import com.guestbook.model.Greeting;

/**
 * @author 110j
 */
public class GreetingActionBean implements ActionBean {
	private static final String VIEW = "/guestbook.jsp";
	private ActionBeanContext ctx;
	private UserService userService = UserServiceFactory.getUserService();
	private Greeting greeting;

	@DefaultHandler
	public Resolution welcome() {
		return new ForwardResolution(VIEW);
	}

	public Resolution addGreeting() {
		if (greeting != null) {
			greeting.setAuthor(getUser());
			greeting.setDate(new Date());

			PersistenceManager pm = PMF.get().getPersistenceManager();
	        try {
	            pm.makePersistent(greeting);
	        } finally {
	            pm.close();
	        }
		}
		return new ForwardResolution(VIEW);
	}

	public Resolution signin() {
		ForwardResolution fd = new ForwardResolution(VIEW);
		if (!userService.isUserLoggedIn())
			fd = new ForwardResolution(userService.createLoginURL("/Greeting.action"));
		return fd;
	}

	public Resolution signout() {
		ForwardResolution ForwardResolution ">fd = new ForwardResolution(VIEW);
		if (userService.isUserLoggedIn())
			fd = new ForwardResolution(userService.createLogoutURL("/Greeting.action"));
		return fd;
	}

	@SuppressWarnings("unchecked")
	public List getGreetings() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String query = "select from " + Greeting.class.getName() + " order by date desc range 0,5";
	    return (List) pm.newQuery(query).execute();
	}

	public Greeting getGreeting() {
		return greeting;
	}

	public void setGreeting(Greeting greeting) {
		this.greeting = greeting;
	}

	public User getUser() {
		return userService.getCurrentUser();
	}

	public ActionBeanContext getContext() {
		return this.ctx;
	}

	public void setContext(ActionBeanContext ctx) {
		this.ctx = ctx;
	}
}

5. Create the model class called Greeting (as described in the google example, no changes here!)


package com.guestbook.model;

import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.users.User;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Greeting {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private User author;

    @Persistent
    private String content;

    @Persistent
    private Date date;

    public Greeting() {}

    public Greeting(User author, String content, Date date) {
        this.author = author;
        this.content = content;
        this.date = date;
    }

    public Long getId() {
        return id;
    }

    public User getAuthor() {
        return author;
    }

    public String getContent() {
        return content;
    }

    public Date getDate() {
        return date;
    }

    public void setAuthor(User author) {
        this.author = author;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

6. Create the utility class that will instantiate the EntityManager (no changes here also!)

package com.guestbook.manager;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
    private static final PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

    private PMF() {}

    public static PersistenceManagerFactory get() {
        return pmfInstance;
    }
}

7. Modify the guestbook.jsp, there are a lot of changes here since in their example google uses scriptlets, I have replaced the scriptlets with jstl tags and Stripes tags, all the logic has moved to the ActionBean.

8. Modify the welcome file list in the web.xml and set as welcome file the Greeting.action

Download the source code!

Getting started with Stripes & Google App Engine

This is a basic example of using Stripes Framework with the cloud infrastructure of Google. I am using Stripes in one of my projects that I am thinking to move it to google app engine so I decided to experiment before the migration. More posts will follow in this topic as I progress with it. The first objective is to create the basic project structure, configure and deploy, well… a hello world web application. This is a trivial application but there are some limitations using google app engine so trying to use the framework as is will fail with some non-sense stack traces.

The following is a list of things that we will be need to complete this application:
1. Stripes Framework (home page: http://www.stripesframework.org/display/stripes/Home )
2. Google app engine sdk – if you use eclipse and google plugin the sdk is included in the plugin.
3. Eclipse (you can use whatever IDE or environment you like, it’s not mandatory to use eclipse, it’s just easier).

Note: For information on how to install the google plugin visit http://code.google.com/appengine/docs/java/tools/eclipse.html

I assume you are familiar with java web frameworks and that you will use eclipse with the google plugin.

The first step is to create a project in the eclipse IDE:

Give a name to the project and an initial package name. For the moment we do not need GWT so just deselect it.

After pressing finish we have the following project structure.

Before continuing copy the Stripes jars in the the lib directory under hello_project/web/WEB_INF/lib and add them to the project’s build path by selecting them, right click-> Build Path -> Add to Build Path. Also copy and paste the StripesResources.properties in the directory “src” (not in a package).

By default the google plugin will generate a servlet for us, under the package name that we entered in the previews step. It will also generate the following configuration files:
Servlet spec requirement:
1. web.xml (this is the well known deployment descriptor required by the servlet specification)

Google App engine specific (we will not use them for this application):
1. appengine-web.xml
2. jdoconfig.xml

Logging property files:
1. log4j.properties
2. logging.properties

For the purpose of this trivial application we will only need to edit the web.xml (a.k.a Deployment Descriptor so from know on I will call it DD).
By default the plugin registers the generated servlet in the DD, so open the DD and delete the servlet and servlet-mapping it’s not needed.

The following is the generated DD that need to be edited:

The following is the new and final DD containing the Stripes filter and dispatcher servlet:

Note that the web-app tag version has changed from 2.5 to 2.4 there are some jsp exceptions with the 2.5.

The Stripes filter includes two initial parameters the ActionResolver.Packages which tells Stripes where to find the ActionBeans (more on this in next post or in Stripes documentation) and the MultipartWrapperFactory.Class, a factory class used to upload files, but uploading files is not supported by google app engine and the Stripes filter will fail to initialize. Therefore we need to disable this by providing an empty configuration.

The first step to disable file uploading is to add MultipartWrapperFactory.Class initial parameter to the Stripes filter as shown in the DD and the second step is to create the appropriate class. So create a package in the project (I created the com.helloworld.exclude but you can create anything that make sense for your project) and add the following class:


import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
import net.sourceforge.stripes.controller.multipart.MultipartWrapper;
import net.sourceforge.stripes.config.ConfigurableComponent;
import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;

/**
 * GAE does not support file uploading so we need to disable this feature from Stripes.
 *
 * @author 110j
 */
public class EmptyMultipartWapper implements ConfigurableComponent, MultipartWrapperFactory {

	/**
	 * @see net.sourceforge.stripes.config.ConfigurableComponent#init(net.sourceforge.stripes.config.Configuration)
	 */
	public void init(Configuration conf) throws Exception {
	}

	/**
	 * @see net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory#wrap(javax.servlet.http.HttpServletRequest)
	 */
	public MultipartWrapper wrap(HttpServletRequest request) throws IOException, FileUploadLimitExceededException {
		return null;
	}
}

Now that we disabled the file uploading lets create an ActionBean that will handle our request. Create a package in the project called com.helloworld.action and add the following class:


package com.helloworld.action;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;

/**
 * The action bean that will handle the our simple request.
 *
 * @author 110j
 */
public class EasyActionBean implements ActionBean {
	private static final String VIEW = "/WEB-INF/jsp/hello_world.jsp";
	private static final String MY_MESSAGE = "hello world";
	private ActionBeanContext ctx;

	private String message;

	@DefaultHandler
	public Resolution showMe() {
		this.setMessage(MY_MESSAGE);
		return new ForwardResolution(VIEW);
	}

	/**
	 * @see net.sourceforge.stripes.action.ActionBean#getContext()
	 */
	public ActionBeanContext getContext() {
		return this.ctx;
	}

	/**
	 * @see net.sourceforge.stripes.action.ActionBean#setContext(ActionBeanContext)
	 */
	public void setContext(ActionBeanContext ctx) {
		this.ctx = ctx;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * @param message the message to set
	 */
	public void setMessage(String message) {
		this.message = message;
	}
}

Next lets create a jsp file that will render the response, create the hello_world.jsp under WEB_INF/jsp/ and add the following content:

Finally create a welcome file called index.jsp if it does not exist or rename the index.html to index.jsp and add just a forward to the action:

You can delete the servlet generated by the google plugin there is no need for it.

In order to test it you just need to run the hello_world in the Run history of eclipse as the google plugin will create one for us, or under the run button in the toolbar, and then visit the address localhost:8080

NOTE: if your application require session you need to enable it in the appengine-web.xml since it is disabled by default (but keep in mind the implication it may have in a distributed environment such as google app engine, maybe your attributes will need to implement the HttpSessionActivationListener if you plan to add them in the session).

You can upload your application by using eclipse or the command line tool, for more information visit http://code.google.com/appengine/docs/java/gettingstarted/uploading.html

To be continued!

javafx on google app engine

Two weeks ago I started to work with python and the django framework in order to deploy a web application in google app engine. (I am really amazed of how fast you can build web applications with python & django – but this will be another post :)

Since JavaFX is my favorite RIA technology I was wondering if we can deploy javafx applications on google app engine. So I started a new project and after 20 minutes it was ready. What surprised me the most is the fact that it is really easy to deploy javafx applications into google app engine. Keep in mind, however, that this is a simple example and I don’t  access the database or other services that are offered by google app engine (maybe I will try that next year ;) .

What you really need to do is to pack your javafx application as an applet and place it under a folder in the google app engine application, declare that folder as a static resource in the app.yaml configuration file and finally use python to write it to the response.

Lets go through it step by step:

1. Create your javafx application and pack it as applet. For this example I will use the SpringAnimation of Josh Marinacci which you can find it here http://javafx.com/samples/SpringAnimation/index.html

2. Create a google app engine application. Instructions on how to create an app engine application can be found here
I have ported the google app engine application into eclipse and it looks something like this:

The most important files are the app.yaml where we need to declare that the javafx folder will serve static files and the mainapp.py python file which will serve our application.

Lets see the app.yaml file

So in the app.yaml configuration file we tell app engine that the application name is javafxtest, we declare the static folder under the handlers and we configure all the urls to be forwarded to the python file mainapp.py

Lets have a look at the python file

The content of this file is straightforward, we just write html code to the response. Note how we refer to the jar file and the folder that servers the static files. In the same folder with the jar file there is also the SpringAnimation_browser.jnlp file, we have to edit this file and change the codebase to the appropriate one (for me it was codebase=”http://localhost:9999/javafx/“) to test the application locally before uploading it, when you are about to upload it, change the codebase to the url of the app engine (for me it is codebase=”http://javafxtest.appspot.com/javafx”)

3. Upload the application in the app engine. The command to upload the application is python appcfg.py update <PROJECT_PATH>\JavaFXonGAE\src enter the email address and the password. You need to create an account if you do not have one.
You can find more info on how to deploy app engine applications here

You can access the application at http://javafxtest.appspot.com/

Resources:
Google app engine: http://code.google.com/appengine/docs/gettingstarted/
JavaFX: http://javafx.com/samples/SpringAnimation/index.html