Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > Author: kevinr1

Introduction

In a previous post I showed how to use an Apache reverse-proxy with a Hazelcast enabled Alfresco Share cluster to load-balance between multiple Share instances in Tomcat. Since moving to Linux as a development platform I thought I would revisit the set-up using the latest version of Apache and also add transparent failover to avoid interruption for users when a node goes down.

 

Share Cluster

At least two instances of Share are needed - with config modified in tomcat/server.xml so they are using different ports and AJP route names. For each server enable the AJP Connector and Engine:

 

<!-- Define an AJP 1.3 Connector -->

<Connector port='8010' protocol='AJP/1.3' redirectPort='8444'

connectionTimeout='20000' URIEncoding='UTF-8' />

 

<!-- You should set jvmRoute to support load-balancing via AJP ie -->

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

 

See my earlier blog post for more details on doing this, but it's really just a case of duplicating a working Tomcat+Share instance and changing the port numbers. Of course you can use instances on separate machines or VMs to avoid some of the port twiddling. On each node also enable Hazelcast Share clustering via tomcat/shared/classes/web-extension/custom-slingshot-application-context.xml as per the previous post again as this also hasn't changed since Alfresco 4.0. There is an example custom-slingshot-application-context.xml.sample provided in the Alfresco distribution which includes this config.

 

Apache 2.4 on Linux

Now install Apache 2.4 - for Ubuntu I used:

sudo apt-get install apache2

This ends up in /etc/apache2. Enable the various Apache2 modules we need to use the reverse proxy via AJP:

sudo a2enmod proxy_balancer

sudo a2enmod proxy_ajp

sudo a2enmod lbmethod_byrequests

Now to edit the Apache default site config to add the proxy configuration. Open /etc/apache2/site-available/000-default.conf file. Inside the root section <VirtualHost *:80> add the following:

 ######################

# ALFRESCO SHARE PROXY

<Proxy balancer://app>

   BalancerMember ajp://localhost:8010/share route=tomcat1

   BalancerMember ajp://localhost:8011/share route=tomcat2

</Proxy>

ProxyRequests Off

ProxyPassReverse /share balancer://app

ProxyPass /share balancer://app stickysession=JSESSIONID|jsessionid

######################

 

You may need to change the port and 'route' values if you aren't using exactly the same as me. Of course you can add more nodes here also if you wish. I also set:

ServerName localhost

to stop the various warnings on starting Apache. Now start Apache:

sudo service apache2 restart

The service should start cleanly, if there is an error instead then look here for info: cat /var/log/apache2/error.log as it may just be missing module dependencies. Start all the Share Tomcat instances - you will see them connect to each other in the Hazelcast INFO log e.g.

 

Nov 07, 2014 12:43:44 PM com.hazelcast.cluster.ClusterManager

INFO: [192.168.221.84]:5802 [slingshot]

Members [2] {

Member [192.168.221.84]:5801

Member [192.168.221.84]:5802 this

}

Now you can point your browser(s) at localhost/share directly. Behind the scenes Apache will automatically load balance out to one of the Share instances. The Share clustering magic will keep things in sync - try creating a site and modifying the dashboard configuration. Another use can immediately visit that dashboard and will see the same configuration, lovely. So, if a node goes down, any users attached to the node are logged out as they are bounced onto another node by Apache. It's great that the users can still access Share, but not so great that they get interrupted and have to log in again. We want to add something called Transparent Failover so the user is not aware of a server crash at all! With clustering, all the servers are the same and so the loss of a server should not interrupt the service.

 

Tomcat Session Replication

Just two steps are needed to enable Session replication between our two Tomcat servers. For all nodes, edit tomcat/webapps/share/web.xml add the following element into the web-app section:

 <distributable/>

 

Then for all nodes, enable the following section in the tomcat/conf/server.xml config:

 <!--For clustering, please take a look at documentation at:

     /docs/cluster-howto.html (simple how to)

     /docs/config/cluster.html (reference documentation) -->

<Cluster className='org.apache.catalina.ha.tcp.SimpleTcpCluster'/>

 

Restart the Share nodes and now you will now see something like this:

Nov 10, 2014 11:21:45 AM org.apache.catalina.ha.tcp.SimpleTcpCluster memberAdded

INFO: Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{127, 0, 1, 1}:4000,{127, 0, 1, 1},4000, alive=1009, securePort=-1, UDP Port=-1, id={-122 10 86 -116 -50 35 77 111 -70 -58 -34 49 -128 -95 -29 -111 }, payload={}, command={}, domain={}, ]

NOTE: You may need to clear the internet cache, delete cookies and restart browser instances to ensure clean startup the first time after making these changes. You may see odd behaviour if you don't do this. Login to Share with a couple of different browsers and examine the Cookies (using Chrome Developer Tools or FireBug etc.) to see what node it is currently attached too - you will see something like:

 

Name: JSESSIONID

 

Value: 5ACD598FD19B6C04FE7EECC1664B69C8.tomcat1

 

Host: localhost

 

Path: /share/

 

