com.smartgwt.client.docs
Interface GaeIntegration


public interface GaeIntegration

Google Application Engine (GAE)

GAE supports Java applications. Google provides a great infrastructure for web applications. It takes care of many web application developer's headaches: hardware, operating system support, backups, scaling, security, mail etc. To run under GAE your application has to comply to GAE rules. The biggest difference is GAE datastore - it is not a relational database - instead they use something called BigTable. To simplify development, Google has adopted DataNucleus Access Platform to provide JPA 1.0 support. Because GAE datastore is not a relational database some JPA features are not supported by this JPA implementation.

Setting up Smart GWT application for GAE

Under the /WEB-INF directory you have to create a file named appengine-web.xml which will hold Google's specific settings.
One important thing to note: static and dynamic contents will be served from different servers. There are special sections in appengine-web.xml specifying static and dynamic resources. All resources are duplicated if not specified. A single GAE application is limited to 3000 files. A typical Smart GWT application consists of many resources and it exceeds the limit when duplicated (even with a single theme). To run a Smart GWT application we have to split resources. Here is an example configuration:

  <?xml version="1.0" encoding="UTF-8"?>
  <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
      <application>GAE_APPLICATION_NAME</application>
      <version>1</version>
      <static-files>
          <include path="/index.jsp"/>
          <include path="/[MODULE_NAME]/**"/>
          <exclude path="/[MODULE_NAME]/**.xml"/>
          <exclude path="/[MODULE_NAME]/**.xsl"/>
          <exclude path="/[MODULE_NAME]/**.wsdl"/>
      </static-files>
      <resource-files>
          <include path="/[PATH_TO_DATA_SOURCE_FILES]/**"/>
          <include path="/[MODULE_NAME]/**.xml"/>
          <include path="/[MODULE_NAME]/**.xsl"/>
          <include path="/[MODULE_NAME]/**.wsdl"/>
      </resource-files>
  </appengine-web-app>
  
To interact with DataSources an additional servlet mapping has to be added to web.xml:
  <servlet-mapping>
      <servlet-name>IDACall</servlet-name>
      <url-pattern>/[MODULE_NAME]/sc/IDACall</url-pattern>
  </servlet-mapping>
  

Setting up DataSources

GAE supports only four types as primary keys:

Primary key can not be altered after entity is saved.
Entities with primary keys Long or String can not participate in transactions and can not be used in relations. Here is an example how to declare primary key of type String with additional annotations:
  import java.io.Serializable;
  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;
  import org.datanucleus.jpa.annotations.Extension;
 
  @Entity
  public class Bar
      implements Serializable
  {
     @Id
     @GeneratedValue (strategy = GenerationType.IDENTITY)
     @Extension (vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
     private String id;
  }
  
DataSource creation is similar to standard JPA with one difference: property serverConstructor should be set to com.isomorphic.jpa.GAEJPADataSource.
Because of GAE queries limitations this DataSource implementation supports only single inequality criteria in filter.
Only TextMatchStyle.STARTS_WITH filtering mode is supported for text fields.
All queries are case sensitive because GAE does not support upper()/lower() functions in criterias.
TextMatchStyle.EXACT is used for all number fields.
com.isomorphic.jpa.EMFProviderLMT or com.isomorphic.jpa.EMFProviderNoTransactions should be used as transaction providers (depending whether you use transactions or not).
To participate in a transaction, entities have to belong to the same group.
Note: entities of different type can not participate in a transaction even if these entities have GAE specific primary key (you can not even fetch (SELECT) entities belonging to different groups).

Relationships

Entities are grouped by establishing owned relationships (where dependent entities are instantiated automatically by the JPA provider) between them. Entities in groups can form a chain of the following sort::

  ClassA has reference to ClassB,
  ClassB has reference to ClassC
  
But it is impossible to have an entity referencing two other entities:
  ClassD has reference to ClassE,
  ClassD has reference to ClassF
  
There are no foreign keys - the actual reference is encoded into the primary key of child entity.
GAE datastore does not support many-to-many relationships.
Unidirectional one-to-many relationships work only if the parent has a declaration of List<ChildEntityClass>.
Unidirectional relationships do not work if only the child entity has reference to the parent.
Bidirectional relationship example:
  @Entity
  public class Country
      implements Serializable
  {
      @Id
      @Column (nullable = false)
      @GeneratedValue (strategy = GenerationType.IDENTITY)
      @Extension (vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
      private String countryId;
 
      @OneToMany
      private List cities;
  //....
  }
 
  @Entity
  public class City
      implements Serializable
  {
      @Id
      @Column (nullable = false)
      @GeneratedValue (strategy = GenerationType.IDENTITY)
      @Extension (vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
      private String cityId;
 
      // This is fake column - it is calculated by provider and is not saved.
      // Actual reference to parent entity is encoded in primary key.
      @Column (nullable = false)
      @Extension (vendorName = "datanucleus", key = "gae.parent-pk", value = "true")
      private String countryId;
 
      @ManyToOne (fetch=FetchType.LAZY)
      private Country country;
  //....
  }
  
Note: GAE does not support FetchType.EAGER.

With Unowned Relationships (when you save parent's primary key as simple child's property) you can model unsupported relationships. But this approach has drawbacks: