close

Filter

loading table of contents...

Content Application Developer Manual / Version 2301

Table Of Contents

4.2.2.2 Guidelines For Data View Design

This section contains some guidelines or rules of thumb for the proper definition of data views.

Define the property configuration recursively

You have to ensure that a bean's data view configuration is recursively reachable from the root bean's data view configuration. For every property returning this bean, a "bridging" data view configuration entry needs to be added. In order to prevent the cache to be filled with unnecessary "bridge" properties, the association type dynamic might be used, for instance.

<dataview appliesTo="com.mycompany.PageBean">
  <property name="content" associationType="dynamic"/>
</dataview>

Why is this important?

From a data view's point of view, the process of rendering nested bean takes place as follows:

  1. The controller computes the root bean (containing nested beans) from an incoming request

  2. The controller invokes DataViewFactory#loadCached(bean, name) for this bean in order to apply a data view

  3. The controller passes the bean to the rendering engine (and therefore to the view templates) where the bean's properties are accessed and rendered

  4. When accessing a bean property which is returning further beans, a data view will be applied automatically to these sub beans

In other words, the initial appliance of a data view to the root bean leads to a recursive appliance of data views to all sub beans. Unfortunately, this is true in case that there is a data view configuration (dataviews.xml) for every relevant bean/property only. Let's say there is no such configuration for the root bean, then no data views will be applied to the sub beans automatically and these beans will be returned as they are. As a consequence, the sub beans wouldn't be cached even if there is a data view configuration available for them.

Example

There is a PageBean having a JSP template:

public interface PageBean {
  ArticleBean getContent();
}
<cm:include target="${self.content}"/>

The template includes the rendering of an ArticleBean

public interface ArticleBean {
  String getHeadline()
}
<c:out value="${self.headline}"/>

If there is a data view configuration for the (supposed "expensive") property "headline"

<dataview appliesTo="com.mycompany.Article">
  <property name="headline"/>
</dataview>

without defining a configuration for the root bean

<dataview appliesTo="com.mycompany.PageBean">
  <property name="content" associationType="static"/>
</dataview>

then there won't be any caching of the "headline" property.

Auto completing the data view configuration

In large projects, a recursive definition of data views might be a difficult and error-prone task. Unwanted gaps in the transitive closure and thus uncached beans may be the result. For this reason, there is a feature called "auto completion" which helps to achieve a complete transitive closure of data views.

Auto completion can be configured in the dataviews.xml like this:

<dataviews>
 ...
 <autocomplete>
  <class name="com.coremedia.objectserver.dataviews.AssumesIdentity"/>
  <class name="java.util.Map"/>
  <class name="java.util.List"/>
 </autocomplete>
 ...
</dataviews>

Example 4.1. Auto completion example


This configuration causes the DataViewFactory to implicitly use the association type DYNAMIC for all bean properties whose getter method's return type inherit from AssumesIdentity, Map or List and which are not already covered by a data view configuration. Not only properties of configured data views will be automatically completed but also those of beans that do not have a data view configuration at all.

Caution

Caution

Please note that only the getter method's return type is taken into account during auto completion, not the concrete type of an object returned from the getter at runtime.

As a consequence of this feature, you are able to design a lean data view configuration with only a few purposeful property configurations.

But there are also some drawbacks: If there are only a few data views explicitly declared, the DataViewFactory will have to create many transient ("uncached") data view objects in order to provide closure. Thus, lots of additional objects populate the java heap temporarily which mean more work for the garbage collector. In addition, some synchronization is required when accessing properties. This might reduce the application's performance. Choose the auto-completion types carefully so that all property return types are covered on the one hand, without being too generic on the other hand. As a rule of thumb, the super interface of your content beans (such as AssumesIdentity) together with java.lang.List and java.lang.Map might be a good starting point.

Of course, there might be properties which should not be automatically completed. For this reason, a pseudo association type none can be used to explicitly exclude a property from being automatically completed.

<dataview appliesTo="com.yourcompany.YourBean">
 <property name="userInfo" associationType="none"/>
</dataview>

Example 4.2. Auto completion exclusion example


