Professional Documents
Culture Documents
Developer Guide
Contents
Contents
Developer Guide........................................................................................3
Alfresco Content Services architecture............................................................................... 3
Guiding design principles............................................................................................ 4
System architecture..................................................................................................... 5
Deployment architecture............................................................................................ 56
Deployment options................................................................................................... 58
Programming models.................................................................................................59
Repository concepts.................................................................................................. 60
Mini glossary.............................................................................................................. 65
Developer Guide 2
Developer Guide
Developer Guide
The Developer Guide includes extensive guidance and reference materials to aid the developer in
creating applications and extensions for Alfresco.
This Developer Guide PDF does not include the full developer documentation and
API references. To access the complete set of documentation, see the online Alfresco
documentation.
There are a number of approaches to developing for Alfresco depending on what you want to
do. For example, if you are writing a client application, perhaps in Ruby or Python to connect to
Alfresco either on-premise, or Alfresco in the Cloud, then you would most likely use the Alfresco
REST API. If on the other hand you wanted to write a server-side extension in Java, you would
use the Public Java API, or perhaps write a web script using Java, JavaScript and FreeMarker.
Generally if you are creating extensions to Alfresco you would use the Alfresco SDK. This allows
you to work in your IDE of choice, using technologies you already know, such as Java and
Maven.
This Developer guide attempts to lay out the various options available to you, so you can use the
right approach, depending on what you want to achieve.
The main component is called the Platform and is implemented in the alfresco.war web
application. It provides the repository where content is stored plus all the associated content
services. Alfresco Share provides a web client interface (that is a User Interface, UI) for the
repository and is implemented as the share.war web application. Share makes it easy for users
to manage their sites, documents, users and so on. The search functionality is implemented on
top of Apache Solr 6 and provides the indexing of all content, which enables powerful search
functionality. There are also mobile clients that will access the content via ReST APIs provided by
the platform.
Most Alfresco Content Services projects will implement a domain specific web client based on the
Alfresco Application Development Framework (ADF). It gives you full freedom to design a content
and process web client supporting exactly the use cases needed by the domain. Giving the end-
users the best possible experience.
The Platform and UI components run in the same Apache Tomcat web application server. The
Search component runs in its own Jetty web application server. The Platform is usually also
integrated with a Directory Server (LDAP) to be able to sync users and groups with Alfresco
Content Services. And most installations also integrates with an SMTP server so the Platform can
send emails, such as site invitations.
For more information about the internals of the Platform, and specifically the content repository,
see the concepts section.
The Platform also contains numerous APIs, Services, and Protocols.
Developer Guide 3
Developer Guide
Alfresco provides a number of extension points to allow you to customize Alfresco Content
Services. These extensions points have various formats, but include:
The links in the list above provide further information on each of these topics.
Modular approach
Alfresco Content Services architecture takes a modular approach in which capabilities are
bundled into modules whose implementation can be replaced if required, or not included at all.
Aspect-Oriented Programming (AOP) techniques allow for fine-tuning and optimization of an ECM
solution.
Environment independence
Alfresco Content Services does not dictate the environment upon which it depends, allowing
choice in the operating system, database, application server, browser, and authentication system
to use when deploying. ECM is less about the application and more about the services embedded
within an application. You can choose how to package Alfresco Content Services — for example,
as a web application, an embedded library, or portlet.
Developer Guide 4
Developer Guide
Solid core
The heart of Alfresco Content Services is implemented in Java. This decision was driven by
the wealth of available Java libraries, monitoring tools, and enterprise integrations. Java is
also a trusted runtime for many enterprises wishing to deploy applications in their data centers.
Each capability is implemented as a black-box Java service tested independently and tuned
appropriately.
Scriptable extensions
Extensions will always need to be created for custom solutions and there are many custom
solutions versus the single Alfresco Content Services core. Therefore, extension points are
developed using JVM-based scripting languages, allowing a much wider pool of developers to
build extensions versus those that can contribute to the core. Extensions are packaged entities,
allowing for the growth of a library of third-party reusable extensions.
Standards-based approach
The architecture always complies with standards where applicable and advantageous. Primary
concerns are to reduce lock-in, improve integration possibilities, and hook into the ecosystems
built around the chosen standards.
Architecture of participation
The architecture promotes a system designed for community contribution. In particular,
the architecture principles of a solid core, modularity, standards compliance, simplicity of
development, and scriptable extensions encourage contribution of plug-ins and custom ECM
solutions. Participation complements the open source approach to the development of Alfresco
Content Services and fosters growth of the Alfresco community. As the community grows,
the quality of self service improves, as well as the quality of feedback. This, in turn, enhances
Alfresco Content Services and creates the ultimate feedback loop.
System architecture
At the core of the Alfresco Content Services system is a repository supported by a server that
persists content, metadata, associations, and full text indexes. Programming interfaces support
multiple languages and protocols upon which developers can create custom applications and
solutions. Out-of-the-box applications provide standard solutions such as document management
and records management.
The Alfresco Content Services system is implemented in Java, which means that it can run
on most servers that can run the Java Standard Edition. The platform components have been
implemented using the Spring framework, which provides the ability to modularize functionality,
such as versioning, security, and rules. The platform provides a scripting environment to simplify
adding new functionality and developing new programming interfaces. This portion of the
architecture is known as Web Scripts and can be used for both data and presentation services.
The lightweight architecture is easy to download, install, and deploy.
Ultimately, Alfresco Content Services is used to implement ECM solutions, such as document
management and records management. There can also be elements of collaboration and search
across these solutions.
A content management solution is typically divided into clients and a server. The clients offer
users a user interface to the solution and the server provides content management services and
storage. Solutions commonly offer multiple clients against a shared server, where each client is
tailored for the environment in which it is used.
Developer Guide 5
Developer Guide
Clients
Alfresco Content Services offers a web-based client called Alfresco Share, built entirely with
the web script technology. Share provides content management capabilities with simple user
interfaces, tools to search and browse the repository, content such as thumbnails and associated
metadata, previews, and a set of collaboration tools such as wikis and discussions. Share is
organized as a set of sites that can be used as a meeting place for collaboration. It's a web-
based application that can be run on a different server to the server that runs the platform with
repository, providing opportunities to increase scale and performance.
Alfresco has offered the Share web client for a long time. However, if a content management
solution requires extensive customization to the user interface, which most do, then it is not
recommended to customize Share. Develop instead a custom client with the Alfresco Application
Development Framework (ADF), which is Angular based.
Clients also exist for mobile platforms, Microsoft Outlook, Microsoft Office, and the desktop. In
addition, users can share documents through a network drive via WebDAV.
Server
The content application server comprises a content repository and value-added services for
building solutions.
The content application server provides the following categories of services built upon the content
repository:
Clients communicate with the content application server and its services through numerous
supported protocols. HTTP and SOAP offer programmatic access while FTP, WebDAV, IMAP,
and Microsoft SharePoint protocols offer application access.
Platform
The platform architecture consists of the repository and related services. The platform contains
the key extension points for building your own extensions.
This section covers the platform architecture in detail. It also goes through Content Modeling,
which is a fundamental part of setting up a content management system. Finally it covers the
platform access protocols and the platform modularity.
Platform architecture
The platform architecture consists of the repository and related services. The platform contains
the key extension points for building your own extensions.
The following diagram illustrates the platform architecture and extension points. Note that this
does not represent a complete list of extension points:
Developer Guide 6
Developer Guide
The platform consists of the repository and all services, developer extension points, and APIs.
The repository provides storage for documents and other content. The content metadata is
stored in a relational database, while the content itself is stored directly on the file system. The
relationships between content items, and their various properties (metadata) are defined in one or
more content models.
Content models can be thought of as describing types of content and the relationships between
pieces of content. For example, there is a relationship between a content that has a container
functionality (that is, folder), and the piece of content contained within it (that is, sub-folders and
files). There might be constraints defined in the content model, such as a content type cannot
contain other content unless it is a container type.
As well as the basic content storage functionality, the platform provides a wide range of content-
related services. These include core services such as the Node Service, and the Version Service.
There are also higher-level services such as Thumbnail Service (for creating thumbnail images
and renditions of documents), the Site Service used for creating and managing sites in the Share
application, and the Tagging Service, which provides the ability to tag content with keywords. The
following sections of this documentation provide a brief tour of the available services.
Typically these services are implemented in Java, and expose an API described by the Public
Java API.
The platform is highly extensible. You can write extensions in Java, JavaScript, and FreeMarker,
and you can write client applications in any language using the . You can create new content
models that define new content types, metadata, and relationships. You can define custom
actions that the repository will carry out when certain events happen (such as when new content
is added to the repository). You can even create entirely new services, if required.
When you need to create custom business workflow you should use the Alfresco Process
Services (APS) product.
Content modeling
Content modeling is a fundamental building block of the repository that provides a foundation for
structuring and working with content.
For more information about working with custom metadata models (aspects, types and
forms), flexible content organization and actions in the Model Manager App, see Content
modeling.
Developer Guide 7
Developer Guide
Content modeling specifies how nodes stored in the repository are constrained, imposing a
formal structure on nodes that an application can understand and enforce. Nodes can represent
anything stored in the repository, such as folders, documents, XML fragments, renditions,
collaboration sites, and people. Each node has a unique ID and is a container for any number of
named properties, where property values can be of any data type, single or multi-valued.
Nodes are related to each other through relationships. A parent/child relationship represents a
hierarchy of nodes where child nodes cannot outlive their parent. You can also create arbitrary
relationships between nodes and define different types of nodes and relationships.
A content model defines how a node in the repository is constrained. Each model defines one
or more types, where a type enumerates the properties and relationships that a node of that
type can support. Often, concepts that cross multiple types of node must be modeled, which the
repository supports through aspects. Although a node can only be of a single type, you can apply
any number of aspects to a node. An aspect can encapsulate both data and process, providing a
flexible tool for modeling content.
Content modeling puts the following constraints on the data structure:
• A node must be of a given kind.
• A node must carry an enumerated set of properties.
• A property must be of a given data type.
• A value must be within a defined set of values.
• A node must be related to other nodes in a particular way.
These constraints allow the definition (or modeling) of entities within the domain. For example,
many applications are built around the notion of folders and documents. It is content modeling
that adds meaning to the node data structure.
The repository provides services for reading, querying, and maintaining nodes. Events are fired
on changes, allowing for processes to be triggered. In particular, the repository provides the
following capabilities based on events:
• Policies: event handlers registered for specific kinds of node events for either all nodes or
nodes of a specific type
• Rules: declarative definition of processes based on addition, update, or removal of nodes
(for example, the equivalent of email rules)
Models also define kinds of relationships, property data types, and value constraints. A special
data type called content allows a property to hold arbitrary length binary data. Alfresco Content
Services comes prepackaged with several content models. You can define new models for
specific use cases from scratch or by inheriting definitions from existing models.
Developer Guide 8
Developer Guide
Access protocols
Alfresco Content Services supports a number of different protocols for accessing the content
repository. Their availability extends the options available to developers, when building their own
applications and extensions.
Protocols provide developers with another possible avenue for building their own applications
and extensions. For example, if you are building a client application to connect with multiple
repositories from multiple vendors, including Alfresco Content Services, then CMIS is a
consideration. If you are building a client to connect via the SharePoint Protocol, then use the
Alfresco Office Services (AOS). Protocols provide a resource for developers, in addition to the
numerous other extension points and APIs built into Alfresco.
When any of these protocols are used to access or upload content to the repository, access
control is always enforced based on configured permissions, regardless of what protocol that is
used.
The following table list some of the main protocols supported by Alfresco Content Services and
links to more detailed documentation.
Alfresco Office Services Alfresco Office Services (AOS) Standard in Alfresco Content
allow you to access Alfresco Services and Community
Content Services directly Edition.
from all your Microsoft Office
applications.
Developer Guide 9
Developer Guide
All the protocol bindings expose folders and documents held in the repository. This means a
client tool accessing the repository using the protocol can navigate through folders, examine
properties, and read content. Most protocols also permit updates, allowing a client tool to modify
the folder structure, create and update documents, and write content. Some protocols also allow
interaction with capabilities such as version histories, search, and tasks.
Internally, the protocol bindings interact with the repository services, which encapsulate the
behavior of working with folders and files. This ensures a consistent view and update approach
across all client tools interacting with the content application server.
A subsystem for file servers allows configuration and lifecycle management for each of the
protocols either through property files or JMX.
Modularity
The Alfresco Content Services system is modular. Every moving part is encapsulated as a
service, where each service provides an external face in a formally defined interface and has one
or more black-box implementations.
The system is designed this way to allow for:
• Pick and mix of services for building an ECM solution
Developer Guide 10
Developer Guide
To support this approach, Alfresco Content Services used the Spring framework for its factory,
Dependency Injection, and Aspect-Oriented Programming (AOP) capabilities. Services are bound
together through their interfaces and configured using Spring’s declarative Dependency Injection.
A service interface is defined as a Java interface. For services that form the internal embedded
API for extensions, cross-cutting concerns such as transaction demarcation, access control,
auditing, logging, and multi-tenancy are plugged in through Spring AOP behind the service
interface. This means that service implementations are not polluted with these concerns. It
also means the cross-cutting concerns can be configured independently or even switched off
across the server if, for example, performance is the top-most requirement and the feature is not
necessary.
Multiple services are aggregated into an Alfresco Content Services subsystem where a
subsystem represents a complete coherent capability of the Alfresco Content Services server,
such as authentication, transformation, and protocols. As a unit, subsystems have their own
lifecycle where they can be shut down and restarted while the server is running. This is useful
to disable aspects of the server, or reconfigure parts of it, such as how LDAP synchronization
is mapped. Each subsystem supports its own administration interface that is accessible through
property files or JMX.
Web UI
The Web UI architecture consists of a number of web clients and the Application Development
Framework (ADF).
This section covers the Web UI architecture in detail. There are a number of web clients available
when accessing the repository. There is also the Application Development Framework that can
be used to build domain specific web applications.
Developer Guide 11
Developer Guide
Developer Guide 12
Developer Guide
components talk to ADF services, which in turn talks to the Alfresco JS API, which internally calls
ACS and APS via their respective ReST APIs. You could use the both the ADF services and the
Alfresco JS API directly from your application if there is no ADF component available to do what
you want. In fact, you will quite frequently have to use the ADF services in your application to
fetch content nodes, process instances, task instances etc.
The following picture illustrates the architecture of an ADF solution:
The ADF components and services are implemented in Angular, which in turn is implemented in
TypeScript. The Alfresco JavaScript library is pure JavaScript and could be used with any other
JavaScript framework.
Application Generator
There is an ADF application generator that can be very useful if you just want to quickly get going
with an ADF project, such as for a demo or proof-of-concept scenario. It covers use cases for
both ACS and APS. It can be used to generate the following types of ADF applications:
• ADF Content Management App (use this template if your app is only going to talk to ACS)
• ADF Process Management App (use this template if your app is only going to talk to APS)
• ADF Content and Process Management App
Using the App Generator is simple. Install the Yeoman tool. Then install the App Generator as
follows:
$ yo
? 'Allo Martin! What would you like to do? (Use arrow keys)
Run a generator
Developer Guide 13
Developer Guide
Share architecture
When developing for Share it is important to understand the application architecture and the
underlying development frameworks. It is also important to know what extension points that are
available to you for customizing the UI in a supported way.
Introduction
Alfresco Share (share.war) is a web application that runs on the Java Platform. In a
development environment it is usually deployed and run on top of Apache Tomcat. Share is built
up of a main menu that leads to pages, which is similar to most other web applications that you
might come across. However, there is one special page type called Dashboard that contains
dashlets. A Dashboard page can be configured by the end-user, who can add, remove, and
organize the dashlets on the page.
Share pages and dashlets are implemented with something called web scripts, which is basically
REST-based APIs. These APIs are called Surf web scripts when you are dealing with Alfresco
Share. There is also repository web scripts that are used to extend the repository web application
(alfresco.war) with REST-based APIs. Surf Web Scripts are referred to as Presentation Web
Scripts and the repository web scripts as Data Web Scripts.
Share web scripts, pages, and dashlets are implemented with a user interface (UI) development
framework called Surf. This framework was originally developed by Alfresco, then donated to the
Spring Source foundation, and finally brought back into Alfresco products. It provides a way of
breaking a HTML page into re-usable component parts. Surf is built on top of the Spring Web
MVC technology, which in turn uses the Spring Framework.
Developers can also add completely new pages and dashlets to the Share UI when content
should be viewed or handled in a specific way. Sometimes it is also required to modify existing
pages. To customize the Share UI developers use so called Extension Points, which are
supported ways of injecting new custom code that should alter the functionality of the Share web
application.
Developer Guide 14
Developer Guide
The following picture gives an overview of the Alfresco Share application architecture, note that
not all available extension points are illustrated in this picture:
Share gets the content that it should display in pages and dashlets by calling repository
web scripts, which returns JSON or XML that can be incorporated into the presentation. The
presentation is actually put together with two different kinds of JavaScript frameworks, Yahoo
UI library (YUI) and Aikau, which is based on Dojo. An Aikau page is based on Surf but it makes
page composition much easier than with pure Surf pages.
You can focus solely on Aikau if the only thing you are going to do is add new stuff to the Share
UI. However, if you need to alter behavior of existing pages, then you might also need to get up to
speed on the details of the Surf page model, as only the following has been converted to Aikau:
• Share Header Menu and Title (4.2)
• Live Search (5.0)
• Filtered Search Page (5.0)
• Search Management Page (5.0)
• Site Management Page (5.0)
• Analytics and Reporting Widgets (5.0)
• Document List prototype (5.0)
The following sections get into a bit more details around Surf pages and Aikau pages.
Developer Guide 15
Developer Guide
To be able to reuse regions we can scope them to page, template, or global usage:
Developer Guide 16
Developer Guide
With all these different objects we might expect there to be some form of model that makes up
the whole Surf UI development framework. It looks like this:
The model is referred to as the siteData and has more stuff than just pages and templates
(siteData Reference). You will however mostly be dealing with component, page, and template-
instance files, which are simple XML files:
/WEB-INF/classes/alfresco
/site-data
/chrome
/components
...
global.header.xml
/component-types
/configurations
/content-associations
/extensions
/page-associations
/pages
...
documentlibrary.xml
Developer Guide 17
Developer Guide
...
search.xml
...
task-details.xml
...
/page-types
/template-instances
1-column.xml
2-columns.xml
3-columns.xml
...
content-viewer.xml
...
search.xml
...
/template-types
/themes
The Site Data model defines the page in XML, like in the following example for Search
(alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco/site-data/pages/
search.xml):
</components>
</page>
Here we can see that some components have been defined inline in the search page definition,
instead of in the /components directory as separate files. The name of the page definition file is
implicitly setting the page id to search. A corresponding template instance file is expected to be
present in the template-instances directory. In our case it will be a file called search.xml:
It will have a link to the physical template that contains the layout of the page. The template files
are located under a different directory called /templates, which is on the same level as the
site-data directory:
Developer Guide 18
Developer Guide
/WEB-INF/classes/alfresco
/site-data
/templates
/org
/alfresco
1-column.ftl
2-columns.ftl
3-columns.ftl
...
content-viewer.ftl
...
search.ftl
...
The search.ftl template file looks like this with the regions etc:
<@templateBody>
<@markup id="alf-hd">
<div id="alf-hd">
<@region scope="global" id="share-header" chromeless="true"/>
</div>
</@>
<@markup id="bd">
<div id="bd">
<div class="yui-t1">
<div id="yui-main">
<@region id="search" scope="page" />
</div>
</div>
</div>
</@>
</@>
<@templateFooter>
<@markup id="alf-ft">
<div id="alf-ft">
<@region id="footer" scope="global" />
</div>
</@>
</@>
The search page reuses the global header and footer components and then defines a page
specific region called search. The web script to call for the search component is already defined
in the page definition XML above (that is, /components/search/search). The controller file for
the search Web Script looks like this (alfresco/tomcat/webapps/share/WEB-INF/classes/
alfresco/site-webscripts/components/search/search.get.js):
/**
* Search component GET method
*/
function main()
{
// fetch the request params required by the search component template
var siteId = (page.url.templateArgs["site"] != null) ?
page.url.templateArgs["site"] : "";
var siteTitle = null;
if (siteId.length != 0)
{
// Call the repository for the site profile
Developer Guide 19
Developer Guide
This is server side JavaScript code that sets up a model with data for the template. The template
looks like this (alfresco/tomcat/webapps/share/WEB-INF/classes/alfresco/site-
webscripts/components/search/search.get.html.ftl):
<@markup id="js">
<#-- JavaScript Dependencies -->
<@script src="${url.context}/res/components/search/search-lib.js"
group="search"/>
<@script src="${url.context}/res/components/search/search.js"
group="search"/>
</@>
<@markup id="widgets">
<@createWidgets group="search"/>
</@>
<@markup id="html">
<@uniqueIdDiv>
<#assign el=args.htmlid>
<#assign searchconfig=config.scoped['Search']['search']>
<div id="${el}-body" class="search">
<#assign context=searchconfig.getChildValue('repository-
search')!"context">
<#if searchQuery?length == 0 && context != "always">
<div class="search-sites">
...
The template is where we will find references to client side code/resources. The css and js
sections above points to the client side CSS and JS that should be part of the <head> section in
the web page, and downloaded and executed by the browser to create the user interface. So as
we are starting to talk about the client side, let's dig into it a bit more in the next section.
Developer Guide 20
Developer Guide
Next, have a look at how to implement the same Hello World page with Aikau.
Hello World Aikau Page
To implement the Hello World page in Aikau we have to go through the following steps:
• Add a Web Script descriptor (XML)
• Add a Web Script template (FTL)
• Add a Web Script controller (JS) with page layout/model
• Add Widget to display content
• Choose what Surf Page you want to use as a basis (dp, hdp, rdp etc)
For a full tutorial and introduction to Aikau Pages, see (Introduction to Aikau Pages on page
26).
Share Configuration
Form Controls
Form Filters
Evaluators
Site Presets
Share Themes
Document Library
Surf Pages
Surf Dashlets
Developer Guide 21
Developer Guide
Surf Widgets
Aikau Menus
Aikau Pages
Aikau Dashlets
Aikau Widgets
Here we are defining the title and description of the page both hard-coded in the definition, and
as references to a properties file with labels (i.e. the title-id and description-id elements).
Developer Guide 22
Developer Guide
The page will not require any authentication, which means we cannot fetch any content from the
Alfresco Repository from it. It is also going to use a three column template, or that is the idea, you
can name the template instance whatever you want.
Now create the template instance file called helloworldhome-three-column.xml in the
alfresco/tomcat/shared/classes/alfresco/web-extension/site-data/template-
instances directory. You will have to create the template-instances directory:
This file just points to where the FreeMarker template for this page will be stored. So create the
alfresco/tomcat/shared/classes/alfresco/web-extension/templates/org/alfresco/
demo directory path. Then add the helloworldhome.ftl template file to it:
Continue with the properties file for the page title and description. Create a file called
helloworldhome.properties in the alfresco/tomcat/shared/classes/alfresco/web-
extension/messages directory. You will have to create the messages directory:
page.helloworldhome.title=Hello World
page.helloworldhome.description=Hello World Home Description
This file just points to where the FreeMarker template for this page will be stored. We also
need to tell Alfresco Share about the new resource file, rename the custom-slingshot-
application-context.xml.sample to custom-slingshot-application-context.xml, it is
located in the web-extension directory. Then define the following bean:
<bean id="org.alfresco.demo.resources"
class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
<property name="resourceBundles">
<list>
<value>alfresco.web-extension.messages.helloworldhome</value>
</list>
</property>
</bean>
To test this page you will have to restart Alfresco. It can then be accessed via the http://
localhost:8080/share/page/helloworldhome. The page does not look very exciting:
So we are missing both the Share header and footer, which turns out to be global components
that we can easily include. We just need to change the template file a bit. Open up the
helloworldhome.ftl file and change it so it looks like this:
Developer Guide 23
Developer Guide
<@markup id="bd">
<div id="bd">
<h1>This is just a test page. Hello World!</h1>
</div>
</@>
</@>
<@templateFooter>
<@markup id="alf-ft">
<div id="alf-ft">
<@region id="footer" scope="global" />
</div>
</@>
</@>
What we are doing here is first bringing in another FreeMarker file called alfresco-
template.ftl that contains, you guessed it, FreeMarker template macros. We then use these
macros (elements starting with @) to set up the layout of the page with header and footer. The
header and footer content is fetched via the share-header and footer global scope components
(Web Scripts). To view the result of our change we need to restart the server again, after this we
should see the following:
So that looks a bit better. The next thing we want to do is to make the page a bit more dynamic,
currently we have hard-coded the content for the page in the template. Let's add a Web Script
that will return the content to display. This will require us to update the template with an extra
region as follows:
We have called the new region body and set page scope for it. This requires us to define a new
component for this region. This can be done either in the page XML, or as a separate file in the
Developer Guide 24
Developer Guide
site-data/components directory, we will do the latter. Create the components directory and add
a file called page.body.helloworldhome.xml to it:
<webscript>
<shortname>helloworldbody</shortname>
<description>Returns the body content for the Hello World page.</
description>
<url>/components/helloworld/body</url>
</webscript>
Note that the URL is the same as we set in the component definition. Now implement the
controller for the Web Script, create a file called helloworld-body.get.js in the same place as
the descriptor:
The controller just sets up one field in the model with the Hello World message. Now implement
the template for the Web Script, create a file called helloworld-body.get.html.ftl in the
same place as the descriptor:
<h1>${body}</h1>
Restart the server. Then access the page again, you should see the Hello World message
change to "This is just a test page. Hello World! (Web Scripting)".
To summarize a bit, the following is a picture of all the files that were involved in creating this Surf
page the old school way:
Developer Guide 25
Developer Guide
What you could do now is extend the Hello World page with some more sophisticated
presentation using the YUI library. If you do that you end up with the pattern for how most of the
old school Share pages have been implemented.
Next we will have a look at how to implement the same Hello World page the new way with Aikau.
Back to Share Architecture and Extension Points.
<webscript>
Developer Guide 26
Developer Guide
<shortname>Hello World</shortname>
<description>Hello World page definition</description>
<family>Share</family>
<url>/helloworld</url>
</webscript>
Now implement the controller for the Web Script, create a file called helloworld-aikau.get.js
in the same place as the descriptor:
model.jsonModel = {
widgets: [
{
id: "SET_PAGE_TITLE",
name: "alfresco/header/SetTitle",
config: {
title: "Hello World"
}
},
{
id: "DEMO_SIMPLE_MSG",
name: "example/widgets/HelloWorldTextWidget"
}
]
};
The controller is where the main work is done when it comes to implementing the layout of the
page. If you do not need any custom widgets then it might even be the only major thing you need
to implement to get the Aikau page up and running. Now implement the template for the web
script, create a file called helloworld-aikau.get.html.ftl in the same place as the descriptor:
<@processJsonModel />
The template just kicks off the processJsonModel FreeMarker template macro, which will, as it
says, process the JSON model and assemble the page components.
Our page model contains an example widget that we need to implement. It is specified to be at
the example/widgets package path. Dojo is the JavaScript framework used behind the scenes,
and we need to tell it about the new package path. This can be done via a Spring Surf Module
extension. Create a file called example-widgets.xml and put it in the alfresco/tomcat/
shared/classes/alfresco/web-extension/site-data/extensions directory:
<extension>
<modules>
<module>
<id>Example Aikau Widgets</id>
<version>1.0</version>
<auto-deploy>true</auto-deploy>
<configurations>
<config evaluator="string-compare" condition="WebFramework"
replace="false">
<web-framework>
<dojo-pages>
<packages>
<package name="example" location="js/example"/>
</packages>
</dojo-pages>
</web-framework>
</config>
</configurations>
</module>
</modules>
</extension>
Developer Guide 27
Developer Guide
Now we can start implementing the Aikau Widget that should return the Hello World message. To
do that we need to implement a new Dojo JavaScript class called HelloWorldTextWidget. The
widget is pure client side resource stuff so we need to add the files involved into the exploded
Share web app (this is just because we are not using a build project). Create a file called
HelloWorldTextWidget.js and put it in the alfresco/tomcat/webapps/share/js/example/
widgets directory:
define(["dojo/_base/declare",
"dijit/_WidgetBase",
"alfresco/core/Core",
"dijit/_TemplatedMixin",
"dojo/text!./HelloWorldTextWidget.html"
],
function(declare, _Widget, Core, _Templated, template) {
return declare([_Widget, Core, _Templated], {
templateString: template,
i18nRequirements: [ {i18nFile: "./
HelloWorldTextWidget.properties"} ],
cssRequirements: [{cssFile:"./HelloWorldTextWidget.css"}],
buildRendering: function
example_widgets_HelloWorldTextWidget__buildRendering() {
this.helloWorldMsg = this.message('hello.world');
this.inherited(arguments);
}
});
});
<div class="helloWorldMsgStyle">${helloWorldMsg}</div>
The widget also uses a property called hello.world that needs to be available in a resource file
called HelloWorldTextWidget.properties, create it in the same place as the Widget class:
Finally the widget template uses a CSS style called helloWorldMsgStyle that needs to be
available in a resource file called HelloWorldTextWidget.css, create it in the same place as the
Widget class:
.helloWorldMsgStyle {
border: 1px #000000 solid;
padding: 1em;
width: 100px;
background-color:lightgrey;
}
Now restart Alfresco Content Services and then access the page with the http://
localhost:8080/share/page/hdp/ws/helloworld URL. You should see the following page in
Share:
Developer Guide 28
Developer Guide
The page we choose as a basis (that is, the Hybrid Dynamic Surf Page - hdp) provides both the
header and the footer for the Share web application. If you want to see the page stand-alone you
can use the dp page as a basis.
So when we are working with Aikau pages we do not have to bother about the Site Data model
and all the different kinds of XML files. We just create a web script where the controller will
contain the complete layout of the page. And then the page content will go into an auto-generated
region on the Surf page we select.
Back to Introduction to Surf Pages
Back to Share Architecture and Extension Points
Features
• Scripts and templates: Everything in Surf consists of scripts, templates, or configuration.
This means no server restarts or compilation.
• Reusability: Surf’s presentation objects, templates, and scripts emphasize reusability.
Scoped regions and component bindings allow you to describe presentation with less
code.
• Spring Web MVC: Surf plugs in as a view resolver for Spring Web MVC, enabling you to
use Surf for all or part of a site's view resolution. Surf renders views on top of annotated
controllers and is plug-compatible with Spring Web Flow, Spring Security, Spring Roo, and
Spring tag libraries.
Developer Guide 29
Developer Guide
• RESTful scripts and templates: All page elements and remote interfaces are delivered
through a RESTful API. The full feature set of web scripts is available to Surf applications.
Write new remote interfaces or new portlets with a script, a template, and a configuration
file.
• Content management: A set of client libraries and out-of-the-box components streamline
interoperability with CMIS content management systems, letting you easily access and
present Enterprise content using Surf components and templates.
• Two-tier architecture: Surf works in a decoupled architecture where the presentation tier
is separate from the content services tier.
• Production, development, and staging/preview: Configure Surf to work in a number of
deployment scenarios including development, preview, or production environments.
• Development tools: Tools that plug into the SpringSource suite of development tools
include Eclipse add-ons for SpringSource Tool Suite, as well as Spring Roo plug-ins to
enable scaffolding and script-driven site generation.
Semantic content
Semantic content represents the domain specific content that should be displayed on the web
page. This can be for example project information,document information, customer information,
discussion thread, wiki page data, workflow task information. This content is typically authored,
approved, and published.
Semantic content describes what should be rendered. It contains the approved message but it
does not contain any formatting information. It is represented in a structured data format, such as
JSON or XML. The following code is an example of JSON text for a biography:
{
"author": "Pablo Neruda",
"country": "Chile", "image": "pablo_neruda.jpg",
"description": "Pablo Neruda is adored in South America for his romantic
prose.",
"popular_works": ["Cien sonetos de amor", "Confieso que he vivido"]
}
This code does not contain any formatting like HTML tags or other markup, just simple data. This
type of content is usually fetched by a Spring Surf Web Script dynamically.
Presentation content
Presentation content are files that describe presentation configuration for a website, it is
represented in XML and FreeMarker template files. Presentation content comprises configuration
that tells the Surf rendering engine how the Web page or page component should look and feel.
Presentation content answers questions like:
• What is the layout of the Web page
• Which theme to use to render the Web page
• How many articles to display on a Web page
• Which advertisement to display in a particular section of the site for the current user
A website presentation framework, such as Surf, looks to this content to figure out how to display
the page. For example, the following XML code configures a Surf Web Script for rendering a
Developer Guide 30
Developer Guide
biography to end users and tells the web script to render a link to the full article as well as to show
the image of the author.
<component>
<url>/content/display/biography</url>
<properties>
<link-title-to-full-article>true</link-title-to-full-article>
<show-image>true</show-image>
</properties>
</component>
These properties are custom properties that are just passed on to the Web Script implementation.
This component definition tells Surf to call this Web Script (i.e. /content/display/biography)
to render the biography.
Semantic and Presentation content work together to render the Web page.
The end-to-end rendering flow is illustrated in the following figure.
This figure depicts a simple request for a biography of a poet. Here is what happens:
1. Surf receives the browser request.
2. Surf asks the content delivery services for the Presentation Content that describes what is
being requested.
3. The Presentation Content is handed back as XML and FTL.
4. Surf determines the Web Script to execute using the configuration specified by the
component XML.
5. The Web Script Controller (JavaScript or Java) calls a service somewhere to retrieve
biography data.
6. The biography is returned as JSON.
7. The Web Script Template (FreeMarker) renders HTML markup to the end user. This HTML
contains presentation output (formatting) as well as the semantic data (the biography
itself).
The website user then sees the poet's content. Rending a complete Web page with more stuff
then just the biography, such as title, footer, header etc, will loop through step 4 - 7 multiple
times.
Developer Guide 31
Developer Guide
Surf connects to content delivery services to provide content retrieval and query for presentation
and semantic content.
This means that Surf applications can consist of either single-tier or dual-tier applications. The
following figure shows three valid configurations for Surf. The standalone configuration on the left
shows, all the presentation and semantic content stored as part of the Surf web application. It is
self-contained and has everything that it needs so that requests can be services entirely from the
web application in the presentation tier. This is a perfectly acceptable configuration. Surf imposes
no requirements, it does not require a database, any local persistence, or even a user session.
A more interesting scenario is the full content services configuration on the right, where the Surf
application lives in the presentation tier but relies upon content delivery services in the content
services tier to hand it data so that it can respond to incoming requests. This data consists of
things like the biography or web script configuration information. In this case, Surf provides
developers with connector and credential management so that interactions with the content
delivery services can be performed on behalf of the end user. Surf provisions connectors to
web script developers so they can retrieve feeds of data. This data is often represented in either
JSON or XML, but it could also be in any number of other formats. Developers work with these
feeds and render them back through view templates. Surf focuses on view caching and render
performance to minimize the number of remote calls needed on each request.
Surf also has native support for the CMIS standard (Content Management Interoperability
Services), an industry-adopted API for talking to ECM systems. Alfresco Content Services
provides the leading open-source CMIS implementation, as well as an entire suite of tools around
CMIS authoring and delivery. Surf is an ideal presentation technology for CMIS content delivery.
Surf developers have the option to independently scale out the presentation tier from the content
services tier. The presentation tier is primarily developed with the intention of scaling to user load,
while providing quick end-user responses, whereas the content services tier scales to content
retrieval and query. A single page hit to the Surf application could result in several content
services hits, a single hit, or no hits at all depending on the application design.
Model-View-Controller
MVC applications use a dispatcher to handle requests for an application. It looks at the URL to
determine which controller to invoke to set up a model, and then which view to invoke to render
the model.
The dispatcher uses mappings (usually URL mappings) to determine which controllers to invoke
for the incoming URL. It also uses mappings to figure out which view to invoke to render the
response back. A controller contains business logic that should run before the response is
generated. It can do things like query a database or call out to a service. Its job is to place this
data into the model. A view contains rendering logic responsible for building the response that the
end user receives. It looks to the data in the model to inform its rendering process.
The following figure illustrates the process:
1. The dispatcher handles an incoming request. Imagine that the incoming URI is /hotels.
Developer Guide 32
Developer Guide
The main benefit of the MVC pattern is that it clearly separates the business and rendering
logic. This modularizes your application architecture, allowing you to plug in new views and new
controllers. It provides reuse, as many views can share a single controller, or many controllers
can share a single view.
Spring Web MVC
Spring Web MVC is the Model-View-Controller implementation for Spring framework web
applications.
Based on Spring configuration, Java beans implement controllers, views, the model, and the
mappings between URIs and handlers. Spring Web MVC is very extensible, letting you write your
own Java code, plug in new beans, or rewire things through configuration.
The dispatcher for a Spring Web MVC application is the dispatcher servlet, which handles the
request, executes the MVC pattern, and tries to identify a controller to handle the incoming
request. A controller is a Plain Old Java Object (POJO) registered with the Spring framework. In
the Spring framework, the model is a simple map of named properties. The controller computes
these, and when finished, hands the model back to the dispatcher servlet. The dispatcher servlet
then tries to determine a view to use to render the model to the end user. It consults a registry of
view resolvers and asks each of them if they can handle the incoming request URI. If it finds a
matching view resolver, it is used to produce a view object, rendering the model to the end user.
Typically, Spring Web MVC application developers focus most of their effort writing controllers
and views in Java, which are then wired together with Spring configuration XML.
Surf View Composition framework
Surf provides a view composition framework.
Surf provides a View Composition framework that lets you define user interface items such as:
• Pages
• Templates
• Regions
• Components
Developer Guide 33
Developer Guide
Pages
You can define views of pages including specific pages, page formats, and page types.
Surf page XML defines Surf pages. A page binds to a URI. Surf allows you to render pages by
passing the URI in the request.
• Request a page using a URL as follows:
http://localhost:8080/surf/<page-id>
http://localhost:8080/surf?p=<page-id>
If Surf finds this page, it looks at the page XML configuration to determine which template
to use to render the output. Each page can have multiple templates keyed by format. A
page might have a default template that it uses for HTML output to a browser, but it can
have another template configured that it uses for output to a wireless device.
• Request a particular format for a page using URLs as follows:
http://localhost:8080/surf/<page-id>?f=<format-id>
http://localhost:8080/surf?p=<page-id>&f=<format-id>
This allows you to have different markup for different intended formats, such as for small
display devices or integration purposes. Surf pages are also locale aware. This lets you
finely adjust your site’s pages for different languages and localization needs. When you
make a request for a page, Surf will do its best to find a match for your browser’s locale. If
a locale match cannot be made, Surf will fall back to a specified default locale.
• Request a page type using one of the following formats:
http://localhost:8080/surf/pt/<page-type-id>
http://localhost:8080/surf?pt=<page-type-id>
Surf lets you group pages into page types. By requesting a page type, Surf will determine
which page to use to satisfy your request. Surf defines a login page type. Your site might
have two themes, such as a normal theme and a holiday theme. You can also have two
distinct login pages, such as a normal login page and a holiday login page.
When the holiday theme is active, you would like Surf to resort to using the holiday login
page. All you have to do is switch the theme for the site. None of the links or URLs change
at all. The URLs in this example, will always take you to the theme’s designated login
page.
• Request a login page type using one of the following formats:
http://localhost:8080/surf/pt/login
http://localhost:8080/surf?pt=login
As before, you can request a particular format of the login page type by using a format
parameter. Here are two URLs that request the wireless format of the login page type.
http://localhost:8080/surf/pt/login?f=wireless
http://localhost:8080/surf?pt=login&f=wireless
Developer Guide 34
Developer Guide
eventually produce markup and send it out to the response. The key to making this happen is the
template, which provides the basic layout of the response to the browser.
The following figure shows three pages for a sample website. Two of the pages are similar with
the same page layout. They have four regions on the page, whereas the first page has only three
regions. As such, you can describe these three pages with two templates. The templates are
shown underneath the pages.
The first template defines three regions with placeholder names (HEADER, BODY, FOOTER).
The second template defines four regions (HEADER, MENU, CONTENT, FOOTER). The
HEADER and FOOTER regions are common across all three pages. You can define the two
templates in Surf and define regions along with region scope to allow reuse across templates, as
illustrated in the following figure.
In this figure, the region scope defines the entire website with only two templates and five scoped
regions. There are three scopes: global, template, and page. Regions in the global scope need
to be configured only once. Then, their configuration is reused by any templates or pages that
include them. In this case, the HEADER and FOOTER regions are defined once in the global
scope. Their content appears the same on all of the pages of the site.
Regions in the template scope need to be configured once per template. Any pages that use the
template then reuse their configuration. In this case, the MENU region is defined in the template
scope for one of the templates, but not the other. Thus, the two pages on the right side that
use this template will have the MENU region in common. Regions in the page scope must be
configured once per page, and their configurations are not reused. In this case, the BODY and
CONTENT regions are in the page scope. This allows the two right-hand pages to be slightly
different, but only in the CONTENT region.
The region tag defines regions on a template with the scope, such as page, template, or global.
The following examples show how this is done in FreeMarker:
Developer Guide 35
Developer Guide
A template defines the basic structure of the rendered view, and then defines regions into which
to include additional presentation. The following figure shows an example of the template that
defines four regions: HEADER, MENU, CONTENT, and FOOTER. Sample code after the figure
suggests how you could weave this into a FreeMarker template. It is up to Surf to resolve what to
place in each of these regions when the template is rendered.
<html>
<head>
${head}
</head>
<body>
<div class="header">
<@region id="header" scope="global" />
</div>
<div class="menu">
<@region id="menu" scope="template" />
</div>
<div class="content">
<@region id="content" scope="page" />
</div>
<div class="footer">
<@region id="footer" scope="global" />
</div>
</body>
</html>
When the template is processed, each of its region tags executes and attempts to look up
something that should be included in that location in the template. The region tag is replaced by
the output of something that is bound into that place in the template.
Components
Surf lets you bind components to regions. A component usually associates a region with a web
script.
Templates and scoped regions make it possible to reuse web scripts. You can have as many web
scripts as you like, each encapsulating a unique bit of application functionality.
For example:
Developer Guide 36
Developer Guide
A template brings several web scripts together into an overall markup structure. Here, you are
rendering a page; however, the same concepts apply for any kind of view rendered from Surf
using a template. Surf lets you define regions in various scopes and then resolves these upon
request. This makes your site definition efficient and easier to manage by promoting reuse.
Alfresco Share is an example of a Surf application whose pages are constructed through reuse
of templates. All three scopes are used. The following figure provides an example of how this fits
together.
You can make changes to Alfresco Share pages by tweaking FreeMarker templates and web
scripts. In Surf, web scripts not only provision remote interfaces to your applications, but also
provide your application's presentation logic. These are presentation tier web scripts. Surf
orchestrates them so they can all live together on a single view and interoperate against a
common request context.
There are many more capabilities, such as pre-processing controllers to generate markup that
should be injected into different parts of a page (for example, the <head> of an HTML page). Surf
also provides additional web script and template API root-scoped objects and methods.
Presentation content
Presentation content consists of templates, scripts, and XML files that Surf can pick up without a
server restart.
Surf consults presentation content when it renders the user interface. Surf's presentation content
consists of three kinds of files:
• Surf objects
• Templates
Developer Guide 37
Developer Guide
• Web scripts
Surf objects
Surf objects define website parts and describe how they fit together to build the complete web
application structure.
Objects describe things like pages, page hierarchy, chrome, or components that are reused
across many pages. XML files define objects that are generally short. A single Surf application
will have many XML files to define its objects. When Surf starts up, it looks for all these small
XML fragments and gathers them to form a complete registry of all of the objects.
Example of the XML for a Page object:
A Spring project generally maintains these XML files as part of its project resources. They can
reside under the WEB-INF directory or inside the classpath. Users can also manage these files
inside the Alfresco Content Services server, where XML files can be individually managed,
authorized, and approved as part of a lifecycle process. Once approved, these files are available
to the Surf application.
Here are a few examples of the various presentation objects that Surf provides:
• Chrome-application borders for regions and components
• Components-binds web scripts into templates and pages
• Content Instance-points to pages or templates to use when rendering content types
(cm:content or my:article)
• Page - a navigable location within a site
• Page Type - indirection to non-navigable locations, such as a login page
• Template Instance - configuration for dynamic templates
• Theme - settings that define the site experience
Developer Guide 38
Developer Guide
<html>
<head>
${head}
</head>
<body>
<div class="header">
<@region id="header" />
</div>
<div class="body">
<@region id="body" />
</div>
</body>
</html>
A Spring project generally maintains these template files as part of its project resources. They
can reside under the WEB-INF directory or inside the classpath. Users can also manage these
files inside a content application server.
Web scripts and Surf
Surf lets you reuse web scripts and bind them together into unlimited numbers of pages. The
scripts are lightweight, making them easy to assemble and deploy.
Declarative web scripts implement a Model-View-Controller pattern. They have a single descriptor
XML file that tells the web script dispatcher how to behave. Declarative web scripts have their
own template views and optional scriptable controllers. You write new views by writing new
template files. You write new controllers by writing new script files. Your scriptable controllers
populate the model variable (a map). Your view uses the model during render. Surf allows you
to merge your web scripts into the rendering of the overall page. that is, Surf lets your web script
MVC participate in the overall Spring MVC.
Surf provides each web script with the appropriate context and runtime environment to render in
the context of the overall request. The output of each web script merges with the output of the
template to form the final markup. This markup is returned from the Spring MVC view.
For example:
Rather than produce 100% of the output itself, the rendering template occasionally delegates
work to the web script runtime when the region tags execute. The web script runtime executes
miniature, scriptable MVC processes whose output merges into the overall rendition. The web
script runtime can use and take advantage of the full request, user, and page context. You can
build web scripts to define component implementations that can be accessed either standalone
or stitched into an overall page presentation. A component can be like a widget or a gadget;
something that you can plug into a website on one or more pages as a reusable bit of application
functionality that participates in the overall page experience.
Web scripts can also be invoked standalone in that they can run outside the context of a page.
You can surface components in menus or refresh portions of a web page using AJAX callbacks.
Developer Guide 39
Developer Guide
Surf also provides portlet capabilities that wrap web scripts and components as JSR-268 portlets
and dropped into portal servers.
A Spring project generally maintains web script files as part of its project resources. They could
reside under the WEB-INF directory or inside the classpath. Users can also manage these files
inside a content application server.
Connectors and credentials
Web script developers often work with remote sources of data. Surf makes it easy to reach out to
these information sources and pull together feeds of data.
These data sources are typically RESTful providers, CMIS repositories, or proprietary in nature.
Furthermore, each data source might require a unique set of credentials to work with the data
source.
Surf lets you define connectors responsible for communicating with endpoints where a data
source lives, such as a server residing at an HTTP address. Connectors connect to an endpoint
and communicate with it.
Connectors are wired together with authenticators so that they can effectively handshake and
establish credentials with endpoints. This pattern abstracts away any of the manual management
of connection state that you would otherwise need to perform. Using authenticators, connectors
manage user identity and session state to the endpoint. This is automatically managed for the
duration of the user session in the Surf application itself.
This defines an endpoint named springsurf. When talking to this endpoint, a connector of type
http should be used. The data source lives at www.springsurf.org:8080. Since nothing else is
provided, this is assumed to be an unauthenticated endpoint.
Surf provides a number of out-of-the-box connectors. The http connector lets you connect
to HTTP or HTTPS endpoints. To assert an identity to the endpoint, you can adjust the
configuration:
Developer Guide 40
Developer Guide
<username>USERNAME</username>
<password>PASSWORD</password>
</endpoint>
</remote>
</config>
The credentials for an http connector are passed through using basic authentication. The
values USERNAME and PASSWORD are just placeholders for your own values. With an
endpoint defined, you can code against the endpoint and use it without worrying about managing
connection state and asserting credentials. You could use the following Web script controller
code to retrieve something from the springsurf endpoint:
The remote root-scope variable provides various methods and accessors for working with
connectors. When it is used, the connection mechanics are abstracted away and your web script
code becomes highly portable from one environment to another, as well as reusable across many
users.
Credentials
Surf provides credential management on behalf of users who access content using connectors. If
a connector needs to know which credentials to attach to a given request during an authentication
handshake, it can call upon the credential vault.
Surf's default credential vault is runtime-only; it is populated and used at runtime. If you restart
the server, the credentials are lost and the user must provide their credentials again the next time
the connector is used. Surf lets you override the credential vault implementation. It provides a
number of additional credential vaults out of the box you can use or base your implementations
on. These include a filesystem– persistent credential vault and a credential vault (where your
credentials are stored in an Alfresco Content Services-managed file).
To use the credential vault, you inform the endpoint that its identity is driven from the current
user. You can make this change to your endpoint definition:
Connectors to this endpoint will look for the user’s credentials in the credential vault. If credentials
are not found and the endpoint requires authentication, the connection can fail. However, if
credentials are available in the vault, they will be applied and the connector will access the
endpoint on behalf of the developer without the need for manual login.
Developer Guide 41
Developer Guide
Authenticators
Authenticating connectors are connectors that have authenticators plugged into them. An
authenticator is a class that knows how to perform an authentication handshake with a specific
kind of service or application.
For example, MediaWiki provides a REST-based means for authenticating. You pass in your user
credentials and it hands back an HTTP cookie. This cookie must be applied to every subsequent
request, as MediaWiki looks to it to inform the application of who is making the request.
Alfresco Content Services has a similar REST-based means for authenticating. It is slightly
different in that the RESTful parameters are not the same as those of MediaWiki. Also, Alfresco
Content Services hands back a ticket in an XML return payload. This ticket must be applied to the
HTTP headers of every subsequent call so that Alfresco Content Services knows who is making
the request. Every application has a slightly different way of handling its authentication. For this
reason, Surf makes it easy to write your own authenticators and plug them into your connectors
entirely through configuration.
You define authenticators through configuration as well:
<authenticator>
<id>alfresco-ticket</id>
<name>Alfresco Authenticator</name>
<description>Alfresco Authenticator</description>
<class>org.alfresco.connector.AlfrescoAuthenticator</class>
</authenticator>
You can then bind them to connectors using configuration, or you can write your own connectors:
<connector>
<id>alfresco</id>
<name>Alfresco Connector</name>
<description>Connects to Alfresco using ticket-based authentication</
description>
<class>org.alfresco.connector.AlfrescoConnector</class>
<authenticator-id>alfresco-ticket</authenticator-id>
</connector>
The alfresco-ticket authenticator and the alfresco connector are both available to Surf
developers out of the box to connect to an Alfresco Content Services instance. All you need to do
is define an endpoint that points to an Alfresco Content Services instance and uses the alfresco
connector. Alfresco Content Services connectors use an authenticator to perform a handshake
ahead of any actual interaction. The handshake establishes who the user is and then sets up the
connector session so that subsequent requests contain the appropriate connection information
(cookies, request headers, and so forth). The endpoint definition looks like this:
<endpoint>
<id>alfresco</id>
<name>Alfresco REST API</name>
<description>Alfresco REST API</description>
<connector-id>alfresco</connector-id>
<endpoint-url>http://localhost:8080/alfresco/s</endpoint-url>
<identity>user</identity>
</endpoint>
Developer Guide 42
Developer Guide
This endpoint is named alfresco. It uses an alfresco connector and will draw credentials
from the user’s credential vault. This is all defined in configuration. You could use the alfresco
endpoint to talk to an Alfresco Content Services instance and access its remote API. For
example, you can interact with the CMIS API on the repository. Here is an example of retrieving
XML from the CMIS API:
By simply coding to the remote object, you do not need to worry about how to connect to the
endpoint or pass along user state.
Remote API
The remote root-scoped object lets you connect to remote services and retrieve data feeds.
The basic pattern is to use the remote object to get a connector to a specific endpoint, which is
identified by endpoint ID. For example:
var connector = remote.connect(ENDPOINT_ID);
By filling in ENDPOINT_ID with the correct value, you have a connector to the remote service. The
connector variable is an object with additional methods describing all the ways you can work with
the endpoint.
The following methods are the basic HTTP method types that support the essential CRUD
(create, read, update, delete) operations of most RESTful services. You can use these to work
with services right within your web scripts.:
• post(uri, body)—POSTs content to the given URI
• post(uri, body, contentType)—POSTs content of the specified type to the given URI
• get(uri)—GETs content from the given URI
• put(uri, body)—PUTs content to the given URI
• put(uri, body, contentType)— PUTs content of the specified type to the given URI
• delete(uri)—Invokes a URI as a DELETE request
Surf object XML quick reference (siteData)
Surf objects are defined in XML. This document provides a quick reference guide to the most
commonly used Surf objects, and how they are defined in XML.
File locations
In the following sections you will see that two locations are specified:
• classpath:/alfresco/site-data
• classpath:/alfresco/web-extension/site-data
It's important to note that the alfresco/web-extension/site-data directory will be processed
after the alfresco/site-data directory. Usually core Alfresco Content Services objects would
be located in alfresco/site-data directory, and third-party overrides/extensions would be
located in alfresco/web-extension/site-data.
Component
Component instances describe bindings between a region and a rendering engine that is
responsible for generating the component's markup. Typically the rendering engine is the Surf
web script engine.
Developer Guide 43
Developer Guide
Locations
• classpath:/alfresco/site-data/components
• classpath:/alfresco/web-extension/site-data/components
Definition
<component>
<!-- Required -->
<scope>page | template | global</scope>
<region-id>REGION_ID</region-id>
<source-id>SOURCE_ID</source-id>
Properties
• <id> - Component IDs follow a convention:
• For page and template scoped region bindings the convention is
<scope>.<region-id>.<source-id>
• For bindings to regions in the global scope the convention is global.<region-id>
• <scope> - The scope of the binding (page, template, global)
• <region-id> - The name of the region that is being bound.
• <source-id> - The ID of the page or template instance to which the component is bound.
For the global scope this should be set to global.
Optional properties
• <url> - The web script URL (if a web script is being rendered)
• <component-type-id> - The ID of the component type for this component.
• <chrome> - The ID of the Chrome used to frame this component's presentation.
classpath:/alfresco/web-extension/site-data/compnents/
page.content.home.xml
Developer Guide 44
Developer Guide
classpath:/alfresco/web-extension/site-data/compnents/
template.header.home.xml
classpath:/alfresco/web-extension/site-data/compnents/global.footer.xml
classpath:/alfresco/web-extension/site-data/compnents/
page.content.home.xml
Developer Guide 45
Developer Guide
</component>
Configuration
Configuration files let you store arbitrary XML descriptions for use in your custom Surf objects. In
most cases, the only time you will need to construct one of these objects is when describing site
configuration. An example of a site configuration follows.
Locations
• classpath:/alfresco/site-data/configurations
• classpath:/alfresco/web-extension/site-data/configurations
Definition
<configuration>
<source-id>SOURCE_ID</source-id>
</configuration>
Properties
• <source-id> - Tags the configuration as pertaining to an arbitrary ID. Surf will
automatically look for configuration where source-id is site.
classpath:/alfresco/web-extension/site-data/configurations/
default.site.configuration.xml
Page
A page describes a URL-addressable destination that has been resolved and for which a view
must be produced. A page aligns with the concept of a web page from the end user's point of
view. Pages are often arranged into page hierarchies that constitute a web site's navigation
structure.
Pages can specify whether they require user authentication before rendering. Unauthenticated
users will not be able to render the page.
Pages also have optional types that allow them to be dispatched by page type rather than Page
ID. Pages have one or more template instances associated with them. This allows them to render
distinctly for different intended output formats (for example, HTML, PDF, or wireless).
Developer Guide 46
Developer Guide
Locations
• classpath:/alfresco/site-data/pages
• classpath:/alfresco/web-extension/site-data/pages
Defnition
<page>
<!-- Optional authentication setting -->
<authentication>none | user</authentication>
<!-- Use this to associate a template to this page for a given format -->
<template-instance format="FORMAT_ID">TEMPLATE_ID</template-instance>
</page>
Properties
• <template-instance> - The IDs of one or more template instances that will be used to
render this Page when requested for a give FORMAT_ID. If the format attribute is not
supplied, it is assumed to have the value default.
Optional properties
• <authentication> - the level of authentication required in order for the end user to
access this page. Valid authentication values are none or user (defaults to none).
• <page-type-id> - the ID of the page type of this page.
classpath:/alfresco/web-extension/site-data/pages/products.xml
Developer Guide 47
Developer Guide
Template instance
Template instances wrap configuration around a template file. The template file receives all the
properties of the template instance and can use these properties to inform its rendering logic.
This empowers a single template file to render differently based on the configuration stored in the
template instance.
For simple cases where the template instance is not required to store additional configuration, it
may remain a very lightweight pointer to the template file. For more advanced cases, the template
instance may store render-time information concerning how to lay out elements on the page.
Locations
• classpath:/alfresco/site-data/template-instances
• classpath:/alfresco/web-extension/site-data/template-instances
Definition
<template-instance>
<template-type>TEMPLATE_TYPE_ID</template-type>
</template-instance>
Properties
• <template-type> - the ID of the template type used to render this template instance. If
a template path is provided here, the template type is assumed to be FreeMarker and the
path is used for rendering.
classpath:/alfresco/web-extension/site-data/template-instances/landing1.xml
Template type
Template types contain information that is common across many template instances of the same
type. A template type defines one or more rendering processors. It maybe also define properties
that all template instances of the given type will receive at render time.
When the framework needs to render a template instance, it considers the template type and
merges its properties forward. The uri of the template instance overrides the uri of the template
type.
Developer Guide 48
Developer Guide
Locations
• classpath:/alfresco/site-data/template-types
• classpath:/alfresco/web-extension/site-data/template-types
Definition
<template-type>
<!-- Required "view" processor -->
<processor mode="view">
<id>PROCESSOR_ID</id>
Properties
• <processor> - identifies the rendition processor to use. Valid PROCESSOR_ID
values include freemarker, jsp, and a custom ID. With the FreeMarker processor,
PROCESSOR_URI should identify the path to the FTL file relative to the /templates
directory. With the JSP processor, PROCESSOR_URI should identify the path to the JSP
file relative to the web application root.
classpath:/alfresco/web-extension/site-data/template-types/freemarker.xml
Theme
Themes capture default settings for the rendering of elements in the request. A theme is a unique
identifier as well as a collection of properties and page type overrides. When a theme is selected,
its properties and its page type overrides apply to the request.
A theme captures default settings for the rendering framework. Different themes can have
different rendering behaviors.
File locations
In the following sections you will see that two locations are specified:
• classpath:/alfresco/site-data/themes
Developer Guide 49
Developer Guide
• classpath:/alfresco/web-extension/site-data/themes
Definition
<theme>
<!-- Optional page type overrides -->
<page-types>
<page-type>
<id>PAGE_TYPE_ID</id>
<page-id>PAGE_ID</page-id>
</page-type>
</page-types>
</theme>
Properties
• <page-types> - one or more optional overrides that assign page instances to be used
when Surf asks for a Page of a particular type. Using this mechanism, themes can swap
out different default Pages to significantly affect the look and feel.
Example
The following file defines a theme that overrides the login page type to include a different default
page. When this theme is used, Surf will render back the default-login-page Page when the
login page type is requested.
classpath:/alfresco/web-extension/site-data/themes/default.xml
Developer Guide 50
Developer Guide
been updated during the upgrade. Surf has a service called the “DependencyHandler” which
solves this specific problem.
The approach taken is to append a unique checksum to the end of each requested JavaScript
and CSS dependency, where the checksum is generated from the contents of the file. If file
content is changed the checksum generated will be different. The checksum associated with
the file is cached for the lifecycle of the web server - this means that it does not need to be
generated for each request. Surf performance has actually been enhanced by this mechanism
because Surf also caches the location from which the dependency was retrieved Surf can retrieve
dependencies from a number of different locations, for example, JAR files, class path, file system,
remote location, and so on.
This feature is enabled by default in the webapps/share/WEB-INF/surf.xml file:
<web-framework>
...
<use-checksum-dependencies>true</use-checksum-dependencies>
...
</web-framework>
Note that this value should not be changed for Alfresco version 4.2 and later, or Alfresco
3.4 and earlier. It can however be changed for Share in Alfresco versions 4.0 and 4.1.
In order to make use of the Dependency Handler you will need to use the <@script>, <@link>
and <@checksumResource> FreeMarker directives in your template instance and web script
files, for example:
<@script src="${url.context}/res/yui/yahoo/yahoo.js"></@script>
<@link rel="stylesheet" type="text/css" href="${url.context}/res/css/
base.css" />
<@checksumResource src="${url.context}/res/css/ipad.css"/>
These examples are taken from the resources.get.html.ftl file where the ${url.context} is
a FreeMarker variable set to the application context, for example share.
<@script>
Generates JavaScript script import declarations.
<@link>
Rolls up multiple CSS requests into a style declaration using a separate @import statement
for each usage of <@link>.
<@checksumResource>
Generates just the URL, that is without being specific to CSS or JavaScript and can
therefore be used with images or even web script requests. One additional feature of the
<@checksumResource> directive is that you can specify the attribute parameter which
makes the checksum appear as the value of a request parameter of the supplied name
(rather than as part of the file name itself).
Developer Guide 51
Developer Guide
• _src
• -debug
You can change these suffices by overriding the definition for the dependency.handler bean in
the Spring application context in case you want to add, remove or re-order the default entries.
Current limitations
The current limitation of this solution is that it only works with static requests from the page and
not dynamic requests made from a script. However, many JavaScript libraries provide their own
solution to this problem (for example TinyMCE).
Configuration in Share
Surf can now automatically produce CSS data images by simply adding the following line to
its configuration file. For Share this configuration file is located in webapps/share/WEB-INF/
surf.xml.
<web-framework>
...
Developer Guide 52
Developer Guide
<generate-css-data-images>true</generate-css-data-images>
...
</web-framework>
Providing that checksum dependencies are also enabled then all images reference by CSS files
will be embedded as data within those CSS files. In addition to eliminating HTTP requests for
images, when an image changes, the CSS checksum will change so the browser will not use
stale cached images. The Dependency Handler service defers some of this work to a dedicated
CssDataImage service which can be overridden in the Spring application context if required.
All images are cached for the life-cycle of the server so that performance is not impeded when
requesting the same image multiple times.
CSS data image files are not supported by Internet Explorer versions 6 and 7. If these
browsers are detected then the CSS data image will not be generated.
Introduction
This information expands on FreeMarker template attributes and directives.
<script src="/aaa.js"></script>
<script src="/eee.js"></script>
<script src="/bbb.js"></script>
<script src="/ddd.js"></script>
<script src="/ccc.js"></script>
Developer Guide 53
Developer Guide
Note that /eee.js is the second requested import despite appearing last in the list and that /
ccc.js is last despite it appearing 3rd. This is because all of group "1" is output before any of
group "2", and all of group "2" is output before group "3".
When the final page is rendered in the source you would see an import like this:
Note that the JavaScript from the <@inlineScript> directive is placed between the two imports
because they are in the same group. The same is true for any custom directive that outputs
JavaScript, for example the <@createWidgets> directive.
<web-framework>
…
<aggregate-dependencies>true</aggregate-dependencies>
…
</web-framework>
Any third-party modules or add-ons that have been applied might not support this feature.
var a = 1;
Developer Guide 54
Developer Guide
var c = a + b;
When the final page is rendered in the source you would see an import like this:
var a = 1;
var b = 1;
var c = a + b;
The resource name is an MD5 checksum generated from the combined source code. The
generated resource is cached on the server so that it doesn't need to be generated each time.
If extra content is added to the group (even dynamically by a module) then the resource will
be regenerated and the checksum will naturally change to ensure that the browser requests a
different file.
Debugging
The <client-debug> setting located in webapps/share/WEB-INF/classes/alfresco/share-
config.xml, will work when enabled, even when using aggregation. An aggregated resource will
still be produced but each aggregated file will be separated by a comment similar to the following:
/*Path=A.js*/
This will allow you to determine the source file in which errors occur when debugging.
Developer Guide 55
Developer Guide
Towards the end of the alfresco-template.ftl file you will also see a commented out
directive <@relocateJavaScript>. The purpose of this directive is to change the location
in the page where JavaScript output is rendered. It is suggested to move JavaScript to the
end of a page to increase page performance. It is only possible to use this directive if there is
no hard-coded <script> elements on the page that depend on imported files or JavaScript
dependencies output by using the ${head} property. When uncommented though you will see
that it produces a very clean source file for your page with all the JavaScript located at the end.
The <@relocateJavaScript> directive is available should you wish to use to in custom Surf
pages.
APIs
To access and extend out-of-the-box services, the content application server exposes two flavors
of API, each designed for a specific type of client.
The two main categories of API that are available to use when interacting with the Alfresco
Repository is the remote and the embedded APIs.
Remote APIs
The main remote Application Programmaing Interface (API) is the , which should be the first place
you go to when you want to interact with the Alfresco Repository remotely. If portability is very
important, than have a look at the , which is a standard implemented by many ECM vendors.
Embedded APIs
The embedded APIs have traditionally been used a lot to build customizations that run inside
the same JVM as the Alfresco Repository. There are both a Public Java API and a Repository
JavaScript API. Before using the embedded APIs a thorough investigation should be done to rule
out the possibility of building the extension with a remote a remote API. It is not recommended
to build embedded extensions unless it is absoutely necessary. They make it difficult during
upgrades and can quite easily have unintended side effects on core repository functionality, such
as file upload.
For an overview of all APIs navigate to this .
Deployment architecture
The way Alfresco Content Services is deployed and run from version 6.0 onwards dramatically
changed from previous versions. Docker and Kubernetes are now used and there are no
installers.
Introduction
The way you deploy and run the Alfresco Content Services solution has changed significantly
since version 6.0. Traditionally you would download an installer that would install Java, Tomcat,
Database, WARs, tools, etc., and things would be configured to work together. Then you would
use a script to kick things off. That’s no longer the case and there are no installers available. We
will be working with Docker containers instead.
It’s now possible to kick off Alfresco Content Services from a number of Docker images. These
images are available in the https://hub.docker.com repository. However, kicking off individual
Docker containers based on these images, and configuring them to work together, might not be
the most productive way to get up and running with Alfresco Content Services. To make things
easier, and achieve a one-click to deploy and run solution, a Docker compose file is available to
quickly deploy and run Alfresco Content Services when you need to test something or work on a
proof-of-concept (PoC).
There are also Helm Charts available to deploy the solution in production as a Kubernetes cluster
in for example AWS.
Developer Guide 56
Developer Guide
Docker Architecture
When Alfresco Content Services is deployed with Docker it looks something like this:
A number of Docker images are deployed to make up the Alfresco Content Services solution:
• alfresco/alfresco-share - the Alfresco Share web interface (i.e. share.war) running on
Apache Tomcat
• alfresco/alfresco-search-services - the Solr 6 based search service running on Jetty
• alfresco/alfresco-content-repository - the Alfresco Repository app (i.e. alfresco.war)
running on Apache Tomcat
• alfresco/alfresco-activemq - the Alfresco ActiveMQ image
There are also other supporting features available, such as Docker images for image and
document transformation:
• alfresco/alfresco-imagemagick
• alfresco/alfresco-libreoffice
• alfresco/alfresco-alfresco-pdf-renderer
• alfresco/alfresco-tika
Developer Guide 57
Developer Guide
like in order to run with different versions than those set by default, which are usually the latest
versions.
Kubernetes Architecture
Alfresco Content Services cluster deployments are managed via Kubernetes container
orchestrator. The deployment architecture is defined with the Helm tool.
Deployment options
You can deploy Alfresco Content Services in many different forms and topologies. Because its
infrastructure foundation protects Alfresco Content Services from the environment within which it
executes, you can choose components such as operating system, database, application server,
web browser, and authentication system. It's designed to scale down as well as up.
Clustered
To support large-scale systems, you can cluster Alfresco Content Services. This lets you set up
multiple servers to work with each other, allowing client requests to be fulfilled across a number of
processors. You can cluster both the web application framework and content application server,
allowing each tier to scale out independently. Each node of a clustered content application server
shares the same content repository store, although the store itself can be replicated across the
nodes, if required. Caches and search indexes are also distributed, meaning that a clustered
content application server looks and acts like a single content application server.
Typically, a load balancer is placed in front of the clustered content application server to distribute
requests across the nodes. This setup also supports Cloud deployments. Alfresco Content
Services provides images and tools for easily deploying a clustered content application server
across multiple Amazon EC2 virtual nodes.
Developer Guide 58
Developer Guide
Backup server
This is a special case of the clustered deployment where, in case of failure, an application can
switch to a backup version of the deployed stack. Depending upon configuration, the backup
version might be available immediately on failure (known as hot backup) or shortly after failure,
following some configuration changes (known as warm backup). One of the nodes in the cluster
is designated the master, which supports the live application, while the other node is designated
the slave, which keeps itself replicated with the master. The slave remains read-only until the
point of switchover.
Multi-tenancy
Multi-tenancy allows a single content application server (clustered or not) to support multiple
tenants, where a tenant such as a customer, company, or organization believes they are the only
user of the server as they connect to a logical partition. Physically, all tenants share the same
infrastructure, such as deployed nodes in a cluster and content, repository storage. However,
data maintained by one tenant cannot be read or manipulated by another tenant. A deployment
of this type eases administration and reduces the cost associated with maintaining many different
applications and user bases, in particular when upgrading core services or performing backups,
as this only needs to be done once for all tenants.
Alfresco Content Services provides administration tools for managing tenants, including the
creation of tenants at runtime. In conjunction with clustering, multi-tenancy provides an ideal
deployment option for the Cloud.
Programming models
A number of programming models are available for building an application using the content
application server.
• The main development framework that should be used when building Alfresco Content
Services clients is the Alfresco Application Development Framework (ADF). It is an
Angular based framework with a number of ACS and APS components that can be used to
build a domain specific UI that meets the specific requirements.
• The simplest model for non-programmers is to use out-of-the-box components of the
Alfresco Share application and the Rules and Actions model, a set of conditions and
actions to take on content based on those conditions. You can define rules and actions
using a wizard and perform actions such as converting content, moving content, or
executing a simple JavaScript snippet.
• Web scripts let you perform more sophisticated processing without complex programming.
The Content Management Interoperability Services (CMIS) implementation was built
using web scripts. By using JavaScript to build these data services, it is easy to create
new services. To build new user interfaces or extensions to Share, you can also use web
scripts by using a web templating language like FreeMarker. Most of Share was built using
web scripts.
• To use Java to build applications or extend Share, you can use the many tools associated
with Java that were used to build the system. Surf, the web runtime framework, lets you
extend Share and build web applications. Because Share was built using Surf, you can
build your own extensions as a combination of Java programming and web scripts, or with
Java alone. You can also use Java to access or even replace whole pieces of Alfresco
Content Services, content application server, or Share by using the Spring platform. You
can use the source code as an example for rewriting pieces and using Spring beans and
configuration to extend or replace functionality in Alfresco Content Services.
• To write applications that use Alfresco Content Services but are portable to other ECM
systems, you can use Content Management Interoperability Services (CMIS), the OASIS
standard for accessing content repositories.
Developer Guide 59
Developer Guide
Repository concepts
It is important as a developer to have a good understanding of the fundamental concepts of
Alfresco Content Services when implementing extensions. Important concepts covered include
repository, nodes, stores, types, aspects and so on.
Overview
The repository is comparable to a database, except that it holds more than data. The actual
binary streams of the content are stored in files managed in the repository, although these files
are for internal use only and don't reflect what you might see through the user interfaces. The
repository also holds the associations among content items, classifications, and the folder/file
structure. The folder/file structure is maintained in the database and is not reflected in the internal
file storage structure.
The repository implements services including:
• Definition of content structure (modeling)
• Creation, modification, and deletion of content, associated metadata, and relationships
• Query of content
• Access control on content (permissions)
• Versioning of content
• Content renditions
• Locking
• Events
• Audits
• Import/Export
• Multilingual
• Rules/Actions
The repository implements and exposes these services through an Alfresco ReST API and CMIS
protocol bindings. The storage engine of the repository stores and retrieves content, metadata,
and relationships.
Key Concepts
All files that are stored in Alfresco Content Services are stored in what is referred to as the
repository. The repository is a logical entity that consists of three important parts:
1. The physical content files that are uploaded, which are stored in the file system.
2. The index files created when indexing the uploaded file so it is searchable, which are
managed by an external Apache Solr server.
3. The metadata/properties for the file, which are stored in a relational database management
system (RDBMS).
When a file is uploaded to the repository it is stored on disk in a special directory structure that is
based on the date and time of the upload. The file name is also changed to the UUID (Universally
Unique Identifier) assigned to the file when it is added to the repository. The file's metadata is
stored in an RDBMS such as PostgreSQL. Indexes are also stored on the disk. When the file is
added to the repository it is stored in a folder, and the folder has domain specific metadata, rules,
and fine grained permissions. The top folder in the repository is called Company Home, although
it will be referred to with the name repository in the Alfresco Share user interface.
When a file is uploaded to the repository it is always classified according to a so called content
model. A content model is one of the first things that will be designed and implemented in a
content management project. It customizes the repository to store information for a specific
Developer Guide 60
Developer Guide
domain, such as healthcare, finance, manufacturing, legal etc. By classifying content (i.e. files
and folders) end users can search and process content more effeciently.
Logical Structure
All the files and folders that are uploaded and created in the repository are referred to as nodes.
Some nodes, such as folders and rules, can contain other nodes (and are therefore known as
container nodes). Nodes can also be associated with other nodes in a peer to peer relationship,
in a similar fashion to how an HTML file can reference an image file. All nodes live in a Store.
Each store has a root node at the top, and nodes can reference specific files, as shown in the
following diagram:
Stores Overview
The Repository contains multiple logical stores. However, a node lives only in one store. Most
of the stores are implemented as data in the connected RDBMS, only the Content Store is
implemented so as to store items on disk:
Developer Guide 61
Developer Guide
When the versionable aspect is applied to a node, a version history is created in the Version
Store (workspace://version2Store). Versioned node metadata is stored in the database and
files remain in the {Alfresco install dir}/alf_data/contentstore directory. Versioning is
not applicable to folder nodes.
The System Store is used to save information about installed Alfresco Content Services
extension modules.
Content Store Implementation
When considering file storage, it should be noted that files added to Alfresco Content Services
can be of almost any type, and include images, photos, binary document files (Word, PPT,
Excel), as well as text files (HTML, XML, plain text). Some binary files such as videos and
music files can be relatively large. Content store files are located on the disk, rather than in the
database as BLOBs. There are several reasons for this:
1. It removes incompatibility issues across database vendors.
2. The random file access support cannot be provided by database persistence without first
copying files to the file system.
3. Possibility of real-time streaming (for direct streaming of files to browser).
4. Standard database access would be difficult when using BLOBs as the most efficient
BLOB APIs are vendor-specific.
5. Faster access.
Store Reference
When working with the APIs a store is accessed via its store reference, for example
workspace://SpacesStore. The store reference consists of two parts: the protocol and the
identifier. The first part (for example workspace) is called the protocol and indicates the content
you are interested in, such as live content (workspace://SpacesStore) or archived content
(archive://SpacesStore). The second part is the identifier (the type of store) for the store, such
as SpacesStore, which contains folder nodes (previously called spaces) and file nodes data, or
for example lightWeightVersionStore that contains version history data.
The reason some things are referred to as spaces (for example SpacesStore) is that in
previous versions of Alfresco Content Services a folder used to be called a space. The
Share user interface has generally been changed to use the name folder instead of the
name space. However, there is functionality, such as Space Templates, that still uses the
term "space". A space can simply be thought of as a folder.
Developer Guide 62
Developer Guide
Node Information
A node usually represents a folder or a file. Each store also contains a special root node at the
top level with the type sys:store_root. The root node can have one or more child nodes, such
as the Company Home folder node. Each node has a primary path to a parent node and the
following metadata:
• Type: a node is of one type, such as Folder, File, Marketing Document, Rule, Calendar
Event, Discussion, Data List and so on.
• Aspects: a node can have many aspects applied, such as Versioned, Emailed,
Transformed, Classified, Geographic and so on.
• Properties: both types and aspects define properties. If it is a file node then one of the
properties points to the physical file in the content store.
• Permissions: access control settings for the node.
• Associations: relationships to other nodes (peer or child).
Node Reference
A node is uniquely identified in the Repository via its node reference, also commonly referred
to as NodeRef. A node reference points to a store and a node in that store. A node reference
has the following format: {store protocol://store identifier}/UUID such as for example
workspace://SpacesStore/986570b5-4a1b-11dd-823c-f5095e006c11. The first part is the
store reference and the second part is a Universally Unique Identifier (UUID) for that store. Node
references are used a lot in the available APIs so it is good to have an idea of how they are
constructed.
Node Properties
The node properties, also referred to as the node's metadata, contains the majority of the
information for a node. The sys:store-protocol, sys:store-identifier, and sys:node-
uuid properties contains all the data needed to construct the NodeRef, uniquely identifying the
node. The special property called cm:content points to where the physical content file is stored
on disk (unless it is a folder or other contentless node type). All properties are either contained in
a type or in an aspect defined in a content model. When a node is created some properties are
automatically set by the system and cannot be easily changed, they are called audit properties
(from the cm:auditable aspect) and are Created Date, Creator, Modified Date, Modifier, and
Accessed. Defining new domain specific node properties, together with the types and aspects
that contain them, is the primary way of classifying a node so it can be easily found via searches.
Metadata/Property Extractors
Some of the properties of a file node are set automatically when it is uploaded to the Repository,
such as author. This is handled by metadata extractors. A metadata extractor is set up to extract
properties from a specific file MIME type. There are numerous metadata extractors available out-
of-the-box covering common MIME types such as MS Office document types, PDFs, Emails,
JPEGs, HTML files, DWG files and more. The metadata extractors are implemented via the
Tika library, although custom metadata extractors are available. Each metadata extractor
implementation has a mapping between the properties it can extract from the content file, and
what content model properties that should be set as node metadata.
Node Associations
There are two types of associations:
• Parent to Child associations - these are for example folder to file associations where
deleting the folder will cascade delete its children.
• Peer to Peer - an example could be article to image associations where deleting the article
does not affect the related image node(s). These associations are also referred to as
source to target associations.
Developer Guide 63
Developer Guide
QName
All properties are defined within a specific content model, which also defines a unique
namespace. For example, a property called description can be part of many namespaces
(content models). To uniquely identify what description property is being referenced, a
fully qualified name, or a QName, is used. A QName has the following format: {namespace
URL}property local name, for example:
{http://www.alfresco.org/model/content/1.0}description
The first part in curly braces is the namespace identifier defining the content model that the
property is part of. The second part is the local name of the property (that is description in this
case).
A QName is used for types, aspects, properties, associations, constraints and so on. The
QName for the generic folder type that is part of the out-of-the-box document content model is
cm:folder. Note the use of cm to denote the namespace. Each content model defines a prefix for
each namespace that is used in the content model. Each type, aspect, property and so on in the
content model definition uses the namespace prefix instead of the full namespace URL. You will
also use the prefix when referring to entities such as types, aspects, properties, in the different
APIs.
Permissions
Permissions are set up per node and a node can inherit permissions from its parent node. A Role
(Group) Based Access Control configuration is the preferred way to set up permissions in the
repository. However, permissions can also be set for an individual user. Groups and users can be
synchronized with an external directory such as LDAP or MS Active Directory. Some groups are
created automatically during installation:
• EVERYONE – all users in the system
• ALFRESCO_ADMINISTRATORS – administrators with full access to everything in the
Repository.
• ALFRESCO_SEARCH_ADMINISTRATORS – can access the Search Manager tool and
set up search filters (facets).
• SITE_ADMINISTRATORS – can access the Site Manager tool and change visibility of
sites, delete sites, and perform site related operations.
• E-MAIL_CONTRIBUTORS – users that can send email with content into Alfresco Content
Services.
Permission settings involve three entities:
Developer Guide 64
Developer Guide
A Site is a collaboration area in Alfresco Share where a team of people can collaborate on
content.
Owner
The Repository contains a special authority called owner. Whoever creates a node in the
repository is called the owner of the node. Owner status overrides any other permission setting.
As owner you can do any operation on the node (basically the same as being coordinator/admin).
Anyone with Coordinator or Admin status can take ownership of a node (cm:ownable is then
applied).
Folder Node and File Node Overview
The diagram illustrates a typical folder node with a child file node when it has been classified with
the out-of-the-box default document content model:
Mini glossary
Terms and concepts used when developing for Alfresco Content Services.
Term Description
Developer Guide 65
Developer Guide
Term Description
Content Model The content model describes the nodes and the
hierarchical relationship between them, as well
as any constraints that may exist. For example,
nodes that are of container type can contain other
nodes.
Developer Guide 66
Developer Guide
Term Description
Developer Guide 67
Developer Guide
Term Description
Developer Guide 68
Developer Guide
Term Description
Developer Guide 69