Sunday, November 5, 2017

java.lang.ClassCastException for the same class com.sample.test.Test cannot be cast to com.sample.test.Test - Adobe Experience Manager(AEM)

java.lang.ClassCastException for the same class com.sample.test.Test cannot be cast to com.sample.test.Test - Adobe Experience Manager(AEM)

We were facing a strange ClassCastException - ClassCastException pointing to the same class in Adobe Experience Manager(AEM)

java.lang.ClassCastException: com.sample.test.Test cannot be cast to com.sample.test.Test

While analyzing through depfinder - http://localhost:4502/system/console/depfinder, there is two version of the same class available from two different packages.

But this class is only defined in one of the package and referred in the other package, after analyzing the Sling class loading is little different - If one of the class com.sample.test.Test is referred from different package, Sling copies the classes locally to the target package and if the target package export the same package(<Export-Package>) -  com.sample.* then Sling export the classes copied from other package that matches the export pattern, in this case our target package is already exporting com.sample.* so two version of same class is available now. This will lead to the ClassCastException specified above.

To fix this issue, we can change the target package pom.xml file to restrict the export of referred classes from other package.

<Export-Package>com.sample.*,!com.sample.test</Export-Package>

Please make sure the restricted package - !com.sample.test is kept after the wider package - com.sample.*

Now only one version of the class from source package is available for reference.


Monday, May 8, 2017

Issue while integrating Adobe Experience Manager(AEM) with Dynamic Tag Management(DTM) through HTTP Proxy

Issue while integrating Adobe Experience Manager(AEM) with Dynamic Tag Management(DTM) through HTTP Proxy

The below exception is thrown while integrating Adobe Experience Manager(AEM) with Dynamic Tag Management(DTM)


08.05.2017 14:06:35.894 *ERROR* [10.208.56.253 [1494270332788] POST /etc/cloudservices/dynamictagmanagement/test/jcr:content.companies.json HTTP/1.1] com.adobe.cq.dtm.impl.util.DTMConfigurationUtil Failed to obtain a response from the DTM API Server.
org.apache.http.conn.ConnectTimeoutException: Connect to api.omniture.com:443 [api.omniture.com/192.243.232.77] failed: Connection timed out
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:138)
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
        at com.adobe.cq.dtm.impl.util.DTMConfigurationUtil.callDTMApi(DTMConfigurationUtil.java:210)
        at com.adobe.cq.dtm.impl.servlets.DTMCompaniesServlet.doPost(DTMCompaniesServlet.java:58)

Caused by: java.net.ConnectException: Connection timed out
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:579)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:239)
        at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:123)
        ... 138 common frames omitted

Based on the analysis the Dynamic Tag Management(DTM) cloud connector is not using the the proxy server details configured to establish the connection.
This is the defect with the connector, raise a ticket with Adobe support team to  receive the fix.

As a temporary fix update DTMConfigurationUtil.java in bundle - /libs/cq/cloudservices/install/cq-dtm-0.1.8.jar to support proxy server while establishing the connectivity.

DTMConfigurationUtil.java - callDTMApi

 HttpHost proxy = new HttpHost("proxy.com",80);
 RequestConfig config = RequestConfig.custom().setProxy(proxy).build();   
 apiRequest.setConfig(config);

Refer the following post for updating the java class in a bundle - https://www.albinsblog.com/2017/04/updating-salesforce-connector-jarcq-mcm-salesforce-adobe-cq5-aem.html https://www.albinsblog.com/2017/04/updating-salesforce-connector-jarcq-mcm-salesforce-adobe-cq5-aem.html

This post is written based on the AEM version AEM 6.1 SP1.


Sunday, May 7, 2017

How to get the basic profile details of a user in external clients through OAuth - Adobe Experience Manager(AEM)

How to get the basic profile details of a user in external clients through OAuth - Adobe Experience Manager(AEM)

This post will explain the approach to get the basic profile details of a user through OAuth - AEM/Adobe CQ5

Configure the OAuth client - Adobe Experience Manager(AEM):

Login to AEM through Admin credential
Access - http://localhost:4502/libs/granite/oauth/content/clients.html and click on "Create a new app" or "Add New Client"


Enter Client ID and "Redirect URI" - The URL to which the user will be redirected after successful authorization(external client URL)




Saturday, April 15, 2017

