Skip to content

Implement Custom CQ Rollout Action

A LiveAction is an action that is executed on each resource that is involved in the rollout. A rollout is an operation that copies the contents from blueprint to its livecopies.

CQ supplies out of the box rollout configs live contentUpdate, contentCopy, contentDelete, referencesUpdate, orderChildren, markLiveRelationship etc.

Create the Example Rollout Configuration and edit rollout config

Create the MSM rollout configuration that uses the LiveAction that you are going to create.

  1. In your web browser, open the Tools console. (http://localhost:4502/miscadmin#/etc)
  2. Select the Tools/MSM/Rollout Configurations folder and click New > New Page and provide values for the Rollout Configuration properties:
  • Title: Example Rollout Configuration
  • Name: examplerolloutconfig
  • Select RolloutConfig Template.
Click Create.
Then

  1. Open the rollout configuration that is created and then click Edit.
  2. In the Rollout Config dialog, use the Sync-Trigger drop-down menu to select On Activation, and then click OK.

Add the custom Live Action(exampleLiveAction) to the Example Rollout Configuration

Configure the rollout configuration that you created in the previous procedure so that it uses the ExampleLiveActionFactory class.

  • Open CRXDE Lite. (http://localhost:4502/crx/de)

  • Select the jcr:content node below the /etc/msm/rolloutconfigs/examplerolloutconfig/jcr:content node.

  • Click Create > Create Node, configure the following node properties and click OK:

    • Name: exampleLiveAction
    • Type: cq:LiveSyncAction
    file
  • Click Save All.

  • Select the exampleLiveAction node and add the following property:

    • Name: repLastModBy
    • Type: Boolean
    • Value: true

    This property indicates to the ExampleLiveAction class that the cq:LastModifiedBy property should be replicated from the source to the target node.

  • Click Save All.

Create Example live action that implements the custom live action.


package com.aaa.cq.rollout.actions;

import ...;

@Component(label = "Custom MSM Live Action", description = "Custom MSM Live Action", immediate = true, metatype = false, enabled = true)
@Properties({
 @Property(label = "Vendor", name = Constants.SERVICE_VENDOR, value = "Vendor", propertyPrivate = true),
 @Property(label = "Name", value = "exampleLiveAction", description = "Custom Live Action", name = "cq.wcm.msm.action.name", propertyPrivate = true),
 @Property(label = "parameter", value = "msm:exampleLiveAction", description = "Parameter", name = "cq.wcm.msm.action.parameter", propertyPrivate = true),
 @Property(label = "Title", value = "Custom MSM Live Action", description = "Custom MSM Live Action", name = "cq.wcm.msm.action.title", propertyPrivate = true),
 @Property(label = "Rank", intValue = 10, name = "cq.wcm.msm.action.rank", description = "Custom LiveAction Rank"),
 @Property(label = "Properties", value = { "enabled" }, cardinality = Integer.MAX_VALUE, name = "cq.wcm.msm.action.properties", description = "Custom LiveAction Properties") })
@Service
@lombok.Data
public class CustomLiveActionImpl implements LiveAction, CustomLiveAction {
 private int rank;
 private String name;
 private String title;
 private String[] parameterNames;
 private Dictionary<String, Object> prop;

 @Override
 public void execute(Resource resource, Resource resource2, LiveRelationship liveRelationship,
 boolean b, boolean b2)
 throws WCMException {
 }

 @Override
 public void execute(ResourceResolver resolver, LiveRelationship relation, ActionConfig config,
 boolean autoSave) throws WCMException {
 //execute(resolver, relation, config, autoSave, false);
 }

 @Override
 public void execute(ResourceResolver resolver, LiveRelationship relation,ActionConfig config,
 boolean autoSave, boolean isResetRollout)
 throws WCMException {
 customLiveActionImplementation();
 }

 @Override
 public void customLiveActionImplementation() {
 // custom live action implementation
 }

 @Override
 public String getParameterName() {
 return ACTION_PARAMETER;
 }

 @Override
 public void write(JSONWriter jsonWriter) throws JSONException {
 jsonWriter.object();
 jsonWriter.key("name").value(getName());
 jsonWriter.key("parameter").value(ACTION_PARAMETER);
 jsonWriter.key("title").value(getTitle());
 jsonWriter.key("rank").value(getRank());
 jsonWriter.key("properites");
 jsonWriter.array();
 for (String prop : getPropertiesNames()) {
 jsonWriter.value(prop);
 }
 jsonWriter.endArray();
 jsonWriter.endObject();
 }

 public String[] getPropertiesNames() {
 return parameterNames;
 }

 /**
 * OSGi Component Methods
 */
 @Activate
 @Modified
 protected void activate(ComponentContext context) {
 Dictionary<String, Object> properties = context.getProperties();
 name = PropertiesUtil.toString(
 properties.get("cq.wcm.msm.action.name"), "exampleLiveAction");
 title = PropertiesUtil.toString(
 properties.get("cq.wcm.msm.action.title"), "Custom Live Action");
 rank = PropertiesUtil.toInteger(
 properties.get("cq.wcm.msm.action.rank"), Integer.MAX_VALUE);
 parameterNames = PropertiesUtil.toStringArray(
 properties.get("cq.wcm.msm.action.properties"), new String[0]);
 }

 @Deactivate
 protected void deactivate(ComponentContext context) {
 log.info("Deactivating Custom rollout action.");
 }

 private final static String ACTION_PARAMETER = "msm:exampleLiveAction";
}

public interface CustomLiveAction {
void customLiveActionImplementation();
}

CURL it out – Adobe CQ5 Curl Commands and Usage

Run JCR query builder API:

Find “all” page references for a given image/asset in a jcr path. The below command will return in JSON format:
curl -s -u ${username}:${password} -X GET http://localhost:4502/bin/querybuilder.json?path=/content/my-site&1_property=fileReference&1_property.value=/content/dam/my-site/image.jpg&p.limit=-1
*Note: -1 in the p.limit will return all page references else prints only 10.

You can also specify the required number of page references; something like below which will return only 20 page references:
curl -s -u ${username}:${password} -X GET http://localhost:4502/bin/querybuilder.json?path=/content/my-site&1_property=fileReference&1_property.value=/content/dam/my-site/image.jpg&p.limit=20

To find all pending Jobs
curl -s -u admin:admin “http://localhost:4502/bin/querybuilder.json?&path=/var/eventing/jobs&type=slingevent:Job&p.limit=-1&fulltext=/com/day/cq/replication/job&fulltext.relPath=@slingevent:topic&property.and=true&property=slingevent:finished&property.operation=not&orderby=slingevent:created&orderby.sort=asc&#8221;

To find all Blocking Jobs
curl -s -u admin:admin “http://localhost:4502/bin/querybuilder.json?path=/var/eventing/jobs/anon&type=slingevent:Job&rangeproperty.property=event.job.retrycount&rangeproperty.lowerBound=1&#8243;

CQ Package Manager Commands:
Uninstall a bundle (use http://localhost:4502/system/console/bundles to access the Apache Felix web console)
curl -u admin:admin -daction=uninstall http://localhost:4505/system/console/bundles/”name-of-bundle&#8221;
Upload a package AND install
curl -u admin:admin -F file=@”name of zip file” -F name=”name of package” -F force=true -F install=true http://localhost:4502/crx/packmgr/service.jsp
Upload a package DO NOT install
curl -u admin:admin -F file=@”name of zip file” -F name=”name of package” -F force=true -F install=false http://localhost:4502/crx/packmgr/service.jsp
Rebuild an existing package in CQ
curl -u admin:admin -X POST http://localhost:4502:/crx/packmgr/service/.json/etc/packages/name_of_package.zip?cmd=build

Download a package:
curl -u admin:admin http://localhost:4502/etc/packages/export/name_of_package.zip > name of local package file
Upload a package
curl -u admin:admin -F package=@”name_of_package.zip” http://localhost:4502/crx/packmgr/service/.json/?cmd=upload
Install a package
curl -u admin:admin -X POST http://localhost:4502/crx/packmgr/service/.json/etc/packages/export/name of package?cmd=install

List contents of a package
$ curl -u admin:admin -X POST http://localhost:4502/crx/packmgr/service/console.html/etc/packages/day/cq561/product/cq-content-5.6.1.20130606.zip?cmd=contents

 
CQ Bundle Manager Commands:
Install a bundle
curl -u admin:admin -F action=install -F bundlestartlevel=20 -F bundlefile=@”name of jar.jar” http://localhost:4502/system/console/bundles
Build a bundle
curl -u admin:admin -F bundleHome=/apps/ projects-A/bundles/name of bundle -F descriptor=/apps/projects-A/bundles/com.centrica.cq.wcm.core-bundle/name_of_bundle.bnd http://localhost:4502/libs/crxde/build
Stop a bundle
curl -u admin:admin http://localhost:4502/system/console/bundles/org.apache.sling.scripting.jsp -Faction=stop
Start a bundle
curl -u admin:admin http://localhost:4502/system/console/bundles/org.apache.sling.scripting.jsp -Faction=start
JCR Node Management:
Delete a node (hierarchy) – (this will delete any directory / node / site)
curl -X DELETE http://localhost:4502/path/to/node/jcr:content/nodeName -u admin:admin

Create or add a JCR node:
curl -u admin:admin -F”_charset_=utf-8″ -F”:nameHint=node” -F”jcr:primaryType=nt:unstructured” -F”sling:resourceType=project-A/components/abc-definition” -F”nodeReferenceName=ref-name1″ -F”jcr:createdBy=bala” -F”jcr:lastModifiedBy=bala” http://localhost:4502/content/geometrixx/en_GB/products/jcr:content/abc/

Create or add a JCR node along with some properties:
curl -u admin:admin -F”_charset_=utf-8″ -F”:nameHint=var” -F”jcr:primaryType=nt:unstructured” -F”key=key1″ -F”value=key1-value” http://localhost:4502/content/geometrixx/en_GB/products/jcr:content/abc/variables/

CQ Replication Commands:
Tree Activation
curl -u admin:admin -F cmd=activate -F ignoredeactivated=true -F onlymodified=true -F path=/content/geometrixx http://localhost:4502/etc/replication/treeactivation.html

User & Group Administration
Get User Info:
curl -u admin:admin http://localhost:4502/libs/granite/security/balakondepudi.json

Create User:
curl -u admin:admin -FcreateUser= -FauthorizableId=testuser -Frep:password=abc123 http://localhost:4502/libs/granite/security/post/authorizables

Create Group:
curl -u admin:admin -FcreateGroup=group1 -FauthorizableId=testGroup1 http://localhost:4502/libs/granite/security/post/authorizables

Create user with Profile:
curl -u admin:admin -FcreateUser=testuser -FauthorizableId=testuser -Frep:password=abc123 -Fprofile/gender=male http://localhost:4502/libs/granite/security/post/authorizables

Set a Profile Property on an Existing User:
curl -u admin:admin -Fprofile/age=29 http://localhost:4502/home/users/t/testuser1.rw.html

Create a User as a Member of a Group:
curl -u admin:admin -FcreateUser=testuser -FauthorizableId=testuser -Frep:password=abc123 -Fmembership=contributor http://localhost:4502/libs/granite/security/post/authorizables

Add a User to a Group:
curl -u admin:admin -FaddMembers=testuser1 http://localhost:4502/home/groups/t/testGroup.rw.html

Remove a User from a Group:
curl -u admin:admin -FremoveMembers=testuser1 http://localhost:4502/home/groups/t/testGroup.rw.html

Set a User’s Group Memberships:
curl -u admin:admin -Fmembership=contributor -Fmembership=testgroup http://localhost:4502/home/users/t/testuser.rw.html

Delete user and Group:
curl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/users/t/testuser
curl -u admin:admin -FdeleteAuthorizable= http://localhost:4502/home/groups/t/testGroup

Change an user password:
curl -u testuser:OLD_PWD -F rep:password=”NEW_PWD” http://localhost:4502/home/users/t/testuser.rw.html
curl rep:password=”test” –user admin:admin http://localhost:4502/home/users/a/alister@geometrixx.com

Backup Commands:
Online Backup:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/startBackup/java.lang.String?target=<PATH-TO-BACKUP>/12-feb-2013.zip

Online backup with delay in milli seconds:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/a/BackupDelay?value=<TIME-IN-MILISECOND&gt;
curl -u admin:admin –data “delay=TIME-IN-MILISECONDS&force=false&target=01-dec-2012.zip” http://localhost:4502/libs/granite/backup/content/admin/backups/

How to stop a running online backup:
curl -u admin:admin http://localhost:4502/libs/granite/backup/content/admin/backups.cancel.html

Link to track online progress:

http://localhost:4502/libs/granite/backup/content/admin.html

Datastore GC:
For Datastore Garbage Collection:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/runDataStoreGarbageCollection/java.lang.Boolean

Tar Optimization:
curl -u admin:admin -X POST http://localhost:4502/system/console/jmx/com.adobe.granite:type=Repository/op/startTarOptimization/

Flush Dispatcher Cache:
curl -H “CQ-Action: Flush” -H “CQ-Handle: /content/geometrixx/en/products” -H “CQ-Path:/content/geometrixx/en/products” -H “Content-Length: 0″ -H “Content-Type: application/octet-stream” http://dispatcher-server-hostname:port/dispatcher/invalidate.cache

How to set a unique and strong password for a site

It is becoming a challenge to set different/unique password for each of the websites for login purposes. Some times we end up having same password for most of the login accounts like an   email(gmail/yahoo/hotmail), office logins, bank logins, linked etc etc.

I found an interesting way of solving this issue:

{special-charater(s)}{Upper-Case-Letter(s)}{Login-site-Name}{Numeric-number-sequence}

example password for linked-in: $%Sundaylinkedin1245

example password for gmail: $%Sundaygmail1245

example password for a bank login: $%Sundaymybank1245

So in above examples though the password is unique it is but easy to remember as the text marked in bold is different (based on login site) and rest of the character will remain same.

Also it satisfies the condition of having a special-character, alpha-numeric, upper case; and most importantly it is unique for a given site.

Develop a custom CQ selector

An important feature of CQ5 is the ability to natively use as many selectors as you want in a URL.
This means the following URLs will work:

http://www.adobe.com/products/flash/tech-specs.selectors.are.real.fun.html

http://www.day.com/day/en/products.adobe.cq5.is.fun.html

Following code helps to create a custom selectors which return an image layer instance to the incoming request.

@Component(immediate = true, metatype = false)
@Service(value = javax.servlet.Servlet.class)
@Properties({@Property(name = Constants.SERVICE_DESCRIPTION, value = "Custom Image Selector"),
 @Property(name = Constants.SERVICE_VENDOR, value = OsgiServiceProperties.SERVICE_VENDOR),
 @Property(name = "sling.servlet.resourceTypes",
 value = {"foundation/components/parbase", "cq:Page", "myproject/components/custom-rich-content" }),
 @Property(name = "sling.servlet.selectors", value = {"invokeSelector1", "invokeSelector2" }),
 @Property(name = "sling.servlet.extensions", value = {"jpg", "jpeg", "png", "gif", "bmp" }) })
public class CustomImageSelector extends AbstractImageServlet {
@Override
 protected Layer createLayer(ImageContext ctx) throws RepositoryException {
 // this will returns the custom image layer object to the incoming request
 // A sample implementation of a custom image selector can be found at /libs/foundation/components/page/navimage_png.java in CQ5
 //
 String selectors = ctx.request.getRequestPathInfo().getSelectorString();
 Layer layer = null;
 if (selectors.contains("invokeSelector1")) {
 } else {
 }
 .....
 ....
 .
}

The property "sling.servlet.resourceTypes" defines the incoming resource types of the sling servlet request. It can be CQ and custom resource types like "cq:Page", "cq:Component" etc.

The property "sling.servlet.selectors" defines the name of the selectors that are defined on this servlet. And the request selectors can be retrieved in the code for processing them individually.

The property "sling.servlet.extensions" defines the extensions that are supported on this selector.

So the image request URL for this selector can be as follows:

The above URL can be resolved as follows:


HOST: final-website.com

Displaying Page location: /content/site-1/en_GB/homePageImage

Selectors used in the above URL: invokeSelector1, helloworld, 1350657093639

Selector extension: png

Finally the developed image selector can be used for following URLs:














http://final-website.com/content/site-1/en_GB/homePageImage.invokeSelector1.poloworld.135065709323263339.bmp

But cannot be used in following URLs:


http://final-website.com/content/site-1/en_GB/homePageImage.invokeSelector1.helloworld.13506570283793639.php


http://final-website.com/content/site-1/en_GB/homePageImage.invokeSelector2.blueworld.1350657093620239.aspx


http://final-website.com/content/site-1/en_GB/homePageImage.invokeSelector1.myworld.135065703093639.pdf


http://final-website.com/content/site-1/en_GB/homePageImage.invokeSelector1.ukworld.135065703093639.<b>htm</b>

As the above URLs selectors extensions do not match with the desired/expected extensions.

 

Import JSTL Custom tags to Adobe CQ5

Steps to add JSTL 2.0 custom tags to Adobe CQ5:

1. Create custom tag

Create your own custom tag at location say /apps/myproject/taglibs/foo.tag and the contents of the tag are as below:

<%@ attribute name="greeting" required="true" %>
<%@ attribute name="name" required="true" %>
<h1>Im a custom taglib [${greeting}, ${name}]</h1>

2. Use tags in a html or jsp page:
To use Custom Tag Lib Files within CQ5 and you can just add a tag file somewhere on the JCR and reference it via

<%@ taglib tagdir="/WEB-INF/tags/apps/myproject/taglibs" prefix="ctags" %>
<ctags:foo greeting="Hello" name="CQ User"/>

Note that the "/WEB-INF/tags/" need to be prefixed the path where the tag libs exist.

3. Add below code to the maven-assembly plugin

<assembly> 
....
<filesets>
  <fileSet>
    <directory>src/main/content/jcr_root</directory>
    <outputDirectory>jsp-dependencies/jcr_root/WEB-INF/tags</outputDirectory>
    <includes>
    <include>**/*.tag</include>
    </includes>
  </fileSet>
 </filesets>
  ....
</assembly> 

The output directory filter need to be created for the tag as the custom tags need to be copied from /apps/myproject/taglibs to WEB-INF/tags/apps/myproject/taglibs.

Customize buttons on Day CQ pages

It is rather simple to customize buttons on http://cq-instance/siteadmin or http://cq-instance/damadmin etc pages for an individual user or a group. Customizing includes removal/addition of buttons on the said pages. This can be achieved by manipulating the CQ5 Access Control Lists(ACLs) for user/group.
Say group-A doesn’t require activate, deactivate and workflow buttons on siteadmin/damadmin pages. To achieve this follow these steps:
1. Traverse to http://cq-instance/useradmin url
2. Select group-A from left side menu
3. Click on “Permissions” tab on the right side.
4. Traverse to /libs/wcm/core/content/siteadmin/actions/
5. Then uncheck the checkboxes(Read/Modify/Create etc) for each of activate, deactivate and workflow nodes.
6. Save the changes for the group-A.

The above steps can be repeated for disabling buttons for damadmin or welcome page or tools pages etc.

Reset forgot admin password in Day/Adobe CQ5.4

The below text is directly taken from dev.day.com web site:
System administration ‘admin’ account is the member of the administrator group, with full access rights.
This account is used for the connection between CQ WCM and CRX.
As such its configuration cannot be edited – with the exception of the password.

The forgot or lost admin password can be restored to default in /crx-quickstart/server/etc/server.xml file. Replacing below lines will help to change password back to admin.
<admin>
<crypt>adpexzg3FUZAk</crypt>
</admin>

* adpexzg3FUZAk is equivalent crypt text of admin password.

Note: This is applicable to only CQ 5.4 and older versions; as the directory structure seems to be changed in CQ 5.5.

Follow

Get every new post delivered to your Inbox.