Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > Authors mikeh

Alfresco Content Services (ECM)

4 Posts authored by: mikeh Employee
This post is a quick follow-up to my original article Homebrew: Share thumbnails and previews on OS X.



Some additions to the imagemagick-transform.properties file were introduced as a bug-fix to 4.1.6 Enterprise Edition and subsequently 4.2.d Community and all newer versions of Alfresco. The additions were:

img.coders=${img.root}\\modules\\coders

img.config=${img.root}\\config

img.gslib=${img.root}\\lib


As ImageMagick installed via Homebrew uses a slightly different folder structure, we'll need to override these three properties in alfresco-global.properties in order to restore thumbnail functionality in OS X.

# Overrides for imagemagick-transform.properties

img.coders=${img.root}/lib/ImageMagick/modules-Q16/coders

img.config=${img.root}/lib/ImageMagick/config-Q16

img.gslib=${img.root}/lib


That's it!

Mike

Homebrew. The missing package manager for OS X

 

 

As part of some recent testing for Alfresco Mobile 1.4 (1.4.1 is currently being reviewed by Apple), I noticed that my thumbnails and document previews had stopped working. All this probably coincided with an upgrade to OS X 10.8.2, JDK 7 and/or the phases of the moon - whatever it was it's time to fix it!

 

Previously I'd tried both MacPorts and Fink to install command line utilities, but these two projects seem to either be far too complex, or rarely up-to-date. Fortunately there's a new kid on the block, namely Homebrew. Built upon Ruby and git and some very sensible deployment choices (binaries are linked into your path, rather than installed there) it sounds like exactly what I needed to fix my development setup.

 

The first step is to ensure there's a good GCC compiler installed locally. If you happen to be running Xcode already, that's just a matter of choosing the optional 'Command Line Tools' component in Preferences / Downloads. There are probably many different ways of getting GCC installed, but Xcode would be the simplest, if perhaps not the most efficient disk space-wise. Anyway, now you've got Xcode installed there's nothing stopping you modifying and contributing to the Alfresco iOS Mobile source code -- so that's the option I'm going to recommend!

 

The next step is to install Homebrew itself; very simple by copy & pasting the command line:

$ ruby -e '$(curl -fsSkL raw.github.com/mxcl/homebrew/go)'

 

There's then a quick diagnostic check to confirm everything's copacetic:

$ brew update && brew doctor


In my case this showed I was running an old version of XQuartz (X.11 for OS X), so a quick download and install fixed that.


Homebrew packages are simply installed using 'brew install <package>'. Each package is scripted in such a way to download and install any mandatory dependencies. The Homebrew ethos is to not install any unnecessary cruft, so we'll have to bear that in mind when installing the packages Alfresco needs for transformations.

 

I've already got a local install of Apache OpenOffice, so just need to install: ImageMagick, Ghostscript and swftools. Ghostscript can be installed as an optional submodule of ImageMagick, so that's the first package:

 

$ brew install imagemagick --with-ghostscript

 

Let's check the installation:

$ gs --version
9.06

$ convert --version
Version: ImageMagick 6.7.7-6 2012-12-05 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenCL

 

That all looks fine, so next comes swftools.

$ brew install swftools

 

Check the installation...

$ pdf2swf --version
-bash: pdf2swf: command not found

 

Hmmm.. what's going on here? A little Googling concludes that I'll need to manually install a few dependencies, as pdf2swf is actually an optional component within the swftools suite, so let's uninstall swftools and install the dependencies:

$ brew uninstall swftools
$ brew install lame
$ brew install giflib
$ brew install fftw

 

Now we're good to go with swftools again, and this time should get pdf2swf too:

$ brew install swftools

 

And check:

$ pdf2swf --version
pdf2swf - part of swftools 0.9.2

 

OK, so that was a little long-winded, but pretty easy overall.

 

But we're not quite done yet. OS X has its own version of the infamous Windows so-called 'DLL Hell' regarding .dylib files. The problem here involves the ImageIO system framework located at /System/Library/Frameworks/ImageIO.framework. It's evident when firing up the Alfresco Repository, as we'll start to see some transformation errors during bootstrap:

err: dyld: Symbol not found: __cg_jpeg_resync_to_restart
Referenced from: /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib
Expected in: /usr/local/lib/libjpeg.8.dylib

 

