Extracting simple stats from Alfresco 5

How many documents are created in Alfresco by user?

Someone asked me the question this morning and I remembered that there was a simple SOLR REST service to recover such information from Alfresco 5.

The service can be invoked without parameters by using the following URL

http://localhost:8080/alfresco/s/api/solrstats

and a raw count of document and storage is produced

{
    "resultset": [
    ],
    "queryInfo": {
      "numberFound": "30758"
      ,"totalRows": "0"
         ,"sum": "37910306685"
         ,"max": "2706931488"
         ,"mean": "1239830"
    },
    "metadata": [
        {
            "colIndex": 0,
            "colType": "String",
            "colName": "name"
        },
        {
            "colIndex": 1,
            "colType": "Numeric",
            "colName": "sum"
        },
        {
            "colIndex": 2,
            "colType": "Numeric",
            "colName": "count"
        },
        {
            "colIndex": 3,
            "colType": "Numeric",
            "colName": "min"
        },
        {
            "colIndex": 4,
            "colType": "Numeric",
            "colName": "max"
        },
        {
            "colIndex": 5,
            "colType": "Numeric",
            "colName": "mean"
        }
    ]
}

However, using the listFacets parameter a list of available filters is obtained

http://localhost:8080/alfresco/s/api/solrstats?listFacets=true

[
      "content.mimetype",
      "content.creator",
      "content.modifier",
      "content.created.datetime",
      "content.modified.datetime",
      "content.encoding",
      "content.locale",
      "content.versionLabel",
      "exif.model",
      "exif.manufacturer",
      "exif.iso",
      "exif.focalLength",
      "exif.software"
]

And providing the right filter to the service, created contents by user stats are shown

http://localhost:8080/alfresco/s/api/solrstats?facet=content.creator

{
    "resultset": [
         ...
         ,
         ["angel.borroy",2195237313, 2515, 0, 101617524, 872857]
         ,
         ...
    ],
    "queryInfo": {
      "numberFound": "30758"
      ,"totalRows": "29"
         ,"sum": "37910306685"
         ,"max": "2706931488"
         ,"mean": "1239830"
    },
    "metadata": [
        {
            "colIndex": 0,
            "colType": "String",
            "colName": "name"
        },
        {
            "colIndex": 1,
            "colType": "Numeric",
            "colName": "sum"
        },
        {
            "colIndex": 2,
            "colType": "Numeric",
            "colName": "count"
        },
        {
            "colIndex": 3,
            "colType": "Numeric",
            "colName": "min"
        },
        {
            "colIndex": 4,
            "colType": "Numeric",
            "colName": "max"
        },
        {
            "colIndex": 5,
            "colType": "Numeric",
            "colName": "mean"
        }
    ]
}

It looks like I’ve created 2,515 documents at that Alfresco server installation.

Results may not be exact, as it’s based in SOLR indexation. However they are fine for general stats and comparative studies.

Alfresco, how to notify when a user leaves a Site

Recently a colleague asked me if the sysadmin could be notified every time a user leaves a Site in Alfresco. The short answer is no, as Alfresco does not have this feature by default. However, by using a classical development skill named Behaviour, the feature can be ready in about half an hour.

How a member relation to a Site is stored in Alfresco repository

Alfresco is only a tree of nodes, so every piece of data can be found as a node and its relationships.

For a site member, a child association of type cm:member is created for the user belonging the site. Every role of a site (Manager, Collaborator, Contributor, Consumer) is stored as a node of type cm:authorityContainer, so the role Manager for the Site swsdp has an authority GROUP named site_swdsp_SiteManager including all the members for this role as children (admin and abeecher in the picture below).

Creating a behaviour to react when a member is removed from a role group

Alfresco provides different kind of behaviours, which allows a developer to include custom code when a condition is matched.

In our case, is required to react when an association of type cm:member is removed from an cm:authorityContainer . This can be done with a few lines of Java.

public class MemberAssociationBehaviour
    implements NodeServicePolicies.OnDeleteChildAssociationPolicy {

    // Bind your code to the behaviour
    public void init() {
        policyComponent.bindAssociationBehaviour(
            NodeServicePolicies.OnDeleteChildAssociationPolicy.QNAME,
            ContentModel.TYPE_AUTHORITY_CONTAINER,
            ContentModel.ASSOC_MEMBER,
            new JavaBehaviour(this, "onDeleteChildAssociation",
                NotificationFrequency.TRANSACTION_COMMIT));
    }

    @Override
    public void onDeleteChildAssociation(ChildAssociationRef childAssocRef) {
        // Do some magic!
    }
}

Once declared this behaviour as a Spring bean, any notification mechanism can be developed in the “do some magic” section. Since then, every time a user leaves a site our custom code will be fired.

Final words

A sample implementation for this blog post has been provided at GitHub, however it should be easy to adapt the notification part to your requirements.

No modification has been done to Alfresco product nor configuration, just only a standard extension mechanism has been used to provide this new feature.

Note also that this sample includes i18n messages to provide a consistent log trace for the sysadm.

Alfresco, how to hide categories component from Share app

Every Surf component in a Share page can be extended in order to perform customisations on it.

To identify the target component, enable SurfBug …

… and navigate to the page to identify the component by clicking on it.

Having this component details in mind, you can write a simple surf customisation at /opt/alfresco/tomcat/shared/classes/alfresco/web-extension/site-data/extensions/remove-categories-extension.xml

<extension>
    <modules>
        <module>
            <id>Remove categories from share</id>
            <version>1.0</version>
            <auto-deploy>true</auto-deploy>
            <components>
                <component>
                    <region-id>categories</region-id>
                    <source-id>repository</source-id>
                    <scope>template</scope>
                    <sub-components>
                        <sub-component id="default">
                            <evaluations>
                                <evaluation id="guaranteedToHide">
                                    <render>false</render>
                                </evaluation>
                            </evaluations>
                        </sub-component>
                    </sub-components>
                </component>
            </components>
        </module>
    </modules>
</extension>

After restarting Alfresco, categories tab will disappear from Repository view page for every user. If you want to apply this configuration also for document library, just replace

<source-id>repository</source-id>

by

<source-id>documentlibrary</source-id>

at /opt/alfresco/tomcat/shared/classes/alfresco/web-extension/site-data/extensions/remove-categories-extension.xml or create a new component entry in this XML file to hide categories on both pages.

Remember to include all your customisations under /opt/alfresco/tomcat/shared directory in order to avoid maintenance and upgrading conflicts.