You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Camel on Google App Engine Tutorial

Work in progress

This tutorial is still work in progress but already provides enough information to get a non-trivial Camel application running on GAE.

Overview

Goal of this tutorial is to get a Camel application running on Google App Engine that can send weather reports to user-defined email accounts. The user enters the name of a city and the email address of the report receiver into a form and submits it to the tutorial application. Retrieving weather data for that city and sending the weather report is done in the background.

Download

The packaged tutorial application can be (temporarily) downloaded from here. It is an Eclipse project that requires the Google Eclipse Plugin and the App Engine Java SDK 1.2.6 for running. A Maven-based version of the project should be available soon. The following sections describe how to build that application from scratch.

Create a GAE application

For setting up the Camel-independent parts of a GAE application refer to the Java Getting Started Guide in the GAE documentation. This tutorial uses the Google Plugin for Eclipse and the App Engine Java SDK 1.2.6. After installing the SDK and the plugin, create a new GAE project via File->New->Web Application Project.

After pressing Finish the new GAE project appears in the package explorer.

Add required libraries

The created project is not a Maven project so all required dependencies must be added manually to the war/WEB_INF/lib directory. These are

Then right-click on the Tutorial project and add these libraries to the classpath via Properties->Java Build Path->Libraries->Add JARs.... After adding they should now appear in the Referenced Libraries container.

Setup deployment descriptors

The deployment descriptors web.xml and appengine-web.xml are located in the war/WEB-INF directory.

web.xml

web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app 
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
    
    <servlet>
        <servlet-name>CamelServlet</servlet-name>
        <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>context.xml</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>CamelServlet</servlet-name>
        <url-pattern>/camel/*</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>CamelServlet</servlet-name>
        <url-pattern>/worker/*</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

appengine-web.xml

The <application> element in appengine-web.xml requires a GAE application name. In the following example, replace the value replaceme with a valid GAE application name.

appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>replaceme</application>
    <version>1</version>
	
    <!-- Configure java.util.logging -->
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
	
</appengine-web-app>

Setup the form

Users provide input data to the application by submitting form data. The following form definition should be stored in war/WEB-INF/index.html.

index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Weather Report</title>
</head>

<body>
<h1>Weather Report</h1>
<form action="camel/weather" method="post">
<table>
    <tr>
        <td>City:</td>
        <td><input type="text" name="city"></td>
    </tr>
    <tr>
        <td>Mailto:</td>
        <td><input type="text" name="mailto"></td>
    </tr>
    <tr>
        <td></td>
        <td align="right"><input type="submit" value="Submit" /></td>
    </tr>
</table>
</form>
</body>
</html>

When the user presses the Submit button the form data are POSTed to http://<appname>.appspot.com/camel/weather. The input field values will be available as in message headers city and mailto.

Setup the routes

Add the following TutorialRouteBuilder class to the org.apache.camel.example.gae package. The previously generated TutorialServlet in that package can be deleted.

TutorialRouteBuilder.java
package org.apache.camel.example.gae;

import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.gae.mail.GMailBinding;

public class TutorialRouteBuilder extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("ghttp:///weather")
            .to("gtask://default")
            .setHeader(Exchange.CONTENT_TYPE, constant("text/plain"))
            .transform(constant("Weather report will be sent to ").append(header("mailto")));
      
        from("gtask://default")
            .setHeader(Exchange.HTTP_QUERY, constant("weather=").append(header("city")))
            .to("ghttp://www.google.com/ig/api")
            .process(new WeatherProcessor())        
            .setHeader(GMailBinding.GMAIL_SUBJECT, constant("Weather report"))
            .setHeader(GMailBinding.GMAIL_TO, header("mailto"))
            .to("gmail://<replaceme>@gmail.com");
    }

}

Form data are received via the ghttp component. After receiving the request it is added to the default queue for background processing. Queueing messages on GAE is done with the gtask component. After queueing the request a response is generated for being displayed in the browser. The value of the mailto header is the email address the user entered in the form.

Background processing of the queued messages starts from("gtask://default"). The first step is the construction of the Google weather service URL followed by the weather service invocation using the ghttp component. For example, if the user entered London in the city field of the form the resulting URL is http://www.google.com/ig/api?weather=London. The resulting XML data are processed by the WeatherProcessor:

WeatherProcessor.java
package org.apache.camel.example.gae;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.w3c.dom.Document;

public class WeatherProcessor implements Processor {

    @Override
    public void process(Exchange exchange) throws Exception {
        // convert XML body to DOM tree
        Document doc = exchange.getIn().getBody(Document.class);

        XPathFactory xpfactory = XPathFactory.newInstance();
        XPath xpath = xpfactory.newXPath();

        // Extract result values via XPath
        String city = xpath.evaluate("//forecast_information/city/@data", doc);
        String cond = xpath.evaluate("//current_conditions/condition/@data", doc);
        String temp = xpath.evaluate("//current_conditions/temp_c/@data", doc);

        String msg = null;
        if (city != null && city.length() > 0) {
            msg = new StringBuffer()
                .append("\n").append("Weather report for:  ").append(city)
                .append("\n").append("Current condition:   ").append(cond)
                .append("\n").append("Current temperature: ").append(temp).append(" (Celsius)").toString();
        } else {
            // create an error message
            msg = "Error getting weather report for " + exchange.getIn().getHeader("city", String.class);
        }
        exchange.getIn().setBody(msg);
    }

}

This processor extracts data from the XML result with XPath expressions and creates a simple text-based report for being sent by email. Add this class to the org.apache.camel.example.gae package. For sending the email the gmail component is used. The sender is given by the endpoint URI where <replaceme> must be replaced with the username of the admin account of the GAE application (usually the account to deploy the GAE application). The recipient is derived from the user-defined mailto header.

Local development server

Please note that on the local development server sending emails does not work and queued tasks must be executed manually from the developer console.

Setup the application context

Add the following application context XML file to the project's src directory (needs to be on the classpath).

context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    <bean id="camelContext" 
        class="org.apache.camel.component.gae.context.GaeSpringCamelContext">
        <property name="routeBuilder" ref="tutorialRouteBuilder" />
    </bean>
    
    <bean id="tutorialRouteBuilder"
        class="org.apache.camel.example.gae.TutorialRouteBuilder">
    </bean>
    
</beans>

Deploy the application

To deploy the application right-click on the Tutorial project and select Google->Deploy to App Engine. In the dialog enter the project name, your email address and password for logging into App Engine and press Deploy.

Use the application

Go to http://<appname>.appspot.com where <appname> must be replaced with a valid GAE application name. The following form should now appear.

Enter the name of a city and your email address, for example:

Then press Submit. Submitting the form the first time will initialize the application on Google App Engine which can take more than 10 seconds. Subsequent submissions are served much faster. Check your emails and you should now see a new email with subject Wheather report and content similar to this one:

Weather report for:  London, England
Current condition:   Klar
Current temperature: 12 (Celsius) 

The report is partly internationalized, depending on the language settings of your browser.

  • No labels