Fortunately it's simple to fix, helped in part by the fact that Homebrew links binaries and libraries. We'll just need to re-link some image dylib files back to the ImageIO framework package, remembering to remove the problematic links first:

$ cd /usr/local/lib
$ rm libgif.dylib
$ ln -s /System/Library/Frameworks/ImageIO.framework/Resources/libGIF.dylib libGIF.dylib
$ rm libjpeg.dylib
$ ln -s /System/Library/Frameworks/ImageIO.framework/Resources/libJPEG.dylib libJPEG.dylib
$ rm libtiff.dylib
$ ln -s /System/Library/Frameworks/ImageIO.framework/Resources/libTIFF.dylib libTIFF.dylib
$ rm libpng.dylib
$ ln -s /System/Library/Frameworks/ImageIO.framework/Resources/libPng.dylib libPng.dylib

 

We'll also double-check that tomcat/shared/classes/alfresco-global.properties contains the right configuration for our new tools:

img.root=/usr/local
swf.exe=/usr/local/bin/pdf2swf

 

That should be it. Testing with Google Chrome (so I don't need a system-wide installation of Adobe Flash!) shows that thumbnails and previews are all working well within Share.

 

Share Document Library - Browse view

 

 

Share Document Library - Details Page

 

Hope this is of use to you.

 

-- Mike

You may have heard already about Share v4.0 (codenamed 'Swift') and the excellent work that has been done allowing the Surf components to be extended, customized and overridden. If you haven't, I highly recommend David Draper's blog for in-depth information.



This post is the first in a series covering the extensions specifically to the Document Library components within Share.



Before version 4.0, adding and customizing actions and other parts of the Document Library was more complex than we would have liked. Actions, for example, required overrides to at least four webscripts, plus client-side JavaScript and CSS. One of the goals for 4.0 was to give developers, partners and implementors the ability to customize & extend the Share Document Library without having to either write or duplicate large amounts of code. This would also allow the Web QuickStart and Records Management modules to be fully isolated from 'core' Share code.

Repository tier changes



A number of changes have been made to the Repository tier (data) webscripts:



  1. In order to preserve existing customizations and third party add-ons, a parallel set of data webscripts were developed rather than replacing the existing ones. The new set of webscripts, imaginatively labelled 'documentlibrary-v2' are used by the Share Document Library now; but are no longer called directly (see later). We still have an evaluator.lib.js, but it's job is greatly reduced to handling Working Copies and File- and Folder-Links and should no longer need to be overridden. These new webscripts can be found in the remote-api project and have URLs starting with /slingshot/doclib2/.


  2. All node properties & aspects are returned by the data webscripts now. This will make it easier to display custom model properties and also key behaviours off marker aspects.


  3. Custom property decorators are employed to augment properties that by themselves are of little use to a user interface. Such examples include nodeRef properties (tags, categories) and usernames (where we would like to display the full name).


  4. Lucene queries are no longer used for path-based navigation; instead calls are made directly to the FileFolderService (via ScriptNode) where they can take advantage of the recent performance enhancements.


Web tier changes



A more extensive set of changes has been made to the web tier (presentation) webscripts within the share.war:



  1. Config definitions for actions now appear ONCE in Share config, rather than across several component webscripts.


  2. Status indicators are defined via configuration.


  3. Metadata templates can now be defined for easier custom property rendering on the main Document List page.


  4. Actions have been redefined in a much more configurable way and have also been regrouped into type- and view-based groups, rather than type- and state-based.


It is also much easier now to define custom client-side extensions, including a specific API for defining custom renderers and action handlers.

Repository Tier



Most of the data webscript work is now handled by two Java classes:

   org.alfresco.repo.jscript.SlingshotDocLibCustomResponse

   org.alfresco.repo.jscript.ApplicationScriptUtils


Document Library Custom Response



A custom response appears within the metadata.custom section of the JSON response. An example of a cleanly installed service is the vtiServer configuration, defined within the slingshot-context.xml file.



The customResponses property defines a map of JSON key to custom response bean within the SlingshotDocLibCustomResponse bean definition.

<bean id='slingshotDocLibCustomResponse'

      parent='baseJavaScriptExtension'

      class='org.alfresco.repo.jscript.SlingshotDocLibCustomResponse'>

   <property name='extensionName'>

      <value>slingshotDocLib</value>

   </property>

   <property name='customResponses'>

      <map>

         <entry key='vtiServer'>

            <ref bean='doclibCustomVtiServer'/>

         </entry>

      </map>

   </property>

</bean>


The bean for returning the vtiServer configuration is defined as:

<bean id='doclibCustomVtiServer' class='org.alfresco.repo.jscript.app.VtiServerCustomResponse'>

   <property name='port'>

      <value>${vti.server.external.port}</value>

   </property>

   <property name='host'>

      <value>${vti.server.external.host}</value>

   </property>

   <property name='sysAdminParams'>

      <ref bean='sysAdminParams' />

   </property>

</bean>


The VtiServerCustomResponse class (which implements CustomResponse) returns a Serializable object (e.g. LinkedHashMap) that is serialized into the JSON response by the DocLib webscripts.



This extension point is designed to return useful information that is not specific to any node, for example the presence of an optional module; whether a subsystem is active or not, etc.

Property Decorators



The other place the data webscripts may be extended is via the property decorator extension mechanism. These are utilized by the org.alfresco.repo.jscript.ApplicationScriptUtils class and allow properties such as nodeRefs, usernames and dates to be returned in a much more usable state to the web tier. For example, the Share interface displays usernames using First- and Last-name, rather than just the username. By decorating the properties returned in the initial webscript request, further requests are not necessary to obtain the missing data.

<bean id='applicationScriptUtils' parent='baseJavaScriptExtension' class='org.alfresco.repo.jscript.ApplicationScriptUtils'>

   <property name='decoratedProperties'>

      <map>

         <entry key='cm:creator'>

            <ref bean='usernamePropertyDecorator'/>

         </entry>

         <entry key='cm:modifier'>

            <ref bean='usernamePropertyDecorator'/>

         </entry>

         ...


The decoratedProperties property defines a map of short-format QName to decorator implementation bean. Each of these decorator beans implements the PropertyDecorator interface and returns a serializable map via the decorate() method. This map is then serialized into the JSON response for each node being returned by the webscript request.

Permissions List



The third place the data webscript response may be extended is via the list of permissions that are returned for each node. These are defined via the userPermissions property on the applicationScriptUtils bean, i.e.

<property name='userPermissions'>

   <list>

       <value>CancelCheckOut</value>

       <value>ChangePermissions</value>

       <value>CreateChildren</value>

       <value>Delete</value>

       <value>Write</value>

   </list>

</property>


The default set of permissions should not be reduced without fully understanding the impact on actions, indicators and metadata evaluators already in use throughout Share.

Web Tier



In versions of Share previous to v4.0, the client-side JavaScript requested JSON data from the Repository directly via the proxy servlet. From v4.0, there is a new data webscript (at /components/documentlibrary/data/) which requests data from the Repository, processes the response based on a configurable set of evaluators before finally returning JSON data to the browser.



All configuration for, and evaluation of, Document Library status indicators, metadata templates and actions is now on the web tier instead of split between the Repository and the browser.

Web Tier Configuration Overview



The individual action configuration files (e.g. documentlist.get.config.xml, document-details.get.config.xml) have been removed and all actions are now defined within common, easily overridable config sections.



The new or altered areas of configuration in share-documentlibrary-config.xml are:











































SectionDescription
DocumentLibraryUpdated for v4.0 New <indicators> section for configuring status indicators. New <metadata-templates> for configuring the metadata displayed within the Document Library’s 'browse' view.
DocLibCustomNew to v4.0 <dependencies> section for defining custom client-side functionality and stylesheets.
DocLibActionsNew to v4.0 <actions> section defining all available actions across the various Document Library view pages. <actionGroups> which define which (and in what order) actions are to appear on the Document Library pages.


Also new to v4.0 is the slingshot-documentlibrary-context.xml file containing all bean definitions for web tier evaluators. Please see the Alfresco wiki for a full reference of the out-of-the-box evaluators.

Status Indicators

















Defined within the DocumentLibrary config section, status indicators are small icons typically used to indicate the presence of a marker aspect, or whether a document is in a particular state, e.g. checked out for editing.



Indicator images by default are referenced by id:

   /res/components/documentlibrary/indicators/{id}-16.png


unless the name is overridden by the 'icon' attribute.



Tooltip labels are also defaulted by id:

   status.{id}


and can be overridden by the 'label' attribute.
Status Indicators


Configuration





























































ElementDescription
<indicators>Parent element
<indicator>Status indicator element.

















































Attributes
idUnique indicator id
indexDetermines display order of this indicator
iconIcon filename. If not specified, 'id' is used
labelTooltip i18n label. If not specified, 'id' is used.
<evaluator>Bean id of evaluator that determines the visibility of the image.Evaluator extends org.alfresco.web.evaluator.BaseEvaluator
<labelParam>Status indicator element.

















































Attributes
idUnique indicator id
indexDetermines display order of this indicator
iconIcon filename. If not specified, 'id' is used
labelTooltip i18n label. If not specified, 'id' is used.
<override>Allows this indicator to override (hide) other indicators which would otherwise be visible. The value is the id of another indicator to override.


Example Configuration



<indicator id='google-docs-locked' index='10'>

   <evaluator>evaluator.doclib.indicator.googleDocsLocked</evaluator>

   <labelParam index='0'>{jsNode.properties.owner.displayName}</labelParam>

   <labelParam index='1'>{jsNode.properties.owner.userName}</labelParam>

   <override>locked</override>

</indicator>


A note about the labelParam value: refactoring on the client-side (JavaScript code) means that a common helper object is available for each node within the Document Library during the rendering cycle, namely 'jsNode'. A full reference for this new resource is published on the Alfresco wiki.

Metadata Templates

















The metadata template refers to the section of the document 'browse' page under the filename. New functionality in v4.0 allows this area to be customized with node properties and/or by custom rendering functions.



In a clean install, there are two templates defined: the default (fallback) template and one used when rendering working copies. These are both defined within share-documentlibrary-config.xml and can be extended or overridden as required (via share-config-custom.xml)
Metadata


Configuration





















































ElementDescription
<metadata-templates>Parent element
<template>Template element

























Attributes
idUnique template id
<evaluator>Bean id of evaluator that determines whether the template is to be used for this node or not. Evaluators have no effect on the default template.



Evaluator extends org.alfresco.web.evaluator.BaseEvaluator
<line>Allows placeholder values within i18n label to be replaced at runtime with node properties. The value refers either to a node property (e.g. cm_description) or a custom JavaScript renderer. To add a label in front of the property, add the label’s i18n messageId after the property value, separated by a space; e.g. {cm_description details.description}

















































Attributes
idId of the line within the template. Must be unique within this template.
indexOptional index for ordering the lines when rendering.
viewIf set to 'simple' or 'detailed' then this line will only be rendered when either the simple or detailed view is toggled on respectively. Leave empty, or omit the attribute for both views.
evaluatorOptional evaluator to determine whether this line will be rendered for a node when using the template.


Example Configuration



<template id='isPhoto'>

   <evaluator>evaluator.doclib.metadata.hasExif</evaluator>

   <line index='10' id='date' view='detailed'>{date}{size}</line>

   <line index='20' id='exposure' evaluator='evaluator.doclib.metadata.hasExposure'>

      {exposure exif.label.exposure}

   </line>

   <line index='30' id='description' view='detailed'>{description}</line>

   <line index='40' id='social' view='detailed'>{social}</line>

</template>


Custom JavaScript Renderers



A renderer can either be a simple property value, or use a custom JavaScript renderer. To register a custom renderer, fire a Bubbling (global) event, passing-in the renderer id and the rendering function:

if (Alfresco.DocumentList)

{

   YAHOO.Bubbling.fire('registerRenderer',

   {

      propertyName: 'renderer id',

      renderer: function(record, label)

      {

         return '...';

      }

   });

}


The rendering function should return properly escaped HTML.



 

Actions

















In versions previous to v4.0, the actions configuration was spread throughout a number of webscript XML config files. From v4.0, actions are all now defined globally in the share-documentlibrary-config.xml file, in the 'DocLibActions' config section. This means they can be overridden and extended via a share-config-custom.xml file. These customizations can be via AMP, JAR or web-extension folder mechanism, or a mixture of all three.



Actions are also now grouped by view type instead of node 'state'.
Actions


Configuration













































































ElementDescription
<actions>Parent element
<action>Action config container element

















































Attributes
idUnique action id
typeAction type. Currently supported are: javascript, link, pagelink
iconOptionally override the icon name. If not set, the id is used.
labelThe action's i18n message id.
<param>Action parameter elements

























Attributes
nameParameter name
<evaluator>Bean id of evaluator that determines whether the action is valid for this node or not.



Evaluator extends org.alfresco.web.evaluator.BaseEvaluator

























Attributes
negateIf set to 'true' the output of the evaluator is inverted
<permissions>Permission config container element
<permission>List of permissions required for the action, as defined in the applicationScriptUtils bean config.

































Attributes
allowIf the permission is to specify the action is allowed
denyIf having the permission means the action should be hidden


Note: only one of 'allow' or 'deny' should be specified and set to 'true'
<override>If this action should override the visibility of other actions, they are specified using this element.


Example Configurations



<!-- Inline edit -->

<action id='document-inline-edit' type='pagelink' label='actions.document.inline-edit'>

   <param name='page'>inline-edit?nodeRef={node.nodeRef}</param>

   <permissions>

      <permission allow='true'>Write</permission>

   </permissions>

   <evaluator>evaluator.doclib.action.inlineEdit</evaluator>

</action>


<!-- Checkin from Google Docs -->

<action id='document-checkin-from-googledocs' type='javascript' label='actions.document.checkin-google'>

   <param name='function'>onActionCheckinFromGoogleDocs</param>

   <evaluator>evaluator.doclib.action.googleDocsCheckIn</evaluator>

   <override>document-checkout-to-googledocs</override>

</action>


<!-- View in Explorer client -->

<action id='view-in-explorer' type='link' label='actions.folder.explorer-view'>

   <param name='href'>{explorerViewUrl}</param>

   <param name='target'>_blank</param>

   <evaluator>evaluator.doclib.action.viewInExplorer</evaluator>

</action>


Action Groups



Actions are grouped using the actionGroup elements. The type of node and also the view currently in use determines the actual group used. The group is calculated by the calculateActionGroupId() function in surf-doclist.lib.js and is designed to be overridden if many new and/or altered actions are required (e.g. Records Management).



The action groups defined in a default installation are:



















































































Action Group IdDefault usage
document-browseDocuments on the browse page
document-detailsDocument on the document details page
folder-browseFolders on the browse page
folder-detailsFolders on the folder details page
document-link-browseLinks to documents on the browse page
document-link-detailsLinks to documents on the document details page
folder-link-browseLinks to folders on the browse page
folder-link-detailsLinks to folder on the folder details page


Configuration













































ElementDescription
<actionGroups>Parent element
<actionGroup>Action group config container element

























Attributes
idUnique action group id
<action>Reference to an action defined within the <actions> config area.

























Attributes
idReference to action as defined in <actions> config section above.


Other action properties are overridable here, although it is recommended from a maintenance point of view to only override 'simple' properties like the icon and label. These make is possible to re-use an action with document-biased icon and label to be used for folders.


Example Configuration



<actionGroup id='folder-browse'>

   <action index='100' id='folder-view-details' />

   <action index='110' id='document-edit-properties' icon='folder-edit-properties' label='actions.folder.edit-metadata' />

</actionGroup>


Custom Client Extensions



The DocLibCustom config section is where dependencies on custom client-side assets can be defined. These are defined in exactly the same way as for custom Forms dependencies.

Configuration













































ElementDescription
<dependencies>Parent element
<css>Stylesheet dependencies element

























Attributes
srcPath to the css file, relative to the /res servlet.
<js>JavaScript dependencies element

























Attributes
srcPath to the js file, relative to the /res servlet.


Example Configuration



<dependencies>

   <css src='/custom/my-customization.css' />

   <js src='/custom/my-customization.js' />

</dependencies>


Future Articles



I'll be publishing some override and extension examples as well as covering client-side template and action extensions.

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



Login dialog



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



This is the process I used:





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


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


    alfresco

       site-data

          themes

             devcon.xml

    META-INF

       themes

          devcon




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


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


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


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


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

    <theme>

       <title>DevCon 2010</title>

    </theme>




 



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



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



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


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



surfjar devcon-theme


from the devcon-theme's parent folder.



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



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



You can download the sample devcon-theme.jar file from http://tenthpla.net/alfresco/

Filter Blog

By date: By tag: