Alfresco: Property Decorators

Note: After fighting through some upgrade issues with MySQL…and it still not being 100% fixed…I’m finally at a point where I can comfortably write to the DB and bring to you two, thats right two!, new posts in quick succession.  I’m hoping to make this a trend to have two new posts a month (so look for 4 this month as these two should have gone live last month). So without further ado….

One of the exciting, at least in my opinion, new features of Alfresco 4 is the Share Document Library Extension’s (hat tip to Mike Hatfield).  In the above post Mike goes in to detail on how to use this new feature and I’m going to share an example on how I’m using it as part of integration with Dropbox I’m working on.

The Problem Set

As part of the integration we need to add a status indicator (see the above article for in depth details on status indicators) to, as the name states, indicate that the file/folder is in a specific state, ie synced to Dropbox.  Early on this was a simple tasks: does it have a specific aspect or not.  As the project has moved forward, we’ve raised the complexity: does it have a specific association and does that association have a child association of a specific value…a direct correlation between this child association and a specific user.  Now that we have moved beyond what the out of the box evaluators can do directly, what are our options?

Options?

The Share Document Library Extension Framework provides two options for retrieving additional metadata/values from the repository tier: Custom Responses and Property Decorators.

Custom Responses allow you to return information that is not specific to any node.  Alfresco 4 uses this to return information about our Sharepoint Protocol integration.

Property Decorators allow you to return node specific information in a more usable format to the web tier (ie Share).  For example rewriting a nodeRef to a filename, or a username as first and last name. Or as in our case, a new set of properties or key/value pairs.

Since we are looking for specific information about a node, a property decorator is what we will need.

Implemention

A property decorator needs to have the following:

A content model property to hold a map of properties. In our model we added a property similar to:

<property name="alf:propertyHolder">
    <type>d:boolean</type>
    <default>false</default>
    <index enabled="false"/>
</property>

This property will never be needed in the index since it will always be the same value until it is requested in Share.

Next we need to implement our logic.  This requires a new Java class that implements PropertyDecorator.

public class CustomProperty
    implements PropertyDecorator
{

  //Add any needed services

    @Override
    public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
    {
        Map<String, Serializable> map = new LinkedHashMap<String, Serializable>(4);

        //Add logic here

        //One to many
        map.put("key", value);

        return (Serializable)map;
    }

}

This also requires a new Spring bean definition.

<bean id="customProperty" class="org.alfresco.extension.repo.jscript.app.CustomProperty">
   <!-- Any needed service -->
  </bean>

Lastly we need to add it to the list of propertyDecorators.  Update: I’ve add a new post that covers how the mapping should occur and added a new bean here. Currently this requires overwriting the out of the box definition for applicationScriptUtils.  This could cause issues if you have several different AMPs that need to overwrite this bean. (I’ve opened ALF-13038 for this issue).

<bean id="customApplicationScriptUtils" parent="applicationScriptUtils">
 <property name="decoratedProperties">
    <map merge="true">
       <entry key="alf:propertyHolder">
          <ref bean="customDecoratorBean"/>
       </entry>
    </map>
 </property>
</bean>

Now this completes the repo side of our extension.  Now we need to work with the values returned on the Share side.  We needr a status indicator so we’ll focus there.

First we’ll define the evaluator.  We need to add the evaluator to web-extension/custom-slingshot-something-context.xml

<bean id="evaluator.doclib.indicator.custom" parent="evaluator.doclib.metadata.value">
      <property name="accessor" value="properties.customProperty"/>
	  <property name="comparator">
         <bean class="org.alfresco.web.evaluator.StringEqualsComparator">
            <property name="value" value="true" />
         </bean>
      </property>
   </bean>

It is important to note that the value of the accessor is not the content model property name, but the key value used in our map from the CustomProperty class.

And finally, we use the evaluator in our indicator config. This is added to our share-config-custom.xml under the META-INF in our custom jar file.

<config evaluator="string-compare" condition="DocumentLibrary">
		<indicators>
			<indicator id="customDecorator" index="250" icon="custom-16.png">
				<evaluator>evaluator.doclib.indicator.custom</evaluator>
			</indicator>
		</indicators>
</config>

In conclusion, the Share Document Library Extension Framework is a powerful new tool in the developer toolbox.