ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

Archive for May, 2009

Google App Engine, GWT, Spring 3 and JPA

Posted by ice09 on May 25, 2009

If you are interested in Spring 3 on the GAE, there is a newer post about just this topic (and some REST!).
UPDATE: The github repository for this post is here. A prepared Eclipse project can be downloaded and imported into Eclipse with the installed Eclipse Google plugin (instructions below, to download a zipped project, press on the github site).

Being really enthusiastic about Java on the Google App Engine, I tried out some simple examples, which I will document here.
Most interesting for me was the combination of the Google App Engine, GWT and – of course – the Spring Framework.
Since the current version of Spring is version 3.0, I tried this version, together with the new Google Eclipse plugin, which currently brings the App Engine SDK 1.2.1 and GWT 1.6.4.
The Eclipse version is Ganymede 3.4.2.

References

Most of this stuff is already described, I will list all useful sites here with a short summary – this post is just a mash-up of the mini-tutorials on these sites.

The first entry point for developing for the Google App Engine is obviously the documentation of Google itself. It is well written, easy comprehensible and there is a lot to find for this early stage.

There are different other solutions described here, here and here. However, these solutions did not fit the demands of low impact, current version compatibility or just simple usage.

Preparation

  • First, a “Google” Web Application is created by File > New > Web Application Project

Project setup

First, the added libraries.

  • Libraries added to WEB-INF/lib and the to the project’s classpath
  • Servlet jar is included in lib directory but not added to classpath

Besides the jar libraries, several configuration files and Java classes had to be included

  • Java classes to be included or changed (detailed description below)
  • Configuration files to be included or changed (detailed description below)

Function

The most innovative part is taken from here and described in detail.

The following parts have been added:

Below are the missing parts.

EMF.java

package com.commons.server;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.springframework.stereotype.Component;

@Component
public class EMF {

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

    public EMF() {}

    public EntityManager entityManager() {
        return emfInstance.createEntityManager();
    }
}

persistence.xml

<?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>
        <class>com.commons.server.Customer</class>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>

</persistence>

Customer.java

package com.commons.server;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    private String lastName;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    } 

    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    } 

}

GreetingsServiceImpl.java

package com.commons.sigae.server;

import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.stereotype.Component;

import com.commons.sigae.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
@Component
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {

 	private boolean first;
	protected EntityManager entityManager;
	
	@Autowired
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	public JpaTemplate getTemplate() {
		return new JpaTemplate(entityManager);
	}
	
	public String greetServer(String input) {
		return getData(input);
	}

	private String getData(String input) {
		String all = "";
		for (Customer customer : getCustomers()) {
			if (!first) {
				removeCustomer(customer);
			}
		}
		first = true;
		for (Customer customer : getCustomers()) {
			all += "id: " + customer.getId() + " - firstname: " + customer.getFirstName() + " - name:" + customer.getLastName();
		}
		createCustomer(input);
		return all;
	}

	private void removeCustomer(Customer customer) {
		EntityTransaction trx = entityManager.getTransaction();
		trx.begin();
		entityManager.remove(customer);
		trx.commit();
	}

	private void createCustomer(String input) {
		EntityTransaction trx = entityManager.getTransaction();
		Customer newCustomer = new Customer();
		newCustomer.setFirstName(input + System.currentTimeMillis());
		newCustomer.setLastName(input + System.currentTimeMillis());
		trx.begin();
		entityManager.persist(newCustomer);
		trx.commit();
	}

	private Collection<Customer> getCustomers() {
		return getTemplate().execute(new JpaCallback<Collection<Customer>>() {
			@Override
			public Collection<Customer> doInJpa(EntityManager arg0) throws PersistenceException {
				return (Collection<Customer>) entityManager.createQuery("SELECT cust FROM com.commons.sigae.server.Customer cust").getResultList();
			}
		});
	}

}

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<context:component-scan base-package="com.commons" />

	<bean id="entityManager" factory-bean="EMF" factory-method="entityManager" />

	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<value>
				/springingae/greet=gwtController
			</value>
		</property>
	</bean>
	
  	<bean name="gwtController" class="com.commons.sigae.server.GWTController">
    	        <property name="remoteService" ref="greetingServiceImpl"/>
  	</bean>	

</beans>

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>

	<!-- Default page to serve -->
	<welcome-file-list>
		<welcome-file>SpringInGAE.html</welcome-file>
	</welcome-file-list>

	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/springingae/greet</url-pattern>
	</servlet-mapping>


</web-app>

Tipps & Tricks:

Posted in Google App Engine, GWT | 15 Comments »