Задачи
Одна из задач, с которой может столкнуться AEM разработчик, - это обработка jcr-контента. Иногда вам надо обновить / изменить / упаковать / проанализировать большое количество данных, а необходимость сделать это в live-окружении вдвойне усложняет задачу. Вот несколько типичных ситуаций:
- Смена структуры контента (например, news/feb/event перенести в news/2015-2016/feb/event);
- Изменение / правка контента (например, нужно изменить ‘colour’ на ‘color’ на каждой странице);
- Анализ контента (например, в MSM, Multi Site Manager, редакторы пользуются мультимедийным контентом других сайтов, поэтому возникает необходимость найти все случаи неверного или неправильного применения);
- Создание пакета с контентом (например, при миграции с CQ 5 на AEM 6 сначала надо проанализировать контент, а затем создать валидный пакет для его миграции).
Решение
Для каждой ситуации может быть несколько решений и обходных путей:
- Сервлеты / jsp / скриптлеты;
- AEM пакеты с различными утилитами;
- Сторонние инструменты;
- Groovy-консоль.
Остановимся на Groovy-консоли - это "серебряная пуля" для решения подобных задач. Достоинства Grooby-консоли:
- Не загрязняет код проекта;
- Короткие и ясные скрипты;
- Предопределенные сервисы и методы.
Приступаем к работе
AEM Groovy-консоль можно получить по адресу https://github.com/Citytechinc/cq-groovy-console, по которому доступны версии для AEM/CQ 5, начиная с CQ 5.4 включительно.
После установки Groovy-консоли на локальный инстанс AEM/CQ 5, например, такой http://localhost:4502, она становится доступна по адресу http://localhost:4502/etc/groovyconsole.html.

Для любого groovy-скрипта сразу доступны следующие предопределенные переменные:
- session - javax.jcr.Session
- pageManager - com.day.cq.wcm.api.PageManager -resourceResolver - org.apache.sling.api.resource.ResourceResolver
- slingRequest - org.apache.sling.api.SlingHttpServletRequest -queryBuilder - com.day.cq.search.QueryBuilder -bundleContext - org.osgi.framework.BundleContext -log - org.slf4j.Logger
А это небольшая часть от всех различных предопределенных методов:
- getPage(String path) - Get the Page for the given path, or null if it does not exist.
- getNode(String path) - Get the Node for the given path. Throws - javax.jcr.RepositoryException if it does not exist.
- activate(String path) - Activate the node at the given path.
- deactivate(String path) - Deactivate the node at the given path.
Для импорта доступны следующие пакеты:
- com.day.cq.search
- com.day.cq.tagging
- com.day.cq.wcm.api
- com.day.cq.replication
- javax.jcr
- org.apache.sling.api
- org.apache.sling.api.resource
Также можно использовать историю и архивы скриптов. Эти возможности позволяют решить типичные задачи, упомянутые в начале статьи, легким и элегантным способом.
Пример
Представим, что нам надо найти страницы, у которых в заголовке есть слово “baking”, и заменить его на “banking”.
import com.day.cq.commons.jcr.JcrConstants
def search = "Baking"
def replace = "Banking"
def path = "/content/geometrixx"
def property = JcrConstants.JCR_TITLE;
def query = createSQL2Query(path, search , property)
def result = query.execute()
result.nodes.each{node ->
def title = node.get(property)
node.set(JcrConstants.JCR_TITLE, title.replaceAll(search ,replace))
println node.path
}
save()
def createSQL2Query(path, term, property) {
def queryManager = session.workspace.queryManager
def statement = "SELECT * FROM [cq:PageContent] AS s WHERE ISDESCENDANTNODE([${path}]) and s.[${property}] like '%${term}%'"
def query = queryManager.createQuery(statement, "JCR-SQL2")
query
}
Как Вы видите, решение при помощи Groovy-консоли очень простое и логичное.