Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > 2013 > November


Following discussions with various Alfresco Community members over recent weeks I've realised that there is possibly a lack of understanding about the relationship between the controller and template in a WebScript related to when JavaScript controller extensions are processed. This post will attempt to clarify the relationship and explain how and why to use a JavaScript controller extension as well as providing another concrete example of how to extend the new header bar in Alfresco Share 4.2


Extensibility Recap

The JavaScript controller (or the Java bean controller if you're writing a Java backed WebScript) has one primary purpose; to create a model object that is then passed to the template renderer (typically FreeMarker).


Even if your WebScript has an additional configuration file (e.g. one that ends '*.config.xml') then it the controller is still responsible for processing that configuration and adding it to the model ... a configuration file achieves nothing by itself!


In Alfresco 4.0 we introduced the ability to apply extension modules that could dynamically manipulate the controller, localization properties and FreeMarker templates. Customizing the FreeMarker templates was by far the most limited of these approaches as it relied on additional <@markup> directives being included in the templates. Unfortunately most of WebScript logic and client-side JavaScript widget instantiation code was defined in the FreeMarker templates which often made it difficult to achieve the desired results through pure extensions.


We completed refactored the Share WebScripts in Alfresco Community 4.2c to move all of the logic and client-side widget instantiation configuration into the controller which made it possible to have greater control over customizations via extension modules. In particular it meant that for the first time you could either reconfigure or replace the client-side JavaScript widgets with an extension module.


In Alfresco 4.2.e Community and Alfresco 4.2 Enterprise we have introduced a new approach to page creation where a JSON model of widgets to render is defined entirely in the JavaScript controller and the FreeMarker template is reduced to a single custom FreeMarker directive. This allows extensions much finer control over the page that make it possible to achieve a wider range of customizations through model manipulation.


The JavaScript Controller Extension

When writing a JavaScript controller you have access to a variable called 'model'. Any attributes added to this object are available in the associated FreeMarker template, e.g.

model.myVariable='This is a variable' a controller can be referenced in a FreeMarker template by:



The controller can add any variables it likes to the 'model' object but the refactored WebScripts make use of the 'widgets' attribute (e.g. 'model.widgets') and the new page creation approach relies on the 'jsonModel' attribute (e.g. 'model.jsonModel').


Surf will check for the existence of any extension controllers mapped to the WebScript before the FreeMarker template is renderer is called.


This means that one or more controller extensions can change the contents of the 'model.widgets' or 'model.jsonModel' attributes before they are processed by the custom directives in the template. The core controller will always be run to setup the default model and all applicable extension controllers will have their turn at updating the model before it is passed to the template.


If you're writing an extension module that you want to distribute around the Alfresco Community then you need to be aware that other extensions might have changed the model in an unexpected way before your extension has it's turn.


Real World Example

Let's see this in action by adding a new menu item to the header in Alfresco 4.2 Enterprise. Information on how to create and deploy your extension module have been covered in detail before so I'm not going to go over those now, instead I'll just focus on the controller extension itself.


If we want to add a new menu item (or indeed any new widget) we need to identify a parent widget to add it to. At the moment this still requires some knowledge of the Alfresco source code (although it is easy enough to identify the source files using SurfBug).


In this case we're customizing the 'share-header.get' WebScript whose controller imports the 'share-header.lib.js' file which provides functions that return a model fragment of the header menu. It's important to note that you don't want to (and indeed can't) extend the lib file directly - but instead much extend the controller that imports the lib file.


All of the widgets are given unique IDs in the JSON model so that they can be easily referenced. In this case we want to add a new 'alfresco/menus/AlfMenuBarItem' widget to the 'alfresco/header/AlfMenuBar' widget identified as 'HEADER_APP_MENU_BAR'. For the purposes of this example it doesn't really matter where the menu item takes the user, but in this case we're going to use it to navigate to the user's trashcan.


The controller extension should contain the following code:

