Hello World using Google AppEngine

I’m looking into the various cloud-hosting providers, so I’m creating a quick and simple Hello World project to see how well they work. This post is for Google’s AppEngine, which provides a free usage tier which is enough to see how well it works.

I develop on a Mac using IntelliJ, so I’m not using the Eclipse IDE** and can’t use their plugin.

First, sign up to get a Google Cloud account, and create an app. You’ll need the application ID later.

Next, your Maven file, which instructs Maven to build into a WAR file, and lists the runtime dependencies for your app atop Google AppEngine. And, in the plugins section it adds the helpers for Maven so it can recognise the ‘appengine’ targets.

This file lives in the project root as pom.xml:-

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
<!--?xml version="1.0" encoding="UTF-8"?-->
 
    4.0.0
 
    uk.co.devsoup.gae
    helloworld
    1.0-SNAPSHOT
 
    <!-- AppEngine uses WAR files -->
    war
 
 
 
            com.google.appengine
            appengine-api-1.0-sdk
            1.8.9
 
 
            javax.servlet
            servlet-api
            2.5
            provided
 
 
 
    <!-- Needed to make enable Maven to recognise the AppEngine targets -->
 
 
 
                com.google.appengine
                appengine-maven-plugin
                1.8.9

4.0.0

uk.co.devsoup.gae
helloworld
1.0-SNAPSHOT

<!– AppEngine uses WAR files –>
war

com.google.appengine
appengine-api-1.0-sdk
1.8.9

javax.servlet
servlet-api
2.5
provided

<!– Needed to make enable Maven to recognise the AppEngine targets –>

com.google.appengine
appengine-maven-plugin
1.8.9

Then you’ll want a Main class (note that I’m using a Servlet, not JSPs to output HTML) in the Standard Directory Layout location.

Here, mine is located in src/main/java/uk/co/devsoup/gae/helloworld/Main.java:-

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
package uk.co.devsoup.gae.helloworld;
 
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Java class which outputs HTML to demo that the code works.
 */
public class Main extends HttpServlet implements Servlet {
    /**
     * Constructor.
     */
    public Main() {
        // Does nothing at present
    }
 
    /**
     * Handle GET requests.
     *
     * @param request  The incoming request object.
     * @param response The outgoing response to modify to incude our custom data.
     *
     * @throws ServletException
     * @throws IOException
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("");
        out.println("Hello from DevSoup");
        out.println("DevSoup's Java Servlet says hello");
        out.println("");
        out.close();
    }
}

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Java class which outputs HTML to demo that the code works.
*/
public class Main extends HttpServlet implements Servlet {
/**
* Constructor.
*/
public Main() {
// Does nothing at present
}

/**
* Handle GET requests.
*
* @param request The incoming request object.
* @param response The outgoing response to modify to incude our custom data.
*
* @throws ServletException
* @throws IOException
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("");
out.println("Hello from DevSoup");
out.println("DevSoup’s Java Servlet says hello");
out.println("");
out.close();
}
}

You’ll want the ubiquitous deployment descriptor to map all requests to my given Main class. This is located src/main/webapp/WEB-INF/web.xml:-

1
2
3
4
5
6
7
8
 
        devsoup-gae_helloworld
        uk.co.devsoup.gae.helloworld.Main
 
 
 
        devsoup-gae_helloworld
        /*

devsoup-gae_helloworld
/*

In addition, Google requires a simple AppEngine deployment descriptor, located src/main/webapp/WEB-INF/appengine-web.xml:-

1
2
3
4
5
<!--?xml version="1.0" encoding="utf-8"?-->
 
    %%YOUR_APP_ID_HERE%%
    1
    true

%%YOUR_APP_ID_HERE%%
1
true

Remember to fill in the application tag with your application id (which you specified when you created a project in the Google Cloud Console).

And that’s it. If you do

1
mvn appengine:devserver

it’ll run up a local copy of your app on your system.

If you want to deploy to Google’s infrastructure, then do

1
mvn appengine:update

When I did this, it failed to deploy first time and rolled back after 5 minutes. I simply did it again and it worked fine. You can get the URL to test the app via the Cloud Console.

If you get

1
2
404 Not Found
This application does not exist (app_id=u'%%YOUR_APP_ID%%').

then it’s likely you’re logged into the wrong Google Account to do the deployment. Simply rename/remove the ~/.appcfg_oauth2_tokens_java file and try again.

Code is available at https://github.com/devsoup/GoogleAppEngine-HelloWorld/releases/tag/v1.0.0.

Currently, the app is deployed at http://devsoup-gae-helloworld.appspot.com/ (may be removed depending on usage tiers).

(** I don’t like Eclipse too much either – it does far too much, and is very heavyweight on system resources)

This is my personal blog - all views are my own.

Tagged with: , , ,