Fornax-Platform View a printable version of the current page. Export Page as PDF
  10. App Engine (CSC)
 
 Browse Space
General


Projects


Latest News
Latest News
(The 15 most recent blogposts in space Fornax-Platform.)


Global Reports
Find all pages that arent linked from anywhere.
Find all undefined pages.
Feed for new pages.
Added by Patrik Nordwall, last edited by Patrik Nordwall on Jul 07, 2010  (view change) show comment

Labels:

Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.

Sculptor App Engine Tutorial

Sculptor provides an implementation for Google App Engine (below referred to as GAE).

In this tutorial we will show you how you can create a project, generate a complete persistence and service layer. Create a simple Springframework MVC client. How to unit test it. How to test it your local GAE environment. And finally, how to deploy it to GAE. We assume you have your Sculptor environment installed. And we are going to use GAE Eclipse plugin, so if you haven't installed it yet, do so from google. Also, we are going to show how to deploy to GAE. For you to do this, you need an GAE account. You can sign up here if you doesn't have one.

Quick start

A fast track to a deployment in the cloud.

Setup project

First we will setup the project structure for maven and eclipse.

1. Use the following command (one line) to create a maven pom and file structure. You can change the groupId and artifactId if you like.

mvn archetype:generate -DarchetypeGroupId=org.fornax.cartridges -DarchetypeArtifactId=fornax-cartridges-sculptor-archetype-appengine \
-DarchetypeVersion=1.9.0 -DarchetypeRepository=http://www.fornax-platform.org/archiva/repository/releases/

Fill in groupId and artifactId:

Define value for groupId: : org.helloworld
Define value for artifactId: : hellogae
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  org.helloworld: :

Ignore warnings
There will be warnings like this:
[WARNING] org.apache.velocity.runtime.exception.ReferenceException: reference :
template = archetype-resources/pom.xml [line 40,column 42] : ${fornax-oaw-m2.ver
sion} is not a valid reference.

Ignore these warnings and continue with next step if you see no errors.

2. In the new directory, run

mvn clean

mvn generate-sources

mvn eclipse:eclipse

to generate example sources and create an Eclipse project with the same dependencies as in the pom.

3. Open Eclipse and import the project.

Run in local GAE

Since Sculptors maven-gae-archetype provides you with a simple example application you are now ready to test it.

The GAE Eclipse plugin comes with a local environment. Lets try to run our new application in it.

Open the 'Run As' menu for your project and choose to run it as 'Web Application'.

When you see the message: 'The server is running at http://localhost:8888/' point you favorit browser to that address and you should see something like this:

Deploy to GAE

To deploy to appengine its just a matter of pushing the right button in the toolbar:
Add the prompted information and push the 'Deploy' button:

If you click the 'App Engine project settings...' link in the window, you can set the application id. This is the id of one of your applications that you have attached to your GAE account.
And after half a minute (or whatever your connection speed allows) you should be able to browse the same application but now its on the cloud

Sculptor Archetype Appengine

So, perhaps it seemed like magic when creating the project. But actually its not. What you get when running the archetype is:

pom.xml

A pre configured pom-file with all the right dependencies, repositories and hooks into the maven build life cycle that copies the dependencies to the right folder to make the GAE tools pick them up when doing deploy's etc.

model.btdesign

The archetype creates a simple sample model, from which Sculptor generates Entity, Repository and Service with the default CRUD operations; findById, findAll, save, and delete.
The model is defined in a textual DSL, with an intuitive syntax, from which Sculptor generates high quality Java code and configuration. It is not a one time shot. The application can be developed incrementally with an efficient round trip loop. The generator is part of the build process (maven).

Spring MVC files

No files are generated for the GUI. Though we provide a set of files that works together with the above model. So basically that is a Spring MVC controller, jsp-files and configuration.

The archetype creates a sample of of a RESTful Spring 3.0 Controller and JSP pages for the CRUD operations.

One module
As of now it is a one module solution. This means that both business tier and client tier resides in the same module.

Relations are special

Since the persistence mechanism behind GAE is BigTable and not an ordinary relational database, relations are very limited.
Sculptor generates JPA mapping annotations for the domain objects defined in the design model.

Owned and embedded associations are supported and mapped as ordinary JPA associations. They are specified with aggregate and BasicType in the Sculptor model.

Unowned associations are handled with id references and you must lookup the objects with findById when needed.

For more information on how relations are handled, see google's doc.

JUnit testing

Sculptor makes it easy to write JUnit tests for Google App Engine. A test case looks like this:

public class PlanetServiceTest extends AbstractAppEngineJpaTests {
    @Autowired
    private PlanetService planetService;
    @Before
    public void populateDatastore() {
        Planet earth = new Planet("Earth");
        getEntityManager().persist(earth);
        Planet mars = new Mars("Mars");
        getEntityManager().persist(mars);
    }
    @Test
    public void testFindAll() throws Exception {
        List<Planet> all = planetService.findAll(getServiceContext());
        assertEquals(2, all.size());
    }
 
    @Test
    public void testFindByName() throws Exception {
        Planet found = planetService.findByName(getServiceContext(), "Mars");
        assertNotNull(found);
        assertEquals("Mars", found.getName());
    }
}

