Showing posts with label Groovy Scripts. Show all posts
Showing posts with label Groovy Scripts. Show all posts

December 2, 2021
Estimated Post Reading Time ~

Groovy Script for Updating countries nodes

import java.text.SimpleDateFormat;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.api.Asset;
import java.util.Iterator;
import com.day.cq.dam.api.Rendition;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

def filePath = "/content/dam/cleanup/input/country-drop-down_nl_NL.xlsx";  //***** Input file the Path *****/

def nodePath = "/etc/acs-commons/lists/countries/jcr:content/list" //***Country Node Path ****/

def sourceProp = "jcr:title.en";
def targetProp = "jcr:title.nl_NL";
def assetorPageNode = "jcr:content";
def countryNodeUpdateNum = 0;
def notFoundCount = 0;

assetManager = resourceResolver.adaptTo(AssetManager)
Resource res = resourceResolver.getResource(filePath);

Asset asset = res.adaptTo(Asset.class);

Rendition rendition = asset.getOriginal();

InputStream inputStream = rendition.adaptTo(InputStream.class);

XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
XSSFSheet worksheet = workbook.getSheetAt(0);

Iterator<Row> itr = worksheet.iterator();

while (itr.hasNext()) {
def colCount = 0;

Row row = itr.next();

Iterator<Cell> cellIterator = row.cellIterator();
XSSFCell enTitleCell = row.getCell((short) 0);

def enTitleCellStr = ""
def noTitleCellStr = ""

//if (enTitleCell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
enTitleCellStr = enTitleCell.getStringCellValue();
//}

XSSFCell noTitleCell = row.getCell((short) 1);

//if(noTitleCell.getCellType() == XSSFCell.CELL_TYPE_STRING){
noTitleCellStr = noTitleCell.getStringCellValue();;
// }

def nofoundNode = true;

if(noTitleCellStr.length() > 0){
getNode(nodePath).recurse { countryNode ->

if(countryNode.get(sourceProp)){

def sourcePropertyVal = countryNode.getProperty(sourceProp);

if(!sourcePropertyVal.isMultiple()){

sourcePropertyValStr = sourcePropertyVal.getString();

//println "sourcePropertyVal : " + sourcePropertyVal;

if(sourcePropertyValStr == enTitleCellStr){

//println sourcePropertyValStr.toString();

println "Found : " + enTitleCellStr;
countryNode.set(targetProp,noTitleCellStr);
session.save();

countryNodeUpdateNum++;
nofoundNode = false;
return true;
}
}
}
}

if(nofoundNode){
notFoundCount++;
println "Not Found : " + enTitleCellStr;

}
}
}

println "Total number of country nodes updated: "+countryNodeUpdateNum;
println "Not found countries: "+notFoundCount;



By aem4beginner

July 1, 2021
Estimated Post Reading Time ~

Groovy Script to update components with dialog property

/* this script is to update the Booking widget component "summarybarDisabled" and "slideOutEnabled"*/

def path = "/content/we-retail"
def pageCount = 0;
def summarybarDisabledProperty = "summarybarDisabled";
def slideOutEnabledProperty = "slideOutEnabled";

getPage(path).recurse { page ->
def content = page.node
def pagePath = page.path;

content?.recurse { node ->
def componentNode = node.get("sling:resourceType")
if(componentNode == "
we-retail/components/content/image"){
def newNodePathtemp = node.path;

if(node.get(summarybarDisabledProperty)){
def summaryBarStr = getPropertyValueAsStr(node, summarybarDisabledProperty);

if (summaryBarStr == "true") {
nodePath = node.path;
if (nodePath.contains("slideouthero/findhotel")) {
//Inside Slide Out Hero Component
println page.path;

//Remove and set the property, uncomment this block to save the changes
/*
node.getProperty(summarybarDisabledProperty).remove();
node.set(slideOutEnabledProperty, "{Boolean}true");
session.save();
*/

pageCount++;

} else {
//Do not do anything
}

} else {
//println summaryBarStr +" " +page.path;
}

}
}
}
}

println "Total number pages : "+pageCount

def getPropertyValueAsStr(def content, def propertyName){
def propertyValStr = "";
if(content.get(propertyName)){
def propertyVal = content.getProperty(propertyName);
if(propertyVal){
if(!propertyVal.isMultiple()){
propertyValStr = propertyVal.getString();
}else{
values = propertyVal.getValues();
values.each {
if(propertyValStr.length() > 0){
propertyValStr = propertyValStr + " ; " + "$it";
}else{
propertyValStr = "$it";
}
}
}
}
}
return propertyValStr;
}


By aem4beginner

February 18, 2021
Estimated Post Reading Time ~

Adding new country list translations in acs-commons using Groovy Script

Sample Code Snippet:

import java.text.SimpleDateFormat;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.api.Asset;
import java.util.Iterator;
import com.day.cq.dam.api.Rendition;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

def filePath = "/content/dam/cleanup/input/set-country-v1.xlsx";    //***** Input file the Path *****/
def nodePath = "/etc/acs-commons/lists/countries/jcr:content/list"    //***Country Node Path ****/