how to include custom meta tag headers fromAdobe Experience Manager(AEM) Tags

how to include custom meta tag headers from Adobe Experience Manager(AEM) Tags

This post explains the approach to include custom meta tag headers from Adobe Experience Manager(AEM)/CQ5 Tags.

Customize the page properties dialog:

Customize the page properties dialog to add the field to select custom tags

Copy /libs/foundation/components/page/dialog and /libs/foundation/components/page/tab_basic under custom page rendering component e.g. /apps/training/components/page-content/

Create a node of type cq:widget under tab_basic with the following properties

Name Type Value
allowBlank Boolean true
fieldLabel String Page Type
name String ./page-type
namespaces String[] page-type
xtype String tags

Refer https://www.albinsblog.com/2017/03/how-to-customize-page-properties-dialog-dynamic-dropdownlist-aem-cq5-in-touchui-classicui.html for more details on customizing the page properties dialog.



Thursday, April 13, 2017

Integration of Adobe Experience Manager(AEM) with Salesforce - Part4

Integration of Adobe Experience Manager(AEM) with Salesforce - Part4

This post will explain the approach to extend the basic Adobe Experience Manager(AEM) Salesforce connector to create/update the Salesforce objects.

Refer the following post for details on integrating Salesforce with Adobe Experience Manager(AEM)
https://www.albinsblog.com/2017/03/integrationofaemcq5withsalesforcepart1.html
https://www.albinsblog.com/2017/04/integrationofaemcq5withsalesforcepart2.html
https://www.albinsblog.com/2017/04/integration-of-aem-with-salesforce-part3.html

Prerequisite  - Configure the Salesforce cloud connection, refer the above mentioned post for more details.
Enable the Salesforce cloud configuration for the Home page of the websites.


Dependency:

Add the below Maven dependency to the project
For 6.0 and 6.1
<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>aem-api</artifactId>
    <version>6.0.0.1</version>
    <scope>provided</scope>
</dependency>

For 6.2
<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>
    <version>6.2.0</version>
    <classifier>apis</classifier>
    <scope>provided</scope>
</dependency>



Tuesday, April 11, 2017

Integration of Adobe Experience Manager(AEM) with Salesforce - Part3

Integration of Adobe Experience Manager(AEM) with Salesforce - Part3

This post will explain the approach to extend the basic Adobe Experience Manager(AEM) Salesforce connector to search for the Salesforce objects other than Lead/Contact.

Refer the following post for details on integrating Salesforce with Adobe Experience Manager(AEM)
 https://www.albinsblog.com/2017/03/integrationofaemcq5withsalesforcepart1.html
https://www.albinsblog.com/2017/04/integrationofaemcq5withsalesforcepart2.html

Prerequisite  - Configure the Salesforce cloud connection, refer the above mentioned post for more details.
Enable the Salesforce cloud configuration for the Home page of the websites.

Dependency:

Add the below Maven dependency to the project
For 6.0 and 6.1
<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>aem-api</artifactId>
    <version>6.0.0.1</version>
    <scope>provided</scope>
</dependency>

For 6.2
<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>
    <version>6.2.0</version>
    <classifier>apis</classifier>
    <scope>provided</scope>
</dependency>



Saturday, April 8, 2017

In place upgrade of Adobe Experience Manager(AEM) to 6.2 version

In place upgrade of Adobe Experience Manager(AEM) to 6.2 version

This post will explain the steps to in place upgrade of Adobe Experience Manager(AEM) server to 6.2 version
  • Backup the current Adobe Experience Manager(AEM) instance
  • Copy aem-quickstart-6.2.0.jar next to current Adobe Experience Manager(AEM) crx-quickstart
  • Perform regular maintenance activities - including workflow purge
  • Run the Traversal check and Data store consistency check one by one - http://localhost:4502/system/console/repositorycheck
  • Disable custom login moduels if any - make sure the default login module is configured as below in crx-quickstart/repository/repository.xml
        <LoginModule class="com.day.crx.core.CRXLoginModule">
            <param name="anonymousId" value="anonymous"/>
            <param name="adminId" value="admin"/>
            <param name="disableNTLMAuth" value="true"/>
            <param name="tokenExpiration" value="43200000"/>
            <!-- param name="trust_credentials_attribute" value="d5b9167e95dad6e7d3b5d6fa8df48af8"/ -->
