Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > 2010 > November
We have just launched our first eLearning course, it feels like it has been a mammoth exercise, where the small team that we have has been dragged through fire and brimstone.

Our goals were extensive and we have produced some visually stunning material which explains complex Alfresco concepts in an easy to understand way.

We created this first course based on feedback from our user base and previous trainees, by having introductory courses online and self-paced people can take training from their office or home, at their own pace and in their own time. They don’t have to travel and the other costs normally associated with training when away from the office are eliminated.

Furthermore for our partners there is less opportunity cost, as eLearning can be taken at a time convenient to them rather than at a time designated by us or our training partners.

Creating this course started earlier this year, it is important for such eLearning courses that the content is correct, all examples work and mistakes in the text and narration are minimal. This is an expensive process. Even so because there is no instructor required for delivery we can make the price more appealing to a wider audience.

I’m hoping that this plays well for our ever growing community who have in the past found the cost of instructor-led training difficult to justify. Alfresco is a brilliant and sophisticated ECM system, but be complex to setup and administer.  We hope that training can make the Alfresco experience smoother for all.

I’ve told you what we have been doing now I have some questions for you? What do you think of online eLearning, have you participated in this type of training previously? How does it compare with instructor-led training?

See you in class soon.


For my presentations at the recent Alfresco DevCons in Paris and New York, I put together a very simple theme modification to style the Share login dialog. The theme was based on our out-of-the-box 'Yellow theme' and very simply replaced the login dialog's background image to look like the picture below:

Login dialog

The interesting bit however, is that I could define a brand-new theme purely through the Spring Surf JAR mechanism; that is by dropping a single JAR file into Tomcat/shared/lib then restarting Share.

This is the process I used:

  • Created a folder called 'devcon-theme'; doesn't matter where.

  • Created the following folder structure within 'devcon-theme'








  • Copied the files within share.war!/themes/yellowTheme to the META-INF/themes/devcon folder. It's always a good idea to start from one of our own custom themes, rather than 'default'.

  • Within that devcon folder, use any text editor to open up presentation.css and yui/assets/skin.css and replace .yui-skin-yellowTheme with .yui-skin-devcon.

  • Replaced the images/loginbg.png and images/logo.png with my DevCon-themed versions.

  • The final step is to populate the devcon.xml file with some theme metadata:

    <?xml version='1.0' encoding='UTF-8'?>


       <title>DevCon 2010</title>



That's it in terms of customisations (I did say it was a very simple modification!).

The new theme needs to be wrapped up into a JAR file, for which I've got a very simple shell script:

jar cvf $APP_TOMCAT_HOME/shared/lib/$1.jar -C $1 .

..where $APP_TOMCAT_HOME is an environment variable that's set to my Tomcat server where Share is deployed. I've called the script surfjar so I use

surfjar devcon-theme

from the devcon-theme's parent folder.

Remember, if you're using Tomcat 6, you'll also have to configure it to look in the shared folder for these Share extensions. See the wiki article here for details.

Restart Share, login as the admin user and choose More / Application from the main header menu to select your new theme.

You can download the sample devcon-theme.jar file from