def sourceProp = "jcr:title.en";
def targetProp = "jcr:title.sv_se";
def assetorPageNode = "jcr:content";
def countryNodeUpdateNum = 0;
def notFoundCount = 0;

assetManager = resourceResolver.adaptTo(AssetManager)

Resource res = resourceResolver.getResource(filePath);
Asset asset = res.adaptTo(Asset.class);
Rendition rendition = asset.getOriginal();
InputStream inputStream = rendition.adaptTo(InputStream.class);

XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
XSSFSheet worksheet = workbook.getSheetAt(0);

Iterator<Row> itr = worksheet.iterator();

while (itr.hasNext())                
{
    def colCount = 0;
    Row row = itr.next();
    Iterator<Cell> cellIterator = row.cellIterator();
    XSSFCell enTitleCell = row.getCell((short) 0);

    def enTitleCellStr = ""
    def noTitleCellStr = ""

    //if (enTitleCell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
        enTitleCellStr = enTitleCell.getStringCellValue();
    //}

    XSSFCell noTitleCell = row.getCell((short) 1);
    //if(noTitleCell.getCellType() == XSSFCell.CELL_TYPE_STRING){
        noTitleCellStr = noTitleCell.getStringCellValue();;
   // }

    def nofoundNode = true;
    if(noTitleCellStr.length() > 0){
        getNode(nodePath).recurse { countryNode ->
            if(countryNode.get(sourceProp)){
                def sourcePropertyVal = countryNode.getProperty(sourceProp);
                if(!sourcePropertyVal.isMultiple()){
                    sourcePropertyValStr = sourcePropertyVal.getString();
                    //println "sourcePropertyVal : " + sourcePropertyVal;
                    if(sourcePropertyValStr == enTitleCellStr){
                        //println sourcePropertyValStr.toString();
                        println "Found : " + enTitleCellStr;
                        countryNode.set(targetProp,noTitleCellStr);
                        session.save();
                        countryNodeUpdateNum++;
                        nofoundNode = false;
                        return true;
                    }
                }
            }
        }
        if(nofoundNode){
            notFoundCount++;
            println enTitleCellStr;
        }
    }
}

println "Total number of country nodes updated: "+countryNodeUpdateNum;
println "Not found country: "+notFoundCount;

Sample Output:




By aem4beginner

January 4, 2021
Estimated Post Reading Time ~

Groovy Script in AEM

Installation of Groovy Console :
The first step to learn Groovy would be to install its IDE. Citytechinc provides a Downloadable zip package that you can install in your instances and you are good to go.
Groovy for AEM 5.6.1 & AEM 6
Groovy for AEM 6.1 with Intelligence (Preferable)

AEM Groovy Console provides an interface for running Groovy scripts in the AEM (Adobe CQ) container. What I will try to do is make you familiar with the language through various examples and then you can solve any use case as per your client's business need.

AEM examples and Sample Use Cases solved by Groovy
Hello World

This is the most basic program for any language and it's a convention to let you know this. We will jump to more client specific requirements in the subsequent examples.

println 'Hello Groovy World '

Find Number of Pages, Page Title, Page Names in a Site hierarchy
By this code piece, I will try to show you guys how a page is traversed in groovy and how its properties can be retrieved and displayed.

/**@author Hashim Khan */

import javax.jcr.Node

/*Flag to count the number of pages*/
noOfPages = 0
/*Pathfield which needs to be iterated for an operation*/
path='/content/geometrixx/en/'
findAllPages()

/*This method is used to Iterate all the pages under a hierarchy
*and get their page title, path, and the overall number of
*pages.*/

def findAllPages(){
getPage(path).recurse
{ page ->
println 'Title:'+page.title
println 'Path:'+page.path
noOfPages ++
}
}


Find all the pages wherein a particular component is being used.
Sometimes there will be a scenario where you have to find (and modify/delete) a particular component from the complete site structure in multiple environments. There is no better solution for that kind of problem, other than Groovy Script.

/** @author Hashim Khan */

/*This method is used to Query the JCR and find results as per the Query.*/
def buildQuery(page, term) {
def queryManager = session.workspace.queryManager;
def statement = 'select * from nt:base where jcr:path like \''+page.path+'/%\' and sling:resourceType = \'' + term + '\'';
queryManager.createQuery(statement, 'sql');
}

/*Defined Content Hierarchy */
final def page = getPage('/content/geometrixx/en/')
/*Component ResourceType which is searched in the content hierarchy */
final def query = buildQuery(page, 'foundation/components/text');
final def result = query.execute()

count = 0;
result.nodes.each { node ->
String nodePath = node.path;
println nodePath
}
println 'No Of Pages found :' + result.nodes.size();
/** @author Hashim Khan */

Find all the pages of a particular Template.
I have depicted to display all the pages using a specific template. In the real world, you might be asked to modify some of the properties of a template or add, subtract something. All this you can easily do in an instant using a groovy script.

/**@author Hashim Khan */

import javax.jcr.Node

/*Flag to count the number of pages*/
noOfPages = 0
/*Pathfield which needs to be iterated for an operation*/
path='/content/geometrixx/en/'
findAllPagesWidTemplate()