</LoginModule>
  • Stop the Adobe Experience Manager(AEM) server
  • Remove all log files under crx-quickstart/logs
  • chown -R aem:aem crx-quickstart(this command is required if AEM is running with different user)
  • su aem(this commad is required if AEM is running with diffrent user)
  • If you are migrating from AEM 5.x or AEM 6.0 with a CRX2 backend then follow URL - https://www.albinsblog.com/2015/09/upgrading-aemadobe-cq5-5.6.1-to-aemadobe-cq5-6.1.html
  • If you are migrating from AEM 6.0 with a oak backend or 6.1 then execute java -jar aem-quickstart-6.2.0.jar -r author,crx3,crx3tar
  • Monitor error.log and stderr.log – Once the migration is completed stderr.log will show the following message                                                                                                                           
          “Opening browser using cmd=x-www-browser "http://localhost:4502/"  || gnome-open                       "http://localhost:4502/"  || firefox "http://localhost:4502/"  || mozilla "http://localhost:4502/"               || konqueror "http://localhost:4502/"  || netscape "http://localhost:4502/"  || chromium-browser           "http://localhost:4502/"  || opera "http://localhost:4502/"  || links "http://localhost:4502/"  ||                lynx "http://localhost:4502/"
           Startup time:442 seconds
           http://localhost:4502/
           Quickstart started”

URL to check the version - http://localhost:4502/system/console/productinfo

Check the bundles in Installed state, most of the obsolete bundles will be removed after upgrade but some cases some of  the obsolete bundles will not be uninstalled - This can be ignored or uninstalled manually (better to compare the bundles with fresh 6.2 installation).Refer the following URL for details on obsolete bundles https://docs.adobe.com/docs/en/aem/6-2/deploy/upgrade/obsolete-bundles.html

Custom core bundles may not start due to the dependency issues. Refer the following URL for API difference between 6.1 and 6.2 - https://docs.adobe.com/docs/en/aem/6-2/develop/ref/diff-previous/changes/changes-summary.html

Update the maven dependency with correct version by identifying the version through depfinder -
http://localhost:4502/system/console/depfinder




Tuesday, April 4, 2017

Integration of Adobe Experience Manager(AEM) with Salesforce - Part2

Integration of Adobe Experience Manager(AEM) with Salesforce - Part2

This post will explain the common issues faced while integrating Salesforce with Adobe Experience Manager(AEM).

Refer https://www.albinsblog.com/2017/03/integrationofaemcq5withsalesforcepart1.html for details on integrating Salesforce with Adobe Experience Manager(AEM)

redirect_mismatch: 

The redirect_mismatch error will be displayed if the calback URL configured in the Salesforce connected app and the redirect_uri send by the Adobe Experience Manager(AEM) Connector is not matching.



Verify the callback URL configured in the Salesforce connected app is same as the value send by AEM connector.
Make sure the AEM Salesforce connector is opened via https URL



Monday, April 3, 2017

Updating the Salesforce Connector jar(cq-mcm-salesforce) to support Proxy server and TLS 1.1 - Adobe CQ5/AEM

Updating the Salesforce Connector jar(cq-mcm-salesforce) to support Proxy server and TLS 1.1 - Adobe CQ5/AEM


Updating the Salesforce Connector jar(cq-mcm-salesforce) to support Proxy server and TLS 1.1 - Adobe CQ5/Adobe Experience Manager(AEM)

Steps to update Salesforce Connector jar(cq-mcm-salesforce) to support Proxy server and TLS 1.1

The AEM Salesforce connector is not supporting the Proxy Server and TLS 1.1 or TLS 1.2 versions:

This is the defect with AEM Salesforce Connector, the connector will not be able to connect to Salesforce server behind the proxy server. The SalesforceClient.java class in the connector should be changed to enable the proxy server.

The connector will not be able to connect to Salesforce server if the Adobe Experience Manager(AEM) server is ruuning with Jave version less than 1.8, Java versions less than 1.8 will not support TLS 1.1 or higher version by default but Salesforce expect TLS 1.1 or TLS 1.2 to establish the connectivity. The SalesforceClient.java class in the connector should be changed to support the TLS 1.1 or TLS 1.2, if the  AEM server is running with Java version less than 1.8

