Alfresco Community 4.2.c

December 10th, 2012 by Kevin Roast

The latest Alfresco Community 4.2 release is out! Here’s some information on what improved features you can expect since the last release.

LightTheme

The latest Share user interface theme to be added to Alfresco and a preview of the newer more modern look we are working towards in the Share UI. This theme is a step towards a lighter looking, more modern UI experience. It is not the final version as we intend to refactor the header bar and top-level menus to add some much needed contrast but it already makes Share look more modern and more pleasing to use in modern browser environments. This theme is now the default for new installations. It also shows just how far you can take a Share theme with just CSS!

LightTheme

Gallery View

Improved performance (large thumbnails are now JPEG format by default) and improved user experience, including a fix to the issue of “squashed” image aspect ratio for thumbnails.

Forms Validation Improvements

A feature that has been present on the Alfresco Cloud product for a while and now part of Community also – improved user feedback for form validation.

Wiki CSS Improvements

The CSS used to render wiki pages has been improved.

Google Docs Integration

The very latest Google Docs integration (2.0.1-13) is present in 4.2.c and has a number of important fixes.

Translations

We have full Chinese, Japanese, Russian, Dutch and Norwegian translations available in 4.2.c as well as the usual English, French, German, Spanish, Italian lang packs.

CSS Data Images

A SpringSurf web-framework feature now on by default. Improves the performance of pages that use a lot of small icon images by including them already encoded into a single style sheet file rather than lots of little image files.

Bugs!

Lots of bugs have been fixed, including the issues with Document Library filters that was present in 4.2.b. You should also find again the performance of 4.2 is so much better out the box than Community 4.0. See the full list of fixed bugs since the 4.2.b release.

In Summary

We hope you enjoy this Alfresco Community release, it’s the last one we will be putting into your stocking before xmas!

Alfresco Community 4.2 – Shiny. Fast. Awesome.

September 20th, 2012 by Kevin Roast

There hasn’t been a release of Alfresco Community for a while, and that’s a shame, but the good news is one is coming soon, very soon in fact – and it will have a lot of new and improved features! Also many, many bug fixes from all the 4.X.Y Enterprise revisions that came before it.

Here’s a quick summary of the new and improved features can you expect to see when you install Community 4.2!

New Share dashboard dashlets:

  • Site Search

search results dashlet that allows a user to enter fts-alfresco search and see results across all their sites (when added to user dashboard) or just within a specific site (site dashboard)

Site Search dashlet

Site Search dashlet

  • Saved Search

Similar to Site Search – but the query is set via the dashlet settings panel – since this panel is only accessible to Site Managers, it means that “pre-canned” site searches can be set up by a Site Manager – great for reporting since it supports the full power of fts-alfresco search syntax. The title of dashlet can also be changed in the settings panel to make it clearer what the dashlet is reporting on.

Saved Search dashlet – settings for Site Managers

  • My Discussions

dashlet to show forum posts that a user has created or replied to recently

My Discussions dashlet

Improved Share dashlets:

  • Image Summary

improved liquid layout, folder path selection to show sub-set of images within a site, improved lightbox view

Image Preview dashlet

  • My Tasks Dashlet

filter “all” has been split into “active” and “completed”, paging added.

  • Content I’m Editing

dashlet converted to asynchronous loading to improve initial dashboard display speed

Document Library extendible views (see blog by Ray Gauss II)

the ability for developers to more easily add custom view modes to the Document Library

Rich Media Gallery View for Document Library

The first version of the Gallery View is now available in the Document Library – try it out to explore the shiny! More Multi-Media related views will be coming soon also. The new view supports the standard Document Library features such as multi-file select, drag-and-drop upload and also new features such the ability to dynamically change the number and size of the thumbnail images that are displayed in real-time.

Gallery View 1

Gallery View 2

Quick Share

public sharing of shortened document URLs

Quick Share action

Workflow UI improvements

delete completed workflow, show the completed tasks and workflows

iPad and Android usability fixes and improvements

HTML editing for Create Content, Wiki, Blogs and Forums (TinyMCE integration improved), drag and drop support for customise dashboard/site and rules ordering.

HTML5 multi-file upload

As well as the existing HTML5 drag-and-drop (in supported HTML5 browsers), the Document Library now supports multi-file selection in the standard upload dialog. With this change, there really is no need for the Flash based uploader any more on modern browsers.

SpringSurf 1.2:

No need to “clear internet cache” for end users when deploying Alfresco 4.2 or any future version. This great feature means the pain of clearing the temporary files cache has gone away when rolling out Alfresco 4.2 to your users!

a prototype feature that is not enabled by default but potentially a great way of saving resources reducing the number of files that need to be downloaded to the client

more impressive Share extensibility features for developers

timeouts, buffer sizes, http proxy settings, tcp settings, the white/black list of unsecure HTML tags for wiki editing and inline display of HTML content from Alfresco is now fully configurable

Prevent 304 revalidations for unchanged thumbnail images

a feature that means Share will no longer need to execute checks back to Alfresco to see if document or user avatar thumbnail images have changed – reduced network traffic and improved performance

Category Manager and Tag Manager fixes and improvements

Sharepoint VTI module improvements

WebDav

stability and coverage (litmus tests), range header support

Latest Activiti BPM engine

Activiti 5.10 release

Search help information

inline help for the main search page when results are found

Download as ZIP action

combined multi-file download

Forms Runtime Validation improvements

improved user feedback for invalid form data 

 

I hope this gives you a good overview of the new and improved features in Alfresco Community 4.2, as ever you can also expect better Repository and Share performance since the last release and significantly improved stability with a large number of bug fixes. Enjoy the shiny!

Configuring the Share HTML processing black/white list

June 19th, 2012 by Kevin Roast

Alfresco Share has a number of features to protect against XSS (Cross Site Scripting) attacks, session hijacking and similar. One of the most aggressive features is the automatic processing of 3rd party HTML to “sanitise” or “strip” out unwanted HTML tags and attributes before rendering in the page. By 3rd party HTML, I mean any HTML content that is displayed in Share that is sourced from a node content stream – such as a Wiki page, Blog post or Discussion post. So any content that may be user edited or could come from any source (not just Share itself!)