/*This method is used to Iterate all the pages under a hierarchy
*and find pages with a specific template
*/

def findAllPagesWidTemplate(){
getPage(path).recurse
{ page ->
def content = page.node
def property= content.get('sling:resourceType')
if(property=="geometrixx/components/contentpage"){
noOfPages ++
println 'Page Path:'+content.path
}
}
}
println 'No Of Pages::'+noOfPages


Alternatively, we could have used Query Builder API to find the pages with a particular template. The below method is more robust and user friendly :

SQL QUERY
/** @author Hashim Khan */

/*This method is used to Query the JCR and find results as per the Query.*/
def buildQuery(page, term) {
def queryManager = session.workspace.queryManager;
def statement = 'select * from nt:base where jcr:path like \''+page.path+'/%\' and sling:resourceType = \'' + term + '\'';
/*Here term is the sling:resourceType property value*/
queryManager.createQuery(statement, 'sql');
}

/*Defined Content Hierarchy */
final def page = getPage('/content/geometrixx/en/')
/*Template which is searched in the content hierarchy */
final def query = buildQuery(page, 'geometrixx/components/contentpage');
final def result = query.execute()

println 'No Of pages found = ' + result.nodes.size();

result.nodes.each { node ->
println 'nodePath::'+node.path
}

XPATH QUERY
/*This method is used to Query the JCR and find results as per the Query.*/
def buildQuery(page, term) {
def queryManager = session.workspace.queryManager;
def statement = "/jcr:root${page.path}//element(*, cq:Page)[jcr:content/@cq:template = '"+term+"']"
/*Here term is the cq:template value*/
def query = queryManager.createQuery(statement, 'xpath')
}

/*Defined Content Hierarchy */
final def page = getPage('/content/geometrixx/en/')
/*Component ResourceType which is searched in the content hierarchy */
final def query = buildQuery(page, '/apps/geometrixx/templates/contentpage');
final def result = query.execute()

count = 0;
result.nodes.each { node ->
String nodePath = node.path;
println nodePath
}
println 'No Of component found :' + result.nodes.size();
result.nodes.each { node ->
println 'nodePath::'+node.path
}


Delete all the nodes of a particular type with a specific property.
Deletion of a particular node is quite handy when you have to similar use case and want to modify the content quickly and easily.

/** @author Hashim Khan */

/*This method is used to Query the JCR and find results as per the Query.*/
def buildQuery(page, term) {
def queryManager = session.workspace.queryManager;
def statement = 'select * from nt:base where jcr:path like \''+page.path+'/%\' and sling:resourceType = \'' + term + '\'';
queryManager.createQuery(statement, 'sql');
}

/*Defined Content Hierarchy */
final def page = getPage('/content/geometrixx/en/')
/*Component ResourceType which is searched in the content hierarchy */
final def query = buildQuery(page, 'foundation/components/flash');
final def result = query.execute()

count = 0;
result.nodes.each { node ->
String nodePath = node.path;

if(nodePath.contains('flash') && !nodePath.contains('jcr:versionStorage') ){
count ++;
println 'deleting--'+nodePath ;
node.remove();
/* Save this session if you are sure the correct nodes are being deleted. Once the session is saved the nodes couldn't be retrieved back.
*session.save();*/
}
}
println 'No Of component found :' + result.nodes.size();
println 'Number of Component Deleted: ' + count;


Modify a property in a complete site hierarchy as per business logic.
There was a real-time problem in one of my projects where we have to fill in jcr:title in the Page-title whenever the Page title was null. Moreover, we were having multiple language sites and have to browse through all of them at once. We used groovy to solve this problem for multiple development environments. Similar to the below example where I am modifying a particular node and its property for the complete hierarchy using Groovy. I have used an example for a Geometrixx site (AEM 6.0) so that you can may the results for yourself.

/** @author Hashim Khan */

/*This method is used to Query the JCR and find results as per the Query.*/
def buildQuery(page, term) {
def queryManager = session.workspace.queryManager;
def statement = 'select * from nt:base where jcr:path like \''+page.path+'/%\' and sling:resourceType = \'' + term + '\'';
queryManager.createQuery(statement, 'sql');
}

/*Defined Content Hierarchy */
final def page = getPage('/content/geometrixx/en/')
/*Component ResourceType which is searched in the content hierarchy */
final def query = buildQuery(page, 'collab/calendar/components/event');
final def result = query.execute()

count = 0;
result.nodes.each { node ->
String nodePath = node.path;

if(nodePath.contains('event') && !nodePath.contains('jcr:versionStorage') ){
/*The below iterator is used to fetch the child pages of the parent node */
node.findAll { it.hasNodes() }.each {
if(it.name.contains("event")){
count ++;
println 'Title--'+it.get('jcr:title') ;
println 'Node Path--'+it.path ;
it.set('jcr:title','Hashim');
println 'Title--'+it.get('jcr:title') ;
session.save()
}
}
}
}
println 'Number Of Component Found :' + result.nodes.size();
println 'Number of Component Modified:' + count;