I have tested this in Adobe Experience Manager(AEM) 6.1 version, this should be the same case with 6.2 also. Raise an issue with Adobe to get the hotfix until the issue is permanently fixed.

The below is the quick fix to resolve the issue.

Download the /libs/mcm/salesforce/install/cq-mcm-salesforce-1.2.8.jar through package manager

Create a sample project -  mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype  -DarchetypeVersion=10 -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/

              groupId=com.day.cq.mcm
              artifactId=cq-mcm-salesforce
              version=1.2.8
              package=com.adobe.cq.mcm.salesforce 
             Enter mcm for other values
 
Execute mvn eclipse:eclipse command in the parent folder of the project and load the project to eclipse

Extract the downloaded jar file and decompile the class files using JAD
Create all the java classes manually in core project with same package details and copy the content from decompiled classes
Replace the pom.xml of core project with the pom.xml content from the decompiled jar





Saturday, April 1, 2017

Generating the missing renditions for the Asset - Adobe CQ5/AEM

Generating the missing renditions for the Asset - Adobe CQ5/AEM

This post will explain the approach to generate the missing renditions for the asset(images) under a specific folder location in  Adobe Experience Manager(AEM)

Create a custom workflow with "Create Thumpnail" step


Edit "Create Thumpnail" step and configure the required renditions.


Servlet to re-generate the missing renditions:

Modify the workflow model path in the servlet with the actual path, the servlet is configured to handle the renditions 370.208 and 470.264(the same renditions are configured in the workflow). The code change is required to handle new renditions by the servlet.

Parameters:
path= the parent path of the assets(images) folder
test=true/false(true - Dry run, false - generate the renditions)



Wednesday, March 29, 2017

How to customize the page properties Dialog to include dynamic DropDownList in AEM/CQ5

How to customize the page properties Dialog to include dynamic DropDownList in AEM/CQ5

This post will explain the details to customize page properties Dialog in both Touch and Classic UI's, the version used for implementing this is Adobe Experience Manager(AEM) 6.1.

The basic page properties dialog will be displayed if the sling:resourceSuperType of the page rendering component is specified as foundation page component(wcm/foundation/components/page for Sightly and foundation/components/page for JSP)

Steps to customize the basic page properties and including dynamic DropDownList to the dialog.

/apps/training/components/page-content/ will be referred as the page rendering component path in the post.

Classic UI:

Copy /libs/foundation/components/page/dialog to /apps/training/components/page-content/
Rename the new node to required name e.g. custom

Copy /libs/foundation/components/page/tab_basic to /apps/training/components/page-content/
Rename /apps/training/components/page-content/tab_basic to required name e.g tab_custom

Remove all the nodes under  /apps/training/components/page-content/tab_custom/items

Change path value in the node /apps/training/components/page-content/dialog/items/tabs/items/custom to /apps/training/components/page-content/tab_custom.infinity.json

Change title property of the node /apps/training/components/page-content/tab_custom to required value e.g Custom

Save All configurations

