Saturday, 12 October 2019

Sitemap Scheulder with Factory Configuration using OSGi annotations

Creating Sitemap for an eCommerce website helps in indexing all the product pages by search engine crawlers. There are situations that sitemap should be created for multiple sites, we can achieve this by adding factory=true and bind methods in schedulers.

Let's see how to create sitemap from an product index file using factory.

  1. Create a service config file
  2. Create a scheduler
  3. Create sitemap read and write service interface and implementation
  4. Create models for parsing the index xml file

Sunday, 29 September 2019

Create Product sitemap in AEM

Creating Sitemap for an eCommerce website helps in indexing all the product pages by search engine crawlers.

Let's see how to create sitemap from an product index file.

Create a service config file
Create a scheduler
Create sitemap read and write service interface and implementation
Create models for parsing the index xml file

Sample XML file hosted on a server, we will be configuring this XML hosted URL in Scheduler 
<aemquickstart
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<channel>
<Item>
<title>
<![CDATA[ AEM Quickstart by Kishore ]]>
</title>
<ProductId>12345</ProductId>
<pubDate>02/28/2017 00:00:00.000000</pubDate>
</Item>
<Item>
<title>
<![CDATA[ Lorel Ipsum ]]>
</title>
<ProductId>56789</ProductId>
<pubDate>02/28/2019 00:00:00.000000</pubDate>
</Item>
<Item>
<title>
<![CDATA[ Create Sitemap in AEM ]]>
</title>
<ProductId>12987</ProductId>
<pubDate>03/28/2019 00:00:00.000000</pubDate>
</Item>
</channel>

</aemquickstart>

Tuesday, 24 September 2019

Access AEM servlet in postman

When you make a POST request to your local AEM author instance, the request will be filtered and restricted by "Apache Sling Referrer Filter" and "Adobe Granite CSRF Filter". Incoming POST requests without the CSRF-Token in the header will be blocked by "Apache Sling Referrer Filter" and "Adobe Granite CSRF Filter".

Steps to configure:

  • Navigate to ConfigMgr
  • Search for 'Apache Sling Referrer Filter'
  • Remove POST method from the filter.
  • Check "Allow Empty" checkbox and click on Save.

  • Search for "Adobe Granite CSRF Filter"
  • Remove POST method from the filter.
  • click on Save.






Click here to download postman and install.

Open Postman app and do the following steps.
  • Select method as POST
  • Enter AEM servlet URL.
  • Navigate to "Authorization" tab and enter username and password.
  • Enter required "Headers"



  • Enter request in the body tab and hit Send button.

Saturday, 14 September 2019

Apache Sling's Request Processing Analyzer

AEM provides a console to check recent requests, by default only 20 requests can be seen which is a troublesome in production environment as we get millions of requests. We can update the default value, but it will be difficult when we get some millions of requests in production.

Recent requests in AEM:



Apache Sling provides a tool to analyze all the recent requests using "Request Processing Analyzer". To install this tool download the code from GitHub and run mvn clean install. Once build is success, we can see jar files in target folder. Install org.apache.sling.reqanalyzer-0.0.1-SNAPSHOT.jar to AEM instance.

A log file requesttracker.txt is created in ${sling.home}/logs folder. To analyze this log file we need to run below command, which opens a graphical window
java -jar org.apache.sling.reqanalyzer-0.0.1-SNAPSHOT.jar D:\CQ5\CQ5\AEM6.4\crx-quickstart\logs\requesttracker.txt

We can see below info in the window
  • Start time stamp in milliseconds
  • Request processing time in milliseconds
  • Request method
  • Request URL
  • Response content type
  • Response status
To analyze a specific request, click on it then we can see new window with more info.

We can see below info
  • Timestamp - shows the timestamp of each step that the request
  • Delta - time between each step
  • Message - shows info about which step is processed

Wednesday, 4 September 2019

Creating Configuration Factory Service

This post talks about creating Configuration Factory service using OSGI R6 annotations. In order to create this service we need to create a Service Interface and Implementation class.

Let's create a interface to define the configurations


package com.aemquickstart.core.interfaces;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "AEM Quickstart Site Configs")
public @interface SiteConfigs {
 
  @AttributeDefinition(name="Site Id", description="Site ID")
     String getSiteId() default "aemquickstart";
  @AttributeDefinition(name="Site Name", description="Site Name")
     String getSiteName() default "AEM Quickstart";
}

Saturday, 27 July 2019

Hide facet item in Adobe Seach and Promote

Using Adobe Search and Promote we can able to hide specific facet items. For example, you have a product type as "Lorem Ipsum" and you want to hide this facet item under "Product Type" facet, you can achieve this by adding a business rule. After adding this rule, "Lorem Ipsum" facet item is not displayed.

Rules -> Business Rule




After adding this rule test it in simular or in author AEM instance.


Click here to see how to integrate AEM and SnP.

Tuesday, 23 July 2019

Redirect to specific page using Adobe Search and Promote

Using Adobe Search and Promote we can redirect a user to a specific page skipping the search results page.

Consider a scenario for eCommerce website, if a user searches for a product id then it's good to redirect the user to product display page instead of the search results page. We can achieve this by adding a post search rule in SnP as shown below.

Rules -> Post Search Rule


After adding this rule test it in simular or in author AEM instance.


Click here to see how to integrate AEM and SnP.

Search each word in query param using Adobe Search and Promote

We can use Adobe Search and Promote to search each word and display the search results. By default, SnP will search whole string in Query param. For example, if your search query is "AEM Quickstart" then your search results will be *AEM Quickstart*. You won't see results with only "AEM" or "Quickstart".

To achieve this, we should add Post Search Rules.

Rules -> Post Search Rule -> +Add Rule


After adding this rule test it in simular or in author AEM instance.

Click here to see how to integrate AEM and SnP.

Sunday, 14 July 2019

Publish AEM Content to Salesforce Communities using CMS Connect

Salesforce has come up with a feature to connect the third-party Content management systems with Salesforce communities. You can connect CMS components, HTML, JSON, CSS, and JavaScript to customize your community and keep its branding consistent with your website. CMS connect feature renders content dynamically from CMS systems.


CMS Connect supports content from different CMS systems like AEM, Sitecore, Drupal, SDL, WordPress and Other.


Let's see how to pull content from AEM to Salesforce community.

Enable CORS in AEM

From AEM 6.3, Adobe added Cross-Origin Resource Sharing Policy (CORS) as OSGi configuration. CORS configurations can be added as an OSGi config factories.

CORS configurations are managed as OSGi configuration factories in AEM, with each policy being represented as one instance of the factory.
  • Navigate to http://localhost:4502/system/console/configMgr
  • Search for Adobe Granite Cross Origin Resource Sharing Policy (com.adobe.granite.cors.impl.CORSPolicyImpl)
Click here to check how to enable CORS for older AEM versions (<6.3)

Monday, 8 July 2019

Nested Multifield (coral 3) with Sling Model in AEM

Create AEM multi module project using archtype 11
Create a new component with cq:dialog for Touch UI as shown below.


<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured"
    jcr:title="Country Details"
    sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
        <items jcr:primaryType="nt:unstructured">
            <column
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/container">
                <items jcr:primaryType="nt:unstructured">
                    <countries
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                        composite="{Boolean}true"
                        fieldLabel="Countries">
                        <field
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="granite/ui/components/coral/foundation/container"
                            name="./countries">
                            <items jcr:primaryType="nt:unstructured">
                                <column
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/container">
                                    <items jcr:primaryType="nt:unstructured">
                                        <countryName
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                            fieldLabel="Country Name"
                                            name="./countryName"/>                                        
                                        <states
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
                                            composite="{Boolean}true"
                                            fieldLabel="States">
                                            <field
                                                jcr:primaryType="nt:unstructured"
                                                sling:resourceType="granite/ui/components/coral/foundation/container"
                                                name="./states">
                                                <items jcr:primaryType="nt:unstructured">
                                                    <column
                                                        jcr:primaryType="nt:unstructured"
                                                        sling:resourceType="granite/ui/components/coral/foundation/container">
                                                        <items jcr:primaryType="nt:unstructured">
                                                            <stateName
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                                fieldLabel="State Name"
                                                                name="./stateName"/>
                                                            <statePostal
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                                fieldLabel="State Postal"
                                                                name="./statePostal"/>
                                                            <statePopulation
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/numberfield"
                                                                fieldLabel="State Population"
                                                                name="./statePopulation"/>
                                                            <stateDensity
                                                                jcr:primaryType="nt:unstructured"
                                                                sling:resourceType="granite/ui/components/coral/foundation/form/select"
                                                                fieldDescription="Select State Density"
                                                                fieldLabel="State Density"
                                                                name="./stateDensity">
                                                                <items jcr:primaryType="nt:unstructured">
                                                                    <high
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="High"
                                                                        value="high"/>
                                                                    <medium
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="Medium"
                                                                        value="medium"/>
                                                                    <low
                                                                        jcr:primaryType="nt:unstructured"
                                                                        text="Low"
                                                                        value="low"/>                                                                    
                                                                </items>
                                                            </stateDensity>
                                                        </items>
                                                    </column>
                                                </items>
                                            </field>
                                        </states>
                                    </items>
                                </column>
                            </items>
                        </field>
                    </countries>
                </items>
            </column>
        </items>
    </content>