This is a well tested feature that handles all commonly known XSS attack holes and many less well known ones – including all the attack vectors listed here: http://ha.ckers.org/xss.html

One of the downsides to this, is the stripping of some otherwise useful HTML attributes and elements is mainly to support issues in legacy browsers such as IE6 and IE7. Consider the STYLE attribute – not a problem attribute you would assume, how could setting a STYLE cause an XSS attack?! Well in IE8, FireFox, Safari, Chrome etc. it can’t. But in IE6/7 Microsoft in their wisdom allowed JavaScript to be inserted into a STYLE attribute (called “CSS Expressions” – a better name would have “CSS Hacks”). This is a potential XSS hole that only affects those legacy browsers – but the HTML stripping process cannot rely on your browser agent (which of course could be faked) so must always assume the worst and strip those STYLE attributes.

For the majority Alfresco users who discarded IE6 (or even just IE…) long ago, why should they be punished with this limitation? And it is an annoying limitation, as most of the in-line editing capabilities of TinyMCE and other in-line editors that can potentially be used with Alfresco use STYLE attributes to apply formatting to much of their generated content.

In Alfresco 3.4.9/4.0.2 and onwards, it is now possible to fully configure the black/white list of HTML tags and attributes that the HTML stripping process will use.

This is the default configuration this is applied OFTB:

      <!-- the set of HTML tags considered safe for rendering when mixing with existing client-side output -->
      <!-- NOTE: define all tags in UPPER CASE only -->
      <property name="tagWhiteList">
         <set>
            <value>!DOCTYPE</value>
            <value>HTML</value>
            <value>HEAD</value>
            <value>BODY</value>
            <value>META</value>
            <value>BASE</value>
            <value>TITLE</value>
            <value>LINK</value>
            <value>CENTER</value>
            <value>EM</value>
            <value>STRONG</value>
            <value>SUP</value>
            <value>SUB</value>
            <value>P</value>
            <value>B</value>
            <value>I</value>
            <value>U</value>
            <value>BR</value>
            <value>UL</value>
            <value>OL</value>
            <value>LI</value>
            <value>H1</value>
            <value>H2</value>
            <value>H3</value>
            <value>H4</value>
            <value>H5</value>
            <value>H6</value>
            <value>SPAN</value>
            <value>DIV</value>
            <value>A</value>
            <value>IMG</value>
            <value>FONT</value>
            <value>TABLE</value>
            <value>THEAD</value>
            <value>TBODY</value>
            <value>TR</value>
            <value>TH</value>
            <value>TD</value>
            <value>HR</value>
            <value>DT</value>
            <value>DL</value>
            <value>DT</value>
            <value>PRE</value>
            <value>BLOCKQUOTE</value>
            <value>BUTTON</value>
            <value>CODE</value>
            <value>FORM</value>
            <value>OPTION</value>
            <value>SELECT</value>
            <value>TEXTAREA</value>
         </set>
      </property>
      <!-- The set of HTML tag attributes that are to be removed before rendering -->
      <!-- NOTE: define all attributes in UPPER CASE only -->
      <!-- IMPORTANT: JavaScript event handler attributes starting with "on" are always removed -->
      <property name="attributeBlackList">
         <set>
            <value>STYLE</value>
         </set>
      </property>
      <!-- The set of HTML tag attributes that are considered for sanitisation i.e. script content removed -->
      <!-- NOTE: define all attributes in UPPER CASE only -->
      <property name="attributeGreyList">
         <set>
            <value>SRC</value>
            <value>DYNSRC</value>
            <value>LOWSRC</value>
            <value>HREF</value>
            <value>BACKGROUND</value>
         </set>
      </property>

As you can see it’s quite a list. The import config for STYLE attribute processing is here:

      <property name="attributeBlackList">
         <set>
            <value>STYLE</value>
         </set>
      </property>

So simply override the black list in the stringutils bean in your custom-slingshot-application-context.xml file – generally found in \tomcat\shared\classes\alfresco\web-extension – as detailed in previous blog posts:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans-2.0.dtd'>

<beans>

   <!-- Override HTML processing black list -->
   <bean id="webframework.webscripts.stringutils" parent="webframework.webscripts.stringutils.abstract"
         class="org.springframework.extensions.webscripts.ui.common.StringUtils">
      <property name="attributeBlackList">
         <set></set>
      </property>
   </bean>

</beans>

Restart the Share web-application and STYLE attributes will no longer be removed by Share.

Using Apache to load balance and clustering Alfresco Share with Hazelcast

January 19th, 2012 by Kevin Roast

This post assumes reasonable sys-admin Alfresco knowledge and assumes you are already familiar with setting up the Alfresco Repository in a cluster configuration and familiar configuring an Apache web-server instance. You should read the previous post first.

Since my last blog on this subject, there has been quite a bit of interest in load balancing Alfresco Share. This is good news but also means that customers and the community have found some issues that needed looking at – good, because more use of Alfresco testing means more stability for everyone when we fix the issues – that’s part of the fun of having a very active user community!

Three main points were raised:

  1. A bug relating to a problem with dashboard template layouts not updating between web-tier nodes – which was quickly resolved for 3.4.8 and 4.0 see ALF-12318
  2. A request for example load balancing config for Share itself as I only posted info on the forward proxy config for Share.
  3. An issue raised in regards to a noticeable drop in performance when the cache config detailed in the previous post was added to each Share instance (which was required for load balancing multiple instances) - see this related blog post http://blog.alfrescian.com/?p=146 and ALF-12336

I’ll address all issues here and share some exciting performance related to item 3 also!

1. A bug that manifested when a user changed the template layout selection for a dashboard – for example from 2 to 3 column layout. The problem was that SpringSurf PageView objects were internally caching the Page object rather than just the PageId – easily and quickly fixed.

2. Config for load balancing Share is very similar to that for load balancing Alfresco.

