You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by bu...@apache.org on 2013/04/14 14:13:45 UTC

svn commit: r858426 - in /websites/staging/isis/trunk: cgi-bin/ content/ content/components/objectstores/jdo/deploying-on-the-google-app-engine.html

Author: buildbot
Date: Sun Apr 14 12:13:45 2013
New Revision: 858426

Log:
Staging update by buildbot for isis

Modified:
    websites/staging/isis/trunk/cgi-bin/   (props changed)
    websites/staging/isis/trunk/content/   (props changed)
    websites/staging/isis/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.html

Propchange: websites/staging/isis/trunk/cgi-bin/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Sun Apr 14 12:13:45 2013
@@ -1 +1 @@
-1464544
+1467772

Propchange: websites/staging/isis/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Sun Apr 14 12:13:45 2013
@@ -1 +1 @@
-1464544
+1467772

Modified: websites/staging/isis/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.html
==============================================================================
--- websites/staging/isis/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.html (original)
+++ websites/staging/isis/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.html Sun Apr 14 12:13:45 2013
@@ -275,10 +275,444 @@ private String key;
 <p>The above notwithstanding, Andy Jefferson at DataNucleus tells us:</p>
 
 <blockquote>
-  <p>GAE JDO/JPA does support <em>some</em> type conversion, because looking at <a href="http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/StoreFieldManager.java#349">[1]</a> for any field that is Object-based and not a relation nor Serialized it will call <a href="http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/TypeConversionUtils.java#736">[2]</a> and that looks for a <code>TypeConverter</code> (specify <code>@Extension</code> with key of "type-converter-name" against a field and value as the <code>TypeConverter</code> class) and it should convert it. Similarly when getting the value from the datastore.</p>
+  <p>GAE JDO/JPA does support <em>some</em> type conversion, because looking at <a href="http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/StoreFieldManager.java#349">StoreFieldManager.java</a> for any field that is Object-based and not a relation nor Serialized it will call <a href="http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/TypeConversionUtils.java#736">TypeConverstionUtils.java</a> and that looks for a <code>TypeConverter</code> (specify <code>@Extension</code> with key of "type-converter-name" against a field and value as the <code>TypeConverter</code> class) and it should convert it. Similarly when getting the value from the datastore.</p>
 </blockquote>
 