Count Number of Nodes that have more than 1000+ child nodes.
This a common use case wherein you are asked to check whether a particular hierarchy has nodes that have more than 1000 child nodes. You can change the Search Path at your convenience and list down the nodes under that hierarchy.

/** @author Hashim Khan */

import javax.jcr.NodeIterator

def path="/etc/tags"
def variable = 1000

println 'Node,COUNT'
getNode(path).recurse { node >
NodeIterator it = node.getNodes()
def count =0
while(it.hasNext()){
def nodetemp = it.nextNode()
count++
}

if(count>=variable)
println node.path + ','+count
}

Delete all the Unused Tags in an application.
In this script, the unused tags are counted in an application and deleted with a delay. If the tag count is much more it is advisable to run this script in a more specified path. You have to run this script a few times as it doesn’t delete the tags which have any child nodes.

/** @author Hashim Khan */

import org.apache.sling.api.resource.Resource
import com.day.cq.tagging.Tag
import com.day.cq.tagging.TagManager
import org.apache.sling.api.resource.ResourceResolver
import java.lang.Thread.*;
import javax.jcr.Node;

def tagpath = "/etc/tags";
def delay = 10 ; //in Milliseconds.

def query = getAllTags(tagpath)
def result = query.execute()

def rows = result.rows
def unusedTags = 0

rows.each { row >
Resource res = resourceResolver.getResource(row.path)
if(res!=null){
Tag tag = res.adaptTo(com.day.cq.tagging.Tag)
Node tempNode = res.adaptTo(javax.jcr.Node);

if(tag.getCount()==0){
if(!tempNode.hasNodes()){
unusedTags++
println "Deleted Tag : " + tag.getPath()
tempNode.remove()
}
}
Thread.currentThread().sleep((long)(delay));
}

}
println "Total Unused Tags :"+unusedTags
//session.save() //Uncomment this to make it working.

def getAllTags(tagpath) {
def queryManager = session.workspace.queryManager
def statement = "/jcr:root"+tagpath+"//element(*, cq:Tag)"
def query = queryManager.createQuery(statement, "xpath")
}


Merge Duplicate Tags in an Application
This was a requirement in one of my clients who asked us to merge the Duplicate Tags. This way you can list out all the duplicate tags and merge all of them into the first Master Tag. All the related references in the Pages will automatically be changed as per the API.

/** @author Hashim Khan */

import org.apache.sling.api.resource.Resource
import com.day.cq.tagging.Tag
import org.apache.sling.api.resource.ResourceResolver
import com.day.cq.tagging.TagManager
import javax.jcr.Node;
import java.lang.Thread.*;

def tagLocation = "/etc/tags"
def delay = 10 ; //in Milliseconds.

def buildQuery(tagLocation) {
def queryManager = session.workspace.queryManager;
def statement = "/jcr:root"+tagLocation+ "//element(*, cq:Tag)"
def query = queryManager.createQuery(statement, 'xpath')
}

def findDuplicateTags(tagLocation,tagNodeName) {
def queryManager = session.workspace.queryManager;
def statement = "/jcr:root"+tagLocation+ "//element(*, cq:Tag) [fn:name() = '" + tagNodeName + "' ]"
def query = queryManager.createQuery(statement, 'xpath')
}

final def query = buildQuery(tagLocation);
final def result = query.execute()

def tagList = []

result.nodes.each {node->
String nodeTitle = node.name;
tagList.add(nodeTitle);
}
def duplicates = tagList.findAll {tagList.count(it) > 1}
def uniqueUsers = duplicates.unique(mutate = false)
def count = 0;
TagManager tm = resourceResolver.adaptTo(com.day.cq.tagging.TagManager);
def mergecount = 0;

uniqueUsers.each {
def tagquery = findDuplicateTags(tagLocation,it);
def pathresult = tagquery.execute()
Tag tag , masterTag =null;

count = 0;
pathresult.nodes.each {node->
Resource r = resourceResolver.getResource(node.path)
tag = r.adaptTo(com.day.cq.tagging.Tag)
Node tempNode = r.adaptTo(javax.jcr.Node);
if(count == 0 ){
masterTag = tag ;
}else if(tm!=null && !(tag.getPath()==masterTag.getPath())){
if(!tempNode.hasNodes()){
println 'Merging Tag :: ' + tag.getPath() +' into>> '+ masterTag.getPath()
mergecount++
tm.mergeTag(tag,masterTag)
}
}
count++
Thread.currentThread().sleep((long)(delay));
}

}
println 'Merged tags count ::'+ mergecount

Create a CSV File for Duplicate Tags List in the Application.
This script can be used to generate a CSV output and store it in the filesystem. It lists down all the tags which are Duplicate and all the pages where they are being used. It will help to analyze the System Taxonomy.

/** @author Hashim Khan */

import org.apache.sling.api.resource.Resource
import com.day.cq.tagging.Tag
import org.apache.sling.api.resource.ResourceResolver

def filePath = "/opt/adobe/output.csv"
def tagLocation = "/etc/tags/geometrixx-media"