Very natural!

It is interesting to take a look at the base class. It defines a few annotations and extends AbstractJUnit4SpringContextTests to initialize the Spring environment. This enables usage of ordinary @Autowire dependency injection directly in the test class.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =  {"classpath:applicationContext-test.xml"})
public abstract class AbstractAppEngineJpaTests extends AbstractJUnit4SpringContextTests {

The embedded App Engine environment is initialized from a method annotated with @Before, i.e. invoked before each test method.

public static void setUpAppEngine(ApiProxy.Environment testEnvironment) {
    ApiProxy.setEnvironmentForCurrentThread(testEnvironment);
    ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(".")) {
    });
    ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate();
    proxy.setProperty(LocalDatastoreService.NO_STORAGE_PROPERTY, Boolean.TRUE.toString());
    clearSentEmailMessages();
}
 
public static void tearDownAppEngine() {
    ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate();
    LocalDatastoreService datastoreService = (LocalDatastoreService) proxy.getService("datastore_v3");
    datastoreService.clearProfiles();
    clearSentEmailMessages();
}

It is initialized with in memory data store, i.e. it is empty before each test method. You may populate it with initial data in your subclass in a @Before method, see populateDataStore in the sample above.

Transactional gotchas
When working with ordinary databases the Spring transactional test support is very useful, i.e. Spring executes each test method in a transaction, which is rolled back after the test mehtod. That is achieved with the following annotations and usage of the annotation @BeforeTransaction instead of the ordinary @Before.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =  {"classpath:applicationContext-test.xml"})
@TestExecutionListeners(TransactionalTestExecutionListener.class)
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public abstract class AbstractAppEngineJpaTests extends AbstractJUnit4SpringContextTests {

This approach doesn't work when doing appengine tests. It will fail on the last assert when using the above transactional support.

@Test
public void testSave() throws Exception {
    int countBefore = countRowsInTable(Planet.class);
    Planet jupiter = new Planet("Jupiter");
    supplierService.save(getServiceContext(), jupiter);
    int countAfter = countRowsInTable(Planet.class);
    assertEquals(countBefore + 1, countAfter);
}

The reason is that queries see a snapshot of the datastore as of the beginning of the transaction.

Data isolation between test methods is no problem, since the datastore is initialized (empty) before each test method.

Hmm after following the steps above, and importing project in Eclipse i got following error msg:

12/21/09 4:55:09 PM CET: Build errors for hellogae; org.apache.maven.lifecycle.LifecycleExecutionException: Failed to construct build plan for: hellogae
Id: org.helloworld:hellogae:war:1.0-SNAPSHOT
task-segment: [process-test-resources]. Reason: Failed to resolve plugin for mojo binding: org.datanucleus:maven-datanucleus-plugin:1.1.4:enhance

It seems to me that enhancer is not working properly, any suggestions?

Posted by Anonymous at Dec 21, 2009 16:58 | Reply To This

Hi,

Are you using the m2eclipse plugin when you are importing the project?

If so, try importing the project as an eclipse-project.

Otherwise, try to build the project outside of eclipse to see if the enhancer-plugin works there.

From the prompt, in the root of your project, run:

>mvn install -Dmaven.test.skip=true

.../Andreas

I think I got something similar in my environment. It tries to download
javax.jdo:jdo2-api:jar:2.3-ec
from http://www.mvnsearch.org/maven2. version 2.3-ec is not available there.
jdo2-api is a dependency of maven-datanucleus-plugin
I solved it by adding explicit dependency in maven-datanucleus-plugin conf, i.e.

			<plugin>
                <groupId>org.datanucleus</groupId>
			    <artifactId>maven-datanucleus-plugin</artifactId>
			    <version>1.1.4</version>
                <configuration>
                	<api>JPA</api>
                	<mappingIncludes>**/*.class</mappingIncludes>
                    <log4jConfiguration>${basedir}/src/main/resources/log4j.properties</log4jConfiguration>
                    <verbose>false</verbose>
                </configuration>
                <executions>
                    <execution>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>enhance</goal>
                        </goals>
                    </execution>
                </executions>
				<dependencies>
					<dependency>
						<groupId>javax.jdo</groupId>
						<artifactId>jdo2-api</artifactId>
						<version>2.3-eb</version>
					</dependency>
					<dependency>
						<groupId>org.datanucleus</groupId>
						<artifactId>datanucleus-core</artifactId>
						<version>1.1.5</version>
					</dependency>
				</dependencies>
            </plugin>

Hi!

First of all - Sculptor is cool! I like especially the support of GAE - tried it out and it works fine!

But there is one question: how do I associate the data with a Google User? Is there a way to describe this with DSL, maybe something like this:

Entity Account

Unknown macro: { String name - @GoogleUser user }

Or is there another way?

Thanks!

Posted by Anonymous at Aug 26, 2010 22:39 | Reply To This

Hi, glad you like our GAE-support.
Do you mean restrictions/permissions?
In that case, no, we doesn't have any support in the DSL for user restrictions/permissions.
That you have to implement in the code.

Or do you mean that you want to have a type 'GoogleUser' that is defined outside of the dsl and refer to it in your Account Entity?

cheers.../Andreas