-<p>We'll update these notes as and when this gets confirmed.</p>
+<p>On further investigation, it seems that the GAE implementation performs a type check on a <code>SUPPORTED_TYPES</code> Java set, in <code>com.google.appengine.api.datastore.DataTypeUtils</code>:</p>
+
+<pre><code>234 if (!supportedTypes.contains(value.getClass())) {
+235      throw new IllegalArgumentException(prefix + value.getClass().getName() + " is not a supported property type.");
+236 }
+</code></pre>
+
+<p>We still need to try out Andy's recipe, above.</p>
+
+<p>The GAE <code>BlobKey</code> issue has been solved; we hope to publish further details (possibly in a blog series).</p>
+
+<hr />
+
+<h3>GAE compatible version of <code>ToDoItem.java</code></h3>
+
+<p>Is as follows:</p>
+
+<pre><code>@javax.jdo.annotations.Queries( {
+    @javax.jdo.annotations.Query(
+            name="todo_all", language="JDOQL",
+            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy"),
+    @javax.jdo.annotations.Query(
+        name="todo_notYetComplete", language="JDOQL",
+        value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy &amp;&amp; complete == false"),
+    @javax.jdo.annotations.Query(
+            name="todo_complete", language="JDOQL",
+            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy &amp;&amp; complete == true"),
+    @javax.jdo.annotations.Query(
+        name="todo_similarTo", language="JDOQL",
+        value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy &amp;&amp; category == :category"),
+    @javax.jdo.annotations.Query(
+            name="todo_autoComplete", language="JDOQL",
+            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy &amp;&amp; description.startsWith(:description)")
+})
+@javax.jdo.annotations.Version(strategy= VersionStrategy.VERSION_NUMBER, column="VERSION")
+@ObjectType("TODO")
+@Auditable
+@AutoComplete(repository=ToDoItems.class, action="autoComplete")
+@MemberGroups({"General", "Detail"})
+@javax.jdo.annotations.PersistenceCapable
+public class ToDoItem implements Comparable&lt;ToDoItem&gt; {
+//    @PrimaryKey
+//    @Persistent(valueStrategy = javax.jdo.annotations.IdGeneratorStrategy.IDENTITY)
+//    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
+//  private String key;
+    @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
+    @PrimaryKey
+    private Long id;
+
+    private static final long ONE_WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L;
+
+    public static enum Category {
+        Professional, Domestic, Other;
+    }
+
+    // {{ Identification on the UI
+    public String title() {
+        final TitleBuffer buf = new TitleBuffer();
+        buf.append(getDescription());
+        if (isComplete()) {
+            buf.append(" - Completed!");
+        } else {
+            if (getDueBy() != null) {
+                SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
+                buf.append(" due by ", sdf.format(getDueBy()));
+            }
+        }
+        return buf.toString();
+    }
+
+    // }}
+
+    // {{ Description
+    private String description;
+
+    @RegEx(validation = "\\w[@&amp;:\\-\\,\\.\\+ \\w]*")
+    // words, spaces and selected punctuation
+    @MemberOrder(sequence = "1")
+    @DescribedAs("Enter the description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+    // }}
+
+    // {{ DueBy (property)
+    private Date dueBy;
+
+    @javax.jdo.annotations.Persistent
+    @MemberOrder(name="Detail", sequence = "3")
+    @Optional
+    @DescribedAs("Enter the date")
+    public Date getDueBy() {
+        return dueBy;
+    }
+
+    public void setDueBy(final Date dueBy) {
+        this.dueBy = dueBy;
+    }
+    public void clearDueBy() {
+        setDueBy(null);
+    }
+    // proposed new value is validated before setting
+    public String validateDueBy(final Date dueBy) {
+        if (dueBy == null) {
+            return null;
+        }
+        return isMoreThanOneWeekInPast(dueBy) ? "Due by date cannot be more than one week old" : null;
+    }
+    // }}
+
+    // {{ Category
+    private Category category;
+
+    @MemberOrder(sequence = "2")
+    @DescribedAs("Enter the category")
+    public Category getCategory() {
+        return category;
+    }
+
+    public void setCategory(final Category category) {
+        this.category = category;
+    }
+    // }}
+
+    // {{ OwnedBy (property)
+    private String ownedBy;
+
+    @Hidden
+    // not shown in the UI
+    public String getOwnedBy() {
+        return ownedBy;
+    }
+
+    public void setOwnedBy(final String ownedBy) {
+        this.ownedBy = ownedBy;
+    }
+
+    // }}
+
+    // {{ Complete (property)
+    private boolean complete;
+
+    @Disabled
+    // cannot be edited as a property
+    @MemberOrder(sequence = "4")
+    public boolean isComplete() {
+        return complete;
+    }
+
+    public void setComplete(final boolean complete) {
+        this.complete = complete;
+    }
+
+    // {{ Notes (property)
+    private String notes;
+
+    @Hidden(where=Where.ALL_TABLES)
+    @Optional
+    @MultiLine(numberOfLines=4)
+    @MemberOrder(name="Detail", sequence = "6")
+    public String getNotes() {
+        return notes;
+    }
+
+    public void setNotes(final String notes) {
+        this.notes = notes;
+    }
+    // }}
+
+
+
+    // {{ Attachment (property)
+    private BlobKey attachment;
+
+    @Persistent
+    @Optional
+    @MemberOrder(name="Detail", sequence = "7")
+    public BlobKey getAttachment() {
+        return attachment;
+    }
+
+    public void setAttachment(final BlobKey attachment) {
+        this.attachment = attachment;
+    }
+    // }}
+
+
+
+
+    // {{ Version (derived property)
+    @Hidden(where=Where.ALL_TABLES)
+    @Disabled
+    @MemberOrder(name="Detail", sequence = "99")
+    @Named("Version")
+    public Long getVersionSequence() {
+        if(!(this instanceof PersistenceCapable)) {
+            return null;
+        } 
+        PersistenceCapable persistenceCapable = (PersistenceCapable) this;
+        final Long version = (Long) JDOHelper.getVersion(persistenceCapable);
+        return version;
+    }
+    public boolean hideVersionSequence() {
+        return !(this instanceof PersistenceCapable);
+    }
+    // }}
+
+    // {{ completed (action)
+    @Bulk
+    @MemberOrder(sequence = "1")
+    public ToDoItem completed() {
+        setComplete(true);
+        return this;
+    }
+
+    // disable action dependent on state of object
+    public String disableCompleted() {
+        return complete ? "Already completed" : null;
+    }
+    // }}
+
+    // {{ notYetCompleted (action)
+    @MemberOrder(sequence = "2")
+    public ToDoItem notYetCompleted() {
+        setComplete(false);
+        return this;
+    }
+
+
+    // disable action dependent on state of object
+    public String disableNotYetCompleted() {
+        return !complete ? "Not yet completed" : null;
+    }
+    // }}
+
+
+
+
+    // {{ dependencies (Collection)
+    @Unowned
+    private List&lt;ToDoItem&gt; dependencies = new ArrayList&lt;ToDoItem&gt;();
+
+    @Disabled
+    @MemberOrder(sequence = "1")
+    @Resolve(Type.EAGERLY)
+    public List&lt;ToDoItem&gt; getDependencies() {
+        return dependencies;
+    }
+
+    public void setDependencies(final List&lt;ToDoItem&gt; dependencies) {
+        this.dependencies = dependencies;
+    }
+    // }}
+
+    // {{ add (action)
+    @MemberOrder(name="dependencies", sequence = "3")
+    public ToDoItem add(final ToDoItem toDoItem) {
+        getDependencies().add(toDoItem);
+        return this;
+    }
+    public String validateAdd(final ToDoItem toDoItem) {
+        if(getDependencies().contains(toDoItem)) {
+            return "Already a dependency";
+        }
+        if(toDoItem == this) {
+            return "Can't set up a dependency to self";
+        }
+        return null;
+    }
+    public List&lt;ToDoItem&gt; choices0Add() {
+        return toDoItems.allToDos();
+    }
+
+
+    // }}
+
+    // {{ remove (action)
+    @MemberOrder(name="dependencies", sequence = "4")
+    public ToDoItem remove(final ToDoItem toDoItem) {
+        getDependencies().remove(toDoItem);
+        return this;
+    }
+    public String disableRemove(final ToDoItem toDoItem) {
+        return getDependencies().isEmpty()? "No dependencies to remove": null;
+    }
+    public String validateRemove(final ToDoItem toDoItem) {
+        if(!getDependencies().contains(toDoItem)) {
+            return "Not a dependency";
+        }
+        return null;
+    }
+    public List&lt;ToDoItem&gt; choices0Remove() {
+        return getDependencies();
+    }
+    // }}
+
+
+    // {{ clone (action)
+    @Named("Clone")
+    // the name of the action in the UI
+    @MemberOrder(sequence = "3")
+    // nb: method is not called "clone()" is inherited by java.lang.Object and
+    // (a) has different semantics and (b) is in any case automatically ignored
+    // by the framework
+    public ToDoItem duplicate() {
+        return toDoItems.newToDo(getDescription() + " - Copy", getCategory(), getDueBy());
+    }
+    // }}
+
+    // {{ isDue (programmatic)
+    @Programmatic
+    // excluded from the framework's metamodel
+    public boolean isDue() {
+        if (getDueBy() == null) {
+            return false;
+        }
+        return !isMoreThanOneWeekInPast(getDueBy());
+    }
+
+    // }}
+
+
+    // {{ SimilarItems (derived collection)
+    @MemberOrder(sequence = "5")
+    @NotPersisted
+    @Resolve(Type.EAGERLY)
+    public List&lt;ToDoItem&gt; getSimilarItems() {
+        return toDoItems.similarTo(this);
+    }
+
+    // }}
+
+
+
+    // {{ compareTo (programmatic)
+    /**
+     * by complete flag, then due by date, then description
+     */
+    // exclude from the framework's metamodel
+    @Override
+    public int compareTo(final ToDoItem other) {
+        if (isComplete() &amp;&amp; !other.isComplete()) {
+            return +1;
+        }
+        if (!isComplete() &amp;&amp; other.isComplete()) {
+            return -1;
+        }
+        if (getDueBy() == null &amp;&amp; other.getDueBy() != null) {
+            return +1;
+        }
+        if (getDueBy() != null &amp;&amp; other.getDueBy() == null) {
+            return -1;
+        }
+        if (getDueBy() == null &amp;&amp; other.getDueBy() == null || getDueBy().equals(this.getDueBy())) {
+            return getDescription().compareTo(other.getDescription());
+        }
+        return getDueBy().compareTo(getDueBy());
+    }
+    // }}
+
+    // {{ helpers
+    private static boolean isMoreThanOneWeekInPast(final Date dueBy) {
+        return dueBy.getTime() &lt; Clock.getTime() - ONE_WEEK_IN_MILLIS;
+    }
+
+    // }}
+
+    // {{ filters (programmatic)
+    @SuppressWarnings("unchecked")
+    public static Filter&lt;ToDoItem&gt; thoseDue() {
+        return Filters.and(Filters.not(thoseComplete()), new Filter&lt;ToDoItem&gt;() {
+            @Override
+            public boolean accept(final ToDoItem t) {
+                return t.isDue();
+            }
+        });
+    }
+
+    public static Filter&lt;ToDoItem&gt; thoseComplete() {
+        return new Filter&lt;ToDoItem&gt;() {
+            @Override
+            public boolean accept(final ToDoItem t) {
+                return t.isComplete();
+            }
+        };
+    }
+
+    public static Filter&lt;ToDoItem&gt; thoseOwnedBy(final String currentUser) {
+        return new Filter&lt;ToDoItem&gt;() {
+            @Override
+            public boolean accept(final ToDoItem toDoItem) {
+                return Objects.equal(toDoItem.getOwnedBy(), currentUser);
+            }
+
+        };
+    }
+
+    public static Filter&lt;ToDoItem&gt; thoseSimilarTo(final ToDoItem toDoItem) {
+        return new Filter&lt;ToDoItem&gt;() {
+            @Override
+            public boolean accept(final ToDoItem eachToDoItem) {
+                return Objects.equal(toDoItem.getCategory(), eachToDoItem.getCategory()) &amp;&amp; 
+                       Objects.equal(toDoItem.getOwnedBy(), eachToDoItem.getOwnedBy()) &amp;&amp;
+                       eachToDoItem != toDoItem;
+            }
+
+        };
+    }
+    // }}
+
+    // {{ injected: DomainObjectContainer
+    @SuppressWarnings("unused")
+    private DomainObjectContainer container;
+
+    public void setDomainObjectContainer(final DomainObjectContainer container) {
+        this.container = container;
+    }
+    // }}
+
+    // {{ injected: ToDoItems
+    private ToDoItems toDoItems;
+
+    public void setToDoItems(final ToDoItems toDoItems) {
+        this.toDoItems = toDoItems;
+    }
+    // }}
+
+
+
+}
+</code></pre>