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 && complete == false"),
+ @javax.jdo.annotations.Query(
+ name="todo_complete", language="JDOQL",
+ value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && complete == true"),
+ @javax.jdo.annotations.Query(
+ name="todo_similarTo", language="JDOQL",
+ value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && category == :category"),
+ @javax.jdo.annotations.Query(
+ name="todo_autoComplete", language="JDOQL",
+ value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && 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<ToDoItem> {
+// @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[@&:\\-\\,\\.\\+ \\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<ToDoItem> dependencies = new ArrayList<ToDoItem>();
+
+ @Disabled
+ @MemberOrder(sequence = "1")
+ @Resolve(Type.EAGERLY)
+ public List<ToDoItem> getDependencies() {
+ return dependencies;
+ }
+
+ public void setDependencies(final List<ToDoItem> 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<ToDoItem> 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<ToDoItem> 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<ToDoItem> 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() && !other.isComplete()) {
+ return +1;
+ }
+ if (!isComplete() && other.isComplete()) {
+ return -1;
+ }
+ if (getDueBy() == null && other.getDueBy() != null) {
+ return +1;
+ }
+ if (getDueBy() != null && other.getDueBy() == null) {
+ return -1;
+ }
+ if (getDueBy() == null && 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() < Clock.getTime() - ONE_WEEK_IN_MILLIS;
+ }
+
+ // }}
+
+ // {{ filters (programmatic)
+ @SuppressWarnings("unchecked")
+ public static Filter<ToDoItem> thoseDue() {
+ return Filters.and(Filters.not(thoseComplete()), new Filter<ToDoItem>() {
+ @Override
+ public boolean accept(final ToDoItem t) {
+ return t.isDue();
+ }
+ });
+ }
+
+ public static Filter<ToDoItem> thoseComplete() {
+ return new Filter<ToDoItem>() {
+ @Override
+ public boolean accept(final ToDoItem t) {
+ return t.isComplete();
+ }
+ };
+ }
+
+ public static Filter<ToDoItem> thoseOwnedBy(final String currentUser) {
+ return new Filter<ToDoItem>() {
+ @Override
+ public boolean accept(final ToDoItem toDoItem) {
+ return Objects.equal(toDoItem.getOwnedBy(), currentUser);
+ }
+
+ };
+ }
+
+ public static Filter<ToDoItem> thoseSimilarTo(final ToDoItem toDoItem) {
+ return new Filter<ToDoItem>() {
+ @Override
+ public boolean accept(final ToDoItem eachToDoItem) {
+ return Objects.equal(toDoItem.getCategory(), eachToDoItem.getCategory()) &&
+ Objects.equal(toDoItem.getOwnedBy(), eachToDoItem.getOwnedBy()) &&
+ 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>