Data views are defined declaratively using XML according to a schema
/META-INF/dataviews.xsd
which is located inside cae-contentbeanservices-api.jar
. Behind the
scenes, subclasses of the application classes are generated. This process is transparent, as
the remainder of the application should be written to the application class interfaces.
Looking at a data view object’s class, however, it becomes obvious that it is actually an
instance of a subclass of the original business class. How these classes behave, will be
described later.
A sample XML data view definition using the example from above looks as follows:
<dataview appliesTo=”com.company.PageImpl”> <property name=”name”/> <property name=”description”/> <property name=”content”/> <property name=”parent” associationType=”composition”> <dataview appliesTo=”com.company.PageImpl” name=”forLinking”> <property name=”name”/> </dataview> </property> </dataview>
This definition says: The default (no name attribute) data view of a
PageImpl
materializes the properties name
, description
,
content
and
parent
as fields where the latter is itself a bean of type
PageImpl
with data view
forLinking
(which is
defined inline) applied. The association between the two data views is a composition. That
means: the outer object embeds its private parent instance which is not shared with other
beans, that is, the outer element owns the inner element exclusively. Specifically, no cache
lookup is performed to retrieve the inner element, but it is always created when the outer
element is created. The various association types will be described later.
This data view defines a view on Page documents that makes the following properties cached and quickly accessible:
page.{name,description,content,parent}
page.parent.name
All other properties are inherited from your
*Impl
classes and are therefore
accessed dynamically. That does not mean that they are necessarily slow (there is a document
cache after all).
To use the defined data views, the data view factory dynamically constructs two subclasses
of PageImpl
, one for each data view definition. When the default data view is
loaded, the data view factory will look into the cache with a key
<Page content bean, null (default)>
(Remember that
the Page content bean’s equality is defined in terms of its content id). If the key is not
in the cache, the factory will create an instance of the first subclass and load the
properties description,
content
and
name
by
invoking the business methods and storing the results. Furthermore, it will load
parent
(another lightweight PageImpl
) and
construct data view
forLinking
for it. To do so, it will
not do a cache lookup but instantiate the corresponding second subclass of
PageImpl
directly. The result is stored as the materialized
parent
property of the result.
The generated code for the definition from above is roughly equivalent to the following:
class PageImpl$$ extends PageImpl { String name = super.getName(); ... PageImpl parent = (PageImpl)dataviewFactory.lookupUncached( super.getParent(), “forLinking”); ... Page getParent() { return this.parent; } ... }
It is possible to define data views with the same name for different classes. During the lookup for that name, the class of the object determines which data view definition is chosen – a dynamic dispatch very much like for content bean creation or the templates. This way, it is possible to apply a data view to a property value with a varying runtime class.
The default data view has a special meaning: it is the data view that is loaded at the beginning of a request when rendering the bean referenced by the URI. So this data view should correspond to the properties that the default view and its included fragment views require.