There was a request in the forums for how to use the WebPreviewer (found on Share's document details page) outside of Alfresco.

I made a simple example that displays the current functionality that can be downloaded from here.


Note! The folder must be placed on a webserver, otherwise Flash Player will stop the external .swf from loading due to security violations.

Otherwise all you need to do is point your browser to the index.html file.


To test with your own documents simply generate a .swf from a .pdf by running pdf2swf with the following command ...

%> pdf2swf -T 9 -s poly2bitmap,subpixels=72 SomeFile.pdf -o SomeFile.swf.

... and don't forget to change the 'url' parameter in the 'index.html' example page ;-)


The pdf2swf utility can be downloaded from


PS. We will enhance the WebPreviewer to support text searches in the document & text selection w copy to clipboard in fortcoming versions.

The community version of Alfresco 3.4 (currently 3.4.b) has many shiny new features that have been much heralded. I thought that I would make my inaugural Alfresco blog post about a smaller, 'under-the-covers' addition that will hopefully be of use to some of you Alfresco developers out there: new policies for the transfer service.

The transfer service was introduced in version 3.3 to provide a means of pushing information out of an Alfresco repository to a receiver. We also built a repository receiver, thus enabling one Alfresco repository to push content to another Alfresco repository. You can read more about the 3.3 version of the transfer service on the Alfresco wiki. In 3.4, the transfer service has been extended to support many-to-one transfer and is used as the basis of the new replication service and also of the publishing mechanism used by Web Quick Start. For those unfamiliar with policies in Alfresco, they provide hook-points that allow you to plug your own java code ('behaviours') into the Alfresco system to make it do what you want it to do. If helpful, you can think of them as being a little like triggers in an RDBMS. There are many policies available in Alfresco, and they are an extremely powerful mechanism to customise Alfresco to your needs.

Something that was missing from the transfer service was the ability to hook into transfer-related events on the receiving end, so we have added three new policies that allow you to do just that. These are declared as sub-interfaces of the interface 'org.alfresco.service.cmr.transfer.TransferServicePolicies', and are named 'BeforeStartInboundTransferPolicy', 'OnStartInboundTransferPolicy', and 'OnEndInboundTransferPolicy'. All of these policies are invoked on the node type 'trx:transferRecord' (TransferModel.TYPE_TRANSFER_RECORD).

BeforeStartInboundTransferPolicy is invoked by the transfer receiver as soon as a request is received from a remote repository to start a transfer. At the moment a repository may only accept one inbound transfer at a time, and a lock is put in place to prevent more than one. This policy is fired before that lock is put in place, so if a behaviour that is hooked onto the policy throws an exception then the transfer request will be rejected without attempting to add the lock. Behaviours designed to hook onto this policy should specify an operation that follows the prototype defined by the BeforeStartInboundTransferPolicy interface:

  public void beforeStartInboundTransfer();

OnStartInboundTransferPolicy is invoked after the transfer lock has been put in place and an identifier has been allocated to the transfer, but before the identifier has been returned to the calling repository. The prototype of the operation that needs to be hooked onto this policy is:

  public void onStartInboundTransfer(String transferId);

OnEndInboundTransferPolicy is arguably the most useful of the three policies. It is fired at the end of an incoming transfer, and gives behaviours that are hooked onto it information about which nodes were created, updated, and deleted during the course of the transfer. The policy is triggered after the transfer has been committed, so allows custom post-processing of the affected nodes to be carried out. The prototype of the operation that is hooked onto this policy is:
  public void onEndInboundTransfer(String transferId, Set<NodeRef> createdNodes, Set<NodeRef> updatedNodes, Set<NodeRef> deletedNodes);

Together these three policies allow for a number of scenarios that were previously not possible. Hope you find them useful.


An example of how to modify the SpringSurf quickstart application to authenticate users against an Alfresco server, ready to retrieve data from Alfresco REST APIs.

For simplicity in this article, I have renamed the spring-surf-application-quickstart-1.0.0-RC2.war to ssqs.war - so all referenced URLs and files will use the shorter name. Also we will edit the deployed files directly to quickly show what you would add or change based on the SpringSurf example WAR. Obviously you wouldn't do this normally, but it keeps things simple - as the interesting parts of the article are what you need to do to get something useful working against Alfresco!

The article also provides information on what happens under the covers during user login - you can skip the detail in those parts if you wish.

Modifying the Sample Application

1. Test initial deployment.

Download spring-surf-application-quickstart-1.0.0-RC2.war file and rename it to ssqs.war.

Deploy the ssqs.war to TomCat.

Start the server and check it is working by navigating to http://YOURSERVER/ssqs

You will see a home page with a number of components on, including a component with the message Welcome to Alfresco Surf!

2. Surf User Factory and Remote Configuration.

Stop Tomcat.

Open file: \ssqs\WEB-INF\surf.xml

All SpringSurf apps have this config file by default. It is where you can set a number of important boot configuration options, including the developer/production mode flag I mentioned in a previous post, plus other important framework defaults. The change here is to uncomment the following section:

 <!-- User factory for Alfresco 3.3 -->


This informs SpringSurf to make use of the Spring bean with the given ID when it needs to create a User instance. This bean is part of the SpringWebScripts project and will make a remote call back to an Alfresco Repository to the /api/login REST API to authenticate a user. The Alfresco UserFactory makes use of the 'alfresco' endpoint. The 'alfresco' endpoint is also part of SpringWebScripts configuration and is already wired up to the 'alfresco' connector which in turn uses the 'alfresco-ticket' authenticator. It is those objects that perform the hard work of authenticating and maintaining user credential information. If you are interested the default configuration for those objects can be found here:


Like all SpringSurf configuration, this can be overridden in your surf.xml file. It is a simple matter to set the location of your Alfresco repository by overriding the endpoint configuration, so add the following in surf.xml as a new child element:

   <config evaluator='string-compare' condition='Remote'>




         <name>Alfresco - user access</name>

         <description>Access to Alfresco Repository WebScripts that require user authentication</description>







Edit ALFRESCOSERVER value with the server name and port as appropriate. The default install location is usually localhost:8080.

3. Page Authentication.

The sample app currently does not have any pages that require authentication to view, so we'll change that now.

Open file: ssqs\WEB-INF\pages\home\home.xml

Edit the authentication element as follows:


This informs SpringSurf that a valid authenticated user (not the default user instance of 'guest') is required to view this page. When the SpringSurf page dispatcher processes this information during the home page url request, it will automatically perform a redirect to the 'login' page-type (more on this below). This will begin the authentication process.

4. Login template.

Open file: \ssqs\WEB-INF\templates\sample\login.ftl

This is the example login template. The important parts to note here if you want to modify or create your own are the folllowing:

<form accept-charset='UTF-8' method='post' action='${url.context}/dologin'>

The 'action' element for this Form references the SpringMVC controller with the id 'dologin'. This is a SpringSurf controller bean that is wired to attempt a login based on a POST request, and that POST must contain two fields as defined in our Form:

<input name='username' type='text' />

<input name='password' type='password' />

These are the mandatory values it expects. Once the mandatory parameters are confirmed, the controller class will retrieve the appropriate UserFactory (as we configured above) and ask it to perform authentication. As mentioned above, this starts the process of the AlfrescoUserFactory authenticating via the 'alfresco' endpoint and it's associated authenticator class. If everything was successful, then a new User instance will be placed in the session with the Alfresco authentication information (usually a ticket value, but might be a cookie or similar) maintained by the framework for the life of that User instance, generally until their web session expires. We'll discuss it in detail shortly, but this means any further remote calls made by that user via the same 'alfresco' endpoint, such as Alfresco REST APIs, will automatically use the authentication information retrieved during login. This is how it works! And how Alfresco Share and other applications hide away the messy business of authentication from WebScript UI component writers - they simply work with a nice clean remoting API.

If you are interested, the dologin controller is implemented by the class:

It also has two other useful parameters 'success' and 'failure' which provide the redirect URLs SpringSurf should use after a login attempt. In Alfresco Share we redirect to the user dashboard page after a successful login attempt.

Finally, edit the following form values so that the correct pages are shown after a successful or failed login to our application:

<input name='success' type='hidden' value='${url.context}/home' />

<input name='failure' type='hidden' value='${url.context}/type/login' />

This ensures the 'home' page is shown on success, otherwise the 'login' page-type is shown again to allow retry.

5. Login challenge page.

Start TomCat.

Navigate to the root of the example app as before.

You will see that our simple login form has appeared! As expected SpringSurf has detected that as the guest user we are not authenticated to the appropriate level to view the home page.

How did SpringSurf know what login page to display? There are a number of ways to inform the framework as to what page you would like to use to authenticate users. In our surf.xml config for this example application, see the following section:

   <!-- Set up our sample login and logout pages -->









This configuration informs SpringSurf of the page instances to use for the 'special' login and logout page-types. A 'page-type' is really just a well known page that the framework may reference by id. So in this case the 'login' page-type has been defined as 'sample/login' and if you look in \ssqs\WEB-INF\templates\sample you will see two FreeMarker templates that implement those pages. Wondering why there are no page XML definition files in the \ssqs\WEB-INF\pages folder? The answer is that if no specific definition files are provided then SpringSurf will automatically work out what page id->page definition->template instance->template would be required and find those objects by declaration i.e. using the ID as the file name to look for. This saves having to create lots of little XML definition files that point to each other and eventually point to a concrete template file. So having a template with the same name as the page id is enough.

Login as a valid Alfresco user!

Use something like admin/admin or any user you have already created in your Alfresco server.

The home page will appear! This means our authentication configuration has worked, and we can now create components that get data from Alfresco. Exciting.

If you want to force a user logout, there is another SpringMVC controller called dologout that implements this. So navigate to http://YOURSERVER/ssqs/dologout and you will no longer be authenticated and the user session invalidated.

6. Remote calls to Alfresco REST APIs

We are now ready to make remote APIs call to Alfresco! Any component bound into a page that has been marked as requiring user authentication can now safely make a remote call. You can use the CMIS APIs or the various Alfresco Share APIs if you are looking for site specific data. In my next post we look at the remote APIs in more detail, for now take a look at the various CMIS examples or examples in the Share components.

Filter Blog

By date: By tag: