Tuesday, February 28, 2017

How to generate sitemap for multi site environments? - Adobe CQ5/AEM

How to generate sitemap for multi site environments? - Adobe CQ5/AEM

This post will explain how to generate the sitemap for different sites(home pages) in multi site environment of Adobe Experience Manager(AEM).

The sitemap will be generated dynamically whenever user access the sitemap URL for particular site.

Factory servlet to generate the sitemap.xml:

import java.io.IOException;
import java.util.*;

import javax.servlet.ServletException;
import javax.xml.stream.*;

import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.api.*;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.commons.Externalizer;
import com.day.cq.wcm.api.*;

@Component(metatype = true, label = "Site Map", description = "Site Map", configurationFactory = true)
@Service
@SuppressWarnings("serial")
@Properties({
@Property(name = "sling.servlet.resourceTypes", unbounded = PropertyUnbounded.ARRAY,
label = "Homepage Resource Type", description = "Sling Resource Type for Home Page component"),
@Property(name = "sling.servlet.selectors", value = "sitemap", propertyPrivate = true),
@Property(name = "sling.servlet.extensions", value = "xml", propertyPrivate = true),
@Property(name = "sling.servlet.methods", value = "GET", propertyPrivate = true),
@Property(name = "webconsole.configurationFactory.nameHint",
value = "Site Map on resource types: [{sling.servlet.resourceTypes}]") })
public final class SiteMapGeneratorServlet extends SlingSafeMethodsServlet {

private static final Logger LOG = LoggerFactory.getLogger(SiteMapGeneratorServlet.class);
private static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd");
private static final boolean INCLUDE_LAST_MODIFIED_DEFAULT_VALUE = false;

@Property(boolValue = INCLUDE_LAST_MODIFIED_DEFAULT_VALUE, label = "Include Last Modified Date",
description = "If checked, last modified value will be shown in sitemap.")
private static final String INCLUDE_LAST_MODIFIED_PROPERTY = "include.lastmod";

private static final String SITEMAP_NAMESPACE = "http://www.sitemaps.org/schemas/sitemap/0.9";

@Reference
private Externalizer externalizer;

private boolean incLastModified;

@Activate
protected void activate(Map<String, Object> properties) {
this.incLastModified = PropertiesUtil.toBoolean(properties.get(INCLUDE_LAST_MODIFIED_PROPERTY),
INCLUDE_LAST_MODIFIED_DEFAULT_VALUE);
}

@Override
protected void doGet(SlingHttpServletRequest slingRequest, SlingHttpServletResponse slingResponse)
throws ServletException, IOException {

slingResponse.setContentType(slingRequest.getResponseContentType());
ResourceResolver resourceResolver = slingRequest.getResourceResolver();
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page pageObj = pageManager.getContainingPage(slingRequest.getResource());

XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
try {
XMLStreamWriter stream = outputFactory.createXMLStreamWriter(slingResponse.getWriter());

stream.writeStartDocument("1.0");
stream.writeStartElement("", "urlset", SITEMAP_NAMESPACE);
stream.writeNamespace("", SITEMAP_NAMESPACE);

// Current page
writeXML(pageObj, stream, slingRequest);

for (Iterator<Page> children = pageObj.listChildren(new PageFilter(), true); children.hasNext();) {
Page childPage = (Page) children.next();
// If condition added to make sure the pages hidden in search in page properties do not show up in sitemap
if (null != childPage) {
if (!childPage.getProperties().containsKey("hideInSearch")
|| (childPage.getProperties().containsKey("hideInSearch")
&& childPage.getProperties().get("hideInSearch").equals("false"))
|| (childPage.getProperties().containsKey("hideInSearch")
&& childPage.getProperties().get("hideInSearch").equals("")))
writeXML(childPage, stream, slingRequest);
}
}

stream.writeEndElement();
stream.writeEndDocument();

} catch (XMLStreamException e) {
throw new IOException(e);
}
}

private void writeXML(Page pageObj, XMLStreamWriter xmlStream, SlingHttpServletRequest slingRequest)
throws XMLStreamException {
xmlStream.writeStartElement(SITEMAP_NAMESPACE, "url");

String protocolPort = "http";
if (slingRequest.isSecure())
protocolPort = "https";

String locPath = this.externalizer.absoluteLink(slingRequest, protocolPort,
String.format("%s.html", pageObj.getPath()));

writeXMLElement(xmlStream, "loc", locPath);

if (this.incLastModified) {
Calendar calendarObj = pageObj.getLastModified();
if (null != calendarObj) {
writeXMLElement(xmlStream, "lastmod", DATE_FORMAT.format(calendarObj));
}
}
xmlStream.writeEndElement();
}

private void writeXMLElement(final XMLStreamWriter xmlStream, final String elementName, final String xmlText)
throws XMLStreamException {
xmlStream.writeStartElement(SITEMAP_NAMESPACE, elementName);
xmlStream.writeCharacters(xmlText);
xmlStream.writeEndElement();
}

}

Create new servlet configuration from the factory through OSGI console by providing the following details

Home Page Resouce Type - add the Home page resource types that should be considered for generating sitemap.xml

Include Last Modified Date - If selected the last modified date of the page will be included as part of the sitemap.xml



Tuesday, February 21, 2017

How to exclude the replication agent from manual replication actions - Adobe CQ5/AEM?

How to exclude the replication agent from manual replication actions - Adobe CQ5/AEM?

Exclude the replication agent from manual replication actions in Adobe Experience Manager(AEM)- Sometimes we may required to exclude the specific replication agents from manual action but only the actions through workflow or API.

Enable "Ignore Default" in Triggers tab of Agent configuration wizard.


Sunday, February 19, 2017

How to display the dynamic popup in a page through GTM?

How to display the dynamic popup in a page through GTM?

This post will explain how to display the dynamic popup in a page through GTM.

The assumption is the required JQuery scripts are included as part of the page.

Define the cookie type variable:

This will help us to display the popup for every new browser session(this step is not required if the popup should displayed every time visiting the page)
  • Click on Variable in left hand side menu.
  • Go to user defined variables and select new.
  • Select variable configuration as 1st party cookie 
  • Give cookie name as popUpDisplayed and check url decode cookie option.
  • Save the changes and give the name as popUpDisplayed.


Monday, February 6, 2017

How to monitor the Replication Queues through Java - Adobe CQ5/AEM

Monitoring the Replication Queues through Java - Adobe CQ5/AEM

This post will explain the approach to monitor the Replication Queues of Adobe Experience Manager(AEM) through java

Enable the Remote JMX in the AEM server:

Add the following configurations as part of CQ_JVM_OPTS in AEM startup file (start.sh or start.bat)

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=50055

e.g.

CQ_JVM_OPTS='-server -Xmx6144m -XX:MaxPermSize=512M -Djava.awt.headless=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=50055'

Restart the server.

Configuration.txt:

ServerHost=xxxxxxxxxxx
ServerPort=50055
QueueNames=publish,publish_Dev
Environment=Development
EmailHost=xxxxxx
Email_To=xxxxxx
Email_From=xxxxxxx
QueueThreshold=15

GetReplicationQueueStatus.java

import java.io.*;
import java.util.*;
import javax.management.*;
import javax.management.remote.*;
import javax.mail.*;
import javax.mail.internet.*;