def buildQuery(tagLocation) {
def queryManager = session.workspace.queryManager;
def statement = "/jcr:root"+tagLocation+ "//element(*, cq:Tag)"
def query = queryManager.createQuery(statement, 'xpath')
}

def findDuplicateTags(tagLocation,tagNodeName) {
def queryManager = session.workspace.queryManager;
def statement = "/jcr:root"+tagLocation+ "//element(*, cq:Tag) [fn:name() = '" + tagNodeName + "' ]"
def query = queryManager.createQuery(statement, 'xpath')
}

def findPagesWithTag(tagId, tagPath) {
def queryManager = session.workspace.queryManager;
def statement = "//element(*, cq:Page)[(jcr:content/@cq:tags = '" + tagId + "' or jcr:content/@cq:tags = '" + tagPath + "' )]"
def query = queryManager.createQuery(statement, 'xpath')
}

final def query = buildQuery(tagLocation);
final def result = query.execute()

def tagList = []

f = new File(filePath)

result.nodes.each {node->
String nodeTitle = node.name;
tagList.add(nodeTitle);
}

def duplicates = tagList.findAll {tagList.count(it) > 1}
def uniqueUsers = duplicates.unique(mutate = false)

print 'TAGTITLE ,TAGID , Pages , Count'+'\n'
f.append('TAGTITLE ,TAGID , Pages , Count'+'\n')
uniqueUsers.each {
def tagquery = findDuplicateTags(tagLocation,it);
def pathresult = tagquery.execute()
pathresult.nodes.each {node->
Resource r = resourceResolver.getResource(node.path)
Tag t1 = r.adaptTo(com.day.cq.tagging.Tag)
print t1.getTitle()+','
f.append(t1.getTitle()+',')
def pagequery = findPagesWithTag(t1.getTagID(), node.path);
def pageresult = pagequery.execute()
print t1.getTagID()+','
f.append(t1.getTagID()+',')
count = 0;
def totalResults = pageresult.getTotalSize()
pageresult.nodes.each { pagenode->
if(count>0){
print ','
f.append(',')
}
print pagenode.path+','
f.append(pagenode.path+',')

if(count==0){
print t1.getCount()+','
f.append(t1.getCount())+','
}
count++;

if (totalResults != count ){
print '\n'
f.append('\n')
}
print ','
f.append (',')
}
print '\n'
f.append ('\n')
}
print '\n'
f.append ('\n')
}

Fill all the Unused Assets in AEM Content
/*
Find all the Assets which are not referenced in the content and could be removed.
@author Hashim Khan */

def predicates = [path: "/content/dam/geometrixx", type: "dam:Asset", "orderby.index": "true", "orderby.sort": "desc"]
def query = createQuery(predicates)
query.hitsPerPage = 500
def result = query.result
println "${result.totalMatches} hits, execution time = ${result.executionTime}s\n--"

result.hits.each { hit ->
def path=hit.node.path
Resource res = resourceResolver.getResource(path)
if(res!=null){
getAllReferences(path);
}
}

def getAllReferences(assetpath) {
def queryManager = session.workspace.queryManager
def statement = "/jcr:root" + "/content/geometrixx//*" + "[jcr:contains(., '"+assetpath+"')]"
def query = queryManager.createQuery(statement, "xpath")
def result = query.execute()
def rows = result.getRows().size
if(rows==0){
println "Unused Asset: "+assetpath
}

}


Fill all the Unused Components in AEM Content
/*
Find all the Components which are not used in the content and could be removed.
@author Hashim Khan */

def predicates = [path: "/apps/geometrixx/components", type: "cq:Component", "orderby.index": "true", "orderby.sort": "desc"]
def query = createQuery(predicates)
query.hitsPerPage = 1000
def result = query.result
println "${result.totalMatches} hits, execution time = ${result.executionTime}s\n--"

result.hits.each { hit ->
def path=hit.node.path
Resource res = resourceResolver.getResource(path)
if(res!=null){
path = path.substring(6,path.length())
getAllReferences(path);
}
}

def getAllReferences(assetpath) {
def queryManager = session.workspace.queryManager
def statement = "/jcr:root" + "/content/geometrixx//*" + "[@sling:resourceType='"+ assetpath+"']"
def query = queryManager.createQuery(statement, "xpath")
def result = query.execute()
def rows = result.getRows().size
if(rows==0){
println "Asset="+assetpath+"; Results="+rows
println "********Unused Component*******: "
}

}

Validate Dispatcher Security for your website
/*
This script could be used to check the Dispatcher security by checking the below paths as per
Security Checklist https://helpx.adobe.com/experience-manager/dispatcher/using/dispatcher-configuration.html#TestingDispatcherSecurity
Make sure to change the protocol, domain, and one valid page as per your website.
None of the curl response should give a 200 status.
@author Hashim Khan */

/*Defines the protocol for th website */
def protocol="https://"
/*Defines the main domain URL for the website */
def domain="www.intel.com"
/*Defines a sample page in the application to check content grabbing. */
def valid_page="/content/www/us/en/homepage"