Then you can terminate tomcat1 and continue to use Share in that browser - the user experience continues without interruption. If you examine the cookies again you will something like this:

 

Name: JSESSIONID

 

Value: DB984B4A51FB30B5E14B5ED71B65CFD4.tomcat2

 

Host: localhost

 

Path: /share/

 

So Apache has switched the over to tomcat2 and because of the Session replication no logout occurs, nice!

 

This is a basic set-up and there are a lot of options to improve Tomcat replication: http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html

 

For high-performance production systems there are better choices than raw Tomcat replication - for our Alfresco Cloud offering we use haproxy and memcache: https://www.alfresco.com/blogs/devops/2014/07/16/haproxy-for-alfresco-updated-fror-haproxy-1-5/

 

Finally here is another memcache and Tomcat example: https://wiki.alfresco.com/wiki/Tomcat_Session_Replication_with_Memcached

Introduction

As a fun side project I had a go at getting part of the Alfresco 5 platform - Alfresco Share 5 in the Apache Tomcat based web-tier - running on Raspberry Pi.

 

I'm using a Raspberry Pi Model B which has a huge 512MB RAM and crazy fast 700Mhz single-core ARM CPU!! Wow. OK. If you hadn't already guessed, that is not huge nor it is at all fast - in fact it is a lot slower than my HTC One Android phone CPU (quad-core 1.7Ghz ARM CPU with 2GB RAM). To give you comparison - the low-end Intel Atom processor is approx 3-4x faster than this ARM CPU - so it's pretty amazing that it's possible at all.

 

 

Install

The Raspberry Pi is running the standard 32bit Debian Wheezy Linux distribution that is compiled specially for the Raspberry Pi but is not anything special from a Linux perspective. I had previously installed Oracle JDK 7 so that will save some time - but here's how:

 

sudo apt-get update && sudo apt-get install oracle-java7-jdk

 

I expect you can also use JDK 8 but I have not tried it!

 

OK, next I gzipped up my local copy of Apache Tomcat which contains my share.war webapp. IMPORTANT: The Tomcat instance does not contain alfresco.war or solr.war webapps! To be clear, we are only trying the Share web-app on the Pi because the minimum CPU/RAM requirements of the complete Alfresco repository are too much for this tiny $30 computer. Most Alfresco developers run separate Share/Alfresco Tomcat instances as this makes it much easier when doing Share development so that the Alfresco+Solr server instance can be left running - it only takes a few seconds to restart a Tomcat instance containing just Share.

 

Use 'scp' or FTP to get your tomcat zip bundle onto the Pi and unpack it somewhere.

 

 

Configure

1. Edit the tomcat/bin/catalina.sh file to apply JVM memory settings. Add this line near the top of the file:

 

JAVA_OPTS='$JAVA_OPTS -Xms128m -Xmx200m'

 

I set mine to 200MB which is more than enough for Share. Also ensure there are no other JVM options applied that may not be suitable - e.g. for my instance I removed settings for the CMS GC and a few server related flags that were not appropriate for a tiny device with a single-core CPU.

 

2. Edit tomcat/shared/classes/alfresco/web-extension/share-config-custom.xml to point to your remote Alfresco 5.0 repository instance. This is a common Remote config change for an Alfresco Share installation. I won't go into the details here as I have posted about it before on few occasions - but here is what mine looks like:

<alfresco-config>

<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://KEVLINUX: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://KEVLINUX: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://KEVLINUX:8080/alfresco/s</endpoint-url>

<basic-auth>true</basic-auth>

<identity>user</identity>

</endpoint>

</remote>

</config>

</alfresco-config>

 

The important part is the <endpoint-url> address. You may need to use a direct IP address in your config depending on your Alfresco repository machine OS and network.

 

3. In tomcat/bin folder execute ./catalina.sh run as usual to start Tomcat. Because I was using ssh to remote the Pi, I actually used nohup ./catalina.sh run & so I could then tail -f the log and leave it running in the background when logged out - but that's up to you.

 

The server takes a little under 3 minutes to start (rather than around 20 seconds on a modern laptop!)

INFO: Deploying web application directory /home/pi/dev/tomcat/webapps/share

INFO: Starting Servlet Engine: Apache Tomcat/7.0.40

INFO: Server startup in 156202 ms

Point a web browser at the Raspberry Pi Share start page URL e.g. http://raspberrypi:8081/share - again this will vary with your set-up as you might need a direct IP and your port may be different depending on your original Share Tomcat config.

 

The server takes another couple of minutes to warm up (Share is in production mode; warms caches, compiles JS/FTL/Less, retrieves License/DD from Alfresco etc. - lots to do for a single core 700Mhz CPU!)

2014-10-14 21:04:51,434  INFO  [web.site.EditionInterceptor] [http-bio-8081-exec-4] Successfully retrieved license information from Alfresco.

Login to Share!

 

The server takes another 30 seconds to login the first time - then each new page takes ~10sec to warm up - but then response time is very reasonable! Pages appears in <2 seconds.

 