public class GetReplicationQueueStatus {
static JMXConnector m_connector=null;
public static void main(String[] args) {
FileInputStream in=null;
try
{
Properties configuration = new Properties();
in= new FileInputStream("Configuration.txt");
configuration.load(in);
String serverHost=configuration.getProperty("ServerHost");
String serverUrl = "service:jmx:rmi:///jndi/rmi://"+serverHost+":"+configuration.getProperty("ServerPort")+"/jmxrmi";
JMXServiceURL serviceURL = new JMXServiceURL(serverUrl);
m_connector =JMXConnectorFactory.newJMXConnector(serviceURL,null);
m_connector.connect();
MBeanServerConnection m_connection = m_connector.getMBeanServerConnection();
Set<ObjectName> queryResult =m_connection.queryNames(new ObjectName("com.adobe.granite.replication:type=agent,*"),null);
String queueNames=configuration.getProperty("QueueNames");
List<String> queueNameList = Arrays.asList(queueNames.split(","));
for(ObjectName objectName : queryResult) {
if(queueNameList.contains(objectName.getKeyProperty("id").replaceAll("\"", "")))
{
String  attrNames[] = 
                   { "Enabled",
                     "QueueNumEntries",
                     "QueueBlocked",
                     "QueuePaused"                      
                   };
AttributeList  attrList = m_connection.getAttributes(objectName, attrNames);                
           String isEnabled= ((Object) attrList.get(0)).toString().split("=")[1];
           String queueNumEntries= ((Object) attrList.get(1)).toString().split("=")[1];
           String isQueueBlocked= ((Object) attrList.get(2)).toString().split("=")[1];
           String isQueuePaused= ((Object) attrList.get(3)).toString().split("=")[1];
           System.out.println( "Values: " +isEnabled+" "+ queueNumEntries+" "+isQueueBlocked+" "+ isQueuePaused);
           String to=configuration.getProperty("Email_To");
           String from=configuration.getProperty("Email_From");
           String emailHost=configuration.getProperty("EmailHost");
           String queueThreshold=configuration.getProperty("QueueThreshold");
           String environment=configuration.getProperty("Environment");
           if(!isEnabled.trim().equals("true"))
           {
            String subject=environment+": Replication Queue "+"\""+objectName.getKeyProperty("id").replaceAll("\"", "")+"\""+" is Disabled";
            sendEmail(to,from, subject,subject+"\n"+"Server: "+serverHost,  emailHost);
           }else if(isQueueBlocked.trim().equals("true"))
           {
            String subject=environment+": Replication Queue "+"\""+objectName.getKeyProperty("id").replaceAll("\"", "")+"\""+" is Blocked";
            sendEmail(to,from, subject,subject+"\n"+"Server: "+serverHost,  emailHost);
           }else if(isQueuePaused.trim().equals("true"))
           {
            String subject=environment+": Replication Queue "+"\""+objectName.getKeyProperty("id").replaceAll("\"", "")+"\""+" is Paused";
            sendEmail(to,from, subject,subject+"\n"+"Server: "+serverHost,  emailHost);
           }else if(Integer.parseInt(queueNumEntries.trim())>Integer.parseInt(queueThreshold.trim()))
           {
            String subject=environment+": Replication Queue "+"\""+objectName.getKeyProperty("id").replaceAll("\"", "")+"\""+" is Queued with "+queueNumEntries+" Requests";
            sendEmail(to,from, subject,subject+"\n"+"Server: "+serverHost,  emailHost);
           }
               
}
                
}
}catch(Exception e)
{
e.printStackTrace();
}finally {
try {
if(m_connector!=null)
{
m_connector.close();
}
if(in!=null)
{
in.close();
}
}catch(Exception e)
{
}
}
}
static void sendEmail(String to,String from,String subject,String body,String host)
{
 Properties properties = System.getProperties();
     properties.setProperty("mail.smtp.host", host);
     Session session = Session.getDefaultInstance(properties);

     try {
          MimeMessage message = new MimeMessage(session);
        message.setFrom(new InternetAddress(from));
           message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
           message.setSubject(subject);         
           message.setText("Hi Team\n\n"+body+"\n\n"+"Regards\nAdmin");
           Transport.send(message);
           System.out.println("Email send successfully...");

     }catch (MessagingException mex) {
        mex.printStackTrace();
     }
}

}

Configure the data in Configuration.txt file accordingly.
Email will be triggered whenever the configured Queue is disabled, blocked, paused or the pending request is more than the configured threshold.

Executable jar file can be generated for the java class and scheduled for continuous monitoring.