</jcr:root>



Now create slingmodels to get the authored values.
  1. CountriesModel.java
  2. Country.java
  3. State.java

Tuesday, 2 July 2019

Avoid encoding dispatcher URLs

Rewrite rules on Apache web server that attempt to redirect to URLs with special characters such as & or ? or #anchor aren't being redirected properly.  For example:
RewriteRule ^/we-retail.html /we-retail.html#anchor [R=301,L]

To avoid encoding the # character, add the NE flag to the rewrite rules:
RewriteRule ^/test.html /test.html#anchor [NE,R=301,L]

Special characters such as & and ?, will be converted to their hexcode equivalent. Using the [NE] flag prevents that from happening.
RewriteRule ^/anchor/(.+) /bigpage.html#$1 [NE,R]

The above example will redirect /anchor/xyz to /bigpage.html#xyz. Omitting the [NE] will result in the # being converted to its hexcode equivalent, %23, which will then result in a 404 Not Found error condition.
Reference: RewriteRule Flags

Remove .html extension at dispatcher

Add below dispatcher configurations in dispatcher.any file to remove .html extension from the URL.
#Enable RewriteEngine

RewriteEngine on


#Map the root folder to the home page

RewriteRule ^/?$ /content/we-retail/us/en/home.html [PT,L]


# remove any trailing slash, if it's there.

RewriteRule ^(.+)/$ $1


#Remove .html Extension

RewriteRule ^(.*).html$ $1 [R,L]


#Shorten the URL

RewriteRule ^/content/we-retail/us/(.*)$ $1 [R,L]


#Remove .html and map products url

RewriteRule ^/en/products.html/(.*)$ /en/products/$1 [R,L]


RewriteCond %{REQUEST_URI} !^/(apps|content|etc|home|libs|system|tmp|var|services)

RewriteRule ^/en/products/(.*)$ /content/we-retail/us/en/products.html/$1 [PT,L]


RewriteCond %{REQUEST_URI} !^/(apps|content|etc|home|libs|system|tmp|var|services)

RewriteRule ^/(.*)$ /content/we-retail/us/$1.html [PT,L]

Tuesday, 11 June 2019

Disable location tracker in AEM

Location tracker popup is annoying when page is loaded. This is enabled by default when clientcontext is used. 

Steps to disable location tracker:

  • Copy clientcontext component /etc/clientcontext/default to /etc/clientcontext/custom
  • Open this new component and delete the geolocation component.
  • Map this new component path to your design path ex: /etc/designs/default/jcr:content/homepage
We can see location tracker is disabled for specific site now.

Sunday, 13 January 2019

Targeting content in AEM

AEM enables to target content for different audience.

This post will explain how to target title component to display content based on user's location and do A/B testing.

Create a web page called Target under we-retail website.


Click here to check how to enable ContextHub.
Navigate to AEM instance and create Brand and activities. 


Saturday, 12 January 2019

Cannot read property 'extend' of undefined': ContextHub

While adding ContextHub to AEM site could see below errors

Change ContextHub entry in head section from 
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>

to 

!--/* Include Context Hub */-->
<sly data-sly-call="${clientlib.js @ categories='granite.utils'}"/>
<sly data-sly-resource="${'contexthub' @ resourceType='granite/contexthub/components/contexthub'}"/>


Click here to check how to setup ContextHub in AEM.

Using script reference in AEM ContextHub

While creating audience in AEM contextHub, we see a component called Script Reference. When we drag-n-drop the component, we don't see any scripts by default in the drop down.


Wednesday, 9 January 2019

URL Shortening in AEM

Content pages in AEM start with path /content/. It is best practice to hide /content/site in the URL.

Below configs show how to achieve URL shortening on both AEM server and dispatcher.

Configs on AEM Server:

·         There are many ways to configure the rewrites on publish server. e.g. Resource Resolver, Vanity URLs, Sling mapping.
·         Configuring the Apache Sling Resource Resolver Factory is one of the ways to configure rewrites. This service needs to be configured on the publish server so that if someone hits the publish server directly; we see the correct rules applied there.
Make sure that the publish server has the below configuration applied


Saturday, 5 January 2019

Backend forbids caching, sent: 'Dispatcher: no-cache'

When using dispatcher if we use below code then pages will not be cached in dispatcher. Error in dispatcher.log is "Backend forbids caching, sent: 'Dispatcher: no-cache'"

response.setHeader("Dispatcher", "no-cache");                       
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setDateHeader("Expires", 0);