There are a number of design trade offs for data views. Consider the
forLinking
data view of the page, which is a
composition and thus creates a private instance for each child. This design avoids a cache
lookup. Caching has an overhead and allocating a cache entry for a parent object with only
one string property would cost more than it saves.
On the other hand, since you defined a cacheable default data view of a page anyway, you could consider reusing the parent’s default data view for the child:
<dataview appliesTo=”com.company.PageImpl”> <property name=”name”/> <property name=”description”/> <property name=”content”/> <property name=”parent” associationType=”aggregation”/> </dataview>
An aggregation is different from a composition in that a cache lookup is performed for
this property. All children would therefore share the same parent instance (provided it is
not evicted from the cache). In this definition, a
PageImpl
would aggregate
its parent which would again recursively aggregate its parent ... until
null
is reached (any data view for
null
is null
). Since you expect
parents to be frequently accessed anyway, it is OK to have them pulled into the cache by
their children. The generated code is basically equivalent to the following:
class PageImpl$$ extends PageImpl { // null is the default data view PageImpl parent = (Page)dataviewFactory.lookupCached(super.getParent(), null); public Page getParent() { return this.parent; } ... }
However, you also have to take the cache’s dependency tracking into consideration. When a data view reads a content object, a dependency is recorded. When a data view does a cache lookup for another data view, a dependency is recorded as well. Given the page definition above, a child page will therefore depend on its content object and onto its parent which itself has a dependency on its content object and so on. Thus, if you change the name of the root page, all page objects will be invalidated since they have transitively aggregated it.
There is an alternative solution. Instead of embedding the default data view of the parent, you can do the cache lookup on every access to the parent property. You avoid the dependency; instead you always read the latest version from the cache. This lazy lookup is achieved as follows:
<dataview appliesTo=”com.company.PageImpl”> <property name=”name”/> <property name=”description”/> <property name=”content”/> <property name=”parent” associationType=”static”/> </dataview>
Defining a static association will make the caching system store
which
parent a page is associated with (the lightweight
PageImpl
instance that basically only holds the parent id), in place of its
default data view (which contains the parent’s state). Instead, a cache lookup is done
for the default data view whenever the parent property is retrieved. In Java code, this
behavior looks like this:
class PageImpl$$ extends PageImpl { PageImpl parent = super.getParent(); ... Page getParent() { return (Page)dataviewFactory.lookupCached( this.parent, null); } ... }
A cache lookup is reasonably efficient to make this definition possible. You should, however, keep an eye on the number of lookups. A cache lookup requires thread synchronization, and too many synchronization requests might lead to contention.
One last thing needs mentioning: Properties that should not be cached are simply omitted from the data view definition. But what, if you still want to apply a data view to the property value? For this case, a “dynamic” association can be defined:
<property name=”randomPage” associationType=”dynamic”/>
With this definition,
#getRandomPage()
will be generated as follows:
class PageImpl$$ extends PageImpl { ... Page getRandomPage() { // invoke original impl, don’t cache Page p = super.getRandomPage(); // cache lookup return (Page)dataviewFactory.lookupCached( p, null); } ... }
Figure 4.1, “Phases of a data view lifecycle” shows, how data views are loaded and evaluated in the lifecycle of an HTTP request.
To recapitulate, if a property is an association to another bean, it is possible to apply a data view to that bean as well. There are four ways to do that:
Association Type | Reference is stored in field | Data view is applied at ... | Cache Lookup | Implies Cache dependency to |
---|---|---|---|---|
composition | yes | creation time | no | Content Bean and Data View |
aggregation | yes | creation time | yes | Content Bean and Data View |
static (default) | yes | property access | yes | Content Bean |
dynamic | no | property access | yes | none |
Table 4.3. Association types