Memory usage of Share heap is ~120MB during page generation, ~75MB at idle.

 

A fun Raspberry Pi experiment and an example of how lean the Alfresco Share 5.0 web-tier is!

Introduction



In Alfresco 5 we have added two new types of events to the activity stream - for document Download and Preview events. Some concerns have been raised about the number of activities that may be added to the site or user streams and also concerns around privacy - seeing what documents other users have been downloading or previewing.



Firstly, the ability of the server to process activities has been improved considerably since Alfresco 4. The activity processing is now multi-threaded and also handles more activities per stream.



Secondly, the same ACL/permission enforcement that has always been present in Alfresco is still present in 5.0 - that has not changed! So the ability to see a public document is still the same for all users and if a document is private, it will remain private. For example if you add/modify/download a document that is private to you then activity events for the action will not appear on the public activity stream for other users in the site.

Configuration



The activities which are processed by the system can be configured in the Alfresco repository. A config file change is needed to disable certain activities from the various summary processing options. For example if you are still concerned about the Download and Preview activities and want to disable them, then this is how you would do it.

RSS Summary Feeds



To disable them from the RSS summary feeds used by the Document Library components we need to override the bean that deals with processing that list.



In the Alfresco repository tomcat instance, in the tomcat/shared/classes/alfresco/extension folder create a spring context XML file called custom-web-context.xml. If you already have this extension file, then add the bean shown below to the existing file.



The beans that process activities for RSS feeds work against a list of known activity types - the types that are generated by applications such as Alfresco Share. To remove the Download and Preview activities we identify the IDs of those activities which are org.alfresco.documentlibrary.file-previewed and org.alfresco.documentlibrary.file-downloaded and remove them from the list for the documentLibraryActivitySummaryProcessor bean definition.

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

<beans xmlns='http://www.springframework.org/schema/beans'

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd'>

<bean id='documentLibraryActivitySummaryProcessor' class='org.alfresco.rest.api.impl.activities.BaseActivitySummaryProcessor'>

<property name='registry' ref='activitySummaryParser' />

<property name='eventTypes'>

<list>

<value>org.alfresco.documentlibrary.files-added</value>

<value>org.alfresco.documentlibrary.files-updated</value>

<value>org.alfresco.documentlibrary.files-deleted</value>

<value>org.alfresco.documentlibrary.file-added</value>

<value>org.alfresco.documentlibrary.file-created</value>

<value>org.alfresco.documentlibrary.file-deleted</value>

<value>org.alfresco.documentlibrary.file-liked</value>

<value>org.alfresco.documentlibrary.inline-edit</value>

<value>org.alfresco.documentlibrary.folder-liked</value>

<value>org.alfresco.documentlibrary.folder-added</value>

<value>org.alfresco.documentlibrary.folder-deleted</value>

<value>org.alfresco.documentlibrary.folders-added</value>

<value>org.alfresco.documentlibrary.folders-deleted</value>

</list>

</property>

</bean>

</beans>



Restart Alfresco then no more Download and Preview activities in RSS feeds. You can modify the bean config above to remove any other activity types you don't like from the list.

Removing from Activity Email Summary



Of course the Activity Email Summary is generated by something completely different and uses different configuration - anything else just wouldn't be Alfresco. To deal with that, we need to override the bean that handles the generation of the list of Activities for Email templates.



Fortunately that is not too hard either. Create the following folder path tomcat/shared/classes/alfresco/extension/subsystems/ActivitiesFeed/default/default and create a file called custom-activities-feed-context.xml. This specifically overrides configuration for the ActivitiesFeed sub-system. A sub-system in Alfresco is a powerful and highly configurable component that can be enabled/disabled and tweaked at run-time - however because of this flexibility comes some complexity with the configuration - which is why we have the strange looking folder path - see this wiki page for more info.



The file should contain the following bean override:

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

<beans xmlns='http://www.springframework.org/schema/beans'

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd'>

<bean id='feedModelBuilderPrototype' class='org.alfresco.repo.activities.feed.DefaultActivitiesFeedModelBuilder' scope='prototype'>

<property name='ignoredActivityTypes'>

<set>

<value>org.alfresco.documentlibrary.file-previewed</value>

<value>org.alfresco.documentlibrary.file-downloaded</value>

</set>

</property>

</bean>

</beans>


Again you can see the activity types specified in a list to be ignored during Activity processing.

Removing from Alfresco Share



To remove the activities from those made available to Alfresco Share dashlets add the following extension config files to your Alfresco Share Tomcat instance (which will be the same Tomcat instance if you are using a default installed package).



tomcat/shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/dashlets/site-activities.get.config.xml



and



tomcat/shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/dashlets/my-activities.get.config.xml



Both files are identical, so create and edit them to contain:

<config>

<filter-range>

<filter type='today' label='today' />

<filter type='7' label='7days' />

<filter type='14' label='14days' />

<filter type='28' label='28days' />

</filter-range>

<filter-type>

<filter type='mine' label='mine' />

<filter type='others' label='others' />

<filter type='all' label='all' />

<filter type='following' label='following' />

</filter-type>

<filter-activities>

<filter type='org.alfresco.profile.status-changed,org.alfresco.comments.comment-created,org.alfresco.comments.comment-updated,org.alfresco.documentlibrary.file-updated,org.alfresco.documentlibrary.file-added,org.alfresco.documentlibrary.files-added,org.alfresco.documentlibrary.files-deleted,org.alfresco.documentlibrary.files-updated,org.alfresco.documentlibrary.file-deleted,org.alfresco.documentlibrary.inline-edit,org.alfresco.wiki.page-created,org.alfresco.wiki.page-edited,org.alfresco.wiki.page-renamed,org.alfresco.wiki.page-deleted,org.alfresco.blog.post-created,org.alfresco.blog.post-updated,org.alfresco.blog.post-deleted,org.alfresco.site.user-joined,org.alfresco.site.user-left,org.alfresco.site.user-role-changed' label='allItems' />

<filter type='org.alfresco.profile.status-changed' label='statusItems' />

<filter type='org.alfresco.comments.comment-created,org.alfresco.comments.comment-updated' label='commentItems' />

<filter type='org.alfresco.documentlibrary.file-updated,org.alfresco.documentlibrary.file-added,org.alfresco.documentlibrary.files-added,org.alfresco.documentlibrary.files-deleted,org.alfresco.documentlibrary.files-updated,org.alfresco.documentlibrary.file-deleted,org.alfresco.documentlibrary.inline-edit,org.alfresco.wiki.page-created,org.alfresco.wiki.page-edited,org.alfresco.wiki.page-renamed,org.alfresco.wiki.page-deleted,org.alfresco.blog.post-created,org.alfresco.blog.post-updated,org.alfresco.blog.post-deleted' label='contentItems' />

<filter type='org.alfresco.site.user-joined,org.alfresco.site.user-left,org.alfresco.site.user-role-changed' label='membershipItems' />

</filter-activities>

</config>


The important bit is we are removing the same file-previewed and file-downloaded activities mentioned above from the filter-activities configuration.



This may also be a good time to review the above configuration - as it allows you to configure what filters are shown in the Activities summary dashlets, across what date ranges and what other Activities they will show. For instance if you don't want to see 'status' updates from users, then you could completely remove the org.alfresco.profile.status-changed references and filter section.

Alfresco Community 5.0.b

Posted by kevinr1 Oct 2, 2014
I'm pleased to announce that the Alfresco Community 5.0.b release is planned within the next few days. This will be the second Alfresco Community 5.0 release and is based on very latest public community code-line.



Alfresco 5 is built with maven. All artifacts are available on the Alfresco nexus.



Here are some of the exciting new features and improvements that you will find in 5.0.b. Many of these features have improved since 5.0.a, so it is recommended you read the Alfresco Community 5.0.a post first if you have not already done so!

Search Improvements



Search is an area we have improved greatly since Alfresco 4 and even more improvements are present in 5.0.b. Firstly a big step forward - Solr 4 is now the default search and indexing sub-system in Alfresco. I know this has been a long time coming but it is worth the wait! There is some great new search functionality we have been able to expose because of Solr 4, and there will be more in future releases.

Live Search



Since 5.0a the instant search results feature (Live Search) has been improved again and is now more reliable and able to show Wiki and Blog items as well as Documents, People and Sites in the list.



[caption id='attachment_245' align='alignnone' width='226']Instant results in Live Search window. Instant results as you type in Live Search.[/caption]

Filtered Search Results



We first showed an early version of Filtered Search Results in Community 5.0.a built using Solr 1.4, but now with Solr 4 this is faster and more configurable. An administrator can use the interface to add/remove/configure facets, including size and date ranges, Site, Tag and your own custom property filters.



[caption id='attachment_241' align='alignnone' width='632']Select and configure the filters to display in the search screen. Select and configure the filters to display in the search screen.[/caption]

Suggest, Spell Check and Did you Mean?



The search experience continues to improve in 5.0b with the addition of Solr 4 features 'suggest' and 'spell check/did you mean'. The 'suggest' feature performs real-time matching of the current phrase against text phrases extracted from the name, title, description and content of documents.



[caption id='attachment_246' align='alignnone' width='640']Suggestions based on the search text. Suggestions based on the search text.[/caption]



Suggest in combination with Live Search mean that exploratory searching is now genuinely useful and fun in Alfresco! The 'spell check' and 'did you mean' features will help the user correct simple spelling mistakes and suggest possible results from the index if no results for the specified query were found.



[caption id='attachment_240' align='alignnone' width='532']My spelling is not good, but Alfresco is going to help me here! My spelling is not good and didn't match a thing, but Alfresco is going to help me out here![/caption]



[caption id='attachment_243' align='alignnone' width='537']Did you mean this? Did you mean this?[/caption]



If you can't find what you want now in Alfresco, it probably isn't there! As well as inline actions which appeared in 5.0a, document content can now be previewed directly in the search results page without navigating away. It's worth mentioning that even if you do leave the results page, the various filters, settings and sorting features you have applied are fully bookmarkable in your browser and you will be able to navigate back as needed.



