Posts Tagged ‘Google App Engine’

How to use and retain Twitter4J OAuth access token

March 1st, 2010

I  stuck in a problem that how to re use access token, once user has authenticated by Twitter (on call back URL). I got it working. There was problem in my understanding about request token vs access token. When user first time comes on call backed URL. I take request token and token secret from session and prepare the access token. Here the place where I was confused.

Now if user presses the refresh button or you want to get user information again from twitter any where in your application. You need to use the access token and this method twitter.setOAuthAccessToken(String1, String2). Because user has already been authenticated by Twitter. You can save this information in session.

HttpSession session = request.getSession();

twitter.setOAuthConsumer(Constants.CONSUMER_KEY,Constants.CONSUMER_SECRET);

if (session.getAttribute("aToken") == null){
	// request token
	String token = (String) session.getAttribute("token");
	String tokenSecret = (String)session.getAttribute("tokenSecret");
	AccessToken accessToken =
		twitter.getOAuthAccessToken(token, tokenSecret);
	twitter.setOAuthAccessToken(accessToken);

	// save the access token, that are different from request token
	session.setAttribute("aToken", accessToken.getToken());
	session.setAttribute("aTokenSecret", accessToken.getTokenSecret());

}else{
	// use the access token to authenticate user whenever you want
	twitter.setOAuthAccessToken((String)session.getAttribute("aToken"),
		(String)session.getAttribute("aTokenSecret"));
}
User user = twitter.verifyCredentials();

If you are also developing some app by using Twitter4J API on Google App Engine. Please give feedback on it.

Twitter4J Quick Tutorial: A quick tutorial on how to develop Twitter app by using Twitter4J on Google App Engine.

Useful cheat sheets on Cloud Computing and Google App Engine for Java

January 12th, 2010

google_app_engine_javaJust read cheat sheets (Refcard) by Dzone on Cloud Computing and Google App Engine for Java. They contain a very jumped to the point and quick reference on these things. You can read to have a quick overview.

Read them here:

Got two books on Google App Engine for Java

December 28th, 2009

Recently I got two books on Google App Engine for Java. Programming Google App Engine by Oreilly and Beginning Google App Engine by Apress. There is less material and comprehensive online tutorials available on this. So its better that you read book on it. I started reading Oreilly’s book. I completed some of the basic components so quickly by given code examples in the book. Its always a good start on some new technology, if you have books in your pocket.

You guys can share your feedback if you read any book or any material on it.

Apress_Beginning_Google_App_Engine

Oreilly_GoogleAppEngin

Spoken on Google App Engine at a conference in UET

December 19th, 2009

Today I had delivered a workshop on Developing Java Web Applications In Google App Engine. This workshop was the part of events of 3rd International Conference on Open Source Systems and Technologies. It was organized by Al-Khawarizmi Institute of Computer Science , University of Engineering and Technology, Lahore.

I have presented following slides there. Also coded a basic sample application to show how to create and deploy new Java project on GAE. Which can send emails, how to use authentication by Google, and how to do database interaction. It was a very intresting topic for me to present. Participants also liked it.

Comments and feedback is welcomed on the presentation material from you guys.

Tutorial: JPA on Google App Engine

December 13th, 2009

This project will create and delete an entity record. I have chosen JPA for datastore in app engine. You can also look JDO for this purpose. But my choice to go for JPA is due to Sun standardization on it.

I am using App Engine SDK version 1.2.18

Project name: engineplay
URL: http://engineplay.appspot.com

Project structure:

jpa_gae_project_structureUserPrefs.java: The entity class

package com.engineplay.datastore.pojos;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import com.engineplay.datastore.EMFService;
import com.google.appengine.api.users.User;

@Entity(name = "UserPrefs")
public class UserPrefs {
 @Id
 private String userId;
 private int donuts;
 @Basic
 private User user;

 public UserPrefs(String userId) {
 this.userId = userId;
 }

 /* TODO create getter and setters for above properties yourself */

 public static UserPrefs getPrefsForUser(User user) {
 UserPrefs userPrefs = null;
 EntityManager em = EMFService.get().createEntityManager();
 try {
 if (em.find(UserPrefs.class, user.getEmail()) == null) {

 userPrefs = new UserPrefs(user.getEmail());
 userPrefs.setUser(user);

 } else {
 userPrefs = em.find(UserPrefs.class, user.getEmail());
 }
 } finally {
 em.close();
 }
 return userPrefs;
 }

 public void save() {
 EntityManager em = EMFService.get().createEntityManager();
 try {
 em.persist(this);
 } finally {
 em.close();
 }
 }

 public void remove() {
 EntityManager em = EMFService.get().createEntityManager();
 try {
 UserPrefs userPrefs = em.find(UserPrefs.class, user.getEmail());
 em.remove(userPrefs);
 } finally {
 em.close();
 }
 }
}

