Groovy script - BloomReach Experience - Open Source CMS

This article covers a Hippo CMS version 12. There's an updated version available that covers our most recent release.

05-10-2018

Groovy DocumentsInfoScript

The DocumentsInfoScript

The following updater script logs information about documents that are selected by the given XPath query.

Description

Find documents and output their name, type, path and publication workflow properties.

XPath query

Preferably set a query for documents, making sure only one type of the variant is selected to get correct count.
E.g. published documents below 'myroot':

content/documents/myroot//element(*, hippo:document)[@hippostd:stateSummary = 'live' and @hippostd:state = 'published']

E.g. unpublished and new documents below 'myroot':

content/documents/myroot//element(*, hippo:document)[@hippostd:stateSummary != 'live' and @hippostd:state = 'unpublished']

Alternatively, query for handles, where the published document variant will be taken, with fallback to the unpublished.

content/documents/myroot//element(*, hippo:handle)

..or, select documents' parents using /..

content/documents/myroot//element(*, hippo:document)/..

Parameters

The script outputs INFO logging on 3 levels based on the parameter verbosity

{"verbosity":  0} 

0 (default) outputs only a summary of numbers of documents, per type
1 per document the name, type, path, plus the summary
2 per document the name, type, path, publication workflow properties, plus the summary

Script

package org.hippoecm.frontend.plugins.cms.admin.updater

import org.hippoecm.repository.HippoStdNodeType
import org.hippoecm.repository.HippoStdPubWfNodeType
import org.hippoecm.repository.api.HippoNodeType
import org.onehippo.repository.update.BaseNodeUpdateVisitor
import org.onehippo.repository.util.JcrConstants

import javax.jcr.Node
import javax.jcr.NodeIterator
import javax.jcr.Session

/**
 * Find documents and output their type, name, path and publication workflow properties.
 *
 * Parameter:
 *   verbosity: 0 (default) only a summary of numbers of documents, per type
 *              1 per document the name, type, path, plus the summary
 *              2 per document the name, type, path, publication workflow properties, plus the summary
 *
 *  XPath:
 *  1) preferably query for documents, making sure only one type of the variant is selected to get correct count.
 *
 *  E.g. published documents below myroot
 *    content/documents/myroot//element(*, hippo:document)[@hippostd:stateSummary = 'live' and @hippostd:state = 'published']
 *  E.g. unpublished/new documents below myroot
 *    content/documents/myroot//element(*, hippo:document)[@hippostd:stateSummary != 'live' and @hippostd:state = 'unpublished']
 *
 *  2) alternatively query for handle, where the published document variant will be taken, with fallback to the unpublished.
 *    content/documents/myroot//element(*, hippo:handle)
 *    or
 *    content/documents/myroot//element(*, hippo:document)/..
 */
class DocumentsInfoScript extends BaseNodeUpdateVisitor {

    Integer verbosity = 0
    List<DocumentInfo> documents = new ArrayList<DocumentInfo>()
    Map<String,Integer> documentTypes = new HashMap<>()

    void initialize(Session session) {
        String v = parametersMap.get("verbosity")
        if (v != null) {
            verbosity = Integer.parseInt(v)
        }

        log.info "DocumentsInfoScript initialized with parameter verbosity=${verbosity}"
    }