[caption id='attachment_244' align='alignnone' width='640']html5 preview Inline HTML5 document previews - without leaving the search results page.[/caption]

Alfresco Surf 5.0 and Aikau framework



Alfresco Surf is now part of the main Alfresco HEAD codeline and built as part of core Alfresco maven build. Surf has had a number of performance and memory usage improvements. All of which are easier to manage going forward now it is part of the main Alfresco build. The Aikau framework continues to improve - the new search results page and components are built using it. Developer docs are starting to appear and there are plenty of blog post tutorials also.

Activities



Activities are now generated by Share when a user previews or explicitly performs a Download action. This generates quite a lot more activities - so the number that can be processed by the repository has been improved and in the Share Activities dashlet a roll-up of similar activities now occurs. Also similar activities are rolled up in the notification emails that are generated.



[caption id='attachment_242' align='alignnone' width='632']Read and Preview activities - roll-up in Activities dashlet. Read and Preview activities - roll-up in Activities dashlet.[/caption]

Analytics



A taster of the forthcoming analytics features in Alfresco can be found in this version with two new Share dashlets; Site File Type Breakdown and Site Contributor Breakdown. A lot more will be coming around analytics in future Alfresco releases.



[caption id='attachment_239' align='alignnone' width='414']Pretty graphs, you love pretty graphs right? Pretty graphs, you love pretty graphs right?[/caption]

Internals



In Alfresco 5 we have made a big push on upgrading dependent libraries - a lot of developers have been asking for this. As well as moving to Solr 4.9.1, we have upgraded to Spring 3.2.10, myBatis 3.2.7, OpenCMIS 0.11.0, Activiti 5.16.2 and many more. The bundled JDK is 7.0.67 and office document transformation quality and performance is improved using LibreOffice 4.2.5.

Miscellaneous



Various UI tweaks and improvements, including Share header area clean-up.

Installed 3rd party components



Java 1.7.0_67, Tomcat 7.0.53, PostgreSQL 9.3.5, LibreOffice 4.2.5, ImageMagick 6.8.6

Translations



As usual the Share translations have been improved and updated. Translations include: French, German, Italian, Spanish, Japanese, Dutch, Russian, Norwegian, Simplified Chinese, Brazilian Portuguese.

Bugs



Lots of bugs have been fixed as usual. See the list of fixed bugs since the 5.0a release.

In Summary



We hope you enjoy this Alfresco Community release! Please leave feedback on the forums as usual and raise bugs in JIRA.

Alfresco Community 5.0.a

Posted by kevinr1 Jun 27, 2014

I am very happy to announce another Alfresco Community release is planned within the next few days. This will be the Alfresco Community 5.0.a release and is based on very latest public community code-line. This is the same code base that our Alfresco Cloud release is built on. This release represents an early preview of the features and look of Alfresco 5.0! There is more to come as we progress towards the 5.0 Enterprise release of Alfresco.

Alfresco 5.0 is now entirely built with maven. All artifacts are available on the Alfresco nexus. This is the first release we have built entirely with maven so please bear with us if there are any minor teething troubles!

Here are some of the exciting new features and improvements that you will find in 5.0.a.

Search Improvements

Search is an area we are striving to improve greatly in Alfresco 5.0. There are already two big functional improvements that enhance the findability of results, exploratory search and usability of the search user interface. The first is a complete rewrite of the Search page to use filters (facets) and allow inline user actions and browser history. The second is a feature giving instant results within the search box itself for a number of common search entities; documents, people and Share sites.

Before going into details, it is first worth mentioning a small but important improvement for search generally. The default search operator for a multi-term search has changed from OR to AND. This is a seemingly minor change but actually makes a huge difference to the search result relevance to the user and in turn reduces server-load. Generally smaller result sets are returned to the user and these results tend to be more specific which also reduces the number of additional searches required by the user to find relevant results.

Filtered Search Results

Like many modern search interfaces including ones you will be familiar with like Amazon and eBay, the Alfresco search interface now uses filters (also known as facets) to provide a fast, interactive way to reduce a large number of results to a smaller number and help the user to find the specific item they want. Out-of-the box Alfresco provides a number of filters for File Type (mimetype), Creator, Modifier, Created and Modified Date and Size.

More filter types are possible, and configuration screens for this feature will be coming for a future 5.0 release. Custom facet controls can be created using the flexible Aikau framework. Developers may be interested to know that this page is the first complete Share page to be written in 100% Aikau framework - all from reusable, highly extendable web components.

Filtered Search

Inline actions - the user may now perform useful work within the search results page itself, without being forced to navigate away from the results list to a document details page. More actions will be coming in a future 5.0 release. We also intend to add a full inline previewer of a selected document, again to reduce the need to navigate away from the search results just to read a document.

URL fragment history - the user entered search terms, selected search filters and sort settings are made part of the URL history to aid in navigation to/from the search results and easy bookmarking of a useful search.