Open the page from site Admin(e.g. http://localhost:4502/cf#/content/training-site/en.html), now the new tab(Custom) will be added to the page properties with empty panel



Friday, March 24, 2017

Integration of Adobe Experience Manager(AEM) with Salesforce - Part1

Integration of Adobe Experience Manager(AEM) with Salesforce - Part1

Adobe Experience Manager(AEM) Salesforce cloud connector can be used to integrate to Salesforce via connected App configured in the Salesforce

The Adobe Experience Manager(AEM) Salesfore integration supports the following functionalities:
  • Lead Search
  • Contact Search
  • Export AEM user as Salesforce Lead
  • Associate an AEM user with a Salesforce "Contact" or "Lead"
The connector can be extended to support the additional functionalities.


Defining the connected App in Salesforce:

A connected app integrates an application with Salesforce using APIs
Connected apps use standard SAML and OAuth protocols to authenticate and provide tokens for use with Salesforce APIs. The required security policies can be set to control the connected Apps access.

Login to Salesforce - login.salesforce.com
Click on the user name- Setup- Click on Create then Apps
Create New connected App
Enter the name and Email address



Thursday, March 2, 2017

Time zone difference in Author/Publishers - Adobe CQ5/AEM

Time zone difference in Author/Publishers - Adobe CQ5/AEM

The timezone configured in the OS(Linux) level is CST but some time the log files displays the timezone in GMT

To fix the issue force the Adobe Experience Manager(AEM) server to use the required timezone in startup file(start.sh)
e.g.
CQ_JVM_OPTS='-server -Xmx1024m -XX:MaxPermSize=256M -Duser.timezone=US/Central -Djava.awt.headless=true'



Wednesday, March 1, 2017

How to protect the content from anonymous access through SAML based SSO - Adobe CQ5/AEM

How to protect the content from anonymous access through SAML based SSO - Adobe CQ5/AEM

How to enable SAML based SSO for publisher - Adobe CQ5/AEM
How to enable SAML based SSO in publisher to protect the content while accessing via dispatcher - Adobe CQ5/AEM

This post will explain the steps required to protect the published content from anonymous access through SAML based SSO while accessing via dispatcher/publisher - Adobe CQ5/AEM

Out of scope for this post - Configurations of IDP provider. Make sure the return URL configured in SAML provider is /saml_login

Enable Authentication for required content path:

Go to http://localhost:4503/system/console/configMgr(publisher)
Search for Apache Sling Authentication Service
Add the path that required the authentication to Authentication requirements in the following format +<<Content Path>> e.g. +/content/test


Configure the IDP certificate in Adobe Experience Manager(AEM):

Go to http://localhost:4503/system/console/configMgr(publisher)
Under /etc/key in the repository, create a node called "saml"(type nt:folder).
Inside this node, add a new binary property called  "idp_cert" for the public certificate of the IdP.
Upload the certificate file by double clicking on idp_cert property
Save All




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.




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.


Friday, August 19, 2016

How to invalidate the dispatcher cache for dam assets referred from multiple sites? - Adobe CQ5/AEM

How to invalidate the dispatcher cache for dam assets referred from multiple sites? - Adobe CQ5/AEM

Sometimes, we may have the scenario like the same DAM asset is referred from multiple sites and cached locally(site specific) in Adobe Experience Manager(AEM) dispatcher for the different sites. The local cache of the different sites should be invalidated whenever the asset is modified.

This post will explain how to achieve the above mentioned scenario.

Create a user in all the publisher and provide only the access to DAM- /content/dam


Create a flush agent for individual sites with the following details in all the publishers(repeat the below step for all the sites)



Friday, July 8, 2016

How to populate the current page path to the dialog through EXT JS - Adobe Experience Manager(AEM) 6.1

This post will explain, how to populate the current page path to the dialog through EXT JS - Adobe Experience Manager(AEM ) 6.1

Add the listener for the widget and use the below script.

function(widget) {
        var currentPath;
if(CQ.wcm.SiteAdmin.hasListSelection()) {
        var grid = CQ.wcm.SiteAdmin.getActiveGrid();
        var selections = grid.getSelectionModel().getSelections();
currentPath = selections[0].id;
console.log(currentPath);
widget.setValue(currentPath)
}
}







Thursday, June 23, 2016

Caused by: org.apache.sling.api.resource.PersistenceException: Resource is not modifiable - Adobe CQ5/AEM

 Caused by: org.apache.sling.api.resource.PersistenceException: Resource is not modifiable - Adobe CQ5/AEM


The below exception will be thrown most of the cases while accessing the servlet with post from Adobe Experience Manager(AEM).

The actual issue is Adobe Experience Manager(AEM) could not ale to resolve the servlet and assumes it as a resource path but this is not a valid resource path, the below exception will be thrown when AEM tries to set the property values.

Caused by: org.apache.sling.api.resource.PersistenceException: Resource at '/services/formservlet' is not modifiable.
    at org.apache.sling.servlets.post.impl.helper.SlingPropertyValueHandler.setProperty(SlingPropertyValueHandler.java:153)
    at org.apache.sling.servlets.post.impl.operations.ModifyOperation.writeContent(ModifyOperation.java:411)
    at org.apache.sling.servlets.post.impl.operations.ModifyOperation.doRun(ModifyOperation.java:101)

The steps to narrow down the issue:

Resolve the Servlet:

Go to http://<<AEM Host>>:4503/system/console/configMgr - Sling--> Sling Servlet Resolver and resolve the servlet path, if the servlet path is resolved then there is no issue if not the servlet is not configured properly.

Path resolved to a Servlet