EMFService.java: The class to create EntityManagerFactory instance.

package com.engineplay.datastore;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EMFService {
 private static final EntityManagerFactory emfInstance = Persistence
 .createEntityManagerFactory("transactions-optional");

 private EMFService() {
 }

 public static EntityManagerFactory get() {
 return emfInstance;
 }
}

LoginServlet.java

package com.engineplay.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.engineplay.datastore.pojos.UserPrefs;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class LoginServlet extends HttpServlet {

 public void doGet(HttpServletRequest req, HttpServletResponse resp)
 throws IOException {

 UserService userService = UserServiceFactory.getUserService();
 User user = userService.getCurrentUser();
 String navBar, form = null;
 int donuts = 0;
 if (user == null) {
 navBar = "<p>Welcome! <a href=\"" + userService.createLoginURL("/") +
 "\">Sign in or register</a> to customize.</p>";
 form = "";
 } else {
 UserPrefs userPrefs = UserPrefs.getPrefsForUser(user);

 if (userPrefs != null) {
 donuts = userPrefs.getDonuts();
 }
 navBar = "<p>Welcome, " + user.getEmail() + "! You can <a href=\"" +
 userService.createLogoutURL("/") +
 "\">sign out</a>.</p>";
 form = "<form action=\"/donuts\" method=\"post\">" +
 "<label for=\"donuts\">" +
 "Need more donuts?:" +
 "</label>" +
 "<input name=\"donuts\" id=\"donuts\" type=\"text\" size=\"4\" />" +
 " <input name=\"olddonuts\"  type=\"hidden\" value=\"" + donuts + "\" /> " +
 " <input name=\"userId\"  type=\"hidden\" value=\"" +user.getEmail()+ "\" /> " +
 "   <input type=\"submit\" value=\"  ADD  \" /><br><input type=\"submit\"  name =\"deleteBtn\" value=\"  DELETE ME!  \" />" +
 "</form>";

 }
 resp.setContentType("text/html");
 PrintWriter out = resp.getWriter();
 out.print("<html><head><title>Engine Play - Donuts</title</head><body>");
 out.println(navBar);
 if (donuts != 0)
 out.println("<p>Donuts you have: " + donuts + "</p>");
 else
 out.println("<p> No donuts you have :(  </p>");
 out.println(form);
 out.print("</body></html>");
 }
}

DonutsServlet.java

package com.engineplay.servlet;

import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.engineplay.datastore.pojos.UserPrefs;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class DonutsServlet extends HttpServlet {

 public void doPost(HttpServletRequest req, HttpServletResponse resp)
 throws IOException {
 UserService userService = UserServiceFactory.getUserService();
 User user = userService.getCurrentUser();
 UserPrefs userPrefs = UserPrefs.getPrefsForUser(user);
 try {

 String deleteOpt = req.getParameter("deleteBtn");
 if (deleteOpt == null){
 int donuts = new Integer(req.getParameter("donuts")).intValue();
 int oldDonuts = new Integer(req.getParameter("olddonuts")).intValue();

 userPrefs.setDonuts(donuts + oldDonuts);
 userPrefs.save();
 }else{
 String userId = req.getParameter("userId");
 userPrefs.setUserId(userId);
 userPrefs.remove();
 }
 } catch (Exception e) {
 e.printStackTrace();
 }
 resp.sendRedirect("/Login");
 }
}

persistence.xml: Configuration file required for JPA

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"

 version="1.0">
 <persistence-unit name="transactions-optional">
 <provider>
 org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider
 </provider>
 <properties>
 <property name="datanucleus.NontransactionalRead"
 value="true" />
 <property name="datanucleus.NontransactionalWrite"
 value="true" />
 <property name="datanucleus.ConnectionURL"
 value="appengine" />
 </properties>
 </persistence-unit>
</persistence>

web.xml

<?xml version="1.0" encoding="utf-8"?>
<!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 xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">

 <servlet>
 <servlet-name>LoginServlet</servlet-name>
 <servlet-class>com.engineplay.servlet.LoginServlet</servlet-class>
 </servlet>
 <servlet>
 <servlet-name>DonutsServlet</servlet-name>
 <servlet-class>com.engineplay.servlet.DonutsServlet</servlet-class>
 </servlet>

 <servlet-mapping>
 <servlet-name>LoginServlet</servlet-name>
 <url-pattern>/Login</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
 <servlet-name>DonutsServlet</servlet-name>
 <url-pattern>/donuts</url-pattern>
 </servlet-mapping>

 <welcome-file-list>
 <welcome-file>Login</welcome-file>
 </welcome-file-list>
</web-app>

Access the project here: http://engineplay.appspot.com

run_gae_project

Upgrading to Google App Engine Java SDK 1.2.8

December 7th, 2009

