Chapter 11. Services Tutorials

These tutorials build upon the discussion in Chapter 4 WAF Component: Services.

11.1. Categorization Tutorial

This section presents an overview of using the categorization layer within WAF. The focus in this section is on describing the main concepts, classes, and interfaces that a programmer uses to work with the categorization API.

11.1.1. Overview

This section partially overlaps with and elaborates on the material presented in http://rhea.redhat.com/documentation/api/ccm-core-6.1.0/com/arsdigita/categorization/package-summary.html.

A category is a class of objects or things that share something in common within a conceptual scheme. It has a short name and an optional description. Each category also has a unique identity. Two distinct categories may happen to have the same name. They are treated as two different categories, if their identities are different. This abstraction is represented by the Category class.

There are two kinds of things that can be placed in a category. Firstly, a category may contain other categories within it. Such categories are called subcategories or child categories. The enclosing category is referred to as the parent category. Category Y is said to be a descendant of category X if either Y is a child of X, or the parent of Y is a descendant of X. If Y is a descendant of X, then X is called an ancestor category or ascendant category of X.

Secondly, a category may contain objects other than categories. In our system, a category may contain any ACSObject. Note that the Category class is itself an ACSObject, but one that has a special status in the categorization service. If ACSObject A is placed into category X, then we say that A is a child object of X and X is a parent category of A. We say that object B is a descendant object of category X, if either B is a child object of X, or the parent category of B is a descendant of X.

Let us first concentrate on the category-subcategory relationship. A category cannot contain two identically named subcategories.

We also require that there be no cycles. In other words, A must not be its own descendant. As an edge case of this general rule, A cannot contain itself as a subcategory.

A category may have more than one parent. By allowing this, we make possible categorization schemes that do not look like trees (see below). This complicates matters slightly, insofar as trees are easier to deal with than the more general structure known as directed acyclic graphs. To restore the ability to treat categorization schemes as trees, we allow some category-subcategory links to be marked as "default". We require that each category have no more than one default parent. A default parent is also sometimes referred to as a primary parent. Non-default parents are called secondary parents.

A category with no parents is called a root category. This category and its descendants are referred to as a category scheme. By disregarding non-default parent-child links, we can obtain a subset of the categorization scheme that forms a proper rooted tree. The following diagram shows a simple categorization scheme.

Figure 11-1. Categorization scheme

In the above diagram, the default parent of Televised Events is TV Shows. Its secondary parent is Sports. Once we have a categorization scheme, we can start categorizing objects.

The following diagram shows three objects placed in the above categorization scheme.

Figure 11-2. Categorized objects

Note that an object can be categorized under more than one category. In the above example, the movie The Natural belongs to two categories.

It is possible to have two or more separate categorization schemes within the same application. Suppose the Legal and Marketing departments each need their own independent categorization scheme. This is supported through the notion of categorization contexts. Each categorization scheme is uniquely identified by its root category. Each root category is tied to an application that owns it. An application may own more than one category root. Each association may be labeled with a unique string, called a context.

Figure 11-3. Categorization contexts

In the above example, the application name is Content Section. It has two categorization schemes identified by the contexts legal and marketing, respectively.

11.1.2. Classes

To use the categorization layer, you should become familiar with the following classes.

com.arsdigita.categorization.Category

http://rhea.redhat.com/documentation/api/ccm-core-6.1.0/com/arsdigita/categorization/Category.html

A Category encapsulates a persistent category object. This object contains the name and description for the category, as well as information about whether the category is enabled. It also provides an API for placing objects within this category, creating subcategories under the instance category, and retrieving parent and child categories and objects.

This class has several notable methods that you should understand before beginning work with categorization. The URLs have been line broken with a "\" for printing purposes:

com.arsdigita.categorization.CategoryCollection

A collection of categories, e.g. children of the same parent category.

com.arsdigita.categorization.CategorizedCollection

A collection of (non-category) objects, e.g. child objects of a category.

com.arsdigita.categorization.CategorizedObject

http://rhea.redhat.com/documentation/api/ccm-core-6.1.0/com/arsdigita/categorization/CategorizedObject.html

A convenience wrapper for working with the leaf nodes of a category scheme. Methods within CategorizedObject can be used to retrieve the parent categories or default ancestors of the object.

Other Classes

These classes work together to provide access to a Bebop Tree that can be used to display the category tree:

These classes are not of much importance to you unless you want to change the way the tree appears. Displaying a category hierarchy is a multiple-step process. First, create a TreeModelBuilder that will instantiate a CategoryTreeModelLite (based either on a query or some other external data source). This TreeModelBuilder is passed to the Tree, which uses your builder to create its TreeModel. This process is necessary since a DataObject cannot be used across connections.