/*Defines a list of security URLs which are used to verify Dispatcher Configurations.
You can add more if you like. Current list is from https://helpx.adobe.com/experience-manager/dispatcher/using/dispatcher-configuration.html#TestingDispatcherSecurity */
def list = [
protocol+domain+"/admin",
protocol+domain+"/system/console",
protocol+domain+"/dav/crx.default",
protocol+domain+"/crx",
protocol+domain+"/bin/crxde/logs",
protocol+domain+"/jcr:system/jcr:versionStorage.json",
protocol+domain+"/_jcr_system/_jcr_versionStorage.json",
protocol+domain+"/libs/wcm/core/content/siteadmin.html",
protocol+domain+"/libs/collab/core/content/admin.html",
protocol+domain+"/libs/cq/ui/content/dumplibs.html",
protocol+domain+"/var/linkchecker.html",
protocol+domain+"/etc/linkchecker.html",
protocol+domain+"/home/users/a/admin/profile.json",
protocol+domain+"/home/users/a/admin/profile.xml",
protocol+domain+"/libs/cq/core/content/login.json",
protocol+domain+"/content/../libs/foundation/components/text/text.jsp",
protocol+domain+"/content/.{.}/libs/foundation/components/text/text.jsp",
protocol+domain+"/apps/sling/config/org.apache.felix.webconsole.internal.servlet.OsgiManager.config/jcr%3acontent/jcr%3adata",
protocol+domain+"/libs/foundation/components/primary/cq/workflow/components/participants/json.GET.servlet",
protocol+domain+"/content.pages.json",
protocol+domain+"/content.languages.json",
protocol+domain+"/content.blueprint.json",
protocol+domain+"/content.-1.json",
protocol+domain+"/content.10.json",
protocol+domain+"/content.infinity.json",
protocol+domain+"/content.tidy.json",
protocol+domain+"/content.tidy.-1.blubber.json",
protocol+domain+"/content/dam.tidy.-100.json",
protocol+domain+"/content/content/geometrixx.sitemap.txt",
protocol+domain+valid_page+".query.json?statement=//*",
protocol+domain+valid_page+".qu%65ry.js%6Fn?statement=//*",
protocol+domain+valid_page+".query.json?statement=//*[@transportPassword]/(@transportPassword%20|%20@transportUri%20|%20@transportUser)",
protocol+domain+valid_page+"/_jcr_content.json",
protocol+domain+valid_page+"/_jcr_content.feed",
protocol+domain+valid_page+"/jcr:content.feed",
protocol+domain+valid_page+"._jcr_content.feed",
protocol+domain+valid_page+".jcr:content.feed",
protocol+domain+valid_page+".docview.xml",
protocol+domain+valid_page+".docview.json",
protocol+domain+valid_page+".sysview.xml",
protocol+domain+"/etc.xml",
protocol+domain+"/content.feed.xml",
protocol+domain+"/content.rss.xml",
protocol+domain+"/content.feed.html",
protocol+domain+valid_page+".html?debug=layout"
]

list.each {
checkUrlGetStatus(it)

}
checkUserGeneratedPath(protocol,domain)
checkDispatcherInvalidation(protocol,domain)

/*Method to make a GET call for the above list. */
def checkUrlGetStatus(String path) {
print path+" , "
def process ="curl -s -o /dev/null -w %{http_code} ${path} ".execute().text
printf("%2s", "STATUS:")
process.each { text->
print "${text}"
}
println ""
}
/*Method to make a POST call for the user generated path. */
def checkUserGeneratedPath(String protocol,String domain) {
print "POST:"+protocol+domain+"/content/usergenerated/mytestnode ,"
def process ="curl -X POST -s -o /dev/null -w %{http_code} -u anonymous:anonymous ${protocol}${domain}/content/usergenerated/mytestnode".execute().text
printf("%2s", "STATUS:")
process.each { text->
print "${text}"
}
println ""

}
/*Method to make a Dispatcher invalidation call. */
def checkDispatcherInvalidation(String protocol,String domain) {
print "Dispatcher Invalidation: "+protocol+domain+"/dispatcher/invalidate.cache ,"
def process ="curl -s -o /dev/null -w %{http_code} -H \'CQ-Handle:/content\' -H \'CQ-Path:/content\' ${protocol}${domain}/dispatcher/invalidate.cache".execute().text
printf("%2s", "STATUS:")
process.each { text->
print "${text}"
}
}

/* Curl Command Syntax to Parse the XML output.
def proc = "curl -u admin:admin http://localhost:4502/content/geometrixx/en.html".execute().text
def crx = new XmlSlurper().parseText(proc);
def packages = crx.response.data.packages
def status = crx.response.status;
println "status:"+status;
packages.package.each { pack->
println "${pack.name}: ${pack.size}"
}
*/


Validate & Read Sitemap XML paths to create Cache
/*
This script could be used to create Cache by reading Sitemap and making a GET call for all the paths present in it.
Make sure to change the protocol and domain as per your website.
Note that none of the requests should give a 404.
@author Hashim Khan */

/*Defines the protocol for the website */
def protocol="https://"
/*Defines the main domain URL for the website */
def domain="www.lifetime.life"

readSitemapXML(protocol,domain)

