Tuesday, March 7, 2017

AEM Site Performance Tuning - Query monitoring

If you are facing any performance issues with pages developed in AEM, then its time to look on the JCR queries running in your application.

Some of the query monitoring mechanism are given below

1) Identify any potential errors or warnings in error.log.
If you see any warnings as below, then you are required to add proper oak index.
 org.apache.jackrabbit.oak.spi.query.Cursors$TraversingCursor Traversed 12000 nodes with filter Filter... consider creating an index or changing the query

Ref: https://docs.adobe.com/docs/en/aem/6-1/deploy/platform/queries-and-indexing.html

2) Debug query details
Add new logger org.apache.jackrabbit.oak.query and configure the log level to Debug/Trace.




You will more details on query, index and cost.

Ref: http://jackrabbit.apache.org/oak/docs/query/query-engine.html

3) Query Monitoring tools

AEM provides Query Performance tool for analyzing the slow queries.
http://localhost:4502/libs/granite/operations/content/diagnosis/tool.html/_granite_queryperformance

In explain query tab, you can test the query and analyze the time, applied index etc.

In addition, there is ACS Commons which provides additional Explain Query feature for analyzing more details like index cost.
http://localhost:4502/etc/acs-tools/explain-query.html



Thursday, February 23, 2017

Creating AEM service user and defining ACL package

From AEM6 , the usage of admin session is deprecated. In this post, i'll try to explain how to create the service user and get the session.  Also briefly explains how to create the ACL service package.

1) Create a system user
The service user is normal AEM user having enough permissions in required nodes. 

Go to http://localhost:4502/useradmin and create a user and provide proper permissions.

Sample user:  rsa-service-user


2) Create the service mapping Osgi configurations.

File: org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-rsa.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
service.ranking="0"
user.mapping="[org.test.rsa-osgi:repositoryService=rsa-service-user]" />

This mapping is required for getting jcr session in specified Osgi bundles. Here "org.test.rsa-osgi" is orgi bundle name.

3) Getting service user session in Osgi service

// Getting Resource Resolver
ResourceResolver resourceResolver = null;
try {
final Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "repositoryService");
resourceResolver = resolverFactory.getServiceResourceResolver(param);
} catch (LoginException e) {
//
}

// Getting JCR session
Session session = null;
try {
session = repository.loginService("repositoryService", repository.getDefaultWorkspace());
} catch (RepositoryException e) {
//
}
return session;
}

4) Creating ACL package

You may create the ACL service package so it will be useful on deploying in higher environment.
In this package, we need to include rep policy path  and service user path.


The user path can be copied from edit user console.

Edit the package and select the option Overwrite in AC Handling for overwriting the access policies.





Friday, February 3, 2017

How to change authoring mode in AEM 6?

Touch UI is the default authoring mode in AEM 6.  Here is how to change the default authoring mode to CLASSIC mode.

Change via Web console
Go to Felix web console and open configuration Manager
http://localhost:4502/system/console/configMgr

Open WCM Authoring UI Mode Service configuration.

Change the value to CLASSIC. By default it is TOUCH.


Change via Osgi config

Create Osgi config under project /apps/config

com.day.cq.wcm.core.impl.AuthoringUIModeServiceImpl.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="sling:OsgiConfig"
    authoringUIModeService.default="CLASSIC"
    authoringUIModeService.editorUrl.classic="/cf#"
    authoringUIModeService.editorUrl.touch="/editor.html"/>


Note: This setting change globally for all sites hosted in that instance. 

Friday, January 27, 2017

How to create and package the Oak index in AEM 6?


Issue: If you see some warnings like below in error.log, then its time to create index for improving jcr search performance

*WARN* [0:0:0:0:0:0:0:1 [1485528947344] GET /bin/services/rsa/profile.json HTTP/1.1] org.apache.jackrabbit.oak.spi.query.Cursors$TraversingCursor Traversed 26000 nodes with filter Filter(query=select [jcr:path], [jcr:score], * from [nt:unstructured] as a where [userid] like '_%' and [securityservice] like 'rsa' and isdescendantnode(a, '/profile') /* xpath: /jcr:root/profile//element(*, nt:unstructured)[(jcr:like(@userid, '_%') and jcr:like(@securityservice, 'rsa'))] */, path=/profile//*, property=[userid=[(_%..], securityservice=[rsa]]); consider creating an index or changing the query


Steps

1) Identify the potential properties that need to be indexed.

2) Create _oak_index folder and add the content xml for creating oak index definition nodes.

Path: /your_module/src/main/content/jcr_root/_oak_index/.content.xml


<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:slingevent="http://sling.apache.org/jcr/event/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:dam="http://www.day.com/dam/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal"
    jcr:mixinTypes="[rep:AccessControllable]"
    jcr:primaryType="nt:unstructured">
    <userid
        jcr:primaryType="oak:QueryIndexDefinition"
        propertyNames="{Name}[userid]"
        reindex="{Boolean}false"
        type="property"/>
    <securityservice
        jcr:primaryType="oak:QueryIndexDefinition"
        propertyNames="{Name}[securityservice]"
        reindex="{Boolean}false"
        type="property"/>      
</jcr:root>

2) Add the paths in filter.xml

  <filter root="/oak:index/userid"/>
  <filter root="/oak:index/securityservice"/>

This will create Oak index below node /oak:index. You can also use CRXDE to create index. 



Ref: https://docs.adobe.com/docs/en/aem/6-0/deploy/upgrade/queries-and-indexing.html


Tuesday, January 24, 2017

How to unblock POST method filtered by CSRF Filter in AEM 6.1?

Issue: The POST method form submission returns 403 forbidden error in AEM 6.1

Solution: In AEM 6.1, the CSRF security is added besides Apache Sling Referrer. The AEM is expecting a valid CSRF token for every POST by default.

Include following clientlib in the template or component using the HTML form.

<cq:includeClientLib js="granite.csrf.standalone"/>

The script will generates the CSRF token like below and sends with POST request.
CSRF-Token:
eyJleHAiOjE0ODUyNzQ2NDQsImlhdCI6MTQ4NTI3NDA0NH0.AOyz-sTX9Ohh5hfBwFF_Qx8_y6GU8kfdMwIeVZZa88I


For verifying whether the POST method is blocked by CSRF framework, you can test by removing the POST entry in CSRFFilter configuration.

http://localhost:4502/system/console/configMgr/com.adobe.granite.csrf.impl.CSRFFilter

Ref: https://docs.adobe.com/docs/en/aem/6-1/develop/security/csrf-protection.html