The property userInfo of YourBean won't be ever automatically completed and will be treated as if there is no automatically completion and no data view configuration.

Let the controller apply a data view to its beans

A controller's contract is to compute a ModelAndView which contains one or more model beans to be passed to the rendering engine. In order to make the model beans cacheable, it's important to apply a data view to these beans within the controller.

Example

This example demonstrates a simple controller implementation snippet:

ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) {

  // compute the model bean from the request
  MyBean modelBean = computeBean(request);
  // apply a data view to this bean
  MyBean cachedModelBean = (MyBean)
  getDataViewFactory().loadCached(modelBean, null);
  // construct the controller's result
  ModelAndView result = ControllerUtils.viewOf(cachedModelBean);
  return result;
}
Use caching only when it is reasonable

Caching with data views is for improving an application's performance: The results of property computations are stored in the heap memory in order to prevent a repeated computation when accessing the property the next time. The values are removed from the cache when they are becoming invalid or due to evictions.

The process of caching itself is not for free: Each cached entry consumes a bit of the (limited) heap space on the one hand. On the other hand, each cache read or write operation is synchronized by the cache which might lead to decreased concurrency. For this reason data view caching of a single property should be used purposeful, that is when it results in a better performance. Here are some situations where data view caching might not be worthwhile

  • The computation of a property is cheap.

  • The property value is already cached elsewhere. For instance, the Unified API is already caching its content properties: When simply delegating the content bean's property access to the content objects, the content beans need not to be cached again. Another example is a property which accesses another already cached property, for example a property firstSentence which performs a cheap string operation on a cached property text.

  • A cached data view will be generally invalidated or evicted immediately after it is put into the cache without or rarely being accessed in the mean time.

Make sure that it is worthwhile from a performance point of view before enabling a property to be cached by a data view.

Avoid caching of large objects

Caching with data views is especially suited for properties that consume moderate memory. In opposite, large objects (such as binary objects) shouldn't be cached by data views since the heap memory is used disproportionately.

Choose the right association type

Properties can be separated into two groups from the data view's point of view

  • Associating Properties: Properties which values are beans or collections of beans where data views can be applied on again.

  • Simple Properties: All other properties with return values such as String, Int or other objects

You do not need to define an association type for a simple property. Instead, a data view configuration such as <property name="propertyname" /> is sufficient. For an associating property you have to choose between the following association types which differ in terms of memory consumption, synchronization behavior and invalidation/eviction behavior.

  • static

  • composition

  • aggregation

  • dynamic

Despite this different behavior, these aspects doesn't need to be considered primarily when starting to create the data view configuration. For the beginning it is sufficient to choose "static" for a cacheable property and "dynamic" for a non-cacheable property in order to make another property recursively reachable (see above). As soon as you have finished your initial data view configuration, you can do some optimizations by replacing specific association types with "aggregation" or "composition" in second step.

You can use the CoreMedia Contribution "CAE Console" to tweak your data view settings.

Do not implement property methods that use context data

In order to make a bean property cacheable you have to implement a public (non static and non final) getter method without parameters. Make sure that the method's implementation doesn't use any context data such as "current user", "current session" or similar stateful data. Otherwise, a property value is related to an arbitrary context when putting it into the cache. When reading it from the cache then, it might not fit to the reader's context.

The following example demonstrates a bad implementation where a list of content objects is filtered according to the current user's rights.

public List<ContentBean> getLinks() {

  List<Content> contents = getContent().getLinks("links");
  List<ContentBean> result = new ArrayList<ContentBean>();
  for (Content content : contents) {
    if (mayRead(content, getCurrentUser()) {
      // bad use of context data
      result.add(createBeanFor(content));
    }
  }

  return result;
}

Assume the property "links" to be cached when accessing it the first time: The cached result depends on the right of the user which accesses this property for the first time. Another user accessing this property afterwards will obtain a value which is not appropriate to the user's rights and therefore might have access to more or fewer contents than required.

Search Results

Table Of Contents
warning

Your Internet Explorer is no longer supported.

Please use Mozilla Firefox, Google Chrome, or Microsoft Edge.