Cascade Server Hidden Gems Series: The Velocity Tool Edition

Wednesday, March 26th, 2014 at 9:00am

gem three

As of Cascade Server 7.4, two new tools have been added to the Cascade Velocity scripting toolbox. The Locator Tool dynamically locates assets in Cascade Server in the form of Cascade Server API objects. The Property Tool enumerates over the properties and methods exposed by a given Velocity object.

For the non-techies, this means that in your Velocity Formats you can grab (locate) any asset and access its data (metadata, Data Definitions, properties, etc.) without that asset's data being included through the use of a Block.

It should be noted that the Property Tool simply displays the available data structure for a Cascade Server object. It is not to be used for generating live output for your page. It's similar to creating an XML output for a page so you can see the XML data structure you're working with while writing your Format.

A simple example

On the landing page of a news section, it would be common to show a short (or long) list of recent news stories. Those stories could be hand-picked or automatically populate on the page. In either case, let's say you wanted to display the title, the publish date, and a truncated version of the article content.

top stories

Before the Locator Tool, in order to build out this example you would most likely use a Content Type Index Block that includes Page XML and pair that with a Velocity Format. Your Format might look something like this:

#set ( $news = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page") )
#if ( $news.size() > 0 )
$_SortTool.addSortCriterion("start-date", "en", "number", "descending", "upper-first")
<div class="col-md-12 column" id="latestNews">
<h3>Latest News</h3>
#foreach ( $n in $news )
    #set ( $title = $n.getChild("title") )
    #set ( $link  = $n.getChild("link").value )
    #set ( $date  = $n.getChild("start-date").value )
    #set ( $content = $_XPathTool.selectSingleNode($n, "system-data-structure/content").value )
    <h4><a href="${link}">$_EscapeTool.xml($title.value)</a></h4>
        <span class="text-muted">$_DateTool.format("EEEE, MMMM dd, yyyy", $_DateTool.getDate($date))</span>
        $_DisplayTool.truncate($_DisplayTool.stripTags($content), 250, " ...", true)
    #if ( $foreach.count == 2 ) #break #end

A potential downside to this routine is that you are indexing the whole page in your Index Block and including the entire Data Definition (or default WYSIWYG) and Metadata Set when all you really want is four fields — title, link, publish date, and article content. Compound that with the fact that we only want to output the most recent two articles, you may be indexing more pages than you're actually going to output in the end.