Set up two tomcat instances containing “share.war” webapp with the “share-config-custom.xml” and “custom-slingshot-application-context.xml” config as detailed in the previously post. Remember the ports exposed by Tomcat need tweaking if you have those instances on the same physical machine – increment the HTTP and AJP and redirect ports in the tomcat/conf/server.xml config. Also ensure you have set the “jvmRoute” attributes to different values ready for the load balancing config, I used “tomcat3″ and “tomcat4″ as I now have a lot of servers running on a single box!

Create another Apache instance, I just did a copy and paste from the one I used to load balance the Alfresco cluster. Again bump the Apache listener port value if it exists on the same physical machine. Finally configure Apache “httpd.conf” to load balance against your Share web-tier instances:

# Reverse Proxy Settings (Share multi-instance load balancing) ProxyRequests Off ProxyPassReverse /share balancer://app ProxyPass /share balancer://app stickysession=JSESSIONID|jsessionid nofailover=On <Proxy balancer://app> BalancerMember ajp://localhost:8019/share route=tomcat3 BalancerMember ajp://localhost:8024/share route=tomcat4 </Proxy>

Simply point your client browsers at your new Apache instance. If you have set up your Share instances to themselves use an Apache which is load balancing against an Alfresco cluster then you now have a full 2x Alfresco Cluster + Apache + 2x Alfresco Share + Apache set up!

This is great – BUT it leads onto point 3…

3. Scalability and fail-over capability has improved by having multiple Share instances – but individual performance per Share node is reduced. Now you may consider (as I did first) that this is expected, there is after all some additional work here going on – in the case of the Alfresco cluster it’s inter-node communication overhead, and in the case of the Share nodes it is reduced performance due to the caches that have been disabled. What’s apparent here is that if you just cluster Alfresco and keep to a single Share instance, we find that a single instance of Share can easily service a 4 node Alfresco cluster so in practice there is little need to load balance Share for performance reasons – but you certainly might want to for high availability reasons. Perhaps a price worth paying for the ability to remove and drop in additional nodes without your users knowing or having to update their URLs… But it would be nice if there wasn’t such a noticeable performance drop in Share.

The good news is that this has all changed in Alfresco 3.4.8/4.0.1 – in response to the community blog post and our drive to continually improve the performance of Alfresco, a new clustering technique has now been implemented for the web-tier.

For a load balanced environment, Alfresco Share now uses Hazelcast to provide multicast messaging between web-tier nodes. The end result of this is that all caches are now enabled again for each node, and we send very simple cache invalidation message when appropriate to all nodes. So the performance degradation is gone – each node is as fast a single Share instance.

The only changes required for each node are in “custom-slingshot-application-context.xml” – generally located in \tomcat \shared\classes\alfresco\web-extension and used to override the Spring application context beans for Share. There is an example “custom-slingshot-application-context.xml.sample” provided in the Alfresco distribution which now includes this config.
Enable this section on each Share tomcat instance to enable the Hazelcast cluster messaging:

<!-- Hazelcast distributed messaging configuration - Share web-tier cluster config (3.4.8 and 4.0.1) - see http://www.hazelcast.com/docs.jsp - and specifically http://www.hazelcast.com/docs/1.9.4/manual/single_html/#SpringIntegration --> <!-- Configure cluster to use either Multicast or direct TCP-IP messaging - multicast is default --> <!-- Optionally specify network interfaces - server machines likely to have more than one interface --> <!-- The messaging topic - the "name" is also used by the persister config below --> <hz:topic id="topic" instance-ref="webframework.cluster.slingshot" name="slingshot-topic"/> <hz:hazelcast id="webframework.cluster.slingshot"> <hz:config> <hz:group name="slingshot" password="alfresco"/> <hz:network port="5801" port-auto-increment="true"> <hz:join> <hz:multicast enabled="true" multicast-group="224.2.2.5" multicast-port="54327"/> <hz:tcp-ip enabled="false"> <hz:members></hz:members> </hz:tcp-ip> </hz:join> <hz:interfaces enabled="false"> <hz:interface>192.168.1.*</hz:interface> </hz:interfaces> </hz:network> </hz:config> </hz:hazelcast> <bean id="webframework.slingshot.persister.remote" class="org.alfresco.web.site.ClusterAwarePathStoreObjectPersister" parent="webframework.sitedata.persister.abstract"> <property name="store" ref="webframework.webapp.store.remote" /> <property name="pathPrefix"><value>alfresco/site-data/${objectTypeIds}</value></property> <property name="hazelcastInstance" ref="webframework.cluster.slingshot" /> <property name="hazelcastTopicName"><value>slingshot-topic</value></property> </bean> <bean id="webframework.factory.requestcontext.servlet" class="org.alfresco.web.site.ClusterAwareRequestContextFactory" parent="webframework.factory.base"> <property name="linkBuilderFactory" ref="webframework.factory.linkbuilder.servlet" /> <property name="extensibilityModuleHandler" ref="webscripts.extensibility.handler" /> <property name="clusterObjectPersister" ref="webframework.slingshot.persister.remote" /> </bean>

The config enables the Hazelcast Spring integration which starts the Hazelcast server, it is easily configurable and can use either multicast (the default and minimal effort) or TCP-IP direct if preferred. See http://www.hazelcast.com/docs.jsp for more info. For the default set up, identical config can be applied to each Share node and it will “just work”.

When you start Share you’ll see something like this:

INFO: /192.168.2.8:5801 [slingshot] Hazelcast 1.9.4.6 (20120105) starting at Address[192.168.2.8:5801]
19-Jan-2012 13:58:57 com.hazelcast.system
INFO: /192.168.2.8:5801 [slingshot] Copyright (C) 2008-2011 Hazelcast.com
19-Jan-2012 13:58:57 com.hazelcast.impl.LifecycleServiceImpl
INFO: /192.168.2.8:5801 [slingshot] Address[192.168.2.8:5801] is STARTING
19-Jan-2012 13:58:59 com.hazelcast.impl.MulticastJoiner
INFO: /192.168.2.8:5801 [slingshot]
Members [1] {
        Member [192.168.2.8:5801] this
}
19-Jan-2012 13:58:59 com.hazelcast.impl.management.ManagementCenterService
INFO: /192.168.2.8:5801 [slingshot] Hazelcast Management Center started at port 5901.
19-Jan-2012 13:58:59 com.hazelcast.impl.LifecycleServiceImpl
INFO: /192.168.2.8:5801 [slingshot] Address[192.168.2.8:5801] is STARTED

