You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/12/22 20:30:20 UTC

svn commit: r1647386 - in /isis/site/trunk/content: components/objectstores/jdo/using-neo4j.md documentation.md

Author: danhaywood
Date: Mon Dec 22 19:30:19 2014
New Revision: 1647386

URL: http://svn.apache.org/r1647386
Log:
adding page on using neo4j

Added:
    isis/site/trunk/content/components/objectstores/jdo/using-neo4j.md
      - copied, changed from r1630348, isis/site/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.md
Modified:
    isis/site/trunk/content/documentation.md

Copied: isis/site/trunk/content/components/objectstores/jdo/using-neo4j.md (from r1630348, isis/site/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.md)
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/using-neo4j.md?p2=isis/site/trunk/content/components/objectstores/jdo/using-neo4j.md&p1=isis/site/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.md&r1=1630348&r2=1647386&rev=1647386&view=diff
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/deploying-on-the-google-app-engine.md (original)
+++ isis/site/trunk/content/components/objectstores/jdo/using-neo4j.md Mon Dec 22 19:30:19 2014
@@ -1,475 +1,49 @@
-Title: Deploying on the Google App Engine
+Title: Using Neo4J (1.8.0-SNAPSHOT).
 
-The Google App Engine (GAE) provides a JDO API, meaning that you can deploy Isis onto GAE using the JDO objectstore.
+As of 1.8.0-SNAPSHOT Apache Isis has experimental support for Neo4J, courtesy of DataNucleus' [Neo4J Datastore](http://www.datanucleus.org/products/datanucleus/datastores/neo4j.html) implementation.
 
-However, GAE is not an RDBMS, and so there are some limitations that it imposes.  This page gathers together various hints, tips and workarounds.
+The [simpleapp](../../../intro/getting-started/simpleapp-archetype.html) and [todoapp](../../../intro/getting-started/simpleapp-archetype.html) archetypes have been updated so that they can be optionally run under Neo4J.
 
-### Primary Keys and Owned/Unowned Relationships
+The steps below describe the configuration steps required to update an existing app.
 
-All entities must have a `@PrimaryKey`.  Within GAE, the type of this key matters.
-
-For an entity to be an aggregate root, (ie a root of an GAE entity group), its key must be a `Long`, eg:
-
-<pre>
-    @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
-    @PrimaryKey
-    private Long id;
-</pre>
-
-Any collection that holds this entity type (eg `ToDoItem#dependencies` holding a collection of `ToDoItem`s) should then be annotated with `@Unowned` (a GAE annotation).
-
-If on the other hand you want the object to be owned (through a 1:m relationship somewhere) by some other root, then use a String:
-
-<pre>
-@PrimaryKey
-@Persistent(valueStrategy = javax.jdo.annotations.IdGeneratorStrategy.IDENTITY)
-@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
-private String key;
-</pre>
-
-Note: if you store a relationship with a String key it means that the parent object *owns* the child, any attempt to change the relationship raise and exception.
-
-### Custom Types
-
-Currently Isis' `Blob` and `Clob` types and the JODA types (`LocalDate` et al) are *not* supported in GAE.
-
-Instead, GAE defines a [fixed set of value types](https://developers.google.com/appengine/docs/java/datastore/entities#Properties_and_Value_Types), including `BlobKey`.  Members of the Isis community have this working, though I haven't seen the code.
-
-The above notwithstanding, Andy Jefferson at DataNucleus tells us:
-
-> GAE JDO/JPA does support *some* type conversion, because looking at [StoreFieldManager.java](http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/StoreFieldManager.java#349) for any field that is Object-based and not a relation nor Serialized it will call [TypeConverstionUtils.java](http://code.google.com/p/datanucleus-appengine/source/browse/trunk/src/com/google/appengine/datanucleus/TypeConversionUtils.java#736) and that looks for a `TypeConverter` (specify `@Extension` with key of "type-converter-name" against a field and value as the `TypeConverter` class) and it should convert it. Similarly when getting the value from the datastore.
-
-On further investigation, it seems that the GAE implementation performs a type check on a `SUPPORTED_TYPES` Java set, in `com.google.appengine.api.datastore.DataTypeUtils`:
-
-
-    234 if (!supportedTypes.contains(value.getClass())) {
-    235      throw new IllegalArgumentException(prefix + value.getClass().getName() + " is not a supported property type.");
-    236 }
-
-We still need to try out Andy's recipe, above.
-   
-The GAE `BlobKey` issue has been solved; we hope to publish further details (possibly in a blog series).
-
-
-----
-###GAE compatible version of `ToDoItem.java`
-
-Is as follows:
-
-    @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;
-        }
-        // }}
-    
-    
-    
-    }
+#### ConnectionURL
+
+In `persistor.properties`, update the JDO `ConnectionURL` property, eg:
+
+    isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionURL=neo4j:neo4j_DB
+
+The other connection properties (`ConnectionDriverName`, `ConnectionUserName` and `ConnectionPassword`) should be commented out.
+
+
+#### Update pom.xml
+
+Add the following dependency to the `webapp` project's `pom.xml`:
+
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-neo4j</artifactId>
+            <version>3.2.3</version>
+        </dependency>
+        ...
+    </dependencies>
+
+In the [simpleapp](../../../intro/getting-started/simpleapp-archetype.html) and [todoapp](../../../intro/getting-started/simpleapp-archetype.html) applications this is defined under the "neo4j" profile so can be activated using `-P neo4j`.
+
+
+#### Try it out!
+
+If you want to quickly try out neo4j for yourself:
+
+* run the [simpleapp](../../../intro/getting-started/simpleapp-archetype.html) archetype (1.8.0-SNAPSHOT)
+
+* build the app:
+
+    mvn clean install -P neo4j
+
+* run the app:
+
+    mvn antrun:run -P self-host,neo4j -o
+
+If you visit the about page you should see the neo4j JAR files are linked in, and a `neo4j_DB` subdirectory within the `webapp` directory.
\ No newline at end of file

Modified: isis/site/trunk/content/documentation.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/documentation.md?rev=1647386&r1=1647385&r2=1647386&view=diff
==============================================================================
--- isis/site/trunk/content/documentation.md (original)
+++ isis/site/trunk/content/documentation.md Mon Dec 22 19:30:19 2014
@@ -321,19 +321,25 @@ For both:
 * [Externalized Configuration](./reference/externalized-configuration.html)
 * [JVM args](./reference/jvm-args.html)
 
-JDO Objectstore
+#### <a name="more-advanced-topics-jdo-objectstore">JDO Objectstore</a>
 
-* [Deploying on the Google App Engine](components/objectstores/jdo/deploying-on-the-google-app-engine.html)
 * [Using a JNDI Datasource](components/objectstores/jdo/using-jndi-datasource.html)
 * [Enabling Logging](components/objectstores/jdo/enabling-logging.html)
 
+#### <a name="more-advanced-topics-no-sql-support">NoSQL Support</a>
+
+* [Deploying on the Google App Engine](components/objectstores/jdo/deploying-on-the-google-app-engine.html)
+* [Using Neo4J](components/objectstores/jdo/using-neo4j.html) (1.8.0-SNAPSHOT)
+
 
+<!--
 #### <a name="core-bundled-components">Other Core Components</a>
 
 * [Core Runtime](core/runtime.html) [stub]
 * [Webserver](core/webserver.html) [stub]
 * [In-memory Object Store](core/inmemory-objectstore.html) [stub]
 * ['Bypass' Implementation](core/bypass-security.html) [stub]
+-->
 
 }