Templates are widespread throughout Alfresco: They are used within the repository core to generate emails and activities, in the Explorer client to build custom views, at the remote REST API layer, and also as the default rendering mechanism for the Web Script and Surf Frameworks.
Alfresco provides a number of ways to process templates; REST-style URL, Web script components, and JSF UI components. In addition, AVM repository data can be processed in templates.
Multiple template engines are supported, with FreeMarker as the default. The template engine is not tied to any output file format: Templates can output entire HTML files as well as snippets of HTML, XML, JSON, or any other format desired. This makes them extremely flexible and appropriate for developing all kinds of solutions with Alfresco.
Templates can be stored either on the classpath (for example, in alfresco/config/templates) or in the repository store.
Each template file will be specific to a particular template engine. The template service will pick the appropriate engine based on the file extension. By default, FreeMarker template files will be used. In the case of the Web Script and Surf Frameworks, FreeMarker is always selected as the template engine.
A model consists of a number of objects or a hierarchy of objects from which a template file retrieves values that can be used to dynamically generate the output. The model is like the API for the template page: It provides the objects from which properties, values, and further objects can be accessed. The Alfresco repository provides a "default" model that is always available when rendering templates via the JSF template component and the template servlet. The Web Script Framework provides additional model objects relevant to processing output for remote APIs. Programmatically it is also possible to define a custom model that can be merged into the default model to provide additional model objects. Custom Java objects can be configured via Spring to make them available to template models within the repository and/or the Web Script Framework.
The default model provides a number of common objects useful for most templates. Most of the objects wrap the notion of an Alfresco Node (such as a space or document in the repository) and are known as TemplateNode
objects. This provides a rich OO layer to make it easy to display common Alfresco concepts, such as node properties, aspect values, and content.
If you are accessing a template through the Explorer client UI Template component (this is the common case when developers use this component directly), the following named objects are provided by default at the root of the model. Note that Web scripts hosted within the Alfresco repository tier also have access to the following template root objects. Web scripts hosted within the presentation tier (that is, within Alfresco Surf) have their own extras, as described in Appendix B.
companyhome
— The Company Home template node
userhome
— The current user's Home Space template node
person
— The node representing the current user's Person
object
template
— The node representing the template itself
When accessing a template through the Explorer Web client using a custom view for a space, the Preview In Template action, or a URL using the template servlet, the following named object is also provided:
space
— The current space template node
When accessing a template through the Explorer Web client using a custom view for a document, the Preview In Template action, or a URL using the template servlet, the following named object is also provided:
document
— The current document template node
The companyhome, userhome, person, template, space
and document
objects are all TemplateNode
objects. A TemplateNode
object represents a node in the Alfresco repository and has its own rich API for accessing common Alfresco concepts, such as properties, aspects, associations, and content.
If accessing a template via the template servlet, the following object is also available:
args
— A map of any URL parameters passed via the template content servlet. This is a neat way to pass additional parameters to your template. FreeMarker has built-in methods to parse integers and check for the existence of values that can be used to make your template even more interactive and powerful. For example, you can output the names of the arguments passed to a template:
<#assign keys = args?keys> <#list keys as arg> ${arg} </#list>
Various other root objects are also available to provide a full set of rich functional objects to the template developer:
session
— Session-related information providing a single value session.ticket
for the current authentication ticket; useful when generating some Alfresco URLs for accessing outside of the Web client.
classification
— Read access to classifications and root categories.
url
— Provides a single property url.context
that can be used to retrieve the Alfresco container context path, such as /alfresco; useful when generating URL links to objects. This is not available when using the template as a custom view on a space.
workflow
— Read access to information on workflow objects and the currently executing workflows for a user.
The various default model objects can be accessed directly from the root of a model in your template. For example, you could use the following to display the name
property of the userhome
object:
${userhome.properties.name}
The Alfresco node model is built dynamically as you access it, enabling you to write statements such as:
${userhome.children[1].children[0].children[2].name}
It should be noted that the FreeMarker template engine is very strict on the access of empty or null values. Unlike many templating or scripting languages that display empty values or assume FALSE as a default value for a missing property, the FreeMarker engine will instead throw an exception and abort the rendering of the template. To help you build stable templates, most of the TemplateNode API calls provided by the default model that return maps or sequences (lists) of items will return empty maps and sequences instead of null. Also if a null value may be returned by a call (for instance, from accessing a map to find a value by name), you should use the FreeMarker built-in exists
method or, preferably, the shortened form of ??
to check for null first. Therefore:
<#if mynode??> <#if mynode.assocs["cm:translations"]??> ${mynode.assocs["cm:translations"][0].content} </#if> </#if>
checks for the existence of mynode
and then checks for the existence of a translation
association before attempting to access the translation.
TemplateNode
objects and any subsequent child node objects provide access to the common Alfresco concepts, such as properties, aspects, and associations. The following template API is provided:
properties
— A map of the properties for the node, such as userhome.properties.name
Properties may return several different types of objects. This depends entirely on the underlying property type in the repository. If the property is multi-value, the result will be a sequence that can be indexed like any other sequence or array. If the result is an unknown or unsupported type, the toString
() result is generally used; therefore, the result will mostly be a String type. If the property can potentially contain a null value, take care when accessing it and use the exists
FreeMarker built-in method to check for null values before accessing the property.
Date and Boolean property values should be handled carefully. The FreeMarker built-in methods is_date
and is_boolean
can be used to check the property value type if the page developer is unsure of it. These values can then be formatted as appropriate.
If the type of the property is a NodeRef
object (d:noderef
in the content model), the template model will automatically convert the property type into another TemplateNode
object. This means the template developer can continue to dynamically walk the object hierarchy for that node. For example, if a document node has a NodeRef
property called locale
, you could execute the following to retrieve the name of the node the property references:
${document.properties.locale.properties.name}
If a property is of the datatype d:content
, additional API methods are available on the returned object. Methods are provided to retrieve the content, mimetype, displayMimetype, encoding, size
, and url
for the content property. For example:
${document.properties.content.mimetype} ${document.properties.content.content}
As most document nodes are derived from the default Content Model type cm:content
, shortcut APIs to access properties on the default cm:content
content property are supplied directly on the TemplateNode
object.
Helper methods to perform some simple textual operations on the content properties are also provided:
content.getContentMaxLength(length)
—Returns content up to a maximum length
content.getContentAsText(length)
—Converts binary content (such as Word and PDF) to text, up to a maximum length
children
— A sequence (list) of the child nodes. For example:
mynode.children[0]
assocs
— A map of the target associations for the node. Each entry in the map contains a sequence of the Node
objects on the end of the association. For example:
mynode.assocs["cm:translations"][0]
sourceAssocs
— A map of the associations to this node. Each entry in the map contains a sequence of the Node
objects for the given association that reference this node. For example:
mynode.sourceAssocs["cm:avatarOf"][0]
childAssocs
— A map of the child associations for the node. Each entry in the map contains a sequence of the Node
objects on the end of the child association. For example:
myforumnode.childAssocs["fm:discussion"][0]
aspects
— A sequence of the aspects (as QName strings) applied to the node.
hasAspect(String aspectName)
— A function that returns true if a node has the specified aspect. For example:
<#if userhome.hasAspect("cm:templatable")>...</#if>
isContainer
— If the node is a folder node, this is true; otherwise, it is false.
isDocument
— If the node is a content node, this is true; otherwise, it is false.
isCategory
— If the node is a category node, this is true; otherwise, it is false.
content
— Returns the content for the default content property of the node as a string.
url
— The URL to the content stream for the default content property for this node.
downloadUrl
— The URL to the content stream for the default content property for this node as an HTTP1.1 attachment object.
displayPath
— The display path to this node; constructed from the cm:name
property of each parent node in the hierarchy.
webdavUrl
— The WebDAV URL to the node, based on the cm:name
-based path to the content for the default content property.
icon16
— The small icon image for this node.
icon32
— The large icon image for this node.
icon64
— The extra-large icon image for this node.
mimetype
— The MIME type encoding for content for the default content property attached to this node.
displayMimetype
— The human-readable version of the MIME type encoding for the content attached to this node.
encoding
— The character encoding for content attached to the node from the default content property.
size
— The size, in bytes, of content attached to this node for the default content property.
isLocked
— If the node is locked, this is true; otherwise, it is false.
id
— GUID for the node.
nodeRef
— NodeRef string for the node.
name
— Shortcut access to the name
property.
type
— Fully qualified QName type of the node.
typeShort
— Prefix string or "short" QName type of the node.
parent
— Parent node will be null only if this is the root node.
permissions
— Sequence of the permissions explicitly applied to this node; strings returned are of the format [ALLOWED|DENIED];[USERNAME|GROUPNAME];PERMISSION
. For example, ALLOWED;kevinr;Consumer
can be easily tokenized on the semicolon (;) character.
inheritsPermissions
— If the node inherits its parent node permissions, this is true; if the permissions are applied specifically, this is false.
hasPermission(permission)
— Returns true if the current user has the specified permission on the node. For example:
<#if userhome.hasPermission("Write")>...</#if>
childrenByXPath
— Returns a map capable of executing an XPath query to find child nodes, such as companyhome.childrenByXPath["*[@cm:name='Data Dictionary']/*"]
. The map executes an XPath search against the current node and returns a sequence of the nodes as results of the query.
childByNamePath
— Returns a map capable of returning a single child node found by name path, such as companyhome.childByNamePath["Data Dictionary/Content Templates"].
Under the covers, this method is building an XPath and executing a search against the cm:name
attribute on children of the current node. This method allows you to find a specific child node if you know its name.
Note that the previous API calls use the node they are executed against as the current context for the query. For example, if you have a folder node called myfolder and you execute the call myfolder.childByNamePath["MyChildFolder"]
, the search tries to find a folder called MyChildFolder as the child of the myfolder
node.
childrenBySavedSearch
— Returns a map capable of executing a search based on a previously Saved Search object.
It returns a sequence of child nodes that represent the objects from the results of the search. For example:
companyhome.childrenBySavedSearch["workspace://SpacesStore/92005879-996a- 11da-bfbc-f7140598adfe"]
The value specified must be a NodeRef
to an existing Saved Search object.
childrenByLuceneSearch
— Returns a map capable of executing a search against the entire repository based on a Lucene search string.
It returns a sequence of nodes that represent the objects from the results of the search. The value can be any valid Lucene search string supported by Alfresco. Note that you may need to escape Lucene special characters. The entire repository is searched; the current node is only used as an access point to retrieve the search object.
nodeByReference
— Returns a map capable of executing a search for a single node by NodeRef
reference. This method allows you to find a node if you have the full NodeRef
string or NodeRef
object.
The following values are available but are required only for special-use cases.
qnamePath
— QName-based path to the node; useful for building Lucene PATH-style queries that constrain to a path location
primaryParentAssoc
— ChildAssociationRef
instance for the node
auditTrail
— Returns a sequence of AuditInfo
objects representing the Audit Trail for a node; available only if auditing is active for the repository
isTemplateContent(object)
— Returns true if the given object is a TemplateContentData
instance; useful to determine if a value returned from a property is of the d:contentdatatype
isTemplateNodeRef(object)
— Returns true if the given object is a TemplateNodeRef
instance; useful to determine if a value returned from a property is a d:noderefdatatype
Through the Version History API, you can obtain metadata and content for a previous version of a versioned document node.
versionHistory
— Returns a sequence of Version History record objects for a versioned TemplateNode
Each Version History record object has the following API:
id
— GUID for the node
nodeRef
— NodeRef
string for the node
name
— Name property of the node version record
type
— Fully qualified QName type of the node
createdDate
— Created date of the version
creator
— Creator of the version
versionLabel
— Version label of the version record
isMajorVersion
— Boolean true if this was a major version
description
— Version history description
url
— URL to the content stream for the frozen content state
In addition, the properties
and aspects
APIs as described above for TemplateNode
are available, which return the frozen history state of the properties and aspects for the node version record.
The classification
object provides read access to classifications and root categories.
getRootCategories(String aspectQName)
— A function to get a sequence of root categories for a classification
getAllCategoryNodes(String aspectQName)
— A function to get a sequence of the category nodes for a classification
allClassificationAspects
— Returns a sequence of QName
objects of all classification aspects
The following extended node API methods are provided to work with category node objects:
categoryMembers
— Gets all members of a category
subcategories
— Gets all subcategories of a category
membersAndSubCategories
— Gets all subcategories and members of a category
immediateCategoryMembers
— Gets all immediate members of a category
immediateSubCategories
— Gets all immediate subcategories of a category
immediateMembersAndSubCategories
— Gets all immediate subcategories of a category
The FreeMarker language supports XML DOM processing using either DOM functional or macro-style declarative operations. The Alfresco TemplateNode API has been extended to provide access to the FreeMarker DOM model objects.
xmlNodeModel
— Returns the XML DOM model object for the content of the node
If the node content is valid XML and the XML can be parsed, then this method returns the root of the DOM for this node. The DOM can be walked and processed using the syntax as per the FreeMarker XML Processing Guide.
The workflow
root object provides read access to the in-progress and finished tasks for the current user. It also provides a function to look up a single task by its task ID. The functions described mostly return WorkflowTaskItem
objects.
assignedTasks
— The sequence WorkflowTaskItem
objects representing the assigned tasks for the current user
pooledTasks
— The sequence WorkflowTaskItem
objects representing the pooled tasks for the current user
completedTasks
— The sequence WorkflowTaskItem
objects representing the pooled tasks for the current user
getTaskById(taskId)
— A function to return a single task given a known task ID
The WorkflowTaskItem API represents a single WorkflowTask
object. It will probably contain a package of one or more objects that contains references to the objects pertinent to the workflow item, such as a document or folder of documents scheduled for review.
type
— Workflow task type value
qnameType
— Underlying QName model type of the workflow task
name
— Task name value
description
— Task description value
id
— Task ID
isCompleted
— Boolean value true if the task has been completed
startDate
— Start date of the workflow task
transitions
— Returns a map of the available task transition names to transition Labels and IDs
initiator
— Returns a TemplateNode
representing the user who initiated the workflow task
outcome
— The outcome label from a completed task
package
— Returns the NodeRef
to the workflow package node
packageResources
— Returns a sequence of the node resources from the package attached to this workflow task
properties
— A map of all the properties for the task; includes all appropriate BPM-model properties
The people
root object provides basic user and group query API and inspection capabilities.
getPerson(username)
— Returns the person node (cm:person
) for the given username; returns null if not found
getGroup(groupname)
— Returns a group node (usr:authorityContainer
) for the given group authority name; returns null if not found
getMembers(group)
— Gets the members (people) of a group, including all subgroups
getMembers(group, recurse)
— Gets the members (people) of a group; optionally recurses into subgroups
getContainerGroups(person)
— Gets the groups that contain the specified person (cm:person
node)
isAdmin(person)
— Returns true if the specified person (cm:person
node) is a member of the Administrator group
isGuest(person)
— Returns true if the specified person (cm:person
node) is a guest user
getCapabilities(person)
— Returns a map of capabilities (Boolean assertions) for the given person
isAccountEnabled(person)
— Returns true if the specified user account is enabled; returns false if disabled
Custom template methods can be added to the FreeMarker language for use on template pages. The default model provides the following methods:
hasAspect(TemplateNode, String)
— Returns the integer value 1 if the TemplateNode
supplied has the aspect with the supplied QName String; otherwise, the integer value 0 will be returned.
dateCompare(DateA, DateB)
— Compares two dates to see if they differ. This comparison returns 1 if DateA is greater than DateB; otherwise, returns 0.
dateCompare(DateA, DateB, Millis)
— Compares two dates to see if they differ by the specified number of milliseconds. This comparison returns 1 if DateA is greater than DateB by at least the millisvalue in milliseconds; otherwise, returns 0.
dateCompare(DateA, DateB, Millis, Test)
— Same as dateCompare(DateA, DateB, Millis)
but with the test variable being one of the strings ">", "<", or "==" (greater than, less than, or equal to) as the test to perform.
incrementDate(Date, Millis)
— Increments a date by the specified number of milliseconds and returns the new date.
message(String)
— Returns the I18N message string (resolved for current user Locale setting) for the specified String message ID.
cropContent(TemplateNode, Length)
— Returns the first n characters from the content stream for the specified node.
shortQName(String)
— Returns the short, or prefix, version of a long QName.
The return values for all custom methods are rather limited. It is only possible to return string, number
, or date
object. This is why the custom method described does not return a Boolean value, as you might expect.
As well as the commonly used Web script–based mechanisms for rendering template output, developers can write custom JSP pages with JSF components that render templates.
Following is the minimum JSP code required to display a template using the JSF Template component:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> <html> <body> <f:view> <h:form> <r:template template="alfresco/templates/userhome_docs.ftl" /> </h:form> </f:view> </body> </html>
18.224.109.21