This means the config has driven the initialisation of Hazelcast successfully. That’s all there is to creating a Share instance in the cluster, if the config is present it will become a cluster node, if the config is not present (such as for a default install) then Hazelcast never starts . Once each node is started they will find each other automatically. Then once you users interact with Share, only when the following operations occur will cache invalidation messages will be sent from the affected node to the others in the cluster:

  • an existing site/user dashboard layout is modified
  • new site or user dashboard is created
  • runtime app properties are changed (the Share theme currently)

This keeps chatter to a minimum and performance up!

Using Apache to load balance Alfresco Share with an Alfresco Repository Cluster and clustering Alfresco Share.

July 28th, 2011 by Kevin Roast

This post assumes a reasonable sys-admin level of knowledge of Alfresco and assumes you are already familiar with setting up the Alfresco Repository in a cluster configuration and also familiar configuring an Apache web-server instance.

For high availability and performance reasons, clustering the Alfresco Repository is a commonly used setup. But it is also easy to use Apache for both load balancing an Alfresco Share web-tier against an Alfresco cluster and also to cluster (i.e. web farm) the Alfresco Share web-tier itself – or both those combined together. This post examines the configuration required for those setups using Alfresco 3.4/4.0.

These are the three setups we will be considering. Note that all examples assume you have already successfully setup a working Alfresco 3.4/4.0 repository cluster. It also assumes you are deploying the Share web-tier(s) to separate TomCat instance, not the same one as the Alfresco repository instances.

  1. Single Share instance load balanced to a repository cluster e.g. Browser->Share->Apache->Repo Cluster
  2. Share tier cluster to a single repository instance e.g. Browser->Apache->Share Cluster->Repo
  3. Share tier cluster load balanced to a repository cluster e.g. Browser->Apache->Share Cluster->Apache->Repo Cluster

NOTE: all the example config below mentions “localhost” – as for testing purposes I set this all up on a single machine, changing the various TomCat ports as I go – but in reality you would probably be using difference machine instances (virtual or otherwise) for each, so care must be taken when setting up the config!

For setup 1. Configuring Share to point to an Apache reverse proxy that is setup to load balance to a multi-node Alfresco repository cluster.

You should be familiar with “share-config-custom.xml” – generally located in \tomcat \shared\classes\alfresco\web-extension and used to override the common Share startup parameters, including the remote endpoint locations. There is an example “share-config-custom.xml.sample” provided in the Alfresco distribution as a starting point. So add this section:

   <config evaluator="string-compare" condition="Remote">
      <remote>
         <endpoint>
            <id>alfresco-noauth</id>
            <name>Alfresco - unauthenticated access</name>
            <description>Access to Alfresco Repository WebScripts that do not require authentication</description>
            <connector-id>alfresco</connector-id>
            <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>
            <identity>none</identity>
         </endpoint>

         <endpoint>
            <id>alfresco</id>
            <name>Alfresco - user access</name>
            <description>Access to Alfresco Repository WebScripts that require user authentication</description>
            <connector-id>alfresco</connector-id>
            <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>
            <identity>user</identity>
         </endpoint>

         <endpoint>
            <id>alfresco-feed</id>
            <name>Alfresco Feed</name>
            <description>Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet</description>
            <connector-id>http</connector-id>
            <endpoint-url>http://localhost:8089/alfresco/s</endpoint-url>
            <basic-auth>true</basic-auth>
            <identity>user</identity>
         </endpoint>
      </remote>
   </config>

The endpoint-url elements are the important bits – set them to your Apache location, in my example this is “localhost:8089”.
And in your Apache httpd.conf file, enable the various proxy/balancer modules (these modules are used in both examples – so you might not actually need them all, but there is no harm in enabling them):

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so

And then add this section:

# Reverse Proxy Settings (cluster load balancing)
ProxyRequests Off
#NOTE: sticksession only required if non-default Alfresco auth stack is used i.e. NTLM2 or similar
#stickysession=JSESSIONID|jsessionid nofailover=On
ProxyPass /alfresco balancer://app
ProxyPassReverse /alfresco balancer://app
<Proxy balancer://app>
  #Add your Alfresco cluster nodes here
  BalancerMember ajp://localhost:8009/alfresco route=tomcat1
  BalancerMember ajp://localhost:8014/alfresco route=tomcat2
</Proxy>

The various cluster nodes should be added into the Proxy element as above, then in each Alfresco node instance TomCat server.xml, ensure the AJP connector is enabled and that the port matches the BalancerMember setting above, also ensure the Engine element jvmRoute attribute is set to match i.e using the above example:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

and

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">

Note that sticky sessions are not required by default when using the standard Alfresco authentication stack as the communication between Share and Alfresco is completely stateless and does not require a web Session. This means that your Apache instance can load balance the requests, even multiple Ajax requests from a single page instance, across multiple Alfresco cluster nodes to give the best performance. However, the side effect of this is that Lucene results will potentially differ in a cluster and Lucene is used to retrieve even simple things like Share document list and various picker results in 3.4 and below. The good news is that from Alfresco 4.0 and onwards, Lucene is no longer used for list or picker results by default (canned DB queries are used instead), so sticky sessions are not required in 4.0.

For setup 2. We need to configure an Apache forward proxy to point to multiple Share web-tier instances, also each user browser must be configured to point to the Apache proxy. Load balancing can of course be used, although the simple Apache config below doesn’t show that. This time however sticky sessions are required between the browser and the Share instance as a small amount of Session state is managed for each user in Share.

Apache httpd.conf (not a load balanced example but you get the idea)

# Forward Proxy Settings
ProxyRequests On
ProxyVia On
<Proxy *>
  Order Allow,Deny
  Allow from all
