Google App Engine for Java Demo Application

April 30th, 2009

ae_gwt_java2Google App Engine for Java was released a couple of weeks ago and I finally found some time to finish up my first demo application. My original idea was to do a Java version of the Salesforce.com demo that I did in Python on Google App Engine, but I quickly found out that Google App Engine for Java does not support Web services. Hopefully there will be a workaround from Salesforce.com sometime in the near future to make this possible.

This demo has the same functionality as the Python version except that it uses BigTable as the datastore instead of Salesforce.com.

You can run this demo at:

http://jeffdouglas-java1.appspot.com

A couple of observations from this early look:

  1. The documentation is pretty good and really gets you up and going quickly.
  2. If you already have Eclipse running, the Google Plugin for Eclipse is a breeze to install.
  3. The development environment is really slick. The development server (Jetty) runs your application on your local computer for development and testing. The server simulates the App Engine datastore, services and sandbox restrictions.
  4. You can access BigTable with JDO or JPA. I choose JDO as most of the documentation uses this implementation. If you are familiar with Hibernate then JDO is fairly simple to grok.
  5. You can use Google Accounts for account creation and authentication. I didn’t use this service but it looks pretty slick.
  6. Google has included a simple Guestbook app to get you started.

The Google App Engine Dashboard is very feature-rich and intuitive. I think it gives the Amazon’s EC2 Console a run for its money.

ishot-4

The Google Plugin for Eclipse makes deploying the application to Google’s servers simple-stupid. If you’ve ever had to configure Tomcat, JBoss or Websphere, you’ll really enjoy the simplicity of the process. However, when creating a new application, make sure you do so through the Dashboard first before deploying it.

Eclipse Plugin

You can download the source for the application here, but here is the real meat of the application, the Servlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
 
package com.jeffdouglas;
 
import java.io.IOException;
import javax.servlet.http.*;
 
import java.util.Date;
import java.util.List;
import java.text.DateFormat;
import javax.servlet.*;
import javax.jdo.PersistenceManager;
import com.jeffdouglas.entity.*;
 
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
 
@SuppressWarnings("serial")
public class TelesalesServlet extends HttpServlet {
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        // create the persistence manager instance
        PersistenceManager pm = PMF.get().getPersistenceManager();
 
        // display the lookup form
        if(request.getParameter("action").equals("accountLookup")) {
 
            // query for the entities by name
            String query = "select from " + Account.class.getName() + " where name == '"+request.getParameter("accountName")+"'";
            List accounts = (List) pm.newQuery(query).execute();   
 
            // pass the list to the jsp
            request.setAttribute("accounts", accounts);
            // forward the request to the jsp
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/accountLookup.jsp");
            dispatcher.forward(request, response);   
 
        // display the create new account form   
        } else if(request.getParameter("action").equals("accountCreate")) {
            response.sendRedirect("/accountCreate.jsp");
 
        // process the new account creation and send them to the account display page   
        } else if(request.getParameter("action").equals("accountCreateDo")) {
 
            // create the new account
            Account a = new Account(
                    request.getParameter("name"),
                    request.getParameter("billingCity"),
                    request.getParameter("billingState"),
                    request.getParameter("phone"),
                    request.getParameter("website")
                );
 
            // persist the entity
            try {
                pm.makePersistent(a);
            } finally {
                pm.close();
            }
 
            response.sendRedirect("telesales?action=accountDisplay&accountId="+a.getId());
 
        // display the account details and opportunities   
        } else if(request.getParameter("action").equals("accountDisplay")) {
 
            // fetch the account
            Key k = KeyFactory.createKey(Account.class.getSimpleName(), new Integer(request.getParameter("accountId")).intValue());
            Account a = pm.getObjectById(Account.class, k);
 
            // query for the opportunities
            String query = "select from " + Opportunity.class.getName() + " where accountId == "+request.getParameter("accountId");
            List opportunities = (List) pm.newQuery(query).execute();   
 
            // pass the list to the jsp
            request.setAttribute("account", a);
            // pass the list to the jsp
            request.setAttribute("opportunities", opportunities);
 
            // forward the request to the jsp
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/accountDisplay.jsp");
            dispatcher.forward(request, response);   
 
        // display the create new opportunity form   
        } else if(request.getParameter("action").equals("opportunityCreate")) {
 
            Key k = KeyFactory.createKey(Account.class.getSimpleName(), new Integer(request.getParameter("accountId")).intValue());
            Account a = pm.getObjectById(Account.class, k);
 
            // pass the account name to the jsp
            request.setAttribute("accountName", a.getName());
            // forward the request to the jsp
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/opportunityCreate.jsp");
            dispatcher.forward(request, response);
 
        // process the new opportunity creation and send them to the account display page 
        } else if(request.getParameter("action").equals("opportunityCreateDo")) {
 
            Date closeDate = new Date();
 
            // try and parse the date
            try {
                DateFormat df = DateFormat.getDateInstance(3);
                closeDate = df.parse(request.getParameter("closeDate"));
            } catch(java.text.ParseException pe) {
                System.out.println("Exception " + pe);
            }
 
            // create the new opportunity
            Opportunity opp = new Opportunity(
                request.getParameter("name"),
                new Double(request.getParameter("amount")).doubleValue(),
                request.getParameter("stageName"),
                new Integer(request.getParameter("probability")).intValue(),
                closeDate,
                new Integer(request.getParameter("orderNumber")).intValue(),
                new Long(request.getParameter("accountId"))
            );
 
            // persist the entity
            try {
                pm.makePersistent(opp);
            } finally {
                pm.close();
            }
 
            response.sendRedirect("telesales?action=accountDisplay&accountId="+request.getParameter("accountId"));
 
        }
 
    }
 
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        doGet(request, response);
    }
 
}

