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 2013/07/31 09:40:08 UTC
svn commit: r1508746 - in /isis/site/trunk/content: ./ applib-guide/how-tos/
applib-guide/reference/ components/objectstores/jdo/ core/
Author: danhaywood
Date: Wed Jul 31 07:40:08 2013
New Revision: 1508746
URL: http://svn.apache.org/r1508746
Log:
managed 1-m relationships, contract tests, utility classes
Added:
isis/site/trunk/content/components/objectstores/jdo/managed-1-to-m-relationships.md
Modified:
isis/site/trunk/content/applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.md
isis/site/trunk/content/applib-guide/reference/Utility.md
isis/site/trunk/content/components/objectstores/jdo/about.md
isis/site/trunk/content/core/unittestsupport.md
isis/site/trunk/content/documentation.md
Modified: isis/site/trunk/content/applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.md?rev=1508746&r1=1508745&r2=1508746&view=diff
==============================================================================
--- isis/site/trunk/content/applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.md (original)
+++ isis/site/trunk/content/applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.md Wed Jul 31 07:40:08 2013
@@ -1,6 +1,10 @@
How to set up and maintain bidirectional relationships
------------------------------------------------------
+> **Note**:
+>
+> If using the [JDO Objectstore](../../components/objectstores/jdo/about.html) then there is generally no need to explicitly maintain bidirectional relationships. Indeed, doing so may cause subtle errors. See [here](../../components/objectstores/jdo/managed-1-to-m-relationships.html) for more details.
+
The modifyXxx() and clearXxx() methods (see ?) can be used to setup
bidirectional relationships. This is typically done with 1:m
relationships, eg between Order and OrderLine, or Department and
@@ -8,20 +12,19 @@ Employee.
The recommended way of maintaining a bidirectional relationship is to
use the 'mutual registration pattern', a write-up of which can be found
-at
-<http://www.two-sdg.demon.co.uk/curbralan/papers/MutualRegistration.pdf>.
+[here](http://www.two-sdg.demon.co.uk/curbralan/papers/MutualRegistration.pdf).
The general idea is that one side of the relationship is responsible for
maintaining the associations, while the other side simply delegates.
-To implement this in *Isis* for a 1:m relationship, use the addToXxx() /
-removeFromXxx() and modifyXxx() / clearXxx() methods.
+To implement this in *Isis* for a 1:m relationship, use the `addToXxx()` /
+`removeFromXxx()` and the `modifyXxx()` / `clearXxx()` methods.
For example:
public class Department {
- private List<Employee> employees = new ArrayList<Employee>();
- public List<Employee> getEmployees() { ... }
- private void setEmployees(List<Employee> employees) { ... }
+ private SortedSet<Employee> employees = new TreeSet<Employee>();
+ public SortedSet<Employee> getEmployees() { ... }
+ private void setEmployees(SortedSet<Employee> employees) { ... }
public void addToEmployees(Employee e) {
if(e == null || employees.contains(e)) return;
e.setDepartment(this);
@@ -55,8 +58,3 @@ and
...
}
-> **Note**
->
-> For some object stores this explicit coding may not be necessary; the
-> object store automatically maintains the relationship.
-
Modified: isis/site/trunk/content/applib-guide/reference/Utility.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/applib-guide/reference/Utility.md?rev=1508746&r1=1508745&r2=1508746&view=diff
==============================================================================
--- isis/site/trunk/content/applib-guide/reference/Utility.md (original)
+++ isis/site/trunk/content/applib-guide/reference/Utility.md Wed Jul 31 07:40:08 2013
@@ -1,20 +1,17 @@
-Utility Classes
-===============
+title: Utility Classes
> Simple utility classes for domain objects.
The `org.apache.isis.applib.util` package has a number of simple utility
classes designed to simplify the coding of some common tasks.
-Title creation
---------------
+## Title creation
The `TitleBuffer` utility class is intended to make it easy to construct
title strings (returned from the `title()` method). For example, it has
overloaded versions of methods called `append()` and `concat()`.
-Reason text creation (for disable and validate methods)
--------------------------------------------------------
+##Reason text creation (for disable and validate methods)
There are two different classes provided to help build reasons returned
by `disableXxX()` and `validateXxx()` methods:
@@ -36,3 +33,30 @@ For example:
}
Which you use (if any) is up to you.
+
+##ObjectContracts
+
+The `ObjectContracts` test provides a series of methods to make it easy for your domain objects to:
+
+* implement `Comparable` (eg so can be stored in `java.util.SortedSet`s)
+* implement `toString()`
+* implement `equals()`
+* implement `hashCode()`
+
+For example:
+
+ public class ToDoItem implements Comparable<ToDoItem> {
+
+ public boolean isComplete() { ... }
+ public LocalDate getDueBy() { ... }
+ public String getDescription() { ... }
+ public String getOwnedBy() { ... }
+
+ public int compareTo(final ToDoItem other) {
+ return ObjectContracts.compare(this, other, "complete,dueBy,description");
+ }
+
+ public String toString() {
+ return ObjectContracts.toString(this, "description,complete,dueBy,ownedBy");
+ }
+ }
\ No newline at end of file
Modified: isis/site/trunk/content/components/objectstores/jdo/about.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/about.md?rev=1508746&r1=1508745&r2=1508746&view=diff
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/about.md (original)
+++ isis/site/trunk/content/components/objectstores/jdo/about.md Wed Jul 31 07:40:08 2013
@@ -8,6 +8,7 @@ The DataNucleus objectstore enables the
- [DataNucleus and Maven](datanucleus-and-maven.html)
- [`persistence.xml` file](persistence_xml.html)
- [Dates, Blobs and Lazy Loading](dates-blobs-lazy-loading.html)
+- [Managed 1:m bidirectional relationships](managed-1-to-m-relationships.html)
- [Using a JNDI Datasource](using-jndi-datasource.html)
- [Workarounds (the `IsisJdoSupport` service)](workarounds.html)
- [Enabling Logging](enabling-logging.html)
Added: isis/site/trunk/content/components/objectstores/jdo/managed-1-to-m-relationships.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/components/objectstores/jdo/managed-1-to-m-relationships.md?rev=1508746&view=auto
==============================================================================
--- isis/site/trunk/content/components/objectstores/jdo/managed-1-to-m-relationships.md (added)
+++ isis/site/trunk/content/components/objectstores/jdo/managed-1-to-m-relationships.md Wed Jul 31 07:40:08 2013
@@ -0,0 +1,41 @@
+Title: Managed 1:m bidirectional relationships
+
+When an object is added to a 1:m bidirectional relationship, the child object must refer to the parent and the child must be added to the parent's children collection.
+
+In general, *Isis* recommends that the mutual registration pattern is ensure that both the parent and child are updated correctly; the framework supports the `modifyXxx()` and `clearXxx()` methods to accomplish this, and this [how-to](../../../applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.html) describes the boilerplate necessary.
+
+However, in a relational database, these two operations in the domain object model correspond simply to updating the foreign key of the child table to reference the parent's primary key.
+
+So long as the parent's children collection is a `java.util.Set` (rather than a `Collection` or a `List`), the JDO Objectstore will automatically maintain both sides of the relationship. All that is necessary is to set the child to refer to the parent.
+
+For example
+
+ public class Department {
+
+ @javax.jdo.annotations.Persistent(mappedBy="department")
+ private SortedSet<Employee> employees = new TreeSet<Employee>();
+
+ public SortedSet<Employee> getEmployees() { ... }
+ public void setEmployees(SortedSet<Employee> employees) { ... }
+ ...
+ }
+
+and
+
+ public class Employee {
+ private Department department;
+ public Department getDepartment() { ... }
+ public void setDepartment(Department department) { ... }
+ ...
+ }
+
+Contrast the above with the programmatic maintenance described in the [how-to](../../../applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.html).
+
+> **Note**
+>
+In fact, not only do you not need to manually maintain the relationship, we have noted on at least [one occasion](http://markmail.org/message/agnwmzocvdfht32f) a subtle error if the code is programmatically added.
+>
+The error in that case was that the same object was contained in the parents collection. This of course should not happen for a `TreeSet`. However, JDO/DataNucleus replaces the `TreeSet` with its own implementation, and (either by design or otherwise) this does not enforce `Set` semantics.
+>
+The upshot is that you should NEVER programmatically add the child object to the parent's collection if using JDO Objectstore.
+
Modified: isis/site/trunk/content/core/unittestsupport.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/core/unittestsupport.md?rev=1508746&r1=1508745&r2=1508746&view=diff
==============================================================================
--- isis/site/trunk/content/core/unittestsupport.md (original)
+++ isis/site/trunk/content/core/unittestsupport.md Wed Jul 31 07:40:08 2013
@@ -11,13 +11,91 @@ To use, update the `pom.xml`:
</dependency>
</pre>
-##Bidirectional Contract Tests [1.3.0-SNAPSHOT]
-Automatically tests that bidirectional 1:m or 1:1 associations are being maintained correctly (assuming that they follow the [mutual registration pattern](../applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.html)
+##SortedSets Contract Test [1.3.0-SNAPSHOT]
+
+This contract test automatically checks that all fields of type `java.util.Collection` are declared as `java.util.SortedSet`. In other words, it precludes either `java.util.List` or `java.util.Set` from being used as a collection.
+
+
+For example, the following passes the contract test:
+
+ public class Department {
+
+ private SortedSet<Employee> employees = new TreeSet<Employee>();
+
+ ...
+ }
+
+whereas this would not:
+
+ public class SomeDomainObject {
+
+ private List<Employee> employees = new ArrayList<Employee>();
+
+ ...
+ }
+
+If using the JDO Objectstore then we strongly recommend that you implement this test, for several reasons:
+
+* First, `Set`s align more closely to the relational model than do `List`s. A `List` must have an additional index to specify order.
+
+* Second, `SortedSet` is preferable to `Set` because then the order is well-defined and predictable (to an end user, to the programmer).
+
+ The [ObjectContracts](../applib-guide/reference/Utility.html) utility class substantially simplifies the task of implementing `Comparable` in your domain classes.
+
+* Third, if the relationship is bidirectional then JDO/Objectstore will automatically maintain the relationship. See [here](../components/objectstores/jdo/managed-1-to-m-relationships.html) for further discussion.
+
+To use the contract test, subclass `SortedSetsContractTestAbstract`, specifying the root package to search for domain classes.
+
+For example:
+
+ public class SortedSetsContractTestAll extends SortedSetsContractTestAbstract {
+
+ public SortedSetsContractTestAll() {
+ super("org.estatio.dom");
+ withLoggingTo(System.out);
+ }
+ }
+
+##Injected Services Method Contract Test [1.3.0-SNAPSHOT]
+
+It is quite common for some basic services to be injected in a project-specific domain object superclass; for example a `ClockService` might generally be injected everywhere:
+
+ public abstract class EstatioDomainObject {
+ protected ClockService clockService;
+ public void injectClockService(ClockService clockService) {
+ this.clockService = clockService;
+ }
+ }
+
+If a subclass inadvertantly overrides this method and provides its own `ClockService` field, then the field in the superclass will never initialized. As you might imagine, `NullPointerException`s could then arise.
+
+This contract test automatically checks that the `injectXxx(...)` method, to allow for injected services, is not overridable, ie `final`.
+
+To use the contract test, , subclass `SortedSetsContractTestAbstract`, specifying the root package to search for domain classes.
+
+For example:
+
+ public class InjectServiceMethodMustBeFinalContractTestAll extends InjectServiceMethodMustBeFinalContractTestAbstract {
+
+ public InjectServiceMethodMustBeFinalContractTestAll() {
+ super("org.estatio.dom");
+ withLoggingTo(System.out);
+ }
+ }
+
+
+##Bidirectional Contract Test [1.3.0-SNAPSHOT]
+
+This contract test automatically checks that bidirectional 1:m or 1:1 associations are being maintained correctly (assuming that they follow the [mutual registration pattern](../applib-guide/how-tos/how-to-04-060-How-to-set-up-and-maintain-bidirectional-relationships.html)
+
+>
+**Note:**
+>
+If using the [JDO Object Store](../components/objectstores/jdo/about.html), then there is generally no need to programmatically maintain 1:m relationships (indeed it may introduce subtle errors). For more details, see [here](../components/objectstores/jdo/managed-1-to-m-relationships.html).
+
+>If *not* using the JDO Object Store, note that *Isis* provides [Eclipse templates](../getting-started/editor-templates.html) to help generate the necessary boilerplate.
-{note
-Isis provides [Eclipse templates](../getting-started/editor-templates.html) to help generate the necessary boilerplate.
-}
For example, suppose that `ParentDomainObject` and `ChildDomainObject` have a 1:m relationship (`ParentDomainObject#children` / `ChildDomainObject#parent`), and also `PeerDomainObject` has a 1:1 relationship with itself (`PeerDomainObject#next` / `PeerDomainObject#previous`).
Modified: isis/site/trunk/content/documentation.md
URL: http://svn.apache.org/viewvc/isis/site/trunk/content/documentation.md?rev=1508746&r1=1508745&r2=1508746&view=diff
==============================================================================
--- isis/site/trunk/content/documentation.md (original)
+++ isis/site/trunk/content/documentation.md Wed Jul 31 07:40:08 2013
@@ -11,6 +11,7 @@ Title: Documentation
- [Screencasts](getting-started/screencasts.html)
- [Wicket/Restful/JDO Archetype](getting-started/quickstart-archetype.html) ([1.0.3](getting-started/release-notes/about.html))
- [Programming Model and How-tos](applib-guide/about.html)
+- [Applib utility classes](applib-guide/reference/Utility.html)
- [Static and dynamic layouts](core/dynamic-layouts.html)
- [Programming Model Cheat Sheet](getting-started/cheat-sheet.html)
@@ -191,7 +192,8 @@ Note: this viewer is third-party open so
- [DataNucleus and Eclipse](components/objectstores/jdo/datanucleus-and-eclipse.html)
- [DataNucleus and Maven](components/objectstores/jdo/datanucleus-and-maven.html)
- [`persistence.xml` file](components/objectstores/jdo/persistence_xml.html)
-- [Dates, Blobs and Lazy Loading](components/objectstores/jdo/dates-blobs-lazy-loading.html)
+- [Dates, Blobs and Lazy Loading](components/objectstores/jdo/dates-blobs-lazy-loading.html)
+- [Managed 1:m bidirectional relationships](components/objectstores/jdo/managed-1-to-m-relationships.html)
- [Using a JNDI Datasource](components/objectstores/jdo/using-jndi-datasource.html)
- [Workarounds](components/objectstores/jdo/workarounds.html)
- [Enabling Logging](components/objectstores/jdo/enabling-logging.html)