I was getting following exception while trying to code my first interaction with JPA in Google App Engine.

org.datanucleus.metadata.InvalidMetaDataException:
Error in MetaData for field "user" in class "com.engineplay.datastore.pojos.UserPrefs" : this is declared as com.google.appengine.api.users.User with "persistence-modifier=none" yet has either "default-fetch-group=true" or "primary-key=true" specified! These should be false.

After some searching I came to know that I should upgrade my App Engine SDK. To get datanucleus-enhancer-1.1.4.jar. But when I upgraded my SDK from 1.2.0 to 1.2.8. I got following exception.

java.lang.RuntimeException: Unable to locate the App Engine agent. Please use dev_appserver, KickStart,  or set the jvm flag: "-javaagent:<sdk_root>/lib/agent/appengine-agent.jar"
at com.google.appengine.tools.development.DevAppServerFactory.testAgentIsInstalled(DevAppServerFactory.java:102)
at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(DevAppServerFactory.java:77)
at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(DevAppServerFactory.java:38)
Caused by: java.lang.NoClassDefFoundError: com/google/appengine/tools/development/agent/AppEngineDevAgent
at com.google.appengine.tools.development.DevAppServerFactory.testAgentIsInstalled(DevAppServerFactory.java:98)
... 6 more
Caused by: java.lang.ClassNotFoundException: com.google.appengine.tools.development.agent.AppEngineDevAgent
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
... 7 more

I got two problems to fix. First the JPA enhancer was not working and second I was unable to start my server through Eclipse.

Running the server was looking straight forward from the exception that I need to add extra VM arguments for all of my applications. Remember this, your previous application will not work unless you add these VM arguments seprately in their launcher configurations.

Following are the steps to do that.

1. Right click the project and select Run As –> Open Run Dialog.

gae-add-vm-arguments

2. Copy the message which you are getting in exception. This is exactly the same that we need to add in VM arguments section. The only addition we need to do is to add our SDK path.

gae-added-vm-arguments

3. Now if you run or debug your project. You server will run perfectly.

gae-server-run-success

Determine whether application is running on local server or App Engine

December 1st, 2009

If you are working on developing some application on Google App Engine. You may come up with such situation to switch your production code with your local dev code. Following is my solution for this problem. I have initialized a servlet from web.xml. That set appropriate value in a static boolean. I will use this boolean in whole of my application. I used getServletContext().getServerInfo().

Note: You must read App Engine docs about how they take load-on-startup.

App Engine supports the <load-on-startup> element for servlet declarations. However, the load actually occurs during the first request handled by the web server instance, not prior to it.

Following is my code snippet.

StartupServlet.java: A generic servlet. Which will be initialized when server starts.

public class StartupServlet extends GenericServlet {

public void init() {
String serverInfo = getServletContext().getServerInfo();
/* ServletContext.getServerInfo() will return "Google App Engine Development/x.x.x"
* if will run locally, and "Google App Engine/x.x.x" if run on production envoirnment */
if (serverInfo.contains("Development")) {
Constants.DEV_MODE = true;
}else {
Constants.DEV_MODE = false;
}
}

@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub

}
}

web.xml: Add following contents in it

  <servlet>
    <servlet-name>StartupServlet</servlet-name>
    <servlet-class>com.servlet.StartupServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

    <servlet-mapping>
    <servlet-name>StartupServlet</servlet-name>
    <url-pattern>/Startup</url-pattern>
  </servlet-mapping>

Now you can use Constants.DEV_MODE anywhere in your application. It will be true if you are on local server. And false if you are on GAE. For this constant you can make a class with name Constant and declare a static boolean with name DEV_MODE.

If you have anyother idea to implement this solution or you can help me to improve my one. Please drop your comments.

Domain is not working without www prefix in GAE

October 6th, 2009

The current issue I am working on is to make my naked domain http://mydomain.com to redirect to http://www.mydomain.com in Google App Engine. With www prefix I have configured my domain. But my naked domain is not working. I just found on Google support site that they are no more supporting naked URLs for their app engine.

According to Google support:

I’d like to map my app to http://myurl.com (also known as a naked domain).

Due to recent changes, Google App Engine no longer supports mapping your app to a naked domain. If your domain registrar supports URL redirects, you can redirect from http://yourdomain.com to your app, which can be served from domains like http://www.yourdomain.com or http://appid.yourdomain.com.

For instructions on how to configure a redirect for your Google Apps domain, please see the article on URL forwarding.