    boolean doUpdate(Node node) {
        log.debug "Visiting node ${node.path} of type ${node.primaryNodeType.name}"

        Node handle
        Node document
        if (node.isNodeType(HippoNodeType.NT_DOCUMENT) &&
                    !node.isNodeType(HippoStdNodeType.NT_FOLDER)) {
            document = node
            handle = document.parent
        }
        else if (node.isNodeType(HippoNodeType.NT_HANDLE)) {
            handle = node
            document = getDocument(handle)
        }

        if ((handle == null) || (document == null)) {
            log.debug "No handle/document can be determined from node ${node.path} of type ${node.primaryNodeType.name}"
            return false
        }

        String documentName = handle.name
        if (handle.isNodeType(HippoNodeType.NT_NAMED)) {
            documentName = handle.getProperty(HippoNodeType.HIPPO_NAME).string
        }

        if (document != null) {
            String primaryType = document.getProperty(JcrConstants.JCR_PRIMARY_TYPE).string

            String creator = "unknown"
            String creationDate = "unknown"
            String lastModifiedBy = "unknown"
            String lastModificationDate = "unknown"
            String publicationDate = "unknown"

            if (document.hasProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_CREATED_BY)) {
                creator = document.getProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_CREATED_BY).string
            }
            if (document.hasProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_CREATION_DATE)) {
                creationDate = document.getProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_CREATION_DATE).string
            }
            if (document.hasProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_LAST_MODIFIED_BY)) {
                lastModifiedBy = document.getProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_LAST_MODIFIED_BY).string
            }
            if (document.hasProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_LAST_MODIFIED_DATE)) {
                lastModificationDate = document.getProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_LAST_MODIFIED_DATE).string
            }
            if (document.hasProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_PUBLICATION_DATE)) {
                publicationDate = document.getProperty(HippoStdPubWfNodeType.HIPPOSTDPUBWF_PUBLICATION_DATE).string
            }

            documents.add(new DocumentInfo(primaryType, documentName, handle.path, creator, creationDate, lastModifiedBy, lastModificationDate, publicationDate))
            increaseDocumentTypeCount(primaryType)

            return true
        }

        return false
    }

    Node getDocument(final Node handle) {
        Node published = null
        Node unpublished = null
        
        NodeIterator it = handle.getNodes(handle.name)
        while (it.hasNext()) {
            Node variant = it.nextNode()
            if (variant.hasProperty(HippoStdNodeType.HIPPOSTD_STATE)) {
                String state = variant.getProperty(HippoStdNodeType.HIPPOSTD_STATE).getString()
                if (HippoStdNodeType.PUBLISHED == state) {
                    published = variant
                }
                else if (HippoStdNodeType.UNPUBLISHED == state) {
                    unpublished = variant
                }
            }
        }

        return (published != null) ? published : unpublished
    }

    void increaseDocumentTypeCount(final String docType) {
        Integer count = documentTypes.get(docType)
        documentTypes.put(docType, (count == null) ? 1 : ++count)
    }

    void logOutput() {
        final StringBuilder sb = new StringBuilder()
        if ((verbosity > 0) && (documents.size() > 0)) {
            if (verbosity > 1) {
                sb.append("Detailed document information (name, type, creator, creation date, last modified by, last modification date, publication date, path):\n")
                for (DocumentInfo info : documents) {
                    sb.append("  ").append(info.name).append(", ")
                    sb.append(info.primaryType).append(", ")
                    sb.append(info.creator).append(", ")
                    sb.append(info.creationDate).append(", ")
                    sb.append(info.lastModifiedBy).append(", ")
                    sb.append(info.lastModificationDate).append(", ")
                    sb.append(info.publicationDate).append(", ")
                    sb.append(info.path).append("\n")
                }
            } else {
                sb.append("Document information (name, type, path):\n")
                for (DocumentInfo info : documents) {
                    sb.append("  ").append(info.name).append(", ")
                    sb.append(info.primaryType).append(", ")
                    sb.append(info.path).append("\n")
                }
            }
        }

        sb.append("DocumentsInfoScript summary: ").append(documents.size()).append(" documents found.\n")

        Iterator types = documentTypes.keySet().iterator()
        while (types.hasNext()) {
            String type = types.next()
            sb.append("  ").append(documentTypes.get(type)).append(" documents of type ").append(type).append("\n")

        }

        log.info(sb.toString())
    }


    void destroy() {
        logOutput()
    }

    /**
     * Information about a found document.
     */
    class DocumentInfo {
        String primaryType
        String name
        String creator
        String creationDate
        String lastModifiedBy
        String lastModificationDate
        String publicationDate
        String path

        DocumentInfo(final String primaryType, final String name, final String path, final String creator,
                            final String creationDate, final String lastModifiedBy, final String lastModificationDate, final String publicationDate) {
            this.primaryType = primaryType
            this.name = name
            this.path = path
            this.creator = creator
            this.creationDate = creationDate
            this.lastModifiedBy = lastModifiedBy
            this.lastModificationDate = lastModificationDate
            this.publicationDate = publicationDate
        }
    }

    boolean undoUpdate(Node node) {
        throw new UnsupportedOperationException('Updater does not implement undoUpdate method')
    }
}
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?