Infinite scroll - rather than paging we are using infinite scroll to present long result lists. Feedback on this and any other UX feature is welcome!

Instant Search Results

live_search1

The instant results feature (called Live Search) provide near real-time search results for Documents, Sites and People immediately as the user is typing in the search box. Combined with optimized search APIs and the change to AND multiple terms by default, this is a great interactive way to explore search results and find items from any screen in Share.

live_search_all1

Note that improvements to correctly deal with or filter other entity types such as Wiki, Blog and Discussions pages are in development.

HTML5 pdf.js Previewer

Alfresco Share has always had a powerful preview component capable of displaying virtually any document type as a preview, from images to text to Word and Powerpoint. However most of the more complex document types required the 3rd party Flash plugin to enable this. For Alfresco 5.0 we added a pure HTML5 based document previewer with better browser support, faster performance and no reliance on 3rd party plugins.

 

pdf_viewer

The viewer is based on the buoyant pdf.js open-source project originally contributed by Mozilla. It is high performance PDF viewer that can display complex multi-page PDF documents in any HTML5 compatible browser - including desktop browsers and mobile devices. Developers from Mozilla, Opera and many other individuals are contributing to improve the technology at a rapid pace.

Alfresco has taken advantage of its flexible transformation pipeline that can transform virtually any document type into PDF - this is then displayed inline in the browser. The viewer is based on the Mozilla example viewer and we have added a full screen maximized view, document search, search highlighting and the ability to generate a link to any page of the document. We should thank Community contributor Peter Löfgren and Alfresco engineer Will Abson for their collaboration on the Share Extras project this viewer was originally developed in.

Multiple pages can be displayed on screen, with an optional mini summary view and linked table of contents.

pdf_viewer_maximized

This brings usable multi-page document previews to mobile devices including iPad. Users who do not have a compatible browser such as IE8 will still see the original Flash based preview - the improvement is seamless for supported HTML5 browsers.

Developers and Alfresco Administrators may be interested to know that this change should also improve server performance and stability as it actually removes a step in the most common transformation pipeline 'office doc -> PDF via OpenOffice -> SWF via pdf2swf.exe' the pdf2swf step is no longer needed! This step was also the most common problem area with transforming documents for preview - the HTML5 previewer can cope with all the documents we have tested that potentially cause crashes or hangs with the pdf2swf external process. Also as the pdf.js project moves forward with additional compatibility and performance improvements we can take advantage of that effort.

The version of pdf.js used is 1.0.277.

TinyMCE4 Editor

The inline HTML editor used to edit .html content, comments, wiki, blog and discussion pages in Alfresco has been upgraded to TinyMCE4. This provides a more modern looking editing experience with various minor improvements.

 

TinyMCE4 Editor

TinyMCE4 features an improved menu driven interface to hide a lot of UI clutter. Plus a nice 'distraction free' full screen editing mode.

Site Administration

The new Sites Manager feature in Share Admin Tools enables an Administrator to control access and delete sites from a single admin screen.
Site Management

SpringSurf - Aikau framework

The SpringSurf web-framework underpinning the Alfresco Share web-application continues to improve. Surf now has support for LESS CSS pre-processing and WebScript localization import support. Many more Aikau framework widgets are available and the Filtered Search screen and all inline actions it uses are a good example of those components in action. The header and title menu area of all pages are also built using Aikau widgets.

Miscellaneous

    • Previews and thumbnails now generated for OpenOffice ODG drawing format.
    • Dependent libraries have been updated to more recent versions; including PDFBox, Apache Commons, Tikka etc.
    • UI tweaks and improvements - with more coming in future 5.0 Community releases.

 

Installed 3rd party components

Java 1.7.0_60, Tomcat 7.0.53, PostgreSQL 9.2.4, ImageMagick 6.8.6

Translations

As usual the Share translations have been improved and updated. Translations include: French, German, Italian, Spanish, Japanese, Dutch, Russian, Norwegian, Simplified Chinese and new Brazilian Portuguese.

Bugs

Lots of bugs have been fixed as usual. See the list of fixed bugs since the 4.2.e release.

In Summary

We hope you enjoy this Alfresco Community release! Please leave feedback on the forums as usual and raise bugs in JIRA.

A powerful new feature in Alfresco Enterprise 4.2 is the addition of a user friendly Repository Administration Console. This post describes some of the features present in the console and how it can be easily extended.

 

 

Introduction

It is common knowledge that configuring features such as directory management (e.g. LDAP) or for instance tweaking the correct inbound email server settings is tricky in Alfresco due to the number of scattered, complex XML and property file changes that may be required. Previous versions of Alfresco have some admin tools available in Alfresco Explorer and in Alfresco Share but not much that helps with initial server set-up.

 

A JMX interface to many beans has been available in Alfresco Enterprise for a while and is accessible via something like JConsole. Although this is great for run-time changes compared to XML/properties file edits (which require a server restart, JMX does not), it is still a rather mysterious interface with little help or documentation available.

 

The Repository Admin Console goes a long way to improving this situation. A graphical interface with in-line help text and links directly to the appropriate on-line Alfresco documentation.

 