With the Locator Tool, we can exclude the Page XML (the Data Definition or default WYSIWYG) and downsize the amount of data in our Index Block considerably. The data in the Data Definition will no longer be available in the Index Block (you'll be missing a "system-data-structure" or "page-xhtml" element), but you will still be able to access it and grab the content.

How to use the tool

The first thing to take note of is how you call the Locator Tool. Pretty much all of the other tools included in the Velocity context start with "$_" and then the name of the tool ("$_EscapeTool", "$_DateTool", etc). For ease of use, the Locator Tool is a little different in that you only use "$_" to reference it.

Another important piece of information is the method you'll use to reference the asset in question. There are lots of different methods available depending on what type of asset you're looking for, but in this case we'll be using "locatePage()" because we're working with some news article pages. This method is going to expect two parameters (pieces of information): a path for the page and what site the page is in.

$_.locatePage($pagePath, $pageSiteName)

This will return a Cascade Server API object with all of it's included data and properties. To get a quick view of the asset, we can use the "outputProperties()" method to output a list of what data and properties are available. (This is what I noted earlier. We use it to scope the asset, not for actual output.)

#set ( $pageObject = $_.locatePage($pagePath, $pageSiteName) )

When using the Property Tool, you'll get something returned that looks like this:

Object type: com.hannonhill.cascade.api.adapters.PageAPIAdapter
 - lastPublishedBy: String
 - lastModified: Date
 - link: String
 - dataDefinitionPath: String
 - parentFolder: Folder
 - identifier: PathIdentifier
 - getStructuredDataNode(String): StructuredDataNode
 - isUserCanWrite(String): boolean
 - structuredData: StructuredDataNode[]
 - currentUserCanWrite: boolean
 - createdOn: Date
 - metadata: Metadata
 - folderOrder: int
 - parentFolderIdentifier: PathIdentifier
 - createdBy: String
 - lastPublishedOn: Date
 - path: String
 - shouldBePublished: boolean
 - lastModifiedBy: String
 - currentUserCanRead: boolean
 - isUserCanRead(String): boolean
 - hideSystemName: boolean
 - siteName: String
 - shouldBeIndexed: boolean
 - siteId: String
 - xHTMLAsXMLElement: Element
 - name: String
 - xHTML: String
 - getStructuredDataNodes(String): StructuredDataNode[]

That is the structure of the data that is returned by the "$_.locatePage()" method and each property can be referenced easily from the context of that page object.

Depending on the property and resulting object you need, here are some example properties and their example output.

$page.lastPublishedBy - charlie.holder
$page.lastModified - Thu Dec 26 08:19:30 EST 2013
$ - site://News/2013/12/confab-higher-ed-takeaways
$page.dataDefinitionPath - Release
$page.createdOn - Thu Dec 12 11:16:24 EST 2013
$page.folderOrder - 2080374783
$page.createdBy - charlie.holder
$page.lastPublishedOn - Thu Dec 12 15:09:12 EST 2013
$page.path - 2013/12/confab-higher-ed-takeaways
$page.shouldBePublished - true
$page.lastModifiedBy - charlie.holder
$page.siteName - News
$page.shouldBeIndexed - true
$page.siteId - bc6deced7f00000101d07d39221b24a8
$ - confab-higher-ed-takeaways

Some of the data available isn't accessed through a property, but a method instead. Two examples are "getStructuredDataNode(String)" and "getStructuredDataNodes(String)". These two methods are used on the page object to traverse the Data Definition structure just like writing an XPath expression in Velocity and/or XSLT. They expect an XPath expression for which Structured Data Node(s) you want to reference.

#set ( $content = $pageObject.getStructuredDataNode("content") )

This bit of code would access a WYSIWYG field named "content" inside of the Data Definition structure. It's worth reminding you that our Index Block does not actually have to include this information for it to be available. That's the beauty of the Locator Tool.

We can also call the Property Tool on this Structured Data Node to look at it's available properties.

#set ( $pageObject = $_.locatePage($pagePath, $pageSiteName) )
#set ( $content = $pageObject.getStructuredDataNode("content") )

You should get something returned that looks like this:

Object type: com.hannonhill.cascade.api.adapters.StructuredDataNodeAPIAdapter
 - asset: boolean
 - textValues: String[]
 - allowCustomValues: boolean
 - assetIdentifier: PathIdentifier
 - getChildren(String): StructuredDataNode[]
 - getChild(String): StructuredDataNode
 - children: StructuredDataNode[]
 - group: boolean
 - textValueAsXMLElement: Element
 - asset: FolderContainedAsset
 - textNodeOptions: TextNodeOptions
 - textValue: String
 - text: boolean
 - identifier: String
 - group: StructuredDataNode[]

In addition to accessing Structured Data with the Locator Tool, you also have access to Metadata. Using the Property Tool on the Page Object's property called "metadata", you'll get a structure like this:

#set ( $pageObject = $_.locatePage($pagePath, $pageSiteName) )

Object type: com.hannonhill.cascade.api.adapters.MetadataAPIAdapter
 - title: String
 - teaser: String
 - reviewDate: Date
 - startDate: Date
 - keywords: String
 - displayName: String
 - endDate: Date
 - getDynamicField(String): DynamicMetadataField
 - dynamicFields: DynamicMetadataField[]
 - author: String
 - summary: String
 - description: String

Applying what we've learned

From here we should have enough information about the structure and data that is returned to rewrite our original Velocity Script and convert it to using the Locator Tool. We've covered how to reference the page, how to access the Data Definition, and how to access the Metadata.

Most of the code will stay, but we'll make a few changes. The first big change will be to add two variables inside the foreach loop. If we are to use the Locator Tool for each page, we need the path to the page and the site that it's contained in.

#set ( $path = $n.getChild("path").value )
#set ( $site = $n.getChild("site").value )

Next we'll add our calls to access the Page Object and Structured Data Node value.

#set ( $page = $_.locatePage($path, $site) )
#set ( $data = $page.getStructuredDataNode("content").textValue )

These four lines grant us access to everything we need in order to access the Page, dive into the Data Definition, and pull out the content in the WYSIWYG. And because we'll be using the Locator Tool to access the WYSIWYG data, we can remove one of our original lines of code:

#set ( $content = $_XPathTool.selectSingleNode($n, "system-data-structure/content").value )

We can also use the Locator Tool to help output the Metadata. We don't need to create variables for the title, start date, and page link anymore. We can simply reference the page object and use the available properties. (Still use the Escape Tool where you would have before. It's important to preserve XHTML output.) We can remove these lines as well:

#set ( $title = $n.getChild("title") )
#set ( $link  = $n.getChild("link").value )
#set ( $date  = $n.getChild("start-date").value )

Our final version of the code might look something like this:

#set ( $news = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page") )
#if ( $news.size() > 0 )
$_SortTool.addSortCriterion("start-date", "en", "number", "descending", "upper-first")
<div class="col-md-12 column" id="latestNews">
<h3>Latest News</h3>
#foreach ( $n in $news )
    #set ( $page = $_.locatePage($n.getChild("path").value, $n.getChild("site").value) )
    #set ( $content = $page.getStructuredDataNode("content").textValue )
    <h4><a href="${}">$_EscapeTool.xml($page.metadata.title)</a></h4>
        <span class="text-muted">${page.metadata.startDate}</span>
        $_DisplayTool.truncate($_DisplayTool.stripTags($content), 250, " ...", true)
    #if ( $foreach.count == 2 ) #break #end

With this version of our code, your Index Block needs virtually no settings except for a Content-Type and the Indexed Asset Content option for "Regular Content." Those two choices will return a list all the pages that match the Content-Type along with each path and site name. That's all you'll need in order to use the Locator Tool.

In the end, we cut down our code by a few lines and significantly sped up the time needed to render the XHTML content. The Locator Tool is a great option for those lists of pages (short and long) that need just a few pieces of information from the Data Definition. It's an option that keeps your Index Block sizes down and your system running smoothly.

What are some ways you have used the Locator Tool?

Got questions about using the Locator Tool or Property Tool? Post them here and we're happy to help!

Subscribe to our blog via RSS Download RSS

Hannon Hill Corporation

3423 Piedmont Road NE, Suite 520
Atlanta, GA 30305

Phone: 678.904.6900
Toll Free: 1.800.407.3540
Fax: 678.904.6901

GSA Contract Holder