Categories: Google App Engine, Java, Salesforce

Leave a comment

Comments Feed11 Comments

  1. Quick scan of the net - engine dispatcher « Engine Dispatchers Objective Opinion

    [...] http://blog.jeffdouglas.com/2009/04/30/google-app-engine-for-java-demo-app/getRequestDispatcher(”/opportunityCreate.jsp”); dispatcher.forward(request, response); // process the new opportunity creation and send them to the account display page } else if(request. … [...]

  2. James

    Hi Jeff

    What a great little project – this is just what I needed to get me going.

    Thanks – you’re a live saver, great blog btw!

    James

  3. Donnie Demuth

    Thank goodness. I’ll probably be able to put something up today or tomorrow after playing with your app! I wish some of this was covered in GAE-J’s reference docs. I really appreciate the time you put in to share your app.

  4. Thomas Lukasik

    I’ve had an issue with some of my code that recently stopped working (a simple query does not return any data) since upgrading to the latest GAE SDK and Eclipse plugin. In an attempt to troubleshoot the problem I ran your Telesales example on 2 different workstations – one where my code works and one where it has stopped working. Your Telesales example seems to exhibit the same behavior, working on the earlier SDK and not working with the latest one. Have you experienced anything like this?

  5. jeffdonthemic

    I haven’t noticed anything yet but I’ll definitely take a look. Thanks for the heads up.

  6. Belman

    Hi Sir Jeff,
    Thank you for sharing this demo app.
    This helped me a lot in my project using GAE for Java.

  7. leslie

    i am new in learn GAE for java. but i have a problem with jdo
    would u help me

  8. Brian Boelsterli

    Hi Jeff,
    I’m plowing through your book “Beginning Java Google App Engine”. Im having trouble figuring out where the code is. Especially starting with Chapter 4. I’ve plowed through the book about 10 times now and all I see is a reference to the google app engine sdk. Unfortunately, there is no code there. Please advise. Thanks!

  9. Siva

    Can you please help me with running this? So far, this is what I have done.

    I downloaded your project zip, imported it into eclipse and used ‘Run> Debug As> WebApplication’. The server started. But when I navigate to http://localhost:8888 (which is where it said it started the server), I get the following error. Can’t able to find which part of the code is generating it.

    and this is what I got.

    HTTP ERROR 500

    Problem accessing /telesales. Reason:

    INTERNAL_SERVER_ERROR

    Caused by:

    java.lang.NullPointerException
    at com.jeffdouglas.TelesalesServlet.doGet(TelesalesServlet.java:26)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:351)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

    Powered by Jetty://

  10. Siva

    Something is very wrong. I just realized that there is no login method or some kind of credentials even to authenticate, leave aside the error in any file in the project.

  11. Jeff Douglas

    Siva, it uses the web services api therefore the credentials are hardcoded into the app.

Leave a comment

Feed

http://blog.jeffdouglas.com / Google App Engine for Java Demo Application

WordPress Appliance - Powered by TurnKey Linux