</Proxy>

You may be familiar with “custom-slingshot-application-context.xml” – generally located in \tomcat \shared\classes\alfresco\web-extension and used to override the Spring application context beans for Share. There is an example “custom-slingshot-application-context.xml.sample” provided in the Alfresco distribution as a starting point.
So add this section  to each Share tomcat instance to disable the appropriate web-tier caches (this example actually comes from the currently shipped custom-slingshot-application-context.xml.sample, which is where the helpful comments come from):

   <!-- Web-tier cluster configuration -->
   <!-- Enable this section if you are clustering or load balancing the share.war i.e. multiple web-tiers behind a proxy -->
   <!-- If you have a single web-tier running against an Alfresco cluster via a reverse proxy you don't need this -->
   <bean id="webframework.slingshot.persister.remote" class="org.springframework.extensions.surf.persister.PathStoreObjectPersister" parent="webframework.sitedata.persister.abstract">
      <property name="store" ref="webframework.webapp.store.remote" />
      <property name="pathPrefix"><value>alfresco/site-data/${objectTypeIds}</value></property>
      <property name="noncachableObjectTypes">
         <set>
            <value>page</value>
            <value>component</value>
         </set>
      </property>
   </bean>

For setup 3. Use a combination of the above two setups! So modify the “custom-slingshot-application-context.xml“ and “share-config-custom.xml” for each Share TomCat instance to configure the forward and reverse proxy Apache instances (you will need two Apache instances for this) and to disable the web-tier caches.

SpringSurf – Authenticating users against an Alfresco repository

November 1st, 2010 by Kevin Roast

Introduction

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 -->
	<user-factory>webframework.factory.user.alfresco</user-factory>

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:

\SpringSurf\spring-webscripts\spring-webscripts\src\main\resources\org\springframework\extensions\webscripts\spring-webscripts-config.xml

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">
      <remote>
         <endpoint>
         <id>alfresco</id>
         <name>Alfresco - user access</name>
         <description>Access to Alfresco Repository WebScripts that require user authentication</description>
         <connector-id>alfresco</connector-id>
         <endpoint-url>http://ALFRESCOSERVER/alfresco/s</endpoint-url>
         <identity>user</identity>
         </endpoint>
      </remote>
   </config>

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:

<authentication>user</authentication>

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: org.springframework.extensions.surf.mvc.LoginController.

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 -->
   <page-type>
      <id>login</id>
      <page-instance-id>sample/login</page-instance-id>
   </page-type>
   <page-type>
      <id>logout</id>
      <page-instance-id>sample/logout</page-instance-id>
   </page-type>

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.

Developer tips for Alfresco Share 3.3

April 7th, 2010 by Kevin Roast

With Alfresco 3.3, the Share content collaboration platform has never been easier to develop for! With the integration of SpringSurf in Alfresco 3.3, plus a number of improved debugging features, the edit->test->debug development cycle for Share pages and components is more rapid than ever. Once set-up, it can take literally seconds to see the results of changes to any WebScripts, templates, JavaScript or CSS files. This post is a collection of tips direct from Alfresco Engineering on how to set-up your environment, tweak the default Share configuration, debug scripts and enable the fastest possible development cycle.

Get the Tools You Need

Your favorite developers text editor. Obviously. But that’s pretty much all you need to work with Alfresco WebScripts, FreeMarker templates and JavaScript text files – you don’t need anything heavier, but something like Eclipse or IntelliJ will do nicely if you prefer.

Firefox plus the Firebug extension or Google Chrome – because of the nifty HTML, CSS inspection and JavaScript debugging features. Most Alfresco devs prefer the Firefox+Firebug combination as the features are currently stronger than the dev tools built into Chrome, and it gives more accurate and descriptive JavaScript errors – but Chrome is catching up with every release and it’s certainly noticably faster at processing JavaScript and general rendering.

Setting up a Folder Structure

See this previous post on how to set-up your folder structure for creating Share pages, components and WebScripts. It also discusses using the SpringSurf resource servlet to easily access web assets such as images, CSS and client-side JavaScript in your templates and components from within the same folder structure.

During Development Deploy Files and Folders – not a JAR!

Create a quick shell or ant script to copy your working files and folder structure to your tomcat Share classes folder. You can then work on your assets easily and quickly deploy them all to a running Alfresco server. The previous post describes how to package them up for run-time deployment as a single JAR – but that isn’t needed during development, and in fact isn’t really desirable – having the files and folders expanded out ensures quicker deployment and ensures the various config options discussed below will work correctly.

share-config-custom.xml

Share is configured by various Spring config files and Alfresco format config files. These are easy enough to override. There’s really only one file you need to worry about for most situations. The default config override file that Share is already set-up to look for is called share-config-custom.xml and should be placed in your $TOMCAT_HOME$/shared/classes/alfresco/web-extension folder. Here you can override various configuration settings and several of the most useful ones for development and debugging will be discussed here. If you do want to override Spring beans, then Share will look for a file called custom-slingshot-application-context.xml and it should be placed in the same folder. Generally unless you are modifying Surf internals you won’t need to override the Spring beans.

A default installation of Alfresco will include a .sample version of these files in the above location, they can also be found in the source tree: HEAD/root/projects/slingshot/config/alfresco/web-extension

Debugging client-side JavaScript

Here’s an example of a share-config-custom.xml file with the correct config to turn on client-side JavaScript debugging. You may be wondering why you need to do this, after all surely it’s just a matter of turning on FireBug and getting on with it? But for performance reasons, Share will include minimized versions of its client-side JavaScript files during page rendering – it will even combine some of the files – which don’t make for useful debugging. Turning on the client-debug flag forces Share to load the original uncompressed source with all comments and formatting intact, perfect for debugging into. It also ensures the various YUI library files are uncompressed – if you are feeling brave enough to poke around in them.

   <alfresco-config>

      <!-- Global config section -->
      <config replace="true">
         <flags>
            <!-- Developer debugging setting - DEBUG mode for client scripts in the browser -->
            <client-debug>true</client-debug>

            <!-- LOGGING can be toggled at runtime when in DEBUG mode (Ctrl, Ctrl, Shift, Shift).
                 This flag automatically activates logging on page load. -->
            <client-debug-autologging>false</client-debug-autologging>
         </flags>
      </config>

   </alfresco-config>