Issue can be resolved if Google provides us IP address and we set a A record pointing to that IP address. But they dont. :(

If you guys have idea how naked domain can be configured with this URL Forwarding thing please feel free to share. I will also update if I got this problem resolved.

Helpful resources:

How to avoid DeadlineExceededException in Google App Engine

October 3rd, 2009

If you are developing web application on Google App Engine for Java. And you dont know what this exception is. You can be in trouble. The container throws this exception for those requests which take time more than 30 seconds. In other words GAE wants every requests to be fullfilled within 30 seconds.

Case
I am developing a Twitter application and I got this exception when I login my Twitter user name. I have some 120 friends and 170 followers. So I need to fill two lists of Twitter users with their name and image URL. It was a bad practice from my side that I started populating lists in a loop which contain external service lookup overhead (Twitter) and also big in iteration. So I got following exception.
This request (670f658c2bf64b44) started at 2009/10/02 23:18:23.902 UTC and was still executing at 2009/10/02 23:18:52.605 UTC.

Possible solution
As for those users who have friends and followers in thousands, this problem will persist. So what I am thinking is to put lists in session. Populate the page with first 30 users. And give a link to next 30 (paginate). I will keep updating two variables in session which will tell start and end to pick the users from the list. I will use DWR for this. By this my every request will be responded by container with in 30 seconds.

If you guys have some more optimum solution for it, please share me. Another solution has been discussed here too.

Tutorial: Java based Twitter App on Google App Engine

October 3rd, 2009

google_app_engine_javaTwitter a microblogging service is getting more and more popular these  days. A lot of developers are involved to develop applications on its  API.

Two weeks ago I click with a very basic idea and being as a matter of learning I started working on it. I have finished more than 80% of the work. I deployed the application on Google App Engine (I hope you are familiar with it). I used Twitter4J lib a Java wrapper for Twitter API.

If you are also interested in Twitter based app development in Jave, then this tutorial will be helpful for you. Feel free to add comments at the end of the post, I will love to reply.

Things you require for development

Things you need to know before you start

Oauth authentication

You should know Oauth basics and its terminologies. You can little google on it or read this FAQs

Register an App with Twitter

You need to register an application on this URL: http://twitter.com/oauth. Please take care of two things. The call back URL will not be your localhost URL. It should be a valid web address. And while choosing Default Access Type, if your application need to do changes or send tweets then you should choose Read & Write otherwise/if you just want to do readonly operations then leave Read-only checked.

A little bit about Google App Engine

Google App Engine is cloud based hosting environment. You should read on their web or on a post by me.

Steps for any Twitter App

  1. User is on your website
  2. Generate a token
  3. Have a hyperlink and take user to the Twitter from your website for authentication
  4. User will enter its user name and passeword and press allow
    If user’s credentials authentiecated Twitter will call the callback method which you had mentioned. Note that localhost URLs will not work here. You need mentiona a valid web address which will be invoked when user will be authenticated.

Code Section

I will assume that you have developed a helloworld prject in Google App Engine and deployed it on appspot.com domain. Code snippet is available in 2 servlets and 1 jsp page.

LoginServlet.java

Twitter twitter = new Twitter();
twitter.setOAuthConsumer(Constants.CONSUMER_KEY,
Constants.CONSUMER_SECRET);
RequestToken requestToken  = twitter.getOAuthRequestToken();

String token = requestToken.getToken();
String tokenSecret = requestToken.getTokenSecret();

HttpSession session = request.getSession();
session.setAttribute("token", token);
session.setAttribute("tokenSecret", tokenSecret);

String authUrl = requestToken.getAuthorizationURL();

request.setAttribute("authUrl", authUrl);
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);

Consumer key and secrets will be generated when you register an application with Twitter. You need to keep token information into session so that you can use the token when callback URL will be called. authUrl is a link which will take user to the Twitter website for authentication. And if authentication successful it will call your URL mentioned as callback.

login.jsp

<a href='<%=request.getAttribute("authUrl") %>'>Sign in with Twitter</a>

HomeServlet.java (as callback URL)

Twitter twitter = new Twitter();
HttpSession session = request.getSession();

twitter.setOAuthConsumer(Constants.CONSUMER_KEY,
Constants.CONSUMER_SECRET);
AccessToken accessToken = twitter.getOAuthAccessToken(
(String) session.getAttribute("token"), (String) session
.getAttribute("tokenSecret"));
twitter.setOAuthAccessToken(accessToken);

User user = twitter.verifyCredentials();

HomeServlet is your callback. Let say you have mentioned URL mapping of this servlet as /Home. So you mention http://.appspot.com/Home in callback field in your app registeration page at twitter. And this HomeServlet will be called. Now you have the user object to play with. See Twitter4J javadocs for more help.

WEB-INF/appengine-web.xml

<sessions-enabled>true</sessions-enabled>

You need to add this tag in you appengine-web.xml file that you are enabling the session.

So this was a tutorial, feel free to ping me on it. If you stuck somewhere. We will both look into it.

I also suggest following links to you people to must visit them. They helps me a lot in the understanding and the development. I will update this tutorial if got more things to discuss.

Helpful Links