Blueprint is an important feature for all those sites which need to deals with multiple locale and region-specific sites. Consider that we have 20 different regional sites and each regional site has 2 locales (English and regional language). Now let’s say you need to do a small update on an English locale page and that changes are required on all sites, there will be 20 pages that you’ll need to visit and make changes one by one (if you have not used blueprint and live copy).
With blueprint we can create a master copy (which is called as a blueprint) and create many live copies (which are actual sites) and the benefit you get is that as soon as you do any change in blueprint that same change will be propagated to all live copies pages when changes are rolled out by authors…this is cool. With blueprint you’ll need to apply changes only to English locale page on blueprint and all English locale pages (live copies) will receive that change implicitly.
So, how this whole thing works? Whenever a blueprint is created we need to define rollout configurations. Rollout configurations tell what to do when a blueprint page is updated. A rollout configuration consists of A Trigger and Single/Multiple Actions:
1) Trigger: this is a string value (either of “rollout”, “modification”, “publish” etc.) which tells when to trigger (rollout) a particular action on the blueprint.
2) Action (cq: LiveSycnAction): this is actual action performed on blueprint. Action can be content update, content copy, content delete, references update, order children, etc.
AEM provides default triggers and actions that you can combine to suffice your need. Sometimes you may want to perform a custom action (e.g. send an email to author when a blueprint page is updated). In this article we are going to see how to develop custom LiveSyncAction. If you want to understand blueprint, live copy and MSM completely then please go through the links mentioned in the reference section of this article.
As you can see in the above diagram, a rollout configuration is a combination of trigger and multiple (or single) actions. Each node in the above diagram represents an action, and “jcr:primaryType” of these action nodes is “cq:LiveSyncAction”.
To create a custom LiveSyncAction we need to understand the following classes:
1) com.day.cq.wcm.msm.api.LiveActionFactory and com.day.cq.wcm.msm.api.LiveAction
a. LiveActionFactory: An Factory used to create LiveActions. Used to register LiveAction implementations with the ServiceComponentRegistration (in Felix Console) It enables to create LiveActions with a Configuration given by a Resource.
b. LiveAction: Represent an Action to be performed upon a Roll-out from a Source to a Target. Actions are created by a LiveActionFactory that provide instances of LiveActions set-up with given configuration. LiveActions are called during the process of roll-out which on acts on Resources A LiveAction must, therefore, act within the boundary of the given Resource
2) com.day.cq.wcm.msm.impl.actions.BaseActionFactory and com.day.cq.wcm.msm.commons. BaseAction
a. BaseActionFactory: Base implementation of a LiveActionFactory service. We do have other action factory class that provides fileting options. FilteredActionFactoryBase is a BaseActionFactory extension that provides basic support to set-up filtering configuration.
b. BaseAction: Base implementation for the LiveAction interface. This abstract class offers some basic configuration tasks for building a LiveAction and also default implementations for the deprecated methods. It will speed up the implementation of a LiveAction by only implementing the handles and doExecute abstract methods.
To create a custom LiveAction we need to create a factory by extending the “BaseActionFactory” class and implement actual action by extending the “BaseAction” class and fill login in doExecute() method. All live actions in AEM are registered with the OSGi/Felix console.
Here is a sample class that implements a custom LiveAction to send emails (ignore-errors shown below as I don't have dependencies in my maven repo).
@Component(metatype = false)
@Service
public class SendMailAuthenticationFactory extends BaseActionFactory < BaseAction > {
protected static final Logger log = LoggerFactory.getLogger(SendMailActionFactory.class);
@Reference
private MessageGatewayService messageGatewayService;
@Reference
private RolloutManager rolloutManager;
@Reference
private Replicator replicator;
private static final String LIVE_ACTION_NAME[] {
SendMailActionFactory.class.getSimpleName(), "sendMailAction"
};
public SendMailActionFactory() {}
public String createsAction() {
return LIVE_ACTION_NAME[0];
}
protected SendMailAction newActionInstance(ValueMap config) throws WCMException {
return new SendMailAction(config, this, messageGatewayService);
}
protected void bindReplicator(Replicator replicator1) {
replicator = replicator1;
}
protected void unbindReplicator(Replicator replicator1) {
if (replicator == replicator1) replicator = null;
}
protected void bindRolloutManager(RolloutManager rolloutManager) {
rolloutManager = rolloutManager;
}
protected void unbindRolloutManager(RolloutManager rolloutManager) {
if (rolloutManager == rolloutManager) rolloutManager = null;
}
private static final class SendMailAction extends BaseAction {
private MessageGatewayService messageGatewayService;
private SendMailAction(ValueMap config, BaseActionFactory < BaseAction > factory, MessageGatewayService) {
super(config, factory);
this.messageGatewayService = messageGatewayService;
}
/** Method to check whether this live action class should proceed with execution of defined action in doExecute() or not? */
protected boolean handles(Resource source, Resource target, LiveRelationShip relation, boolean resetRollout) throws WCMException, RepositoryException {
return target != null && relation.getStatus().isPage();
}
/** Action to be performed by this action class go into this method body */
protected void doExecute(Resource source, Resource target, LiveRelationShip relation, boolean resetRollout) throws RepositoryException, WCMException {
return target != null && relation.getStatus().isPage();
try {
//Prepare your "email" content here (code has been omited for this article).
this.messageGatewayService.getGateWay(HtmlEmail.class).send(email);
} catch (Exception e) {
log.error("Error While Sending Mail", e));
}
}
}
}
Once a live-action has been created and the corresponding OSGi bundle has been installed in OSGi/Felix container go to Felix console and open the OSGi-> Services tab and verify that “SendMailActionFactory” has been registered similar to figure 2 above. If the action factory has been registered then we are good to use newly create live actions.
How to use newly created custom live action:
1) Go Tools (http://localhost:4502/miscadmin#/etc/msm/rolloutconfigs)
2) From the right-hand side menu select [New… -> New Page…] enter title and name (e.g. test and test for both)
3) Go to CRXDELite and open navigate to /etc/msm/rolloutconfigs
4) You should see a page/node (test) for newly create a page in step# 2
5) Under the “test” node navigate to “jcr:content” node (/etc/msm/rolloutconfigs/test/jcr:content)
6) Create a new node with the name “sendMailAction” of type “cq:LiveSyncAction” and click “Save All…”.
Note that node name (i.e. “sendMailAction”) should match with the “LIVE_ACTION_NAME” static final variable defined in SendMailActionFactory class because we have registered our custom action in AEM container with that name.
7) We have created a rollout configuration and it is ready for use. Now when you go to the “Blueprint” tab on page properties, you should get a new rollout config option.
References:
http://docs.adobe.com/docs/en/cq/current/administering/multi_site_manager.html
http://docs.adobe.com/docs/en/cq/current/developing/multi_site_manager_dev.html#par_title
Source: http://suryakand-shinde.blogspot.com/2015/01/custom-synchronisation-or-rollout.html
No comments:
Post a Comment
If you have any doubts or questions, please let us know.