Restarting the server is required if you make changes to this file. Force a refresh of Share in your browser and you will then be able to use FireBug or the Chrome debugger tool to set breakpoints and debug the client-side JavaScript of Share components.

You’ll notice the client-debug-autologging flag in the example above. There is a logging feature in Share that allows a developer to make use of log4j style debugging methods in client-side JavaScript. It’s not a commonly used feature as it’s pretty low-level, but if you can’t solve your issue with breakpoint style debugging then logging may be useful. The flag is used to automatically active the logging output window in Share rather than having to toggle it with a funky key combination.

To log from within your client-side JavaScript:

if (Alfresco.logger.isDebugEnabled())
   Alfresco.logger.debug("some string value");

The log4j info, warn, error and fatal levels can be used if required.

SpringSurf Development Mode

SpringSurf has a number of autowire configuration modes. By default Share is configured in the “production” mode – this ensures that web-tier JavaScript and FreeMarker templates are compiled and cached for maximum performance. For development, it is much more useful to have JavaScript and templates not cached. As mentioned above this allows simple scripts to quickly copy over new versions of files and see the results immediately in the application – no restarts required.

This is an example of the config required for share-config-custom.xml:

   <alfresco-config>

       <config evaluator="string-compare" condition="WebFramework">
           <web-framework>
               <!-- Autowire Runtime Settings -->
               <autowire>
                   <!-- Pick the mode: development, preview, production -->
                   <mode>development</mode>
               </autowire>
           </web-framework>
       </config>

   </alfresco-config>

Web-Tier JavaScript debugging

Share SpringSurf components are simply a special case of an Alfresco WebScript – with a few additional rules and restrictions on what objects are available and what presentation templates can output. The web-tier JavaScript controller associated with a WebScript can be debugged via the Rhino debugger window. Once “development” mode is activated as mentioned above, the script debugger will be able to break on JavaScript functions and breakpoints. To turn on the debugger, use the browser to navigate to /<yourserver>/share/service/index – this will display the WebScripts index page. Click the Alfresco JavaScript Debugger link and then Enable. A Java GUI window will appear, this is the Rhino debugger interface. The easiest way to get into the web-tier JavaScript is to select Debug->Break On Function Enter from the menus. The next WebScript that is executed in the app will break in the debugger. Once the appropriate source files are loaded breakpoints can be added and the Break On Function Enter can be disabled to reduce the noise during debugging.

Web-Tier Javascript Logging

Logging from within WebScript code can be another useful debugging aid. On both the Repository and Web-Tier, the “logger” root scoped JavaScript object is available for simple logging tasks. The output is directed to the App-Server console window.

logger object API:

boolean logger.isDebugEnabled() - returns true/false to indicate if debug logging output via log4j is active,
this can be used to ensure performance isn't degraded when console logging is inactive.
void logger.log(string message) - output a log message to the console

To turn on logging for your application, modify the log4j.properties file and set the following class to debug:

log4j.logger.org.alfresco.repo.jscript.ScriptLogger=debug

Note that the same logging class name is used by the Alfresco repository and SpringSurf – it is maintained for backward compatibility.

Refreshing WebScripts

On a production deployed instance of Share or any instance where all the various debug settings noted above are not applied, most caching and refresh issues can be quickly resolved without restarting the app-server. The Refresh WebScripts option in the Share WebScript index page can be used to clear the caches for all components and compiled scripts. It also means that additional WebScripts can be deployed or removed at runtime without restart. Use the browser to navigate to /<yourserver>/share/service/index – this will display the WebScripts index page. Click the Refresh Webscripts button to clear the caches and refresh the list of available WebScripts.

Separate Alfresco and Share Server Instances

Since Alfresco 3.0, the Share client is a stand-alone web-application and the share.war can be deployed on a separate TomCat instance to the Alfresco repository, on another server entirely if required. This is recommended for development and production. For development, it enables the Share application to be restarted quickly (a few seconds on a modern laptop or server) without interfering with the main Alfresco repository instance. For production, it allows proxies and clustering to be implemented.

The configuration to do this is simple, but first it requires the set-up of a new TomCat instance, with appropriate tweaks as recommended for an Alfresco server such as; JVM memory settings, server URIEncoding set to UTF-8, web-extension folder etc. The easiest way to do this is to take a copy of the Alfresco installed TomCat instance and remove the alfresco.war. If you are running the new TomCat instance on the same machine as the Alfresco repository instance then modify the port settings in tomcat/conf/server.xml to ensure Share can be started at the same time as Alfresco. Developers at Alfresco generally use port 8080 for Alfresco and port 8081 for Share.

By default the Share web-application will attempt to communicate with the Alfresco server via HTTP on port 8080. There should be no additional configuration required if you use those settings. However if your Alfresco instance is not running on this port then the following example of configuration for share-config-custom.xml can be used to modify the endpoint settings, change the endpoint-url values as appropriate:

   <!-- Overriding endpoints to reference a remote Alfresco server -->
   <config evaluator="string-compare" condition="Remote">
      <remote>
         <endpoint>
            <id>alfresco-noauth</id>
            <name>Alfresco - unauthenticated access</name>
            <description>Access to Alfresco Repository WebScripts that do not require authentication</description>
            <connector-id>alfresco</connector-id>
            <endpoint-url>http://localhost:8080/alfresco/s</endpoint-url>
            <identity>none</identity>
         </endpoint>

         <endpoint>
            <id>alfresco</id>
            <name>Alfresco - user access</name>
            <description>Access to Alfresco Repository WebScripts that require user authentication</description>
            <connector-id>alfresco</connector-id>
            <endpoint-url>http://localhost:8080/alfresco/s</endpoint-url>
            <identity>user</identity>
         </endpoint>

         <endpoint>
            <id>alfresco-feed</id>
            <name>Alfresco Feed</name>
            <description>Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet</description>
            <connector-id>http</connector-id>
            <endpoint-url>http://localhost:8080/alfresco/s</endpoint-url>
            <basic-auth>true</basic-auth>
            <identity>user</identity>
         </endpoint>
      </remote>
   </config>

