DevOps System Administrator Jahia 8.2

How to retrieve nodes thanks to a Groovy script and modify one of the properties?

Question

I'd like to retrieve nodes of a specific type and modify a property. How can I do that with a Groovy script?

Answer

Let's take an example: we want to set the value of the property j:alternateText when it's empty/missing for the nodes having the type jnt:imageReferenceLink

import org.jahia.api.Constants
import org.jahia.services.content.JCRContentUtils
import org.jahia.services.content.JCRNodeWrapper
import org.jahia.services.content.JCRSessionWrapper
import org.jahia.services.content.JCRTemplate
import org.jahia.services.query.ScrollableQueryCallback
import org.jahia.services.usermanager.JahiaUserManagerService
import org.jahia.services.query.ScrollableQuery

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import javax.jcr.ItemNotFoundException
import javax.jcr.NodeIterator
import javax.jcr.RepositoryException
import javax.jcr.query.Query
import javax.jcr.query.QueryResult

final Logger logger = LoggerFactory.getLogger("org.jahia.tools.groovyConsole")

private static Query getQuery(JCRSessionWrapper session, String nodeType, String propertyName) {
    String textQuery = "SELECT * FROM [" + nodeType + "] AS node WHERE [" + propertyName + "] IS NULL order by [jcr:uuid] asc"
    Query query = session.getWorkspace().getQueryManager().createQuery(textQuery, Query.JCR_SQL2)
    return query
}

private static int handleNodes(JCRSessionWrapper session, QueryResult stepResult, Logger logger, String propertyName)
        throws RepositoryException {
    logger.info("Manage next {} nodes", JCRContentUtils.size(stepResult.getRows()))

    long timer = System.currentTimeMillis()

    NodeIterator nodeIterator = stepResult.getNodes()
    Integer numberUpdated = 0
    while (nodeIterator.hasNext()) {
        JCRNodeWrapper node = (JCRNodeWrapper) nodeIterator.nextNode()
        node.setProperty(propertyName, "XXXXXXXXXXXXXXXX");
        numberUpdated++;
    }
    session.save()
    session.refresh(false)

    logger.info("Took {}ms to update {} nodes in default", System.currentTimeMillis() - timer, numberUpdated)
    return numberUpdated
}

private void modifyNodes(Integer pageSize, Logger logger, String nodeType, String propertyName, String workspace, Locale locale, Closure handler) {
    logger.info("---------------------------------------")
    logger.info("Update nodes of type {} in the {} workspace", nodeType, workspace)
    logger.info("---------------------------------------")

    Integer numberUpdated = JCRTemplate.getInstance()
            .doExecuteWithSystemSessionAsUser(JahiaUserManagerService.getInstance().lookupRootUser().getJahiaUser(),
                    workspace, locale, session -> {
                try {
                    ScrollableQuery scrollableQuery = new ScrollableQuery(pageSize, getQuery(session, nodeType, propertyName))


                    return scrollableQuery.execute(new ScrollableQueryCallback<Integer>() {

                        Integer result = 0

                        @Override
                        boolean scroll() throws RepositoryException {
                            result += handler(session, stepResult, logger, propertyName)
                            return true
                        }

                        @Override
                        protected Integer getResult() {
                            return result
                        }
                    })
                } catch (RepositoryException e) {
                    logger.error("Failed to modify nodes: ", e)
                }
            })
    logger.info("{} nodes updated while checking {} workspace", numberUpdated, workspace)
}

Integer pageSize = 1000
modifyNodes(pageSize, logger, "jnt:imageReferenceLink", "j:alternateText", Constants.EDIT_WORKSPACE, Locale.ENGLISH, this::handleNodes)