/*Method to make a GET call for the above list. */
def checkUrlGetStatus(String path) {
print path+" , "
def process ="curl -s -o /dev/null -w %{http_code} ${path} ".execute().text

printf("%2s", "STATUS:")
process.each { text->
print "${text}"
}
println ""
}

/*Method to make a GET call at Sitemap and read the XML output recursively. */
/* Curl Command Syntax to Parse the XML output. */
def readSitemapXML( String protocol,String domain) {

def proc = "curl -X GET ${protocol}${domain}/sitemap.xml".execute().text
def output = new XmlSlurper().parseText(proc);
def urls = output.url.loc
urls.each { path->
def url = "${path}"
checkUrlGetStatus(url)

}
}


So friends as you may have noticed that Groovy could be quite useful in an AEM project where you need to modify some content/property in one go.
There could be millions of other things where Groovy is very useful. If you want to explore more on Groovy use the pdf:: Groovy Recipes

Now all the Groovy Scripts are available in the GITHUB Project – https://github.com/hashimkhan786/aem-groovy-scripts


By aem4beginner

October 1, 2020
Estimated Post Reading Time ~

Groovy Script Console integration in AEM

Introduction: Groovy was developed by Jochen Theodorou, Guillaume Laforge, Cedric Champeau, and Paul King. Its typing discipline is strong, static, and dynamic. It was licensed under the Apache 2.0 license. It first appeared in the year 2003. Its file extension is .groovy and was designed by James Strachan.

What is Groovy Script: Apache Groovy is an Object-oriented programming language used for the Java platform. It can be used as a scripting language for the Java platform.

Groovy vs Java
Groovy vs JavaGroovyJava
DefinitionIt is compiled to JVM bytecode and is compatible with the Java Platform.It is developed on JDK and is run on JVM.
UsageIt is used when both programming language and scripting language.It is used as a programming and object-oriented language.
IntegrationIt can be integrated along with any web applications and scripting applications.It can also be integrated with any object-oriented application as it is compatible with any JVM based applications.
PlatformIt supports any operating systems or platformsIt supports cross-platform operating systems
SyntaxThe syntax is very similar to Java syntax.It has a strong disciple in its syntax.
CommunityIt has been submitted to JCP for specification request.It has a larger community called Java Community process i.es JCP being maintained by a large group of highly qualified technical experts across the industry.
LicenseIt was licensed under Apache license 2.0It was licensed under GNU General Public License.
ImportsAll the packages will be imported by default.It has to be mentioned clearly to import any package into the java class file.
DocumentationIt provides single page documentation.It has documentation in the form specification given by JCP.
Setup:
Download the Groovy Console package. Check the version compatible with your AEM instance. For AEM 6.5 I am using the 14.0.0 version.
Install the downloaded package using the CRX package manager.
To verify the installation, open http://localhost:4502/apps/groovyconsole.html in the browser to view the groovy console.

Note: From 13.0.0 release, paths were changed from /etc/ to /apps/ to access Groovy Console

GUI Console:


Sample scripts are available in the Groovy Console.


Open any script and click on Run Script.


If you get an error when running scripts, add user group in Allowed Group property of "Groovy Console Configuration Service".


Sample Script:
getPage("/content/wknd-events").recurse { page ->
    def content = page.node

    if (content && !content.get("hideInNav")) {
        println page.path
    }
}

The above script will pull the pages which have the property "hideInNav" as false from the Weekend Event site.




By aem4beginner

May 11, 2020
Estimated Post Reading Time ~

Batch Processing Content in AEM with Groovy Console

Problems?
One of the issues that the AEM developer may meet is processing JCR content. Sometimes you need update/modify/package/analyze a really big amount of data and double challenge if you need to do it in a live environment: There are some typical cases:
  • - Change content structure (for example news/feb/event -> news/2015-2016/feb/event)
  • - Modify/fix content (for example need to change ‘color’ on ‘color’ on every page)
  • - Analyze content (on MSM, editors use assets from another website, need to find all wrong usages)
  • - Prepare and package content (for example during migration from CQ5.x on AEM6.x you need to analyze content first and create a valid package for its migration)
Solutions
There are maybe several solutions and workarounds for each case:
  • - Servlets/JSP/Scriptlets
  • - AEM Util packages
  • - External tools
  • - Groovy Console
Let's stop on Groove Console it is a real silver bullet. Advantages of Groovy Console:
  • - does not mess project code
  • - short and clear scripts
  • - predefined services/methods
Let’s start
The AEM Groovy Console is hosted on https://github.com/Citytechinc/cq-groovy-console and available for versions AEM/CQ5 starting from CQ5.4. Once Groovy Console is installed on AEM/CQ5 instance go to http://localhost:4502/etc/groovyconsole.html

New URL from AEM 6.5 onwards: http://localhost:4502/apps/groovyconsole.html

For any groovy script you have already defined variables:
  • - 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
methods (some of them):
  • - 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.
And imports:
  • - 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
Also available history and scripts archive. Those features make solving the kind of issues mentioned at the beginning of the post easy and in an elegant way.
Example:
Suppose we need to find pages that have “baking” in title and replace it with “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
}