Conclusion

Hopefully this list of tips should help speed up development and improve your experience when customising and working with Alfresco Share components. In the next post we will explore the architecture of SpringSurf components, templates and page rendering.

Alfresco Share 3.3 Extensions and SpringSurf

January 28th, 2010 by Kevin Roast

This quick tutorial shows how much easier it is to package up custom extensions to Alfresco Share in version 3.3.

The features for handling the new single package deployment and simpler more compact configuration are part of the SpringSurf web framework recently contributed to SpringSource by Alfresco engineering.

Background

In versions of Alfresco Share previous to 3.3, developing and particularly packaging extensions was a laborious task, the number of individual config files required and the need to place web-assets such as CSS and JavaScript files directly into a separate web-app – such as the TomCat ROOT web-app and then referencing them there was particularly fiddly.

Most of these issues have been solved with SpringSurf:

  • Loading of Surf configuration files directly from a JAR
  • Referencing web-assets packaged within a JAR or the class path via a simple Resource servlet URL
  • Combining multiple Surf config elements – pages, templates, component into a single file

It might not sound like much, but these changes make a big difference to reducing the complexity of developing and packaging Share extensions.

Downloads

The tiny JAR files related to this tutorial – it’s worth having them open to examine while reading the rest of the article:
share-sample-dashlet-extension-3.3.jar
share-sample-page-extension-3.3.jar

Share Dashlets

Dashlets are small portlet like units of functionality available in either the User or Site dashboards (or both). An example might be a summary of user tasks, site activities or documents recently added to a site. Custom dashlets are one of the easiest items to add to Alfresco Share

Each dashlet is generated by a single Share WebScript component. The needs to be marked as a member of the “site-dashlet” family. The ‘family’ of a WebScript is like a simple tagging or categorisation mechanism – applications can use the Surf APIs to retrieve the IDs of all WebScripts within a named family, which is exactly what Alfresco Share does to generate the list of dashlets available to the user on the Configure Dashboard page.

So, no further configuration of Share is required other than to make sure it is found by the web-app on initialisation.

To mark a dashlet as available in the User dashboard, use the “user-dashlet” family. The mark as dashlet as available for both dashboard types, use the “dashlet” family. Of course a site dashlet written expecting specific context information such as the current site id will not work in the user dashboard context so care should be taken when applying the correct family category.

Dashlet Example

This example shows how to package up a Tag Cloud dashlet that was previously built for use as a demonstration of how to incrementally develop a dashlet for Alfresco Share 3.2 at the recently held Alfresco Meetup user conferences. This article won’t go into the detail of the dashlet code itself – but it does make an excellent example of several key concepts and features that are important to understand if you want to build rich, Ajax enabled components for Alfresco Share. It demonstrates:

  • The artifacts that make up a WebScript component
  • How simple it is to make a remote call from web-tier JavaScript (part of the WebScript component) to an Alfresco server and process the JSON response
  • Passing values from the JSON response into the WebScript FreeMarker template for rendering the dashlet response
  • Including component specific CSS and client-side JavaScript into the main page (the .head.ftl part of the WebScript component)
  • The client-side JavaScript required for a rich Ajax enabled Share component
  • Performing an Ajax call via the Surf proxy back to the Alfresco server to perform live refresh of the Tag Cloud
  • Retrieving labels from the WebScript I18N message bundle
  • Linking to other Share pages (the Search results page when clicking on a tag)
  • Making the dashlet resizable

So there is quite a lot of functionality in a small dashlet – and a lot of Alfresco and Surf framework knowledge required to build it. Obviously it could be made much simpler – for instance the Ajax refresh is not essential and would reduce the complexity a lot (no client-side JavaScript would be required for a start). It is well worth examining further as a starting point for these concepts.

A blog page on the original Tag Cloud dashlet can be found here http://blogs.alfresco.com/wp/wabson/site-tags-dashlet and some other blog pages on Alfresco Share dashlets http://drquyong.com/myblog/?cat=15 and http://www.ixxus.com/blog/2009/04/dashlet-tips

Packaging the Dashlet

To reduce the complexity when packaging this dashlet for deployment in Alfresco Share 3.3, several small changes were made. Firstly since web-assets can now be packaged along with the component, the URLs to those assets were modified. Within the site-tags.get.head.ftl file the path to the CSS and JavaScript files now start with /res this is the path to the SpringSurf Resource servlet. This servlet looks for web-assets within the usual servlet context and web-app and also the classpath and JAR files – which means any web-assets can now be packaged up into the same JAR as the components.

SpringSurf features a number of “persisters” which iterate the configured classpath and JAR locations for all the various page, component and template files that are available. This means to make WebScript components, pages and other objects available to Share, they simply need to be located under one of those configured paths. The JAR file structure required is as follows:

   /alfresco
      /site-webscripts
         /dashlets
            site-tags.get.* <- the WebScript artifacts for the dashlet component
   /META-INF
      /components
         /dashlets
            site-tags.css
            site-tags.js
            /images
               refresh.png

Your WebScript components can live in any folder structure you require under alfresco/site-webscripts – that is one of the paths automatically searched by Share.

Note that it is possible to override the default SpringSurf persister configuration if you want to add your own classpath/JAR path search locations. This is exactly what Share itself does to to add the Alfresco specific paths in addition to the common SpringSurf locations.

The web assets required for your components now live under META-INF – this is effectively the root of all URLs that are processed by the Resource servlet. For example:

   <link rel="stylesheet" type="text/css" href="${page.url.context}/res/components/dashlets/site-tags.css" />

You should find that relative paths to images etc. in CSS classes work also, for example in the Tag Cloud dashlet CSS the file <CODE>images/refresh.png</CODE> is referenced thus:

   .site-tags .refresh
   {
      background-image: url(images/refresh.png);
   }

No references to any other web-app are required!

Deploying the Dashlet

In a default Alfresco installation the included TomCat bundle is already configured to pickup extensions of classes and JARs added to $TOMCAT_HOME$/shared/classes and $TOMCAT_HOME$/shared/lib respectively. So it is a simply matter of dropping the JAR into the lib folder and then restarting the app-server. Note that a plain install of TomCat 6 will need to be tweaked to find classes and jars in those locations – ensure this line is present in $TOMCAT_HOME/conf/catalina.properties

   shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar

If you create a new Share site (or navigate to an existing one), click the Customize Dashboard button on the toolbar and then click the Add Dashlets button you should see the Tag Cloud dashlet listed! That’s it. If you want to play with the tag cloud itself you’ll need to add some documents to the site and tag them.

Share Page Extensions

Additional custom pages with associated templates and components can be added to Share, it is a little more complex than adding a dashlet, but less so with Share 3.3. This article does not go into great detail on the structure of Share pages or specific SpringSurf concepts here, however more information on concepts like pages, templates and component binding can be found on the Alfresco Developer Wiki http://wiki.alfresco.com/wiki/Surf and http://wiki.alfresco.com/wiki/Surf_Platform_-_Developers_Guide

Page Extension Example

This example is a simple Share page extension that again introduces a number of concepts that should be understood before developing Share pages. The example demonstrates adding a new Site page called Site Profile. The Site Profile page configuration identifies the template used to render it and the template itself supplies the mark up and the location of the “regions” that bind to the components within it. Templates are generally small, lightweight and responsible only for providing the markup for the component areas – generally just a few nested DIVs and SPANs – it’s the WebScript components bound to the regions that really do the work. The template is as follows:

   <#include "org/alfresco/include/alfresco-template.ftl" />
   <@templateHeader>
      <!-- add template HEAD items here - such as additional CSS or script includes -->
   </@>

   <@templateBody>
      <!-- standard Alfresco Share header component - you may wish to add navigation etc. -->
      <div id="alf-hd">
         <@region id="header" scope="global" protected=true />
         <@region id="title" scope="template" protected=true />
      </div>
      <!-- YUI layout for a body component area in Share -->
      <div id="bd">
         <!-- Site Details page component binding -->
         <@region id="sitedetails" scope="page" protected=true />
      </div>
   </@>

   <@templateFooter>
      <!-- standard Alfresco Share footer component - you may wish to add your own -->
      <div id="alf-ft">
         <@region id="footer" scope="global" protected=true />
      </div>
   </@>

Note the @region tags – these define the component bindings. The complete page is designed to look like most other Share pages – with the “global” scoped header and footer regions already defined in Share. The interesting parts are the “title” and “sitedetails” regions. Previously to Share 3.3 each of these template or page specific components would require another configuration file – but with SpringSurf these components can be defined as part of the page and template configuration files to reduce complexity further.

The “sitedetails” page component is defined within the page definition thus:

   <?xml version='1.0' encoding='UTF-8'?>
   <page>
      <id>siteprofile</id>
      <title>Example Site Profile Page</title>
      <template-instance>siteprofile</template-instance>
      <authentication>user</authentication>

      <!-- in SpringSurf page scoped component config can now be embedded directly
           into the page config - no more additional xml files required -->
      <components>
         <!-- a custom page component packaged with this example -->
         <component>
            <region-id>sitedetails</region-id>
            <url>/components/sitedetails</url>
         </component>
      </components>
   </page>

It binds the “sitedetails” region id to the WebScript with a URL of /components/sitedetails – we register our WebScript with the same URL. Here is the WebScript descriptor for our sitedetails component in sitedetails.get.desc.xml

<webscript>
   <shortname>Example Site Details</shortname>
   <description>Example Site Details Share extension component</description>
   <url>/components/sitedetails</url>
</webscript>

The WebScript component itself does not do much work, it is quite simple and does not require any client-side JavaScript. It does include a CSS file via the .head.ftl file using the Resource servlet mentioned above. Within the component web-tier JavaScript a remote call is executed to retrieve details of the current site – with the Site Id retrieved from the Share URL template. The JSON response is processed and the data is placed in the model. The model is passed to the component template for markup by the framework. Within the component template the site details are marked up with snippets of XHTML. Within the template there is also another example of using a Resource servlet URL to access an image that is packaged up within the JAR.

Packaging the Page Extension

As noted above, to make your configuration objects available to Share, they simply need to be located under one of its configured search paths. The JAR file structure required is as follows:

   /alfresco
      /site-data
         /pages
            siteprofile.xml
         /template-instances
            siteprofile.xml
      /site-webscripts
         /sitedetails
            sitedetails.get.* <- the WebScript artifacts for the Site Details page component
   /META-INF
      /components
         /sitedetails
            sitedetails.css
            /images
               SurfLogo200.jpg

In addition to the alfresco/site-webscripts folder mentioned in the previous example, we have added an alfresco/site-data folder – this is on the search path to lookup pages, template and component definition files. Again you can use any structure you like under this folder, the page and template definition files here have been placed into separate folders but that is not essential.

Deploying the Page Extension

Place the JAR file into the $TOMCAT_HOME/shared/lib location as mentioned above as start the server. Then either create or navigate to an existing Share site. To access the new page, modify the url in the browser as follows:

 <your-server>/share/page/site/<your-site-id>/siteprofile

Obviously ensuring the your-server and your-site-id elements are correct. You should see a new page appear containing details on the current site with the Surf logo at the bottom!

Conclusion

This quick example of repackaging and light refactoring of a dashlet and a simple page extension into single “drop-in” JAR files show some of the improvements in Share 3.3 now possible thanks to SpringSurf. The combination of the two examples also introduce most of the concepts and frameworks required to developer rich Alfresco Share pages and Ajax enabled components.

Follow me on Twitter!


Alfresco Home | Legal | Privacy | Accessibility | Site Map | RSS  RSS

© 2012 Alfresco Software, Inc. All Rights Reserved.