var menuBar = widgetUtils.findObject(model.jsonModel, 'id', 'HEADER_APP_MENU_BAR');
if (menuBar != null)
    name: 'alfresco/menus/AlfMenuBarItem',
    config: {
      label: 'My Trashcan',
      targetUrl: 'user/' + encodeURIComponent( + '/user-trashcan'


...and when the module is deployed you will see the following added to the Share menu:


Alfresco Share With Added Menu Item



The key thing to take away from this post is how JavaScript controller extensions fit into the the processing order of WebScript files and that the sole purpose of a JavaScript controller is to set up a default model that extending controllers can then manipulate.

Unfiled Records

RM 2.1 makes record capture very easy, but we haven't discussed where these captured records go or how the records management team deals with them.

To understand this lets take a look at the file plan.

File Plan


Those of you who are already acquainted with previous versions of the Alfresco Records Management module will recognize this familiar sight, with the more observant of you spotting the new 'Unfiled Records' filter on the left hand side.

Unfiled Record Filter

An unfiled, or unclassified, record is one that not yet been filed, or placed, into it's final location within the file plan.  The 'Unfiled Records' filter shows the records management team all these unfiled records in one place, called the unfiled record container.  This area that can be thought of as a staging area for new records.

When a record is declared within a collaboration site behind the scenes it ends up here and awaits the records managements team attention.

The records management team has a few options when dealing with unfiled records:

  • File into the file plan - This moves a record from the unfiled record container into a record folder within the file plan where it will be classified by the appropriate disposition schedule.

  • Reject - This removes the unfiled record from the file plan.  In the case of an in-place record it will be returned it's original location with information about why it was rejected.

  • Request more information - This allows the records management team to request more information about a new record via a workflow.  This workflow request is passed to the content authoring team and makes it easy for the records management team to gather missing information or understand the context of the record.

Unfiled Record Actions

So now we can see how the records management team deals with newly captured records,  but how do we automate these tasks to reduce their work load?

In part 4 we will take a look at automatic filling and how it can be used to dynamically build areas of the file plan based on record context.

This blog is somewhat out of date - the new framework became Aikau and the JSDoc can be found here.



Any new framework is going to live and die by the strength of it's documentation, so it's important that we try to ensure that we make as much information on the new Alfresco Share widget library available as possible. In an ideal world we'd have have a big team working on the widgets (and the supporting framework) that would include people dedicated to writing blogs, tutorials and documentation for it.  Sadly that's not the case at the moment but we're going to do the best we can to support the Alfresco Community in getting up to speed with this new approach for Alfresco Share development



Source Documentation

From the outset we wanted to ensure that we provided useful documentation within the source through commenting and JSDoc. Hopefully we've created well-commented code that is easy to read and understand but sometimes it's better to read and navigate comments via a browser through linked files rather than in the source itself. Therefore we've added comments using a JSDoc3 supported syntax that allows us to build a HTML representations of the source documentation.

We haven't included or published this documentation with the release of Alfresco Enterprise 4.2 for a few reasons:

    • We haven't had the time to put together an Alfresco specific template for the HTML output
    • Many of the widgets are still of beta quality (as explained at Alfresco Summit and mentioned briefly in my last post)
    • We're not completely satisfied with the current quality of the existing documentation

I also discovered whilst writing this post that there are still some syntax errors in the comments that prevents the released code from being used to generate the documentation. However, in the spirit of getting information out to the Community early I wanted to provide a sample of what to expect in future releases.



Writing Widgets Supporting JSDoc3

We encountered a few issues when initially trying to generate the JSDoc due to the AMD-style template that we were using for our source files. This means that we have had to adopt a specific use of the available tags to generate output that meets our needs.

You can browse the source files to get an idea of the tags that we've used, but if you are writing your own widgets and want to document them in a similar style then you should follow these broad guidelines:

    1. Use @module, @extends, @mixes and @author in the root comment block
    2. Use @instance for each function and variable
    3. Use @type and @default for each variable
    4. Use @param and @returns as appropriate for each function


Sample JS Doc

You can download a current snap-shot of the widget library documentation here. This was generated using the code currently on the Community SVN trunk (although I need to to fix a few tagging syntax errors that I will commit as soon as possible). Please bear in mind that this is very much a work in progress but as always we welcome your feedback. If you find any issues such as typos, missing links or specific areas where a better explanation is required then please let us know.

by Dave Draper


Over the last couple of weeks I've presented a couple of sessions at the Alfresco Summit conferences in Barcelona and Boston. The purpose of these sessions were to socialise the new framework that we're going to be taking for developing the Alfresco Share application going forwards. The PowerPoint slides from these sessions are available at the Summit web site at the following links:

The sessions in Barcelona were also videoed and will be released at some point in the future if you were unable to attend either of the conferences.

Key Points

The key points to take away from the presentations are as follows:

  • It's now possible to create Share pages via a single WebScript that defines a JSON model of widgets and services to include in the page

  • We're going to be continuing to create new widgets for this framework and will be using them for all future Alfresco Share features

  • We're not going to be re-writing all of Share and it will still be possible to create pages using all the old development techniques

  • The majority of widgets that are currently in the Community source should be considered BETA and will be subsequent to change - but we wanted to get some code out to the Community as early as possible

  • Although the framework relies heavily on Dojo, it does not prevent you from developing widgets using any client-side JavaScript framework of your choosing (we've already built widgets using YUI 2, JQuery and ACE)

Page Creation Tools

I've demonstrated two page creation tools that are not included in Alfresco 4.2 - a JSON editor and a drag'n'drop GUI. The tools were created primarily as a means to better demonstrate the power of the widget framework but there have been subsequent requests for these tools to be released to the Community.

[vsw id='iMLk5p9Y9rA' source='youtube' width='425' height='344' autoplay='no']

[vsw id='CPzCFIGOzbM' source='youtube' width='425' height='344' autoplay='no']

Given that these tools are not production quality (they haven't been through our QA process, are not localized and are not accessible) and were not written to meet any specific Alfresco features I'm not going to commit the code to the Community SVN but will instead release them as standalone JAR files.

Unfortunately this won't happen for a few weeks until I can commit some of the supporting code back from development branch to the main Community trunk (otherwise the tools won't work properly). As soon as I make the tools available I'll announce it via the Alfresco Developer Blog and on Twitter.

We Want Your Feedback!

I always stress at the conference sessions how important the Community feedback is to us. This framework is still very much in its infancy and there is plenty of time to contribute to it's development. Our aim is to make it easier to develop and customise Share and we greatly value your comments and criticism and (if you feel we've earned it - your praise! ;) ).

We're aware that there isn't a great deal of documentation around this framework beyond these blogs but we'll endeavour to address this going forwards. If you're trying out the framework either by building page models or writing your own widgets and are struggling with any concepts or code then please start a topic on the forums, raise an issue in JIRA, add comments to this blog or ping me on twitter @_DaveDraper.

HAProxy for Alfresco

Posted by spoogegibbon Nov 13, 2013
Since this post was published there has been a HAProxy 1.5(.x) release version, so this post is now out of date.

An updated post with the changes relevant to HAProxy 1.5 can be are here:


For the cloud service we (Alfresco DevOps) used to use apache for all our load balancing and reverse proxy use, but more recently we switched to use HAProxy for this task.

In this article I'll list some of the settings we use, and give a final example that could be used (with a bit of environment specific modifications) for a general Alfresco deployment.

The main website for HAProxy is:

The docs can be found here:

I suggest that for any of the settings covered in the rest of this article, the HAProxy docs are consulted to gain a deeper understanding of what they do.

The 'global' section:


pidfile /var/run/

log local2 info

stats socket /var/run/haproxy.stat user nagios group nagios mode 600 level admin

A quick breakdown of these:

  • global - defines global settings.

  • pidfile - Writes pids of all daemons into file <pidfile>.

  • log - Adds a global syslog server. Optional

  • stats socket - Sets up a statistics output socket. Optional

The 'defaults' section:


mode http

log global

A quick breakdown of these:

  • defaults - defines the default settings

  • mode - sets the working mode to http (rather than tcp)

  • log - sets the log context

Now we configure some options that specify how HAProxy works, these options are very important to get your service working properly:

option httplog

option dontlognull

option forwardfor

option http-server-close

option redispatch

option tcp-smart-accept

option tcp-smart-connect

These options do the following:

  • option httplog - this enables logging of HTTP request, session state and timers.

  • option dontlognull - disable logging of null connections as these can pollute the logs.

  • option forwardfor - enables the insertion of the X-Forwarded-For header to requests sent to servers.

  • option http-server-close - enable HTTP connection closing on the server side. See the HAProxy docs for more info on this setting.

  • option redispatch - enable session redistribution in case of connection failure, which is important in a HA environment.

  • option tcp-smart-accept - this is a performance tweak, saving one ACK packet during the accept sequence.

  • option tcp-smart-connect - this is a performance tweak, saving of one ACK packet during the connect sequence.

Next we define the timeouts - these are fairly self-explanatory:

timeout http-request 10s

timeout queue 1m

timeout connect 5s

timeout client 2m

timeout server 2m

timeout http-keep-alive 10s

timeout check 5s

retries 3

We then configure gzip compression to reduce the amount of data being sent across the wire - I'm sure no configuration ever misses out this easy performance optimisation:

compression algo gzip

compression type text/html text/html;charset=utf-8 text/plain text/css text/javascript application/x-javascript application/javascript application/ecmascript application/rss+xml application/atomsvc+xml application/atom+xml application/atom+xml;type=entry application/atom+xml;type=feed application/cmisquery+xml application/cmisallowableactions+xml application/cmisatom+xml application/cmistree+xml application/cmisacl+xml application/msword application/ application/

The next section is some error message housekeeping. Change these paths to wherever you want to put your error messages:

errorfile 400 /var/www/html/errors/400.http

errorfile 403 /var/www/html/errors/403.http

errorfile 408 /var/www/html/errors/408.http

errorfile 500 /var/www/html/errors/500.http

errorfile 502 /var/www/html/errors/502.http

errorfile 503 /var/www/html/errors/503.http

errorfile 504 /var/www/html/errors/504.http

Now we have finished setting up all our defaults, we can start to define our front ends (listening ports).

We first define our frontend on port 80. This just does a redirect to the https frontend:

# Front end for http to https redirect

frontend http

bind *:80

redirect location

Next we define our https frontend which is where all traffic to Alfresco is handled:

# Main front end for all services

frontend https

bind *:443 ssl crt /path/to/yourcert/yourcert.pem

capture request header X-Forwarded-For len 64

capture request header User-agent len 256

capture request header Cookie len 64

capture request header Accept-Language len 64

We now get into the more 'fun' part of configuring HAProxy - setting up the acls.

These acls are the mechanism used to match requests to the service to the appropriate backend to fulfil those requests, or to block unwanted traffic from the service. I suggest that if you are unfamiliar with HAProxy that you have a good read of the docs for acls and what they can achieve (section 7 in the docs).

We separate out all the different endpoints for Alfresco into their own sub-domain name, e.g. for share access, for webdav, for sparepoint access.

I'll use these three endpoints in the examples below, using the following mapping:

  • Share -

  • Webdav -

  • Sharepoint -

We first set up some acls that check the host name being accessed and match on those. Anything coming in that doesn't match these won't get an acl associated (and therefore won't get forwarded to any service).

# ACL for backend mapping based on host header

acl is_my hdr_beg(host) -i

acl is_webdav hdr_beg(host) -i

acl is_sp hdr_beg(host) -i

These are in the syntax:

acl acl_name match_expression case_insensitive(-i) what_to_match

So, acl is_my hdr_beg(host) -i states:

  • acl - define this as an acl.

  • is_my - give the acl the name 'is_my'.

  • hdr_beg(host) - set the match expression to use the host HTTP header, checking the beginning of the value.

  • -i - set the check to be case insensitive

  • - the value to check for.

We then do some further mapping based on url paths in the request using some standard regex patterns:

# ACL for backend mapping based on url paths

acl robots path_reg ^/robots.txt$

acl alfresco_path path_reg ^/alfresco/.*

acl share_path path_reg ^/share/.*/proxy/alfresco/api/solr/.*

acl share_redirect path_reg ^$|^/$

These do the following:

  • acl robots - checks for a web bot harvesting the robots.txt file

  • acl alfresco_path - checks whether the request is trying to access the alfresco webapp. We block direct access to the Alfresco Explorer webapp so you can remove this check if you want that webapp available for use.

  • acl share_path - We use this to block direct access to the Solr API.

  • acl share_redirect - this checks whether there is any context at the end of the request (e.g. /share)

We next add in some 'good practice' - a HSTS header. You can find out more about HSTS here:

Note, is in the internal HSTS list in both Chrome and Firefox so neither of these browsers will ever try to access the service using plain http (see

# Changes to header responses

rspadd Strict-Transport-Security:\ max-age=15768000

We next set up some blocks, you can ignore these if you don't want to limit access to any service. The example below blocks access to the Alfresco Explorer app from public use via the '' route. These use matched acls from earlier, and can include multiple acls that must all be true.

# Blocked paths

block if alfresco_path is_my

Now we redirect to /share/ if this wasn't in the url path used to access the service.

# Redirects

redirect location /share/ if share_redirect is_my

Next we set up the list of backends to use, matched against the already defined acls.

# List of backends

use_backend share if is_my

use_backend webdav if is_webdav

use_backend sharepoint if is_sp

Then we set up the default backend to use as a catch-all:

default_backend share

Now we define the backends, the first being for share:

backend share

On this backend, enable the stats page:

# Enable the stats page on share backend

stats enable

stats hide-version

stats auth <user>:<password>

stats uri /monitor

stats refresh 2s

The stats page gives you a visual view on the health of your backends and is a very powerful monitoring tool.

option httpchk GET /share

balance leastconn

cookie JSESSIONID prefix

server tomcat1 server1:8080 cookie share1 check inter 5000

server tomcat2 server2:8080 cookie share2 check inter 5000

These define the following:

  • backend share - this defines a backend called share, which is used by the use_backend config from above.

  • option httpchk GET /share - this enables http health checks, using a http GET, on the /share path. Server health checks are one of the most powerful feature of HAProxy and works hand in hand with tomcat session replication to move an active session to another server if the server your active session on fails healthchecks.

  • balance leastconn - this sets up the balancing algorithm. leastconn selects the server with the lowest number of connections to receive the connection.

  • cookie JSESSIONID prefix - this enables cookie-based persistence in a backend. Share requires a sticky session and this also is used in session replication.

  • server tomcat1 server1:8080 cookie share1 check inter 5000 - this breaks down into:

  • server - this declares a server and its parameters

  • tomcat1 - this is the server name and appears in the logs

  • server1:8080 - this is the server address (and port)

  • cookie share1 - this checks the cookie defined above and if matched routes the user to the relevant server. The 'share1' value has to match the jvmroute set on the appserver for Share/Alfresco (for Tomcat see

  • check inter 5000 - this sets the health check, with an inter(val) of 5000 ms

Define the webdav backend.

Here we hide the need to enter /alfresco/webdav on the url path which gives a neater and shorter url needed to access webdav, and again we enable server health checking:

backend webdav

option httpchk GET /alfresco

reqrep ^([^\ ]*)\ /(.*) \1\ /alfresco/webdav/\2

server tomcat1 server1:8080 check inter 5000

server tomcat2 server2:8080 check inter 5000

Define the SPP backend.

Here we define the backend for the sharepoint protocol, again with health checks:

backend sharepoint

balance url_param VTISESSIONID check_post

cookie VTISESSIONID prefix

server tomcat1 server1:7070 cookie share1 check inter 5000

server tomcat2 server2:7070 cookie share2 check inter 5000

Once this is all in place you should be able to start HAProxy. If you get any errors you will be informed on which lines of the config these are in. Or, if you have HAProxy as a service, you should be able to run 'service haproxy check' to check the config without starting HAProxy.

There are many more cool things you can do with HAProxy, so give it a go and don't forget to have a good read of the docs!
by Dave Draper


It seems like quite a while ago that I asked the Community for suggestions for topics to blog about around Alfresco Share and even went to the trouble of raising a JIRA issue for community members to add their ideas to. It's been extremely busy at Alfresco over the last few months as we've been finished off 4.2 Enterprise and preparing for Alfresco Summit, but I've finally found some time to catch-up!

This first post was suggested by Peter Löfgren and regards the new debugging options that are available in Share when you're running in 'client-debug' mode and this topic nicely ties into a couple of other concepts that are worth exploring.

Enabling Client-Debug Mode

When Alfresco is running in production it's important to make sure that its performing as well as possible. From a web client point of view this means ensuring that the JavaScript and CSS resources that are being loaded are 'minified' to the smallest functional size to reduce the amount of data that the browser needs to load. The downside of this is that it becomes harder to debug because line breaks are removed and variable names are shortened removing any meaning from them.

It is possible to switch Share in to 'client-debug' mode so that the uncompressed resources are downloaded. This is done by modifying the 'client-debug' XML value found in the configuration. The default setting is found in 'tomcat/webapps/share/WEB-INF/classes/alfresco/share-config.xml'. Setting this value to 'true' in Alfresco Share 4.2 Enterprise (or 4.2.e Community) will have the following effects:

  1. The underlying Surf platform will serve uncompressed JavaScript and CSS resources

  2. A new LoggingService will be included in pages

  3. A new Debug Menu will be displayed on the main header menu.

New Debug Menu

The New Debug Menu

This menu relates only to the new style of widgets that have been used to create the updated header bar so will NOT effect the logging from any of the old YUI2 based client-side widgets. The following options are provided

  • Toggle logging on and off ('Debug logging')

  • Toggle full logging on and off ('Show All Logs')

  • Toggle just the warning messages ('Show Warning Messages')

  • Toggle just the error messages ('Show Error Messages')

  • Configure the filter for messages ('Update Logging Preferences')

If you ensure that both 'Debug Logging' and 'Show All Logs' are checked and that you have a debugging tool (such as Firebug (for Firefox) or the Chrome Developer Tools open) and then refresh the main page. Hopefully you'll see something like this:

Chrome Dev Tools Console

The main thing to notice is the how each line of debug is prefixed, e.g. 'alfresco/core/Core[createWidget] >>'. The first part is the widget that has output the log message and the value between the square brackets is the function that output the log message. This information is obtained directly from the calling function (where the browser supports it) so long as the function has been declared according to the following standard:

createWidget: function alfresco_core_Core__createWidget(config, domNode, callback, callbackArgs) {

...and for log requests to be made as follows:

this.alfLog('log', 'Creating widget: ',config);

All logging is decoupled over a publication/subscription model and calling 'alfLog' function publishes on a specific log topic ('ALF_LOG_REQUEST') to which the default logging Service ('alfresco/services/LoggingService') subscribes. The logging service inspects the calling function and attempts to determine the widget name and function name from the supplied data. The pattern it looks for is that the widget name and function are delimited by the last double underscore '__' and it converts single underscores into forward slashes.

By providing the widget and function names it should be easier to get identify exactly in the source code where problems exist.

Logging Filters

The other benefit from defining widget function names using this pattern is that they can then be passed through a logging filter.

If you click the 'Update Logging Preferences' option from the 'Debug Menu' you will be presented with a dialog for entering a filter.

Logging Filter

Currently the filtering is done through Regular Expressions and allow you to filter logging output to show you just the code that you're interested. The screenshot shows the value 'alfresco/menus/.*' being entered and will result in only logging from the widgets in the 'alfresco/menus' package being output.

Filtered Logs

Decoupling and Alternate Logging Services

The code that outputs the log is intentionally decoupled from the code that is requesting logging. This means that it's possible to swap out or modify the logging behaviour without needing to re-write all the code that requests logs.

By default the log output is written to the browser console but this means that the information is only available to the end-user. It would be entirely possible to switch out the default LoggingService and replace it with a service that captures logging output and posts it back to the server in batches so that end-user errors are captured and available for analysis by Admins or IT.

Using the 'alfresco/core/Core' Mixin

In order to use the logging you should ensure that your widgets 'mixin' the 'alfresco/core/Core' module. This module effectively provides an API to the core client side features for logging, data bindings, widget model processing and pub/sub.

The advantage of writing to this API is that it is possible to modify the client-side internal capabilities without breaking any existing widgets. Since we started creating the new widget library that has allowed us to make substantial changes to these features without needing to update the widgets that use them.

Debug Menu and Logging Service Caveats

It's worth noting that the Debug Menu and the Logging Service are included by default by the Share header component. If you are writing pages that don't use those components it's important to ensure that you include at least the Logging Service and a mechanism for updating logging preferences.

It's also important to note that the filter information is persisted to a users preferences by default. This means that if you are debugging using different user accounts you will need to update the preferences for each user that you login with.


Hopefully this has provided a useful introduction to the new debug features that are available in 4.2.e Community and 4.2 Enterprise. We're going to continue to make improvements for debugging the new widget library. Improving the development experience is something we're taking seriously and as we implement use cases using this new approach we will strive to add debug features to benefit both Alfresco developers and the wider Alfresco Community.

Filter Blog

By date: By tag: