Category Rendering
Introduction
While parameter rendering is a way to explicitly influence how a component will render itself by providing parameters to the render instruction, category rendering is an implicit rendering method that allows a component to define different templates, recources, etc. that are used in different rendering contexts. Implicit means that the information is usually gathered from the invocation context; that is, contelligent allows to deploy so called Category Resolvers that do check the invocation context before any contelligent rendering or action execution takes place.
To understand what categories actually do, we have to talk a bit about contelligent internals here. Contelligent components that are renderable usually provide a method called render that is called to externalize the content of a component as it is later send to the output channel. In order to allow components to adapt to various situations, the render call is invoked using a parameter called CallData. The CallData contains information about the calling context. Typically components should not try to adapt themselves to CallData internals like some specific HTTP request properties. Doing so will constraint the applicability of your component to just HTTP based channels. The better way is to rely on contelligents mechanism to define the content. One way to achieve this is the technique of categories employed in contelligent. This section will cover the basics on this topic.
The illustration below shows the abstract rendering process incorporated in contelligent. The Rendering is typically invoked through some channel (in this example a synchronous HTTP Channel). Various contelligent channels exists. The HTTP Channel is served by a contelligent servlet illustrated in this example. Before actually rendering logic is done by contelligent, the Servlet calls all deployed category resolvers that are allowed to inspect the request and the currently active sessions for hints on which category values to use. After the call is prepared, the contelligent servlet invokes the rendering engine to produce a rendered answer for the request. Components invoked in course of this rendering can use the current category values to determine the actual rendering behaviour. This is illustrated in our example by the Category Sensitive Component evaluating to three different looking results (e.g. green, orange, purple).
Developing a category sensitive component as well as developing and deploying a CategoryResolver implementation will be left out for later sections. See the various Developing Component sections in this tutorial to get further information on this topic. For now we will focus on existing contelligent components and how they can be used to adapt the output based on the category definitions associated with the current invocation context.
CategoryResolver setup
Categories are defined in the *-project.xml files residing in your contellingent-home/config directory. The default project.xml file defines some categories for illustration purpose. Usually those definitions should be easy to adapt to your specific needs. In order to setup or modify the category definitions, you can open the project.xml file and modify the <category-definition> section to suite your needs. The following snippets should be used as an example to explain how category definitions are actually deployed:
<category-definition>
<category name="channel" default="html">
<description lang="en" title="channel" help="none">
Defines the format a client expects to receive from the server,
for example HTML or XML.
</description>
<description lang="de" title="Kanal" help="none">
Definiert das Format, das eine Client-Applikation vom Server
erwartet, zum Beispiel HTML oder XML.
</description>
<resolver
className="de.finix.contelligent.category.RequestAttributeResolver"
/>
<resolver
className="de.finix.contelligent.category.ChannelResolver"
/>
<element name="html"/>
<element name="wml" fallback="html"/>
<element name="xml"/>
</category>
<category name="locale" default="de">
<description lang="en" title="locale" help="none">
This category enables multi-language support.
</description>
<description lang="de" title="Sprache" help="none">
Die Kategorie Sprache erlaubt die Erstellung eines
mehrsprachigen Auftritts.
</description>
<resolver
className="de.finix.contelligent.category.RequestAttributeResolver"
/>
<resolver
className="de.finix.contelligent.category.LocaleResolver"
/>
<element name="de"/>
<element name="de_AT" fallback="de"/>
<element name="en"/>
</category>
<category name="custom" default="generic">
<description lang="en" title="Custom" help="none">
A customer category based on request parameters only
</description>
<description lang="de" title="Nutzerdefiniert" help="none">
Eine Benutzerdefinierte Kategorie
</description>
<resolver
className="de.finix.contelligent.category.RequestAttributeResolver"
/>
<element name="someValueA"/>
<element name="someValueB"/>
<element name="generic"/>
</category>
</category-definition>
The example above defined three categories channel, locale & custom. A category definition element has to define its name in the name attribute. The default value of the category is defined in the default attribute in the category element itself. In addition to a description element which can be localized (using the lang attribute), the category element contains resolver and element tags. The resolver tags provide a hook to define so called Resolver implementations used to decide which category value applies to the current invocation context and is thus added to the CallData. The element tags allow you to declare which values are actually support. This can be used to constraint the values the resolver might return.
Let's say you don't like the locale setup provided by the default example config. You may decide that you don't want to provide the german locale (de) and neither the regional german austrian locale (de_AT) but want to provide english and french content. You might do so by changing the category definition as followed:
<category name="locale" default="de">
<description lang="en" title="locale" help="none">
This category enables multi-language support.
</description>
<description lang="fr" title="locale" help="none">
french category for multi-language support
</description>
<resolver
className="de.finix.contelligent.category.RequestAttributeResolver"
/>
<resolver className="de.finix.contelligent.category.LocaleResolver"/>
<element name="fr"/>
<element name="en"/>
</category>
Editing Multi-Category Content and Templates
In order to learn how to use Contelligent Categories to define content and templates that differ based on the calling contexts current category combination, you can start to create a component somewhere in the tree. Actually any component that support general categories is good for this purpose, but to stay in synch with this tutorial, just create a plain Text component.
Once you created a text component you can switch to edit mode and use the 'Define Sensitive Categories' tool. To access it you must explicitly focus the editor of the content you want to set the Categories on. In case of a text component selecting the 'Text' Tab should bring up the toolbar you need in order to do this. After you have selected the Define sensitive Categories Action you will be presented with a category wizard which will ask you what categories you want your component to be sensitive for. For our example just select locale here and enable both languages on the second form of the category wizard.
After you have finished adding your new category sensitivity to your text component. Editing will show up a new tab for each unique category combination available for your setup.
To illustrate the steps mentioned above we capture a movie for your convenience (see above).