You can see solution using Groovy Сonsole is pretty short and straightforward.


By aem4beginner

May 9, 2020
Estimated Post Reading Time ~

Reporting using Groovy scripts

It's often necessary to get different kinds of statistics on CQ data. You can do it in several ways:
  1. Using the build-in CQ reporting engine. Unfortunately, it is pretty inflexible and requires lot's of configuration to be done, so I would recommend using it for simple JC queries only;
  2. Writing custom components with required logic in ESP/JSP/Java/Groovy
  3. Use third-party tools like Splunk which parses CQ logs (you should have required data in logs!.
In this blog post, I focus on groovy scripts as one of the quickest ways to operate with CQ API.
To use Groovy scripts you can use a pretty nice groovy console, which is ultimately installed as a CQ package.

As an example, let's write a simple script that will gather DAM statistics (# of all assets in JCR repository, total DAM storage size, asset name, asset path, asset file size).

First, you need to install groovy console according to instructions from https://github.com/Citytechinc/cq-groovy-console

Once installed, navigate to http://localhost:4502/groovyconsole. You should see code area in the center of the screen, type the following code there:

import javax.jcr.query.*
import com.day.cq.dam.api.*
import javax.jcr.*
import org.apache.sling.api.resource.*

def query = createSQL2Query("/content/dam") // TODO start folder for search
def result = query.execute()
def rows = result.rows

totalSize = 0
rows.each { row ->
    Resource res = resourceResolver.getResource(row.path)
    Asset asset = res.adaptTo(Asset.class)
    fileSize = asset.getOriginal().getSize();
    totalSize += fileSize
//    println "Name=$asset.path; fileSize=$fileSize"
}
println "Total assets number: ${rows.size}; Total file size: ${formatFileSize(totalSize)}"


def createSQL2Query(startPage) {
    def queryManager = session.workspace.queryManager

    def statement = "select * from [nt:base] as p where (isdescendantnode (p, '$startPage')) and p.[jcr:primaryType] = 'dam:Asset'"

    def query = queryManager.createQuery(statement, Query.JCR_SQL2)

    query
}

// Convert a number of bytes to a more readable string
def formatFileSize(size) {
    labels = [ ' bytes', 'KB', 'MB', 'GB', 'TB' ]
    label = labels.find {
        if( size < 1024 ) {
            true
        } else {
            size /= 1024
            false
        }
    }
    "${new java.text.DecimalFormat('0.##').format( size )}$label"
}

After pressing the "Run Script" button you will see output below the console. You can, of course, substitute println to SLF4J methods, here it's just for brevity.



By aem4beginner

April 26, 2020
Estimated Post Reading Time ~

Groovy Script Console integration in AEM

Introduction
Groovy was developed by Jochen Theodorou, Guillaume Laforge, Cedric Champeau, and Paul King. Its typing discipline is strong, static and dynamic. It was licensed under the Apache 2.0 license. It first appeared in the year 2003. Its file extension is .groovy and was designed by James Strachan.

What is Groovy Script:

Apache Groovy is an Object-oriented programming language used for Java platform. It can be used as a scripting language for the Java platform.

Groovy vs Java

Groovy vs Java
Groovy
Java
Definition
It is compiled to JVM bytecode and is compatible with Java Platform.
It is developed on JDK and is run on JVM.
Usage
It is used when as both programming language and scripting language.
It is used as programming and object-oriented language.
Integration
It can be integrated along with any web applications and scripting applications.
It can also be integrated with any object-oriented application as it is compatible with any JVM based applications.
Platform
It supports any operating systems or platforms
It supports cross-platform operating systems
Syntax
The syntax is very similar to Java syntax.
It has a strong disciple in its syntax.
Community
It has been submitted to JCP for specification request.
It has a larger community called Java Community process i.es JCP being maintained by a large group of highly qualified technical experts across the industry.
License
It was licensed under Apache license 2.0
It was licensed under GNU General Public License.
Imports
All the packages will be imported by default.
It has to be mentioned clearly to import any package into the java class file.
Documentation
It provides single page documentation.
It has documentation in the form specification given by JCP.
Setup:
  1. Download the Groovy Console package. Check the version compatible with your AEM instance. For AEM 6.5 I am using 14.0.0 version.
  2. Install the downloaded package using the CRX package manager.
  3. To verify the installation, open http://localhost:4502/apps/groovyconsole.html in browser to view the groovy console.
Note: From 13.0.0 release, paths were changed from /etc/ to /apps/ to access Groovy Console

GUI Console:


Sample scripts are available in the Groovy Console.


Open any script and click on Run Script.



If you get an error when running scripts, add user group in Allowed Group property of "Groovy Console Configuration Service".


Sample Script:

getPage("/content/wknd-events").recurse { page ->
    def content = page.node

    if (content && !content.get("hideInNav")) {
        println page.path
    }
}

The above script will pull the pages which have property "hideInNav" as false from the Weekend Event site.


Reference:
https://github.com/icfnext/aem-groovy-console
https://www.educba.com/groovy-vs-java/


By aem4beginner