Thursday, June 21, 2012

Type subcomponent evaluator ...

A new Alfresco 4.0.x feature is the customisation of Share by component replacement ... see http://blogs.alfresco.com/wp/ddraper/2011/07/29/sub-component-evaluations/

If you want to show/hide/change components based on types? Look no further. Here is an example that lets choose a type or all others not this type (inverted/negated).

The extension configuration holdes the reference to the Java-bean id and the parameters you define:

<evaluator type="share.evaluation.type" >
   <params>
      <nodetype>cm:folder</nodetype>
      <negate/>
   </params>
</evaluator>

Bean Id should be some thing like (replace <java-package>):

<bean id="share.evaluation.type"  class="<java-package>.TypeSubComponentEvaluator"/> 

 The Share java code needs to resolve the parameters, find the current nodeRef and perform a CMIS call to the repository to retrieve the type info.

public class TypeSubComponentEvaluator extends DefaultSubComponentEvaluator {

    @Override
    public boolean evaluate(RequestContext context, Map<String, String> arg1) {
        String requestedType = arg1.get("nodetype");
        boolean resultSuccess = arg1.get("negate") != null ? false : true;

        if (null == requestedType)
            return !resultSuccess;

        Map<String, String> uriTokens = context.getUriTokens();
        String nodeRef = uriTokens.get("nodeRef");
        if (nodeRef == null) {
            nodeRef = context.getParameter("nodeRef");
        }

        try {

            final Connector conn = context
                    .getServiceRegistry()
                    .getConnectorService()
                    .getConnector("alfresco", context.getUserId(),
                            ServletUtil.getSession());

            final Response response = conn.call("/api/node/"
                    + nodeRef.replace(":/", ""));
            if (response.getStatus().getCode() == Status.STATUS_OK) {

                String type = parseReponse(response);

                if (requestedType.equals(type))
                    return resultSuccess;
            } else {
                return !resultSuccess;
            }
        } catch (ConnectorServiceException cse) {
            cse.printStackTrace();
            return !resultSuccess;
        }

        return !resultSuccess;
    }

    private String parseReponse(Response response) {
        try {
            Document dom = DocumentBuilderFactory.newInstance()
                    .newDocumentBuilder().parse(response.getResponseStream());
            NodeList list = dom.getElementsByTagName("cmis:propertyId");
            int len = list.getLength();

            for (int i = 0; i < len; i++) {
                Element element = (Element) list.item(i);
                String propertyName = element
                        .getAttribute("propertyDefinitionId");
                String objectTypeId = null;
                if (propertyName.equals("cmis:objectTypeId")) {
                    objectTypeId = element.getElementsByTagName("cmis:value")
                            .item(0).getTextContent();
                    objectTypeId = objectTypeId.replaceAll("F:", "");
                }
                if (objectTypeId == null) {
                    continue;
                }
                return objectTypeId;
            }
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        return null;
    }
}


I use this functionality to hide all comments for types not of a certain type :)