Under the covers, the JMX interface is used to retrieve and persist configuration changes made via the console. This means changes are persisted to the DB and will take precedence over XML and property file settings, it will also mirror changes still made via JMX interfaces.

 

It should also be noted that the console is an 'in process' application, part of the /alfresco web-app context. This means set-up of a remote application like Share is not needed to use it. Also it has complete access to the rich set of internal Alfresco APIs beyond what would be possible via a REST interface back to Alfresco. It also removes a point of failure - no longer having to ensure a remote application is working and can be authenticated before the system can be managed and configured.

 

System Summary

When you first enter the admin console a System Summary screen is presented that displays a quick overview of the status of the various sub-systems in Alfresco. Including information on clustering, AMPs applied and the current authentication chain. It also displays instance data such as the memory usage, content store disk space, Java and OS version information. The current host-name and IP is always displayed in the header area for all pages.

System Summary

 

General

There are a number of other general information pages, including information on the current license details and what server features are enabled on the license, plus meta like the unique repository ID and the installed/current DB schema numbers.

 

The License page allows you to upload and apply a new Alfresco license instance immediately without having to restart the server.

 


 

Directory Management

One of the most featured areas of the Admin Console is the ability to configure and test connections to various directory services. The Directory Management page provides an interface to create, configure and manage internal Alfresco directories, OpenLDAP, Active Directory and configure authentication chain options for services such as CIFS and browser SSO. Connections to various services can be tested before activating them in the authentication chain and common user synchronization settings are also managed here. It is a powerful new mechanism to set up directory services for Alfresco that anyone who had previously configured LDAP or similar before via property files with far-too-many server restarts should be much happier with.

Directory Management

 

Repository Services

Many of the important sub-systems in Alfresco have a page in the new Admin Console. Features such as Activities, Clustering, Process Engines (workflow) and Transformation services can all be configured via the interface. There is very rich Search Service page with lots of in-line help for the advanced options for Lucene and SOLR and settings for the new Transactional Query feature in 4.2. Finally there are pages for inbound and outbound email server plus File Servers such as CIFS and IMAP.

 

Extending the Admin Console

Each page of the Admin Console is a simple WebScript component. There are no new client-side JavaScript libraries to learn and no new REST API. Each page is built from a library of useful functions and macros imported into each Admin Console WebScript.

 

The JS library functions are responsible for doing the hard work, retrieving the JMX MBean properties and then handing over to flexible FreeMarker macros which automatically render the appropriate control for a JMX property in a consistent way. Assuming no additional processing logic is required, the WebScript library functions will automatically persist them back to the correct property. If you are building simple JMX Form style pages then it really is extremely simple to do. The Alfresco Support team have already been building new pages that they will make available as needed, including; Thread Dump, Active Sessions, Log4J settings and Test Transforms.

 

A sample commented page is included as a starting point for creating new pages.

 

Example controller code from admin-example.get.js:

<import resource='classpath:alfresco/enterprise/webscripts/.../admin-common.lib.js'>

/* Repository Admin Console - Example GET method */

Admin.initModel(

   'Alfresco:Name=License',

   ['Subject', 'Issued', 'RemainingDays'],

   'admin-example'

);

 

This will retrieve the 'Subject', 'Issued' and 'RemainingDays' properties from the 'License' JMX bean.

 

Example template code from admin-example.get.html.ftl:

<#include 'admin-template.ftl' />

<@page title='Example Page'>

   <div class='column-left'>

      <@section label='Some Values' />

      <@control attribute=attributes['Subject'] />

   </div>

   <div class='column-right'>

      <@section label='More Values' />

      <@control attribute=attributes['Issued'] />

      <@control attribute=attributes['RemainingDays'] />

   </div>

</@page>

 

Example output from admin-example WebScript:

 

admin-example

 

The values from the License JMX bean are read-only and the template macros are smart enough to know this and display read-only text. However, if they were editable or you wanted to show a different form field a simple change to the template is all that's needed:

      <@attrtext attribute=attributes['Subject'] />

Example output:

admin-example

Final Words

You can still use XML/properties files to set-up Alfresco if that's your preference - we haven't removed anything related to this, just added the new interface over the top.

Already we've had suggestions from Alfresco partners on how to improve it going forward, and we will certainly be looking at features in the future such as:

    • Import/export of data, allowing a server set-up via the console to be replicated across multiple instances.
    • Read-only mode for Admin Console - to ensure an instance can be examined in detail but no accidental changes made.


If you have any further suggestions, feel free to raise an Improvement request on JIRA or post a comment here. We hope you find it useful!

Alfresco Community 4.2.d

Posted by kevinr1 Aug 22, 2013

I am very happy to announce another Alfresco Community release is planned for next week! This will be the Alfresco Community 4.2.d release and is based on the very latest 4.2 community code-line.

Here are some of the exciting new features and improvements that you will find in 4.2.d. This release builds on the features added to Community 4.2.c which you can also read about.

LightTheme and Share Header

The latest iteration of the new Share user interface theme. This theme is progress towards a lighter looking, more modern UI experience.

LightTheme

This release includes an improved and redesigned Share header component - built on the enhanced Surf UI framework that is part of 4.2. The header includes access to the new application areas such as My Files which is described below, and improved Site favourite management. LightTheme is the default for new installations. It is also the default theme in the very latest MyAlfresco cloud update. If you haven't tried MyAlfresco for a while, now is a good time to do just that - as the interface is now snappier and more responsive.

Share Header

Simplified Document Library Toolbar

A collapsed and simplified user experience for the Document Library toolbar area. Multiple toolbar areas and multiple menus have been collapsed into single toolbars and menus giving much more vertical screen estate. With a simplified Create menu making for a less cluttering view and easier to find places to put customised menu options. The addition of Create Document From Template option is also a new feature.

Document Library Toolbar

The document library also has improved performance due to performance related bug fixes from our 4.1 Enterprise branches.

Filmstrip and Full Screen View

Since 4.2.c the Gallery View has also been improved with the addition of a Filmstrip view that enables rapid viewing of large thumbnails for media files directly from the Gallery View. File Drag and Drop and multi-select actions are still supported from this new view. It also features Full Window and Full Screen options for distraction free viewing of large media files.

Filmstrip View

Table View and Configurable Document Library Views

A brand new Table or 'spreadsheet' like view has been added to the document library. The Table View is an excellent example of the new configurable document library view framework that is part of 4.2. A basic document table view plus Audio and Media focused table views are configured and available by default. See the <view-renderers> section in share-config.xml for examples of how these views are configured, including example Email and Dublin Core views.

Table View

It is also worth pointing out that you can now set a view as a 'default' for a folder you own so Share will remember when you next visit it, other users who visit the folder will be presented with that persisted view preference as the default also.

Icon Refresh

Share has had a new set of icons rendered for it, in keeping with the flat styling of most modern web-sites and applications.

My Files and Shared Files

The return of user home directories to Alfresco! A very popular feature in Alfresco Explorer, users now have their home folder exposed in Alfresco Share, accessible from the 'My Files' option in the header.

Shared Files is a common Contributor location accessible to all users (by default) - this maps to a new folder under the 'Company Home'. An Administrator can set-up appropriate company permissions to use this as a central location for shared documents.

User Trashcan

Now all users can retrieve accidently deleted files and folders without contacting an Adminstrator. Accessible under the My Profile area, a user Trashcan is a searchable location where files can be restored or purged with multi-select actions. It is also possible to restore entire deleted Share sites with document library content and all components and permissions still intact. Users can also view the content of deleted documents without restoring them completely, as a quick way of retrieving or validating accidently deleted content.

User Trashcan

Updated CMIS API

Including support for CMIS 1.1 features such as the Browser Binding.

Alfresco Public REST API

Including access to Sites, People, Favorites, Tags and more

Refresh of installed 3rd party components

Java 7u25, Tomcat 7.0.42, PostgresQL 9.2.4, ImageMagick 6.8.6

Translations

As usual the Share translations have been improved and there are more languages available than ever. Translations include: French, German, Italian, Spanish, Japanese, Dutch, Russian, Norwegian, Simplified Chinese.

Metadata Query

A subset of CMIS queries may be automatically executed against the database if they do not contain OR, CONTAINS(), SCORE() or IN_TREE(); nor refer to decimal, boolean or URI CMIS data types.

https://issues.alfresco.com/jira/browse/ALF-19126

Bugs!

Lots of bugs have been fixed as usual. You should also again find the performance of 4.2 is much better than Community 4.0. See the full list of fixed bugs since the 4.2.c release.

In Summary

We hope you enjoy this Alfresco Community release!

Alfresco Community 4.2.c

Posted by kevinr1 Dec 10, 2012

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!
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)







[caption id='attachment_94' align='alignnone' width='210']Site Search dashlet Site Search dashlet[/caption]



  • 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.







[caption id='attachment_95' align='alignnone' width='389'] Saved Search dashlet - settings for Site Managers[/caption]



  • My Discussions


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







[caption id='attachment_111' align='alignnone' width='316'] My Discussions dashlet[/caption]



Improved Share dashlets:



  • Image Summary


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







[caption id='attachment_107' align='alignnone' width='387'] Image Preview dashlet[/caption]



  • 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.







[caption id='attachment_99' align='alignnone' width='722'] Gallery View 1[/caption]



[caption id='attachment_100' align='alignnone' width='722'] Gallery View 2[/caption]



Quick Share

public sharing of shortened document URLs







[caption id='attachment_120' align='alignnone' width='421'] Quick Share action[/caption]



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!
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.

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
    1. A request for example load balancing config for Share itself as I only posted info on the forward proxy config for Share.
      1. 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!

      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
        1. Share tier cluster to a single repository instance e.g. Browser->Apache->Share Cluster->Repo
        2. 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.

        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.
        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.
        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 https://www.alfresco.com/blogs/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!

        Filter Blog

        By date: By tag: