Multifields in Touch UI AEM 6.

I have been using touch ui entirely across all the client from last year or so. I have come across several articles online working with Touch UI and multifields. Multifields always being inconsistent, i always had to devise new strategies to cater to ever changing multifield requirements of clients.

I came across ACS Touch UI multifield and that happen to be very consistent and have started using it across all the clients. ACS uses definition list component where they have shown sample of how they use the multifield. The location of the component is \apps\acs-commons\components\content\definition-list. The component stores the data in the jcr as json. If you can write up a generic iterator which i have you can use this multifield across any component. Happy Component development.

How to download the jar/bundle file from AEM for a particular class Felix Console

While working on SAML, I found myself in situation where I wanted to see the code for the saml jar in AEM. When I searched for saml in /system/console/configMgr. I found that the jar was referring to version number 0.3.32.jar. The public repository of Adobe had the 0.2.22 jar as the latest version.

The trick to download the jar is to first locate the bundle that has the class file. I went to /system/console/bundles and looked for saml and found that the bundle hosting the class file had number 149. This can vary from system to system.

To download the jar/bundle from AEM you can go to the below location crx-quickstart/launchpad/felix/bundle149/version0.0.

Config Manager Properties where are they saved? AEM 6

We know the flexibility that we get out of OSGI container where we can edit values and those values are saved immediately. The next request starts picking up the values that the sys admin just put in.

The values are stored under /crx-quickstart/config directory. Basically osgi will find out the PID of the class/bundle and creates directories within the config directories.

So for example, Login Authentication Handler the values are stored under com/day/cq/auth/impl/LoginSelectorHandler.config.

If you change the value in the server itself the values are not picked up by the OSGI container, you have to do a restart if you want OSGI to pick up the values that you have change manually.

Global AEM spell checker

I have recently started working a AEM library of common features. We have started adding a lot of stuff within that library. A recent addition to the library is AEM/CQ5 spell checker.

AEM CQ Spell Checker Utility
The project aem spell checker has been created using maven archetype 7 project.

Modules

Spell checker utility consists of two modules. Spell checking in both the modules in done using Jazzy spell checker utility. It is a very common spell checking utility used in J2ee projects. It is easy to integrate it with existing projects as well. All the code is servlet based which are registered under /bin/aemfeatures/* so this path should be enabled in case you want to run this code via dispatcher. The servlets have properties to provided phonet and dictionary files. Currently, both of these files have to live under crx-quickstart/conf directory. Samples files have been checked into the core/resource directory. Adding a word is a simple as adding in the en.0 file. Below should be modified in SpellCheckerServlet if you want to put directory in a custom field.

@SlingServlet(paths=”/bin/aemfeatures/spellChecker”, metatype=true) @Properties(value = { @Property(label=”dictionary.location”,name = “dictionary.location”, value = “crx-quickstart/conf/en.0″), @Property(label=”phonet.location”,name = “phonet.location”, value = “crx-quickstart/conf/phonet.en”)})

1) Global Spell Checker -: The global spell checker allows you to spell check the whole website in one go. You should have access to latest content package for running this module. The project only works on the publisher instance as for each page a server request is made and dom in parsed and misspelled words are found. The logic to do all the iteration is quite fast. Whole Geometrixx was parsed and spell checked in 20-30 seconds. Once the results are returned all the words with their pages references are downloaded to users computer automatically as csv.

The spell checker was also extended to provide a raw .txt file with comma separated words which will not be returned in the csv list.

2) Page Spell Checker -: It is a single page spell checking mechanism. Whatever misspelled words are found on the page they get highlighted in yellow much like what happens with RTE spell checking utility. All the misspelled words are found first and then Jquery highlighter plugin highlights them in yellow colour on the page.

The code can be downloaded from GITHUB https://github.com/sahilthadhani/cq-aem-spellchecker

The page spell checker works by replacing the buttons or menu in the sidekick/coral UI. Basically, it makes an ajax call to the server to find out the misspelled words and with the help of jquery highlighter plugin highlights them. So here is the code for adding a new button in Sidekick.js file and you just add this button to the list of buttons in sidekick

//Button definition
this.spellCheckButton = new CQ.Ext.Button({
“iconCls”: “cq-sidekick-reload”,
“tooltip”: {
“title”: “spell Check”,
“text”: CQ.I18n.getMessage(“Spell check the page”),
“autoHide”: true
},
“handler”: function() {
var arr = {};
var bodyText = $(‘body’).html();
var bodyFrameText = $(‘iframe’).contents().find(‘body’).html();
if(bodyFrameText.length>bodyText.length){
bodyText=bodyFrameText;
}
arr [‘bodyText’] = bodyText;
$.ajax({
url: “/bin/aemfeatures/spellChecker”,
type: ‘POST’,
data: arr,
async: false,
success:
function(data, textStatus, xhr) {
$(“body”).highlight($.unique(xhr.responseJSON));
$(‘iframe’).contents().find(‘body’).highlight($.unique(xhr.responseJSON), {wordsOnly: true});
},
error:
function(xhr, textStatus, errorThrown) {
$(“#result”).html(“textStatus : ” + textStatus);

}
});
}
});

// Adding the button to the list.

addButtons: function() {
var bbar = this.getBottomToolbar();
bbar.removeAll(true);
bbar.add([
this.editButton,
this.previewButton,
this.spellCheckButton
]);

2) For doing a global spell check a page already exists within the code base /content/aemfeatures/spell-checker-demo.html. Make sure that you run the code on the publisher.

How to check if the page is published? CQ5/AEM

If you want to know if the page is published or not you can use the below utility method to know if the page is published or not

public static Boolean isPublished(Resource resource) {
Boolean activated;
ReplicationStatus status = null;
activated = false;
if (resource != null) {
try {
Page page = resource.adaptTo(Page.class);
status = page.adaptTo(ReplicationStatus.class);
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
}
if (status != null) {
activated = status.isActivated();
}
}
return activated;
}

Configure SSL on Windows/Linux environment CQ5/AEM

I was recently asked to work on https on my local environment of AEM. Since i am using windows, i had a little bit of trouble configuring SSL.

I was following this article http://docs.adobe.com/docs/en/cq/5-6-1/deploying/config-ssl.html to configure SSL over the developer environment. Please see that since it is just a dev environment you don’t need a trust store hence only follow the steps for developer environment.

The only problem was the parameter below

org.apache.felix.https.keystore String [quickstart_dir]/ssl/cqkeystore.keystore

Now, this parameter uses absolute path and not relative. So my windows settings were akin to below. The ssl directory was placed alongside the crx-quickstart and the jar file.  It is very easy to configure SSL. For linux the path can changes to /opt/abc/ssl/cqkeystore.keystore

org.apache.felix.https.keystore String C:/cq/ssl/cqkeystore.keystore

Automate the creation of component and clientlibs in AEM/CQ5

While working for a client, i got a requirement. The requirement was simple they had front end team which was producing angular apps and i had to use the developed app and create an AEM component with clientlibs automatically with all the editing capabilities liked dialog etc. For anyone who isn’t aware about angular app, angular apps are one page apps and they use Angular JS. So for most part except header and footer nothing is going to be shared among all the apps that the front end devs were producing.

The solution that i devised was to use grunt. Grunt has several apis for file manipulation, json iteration etc. While creating the dialogs, i asked the front end devs to provide me a json which i then iterated and successfully produced the dialog.xml.

I also used the js and css that front end produced to produce the clientlib and js.tx and css.txt file. This was all done using grunt. Finally, they also produced html which i had to then parse and convert into sightly compatible html file.

The process took a while to deliver but now there is no upfront cost to the client in terms of having a AEM developer. The front guys can get the component produced by executing just a command.

The implementation was client specific but can help someone in developing something along the lines if there is any such need.

How to Use Jquery with Grunt

I have recently started working with Grunt, i loathed it first but it has many varied uses and i seem to have started liking it.

I was recently working on a requirement where i had to create a AEM component automatically with dialogs and clientlibs. More on this later, in a later post. While implementing the requirement, i wanted to use Jquery on grunt for some dom manipulation.

Here is how you do it.

var doc = jsdom(grunt.file.read(//path to html file));
var window = doc.parentWindow;
var $ = require(‘jquery’)(window);
var bodyText = $(“body”).html();

So, simple. I was reading Stackoverflow and came across fs.readFile and fs.readSyncFile which are async and sync functions but they were not simply working and hence i had to use grunt.file.read function.

Create Maven Project for CQ5/AEM using archetype 7,8

Before, i started working with AEM 6, i was building CQ5 maven project with archetype version ~1.

Recently, i had to setup another project and i did the below steps to produce a maven project. Please note that archetype 7&8 are compatible with AEM 6.

How to Archetype 8 with MAVEN and CQ5

1) Install Maven and configure it with the environment variables etc.

2) Use the latest archetype available at

https://github.com/Adobe-Marketing-Cloud/aem-project-archetype

3) Currently, the latest archetype version available is 8.

4) Before you create an empty project you have to access if you need additional sub modules inside the project. It is always good to create a parent project and add the modules inside them, even if you don’t need them right away. This enables you to add sub modules inside if needed later on.

5) If you want to create a parent module use the command below.

mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=pom-root -DarchetypeVersion=RELEASE

This will generate a folder with a pom file where the packaging type will be pom.

6) Now, go into the directory that you created and run the command below to generate maven project for CQ, you can also generate a project using the command below if needed for dev purposes.

mvn -X archetype:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype -DarchetypeVersion=8 -DarchetypeRepository=adobe-public-releases

Once the project generates, you will see that it gets automatically added to the parent project. Inspect the pom file for changes.

Errors that you might encounter when you create this project

1) content-package-plugin cannot be resolved. I removed the version number and it was downloaded fine from the adobe remote repository.

2) The same can happen for enforcer plugin. Since you can’t browse the maven repository of Adobe on your browser as it is just maven compatible , you will end up experimenting with few versions and plugins.

3) After the project generates, you also need to run mvn clean install and the profile autoInstallPackage. This might generate additional errors. The common one being that it-launcher project will fail every time.  I couldn’t asses if I really needed this project and hence removed it from the pom.xml file module section and removed the directory as well.

Archetype 7 works well without issues and hence is recommended to use. 

Below command will help you generate such a project with AEM and MAVEN and Archetype version 7.

mvn archetype:generate -DgroupId=de.test -DartifactId=testAEM -DarchetypeArtifactId=sample-project-archetype -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeVersion=7 -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/archetype-catalog.xml -DinteractiveMode=true

Prerequisites for maven to work.

You need to have adobe repository reference in your maven settings.xml file.

<profiles>

<profile>

<id>adobe-public</id>

 

<activation>

<activeByDefault>true</activeByDefault>

</activation>

 

<properties>

<releaseRepository-Id>adobe-public-releases</releaseRepository-Id>

<releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>

<releaseRepository-URL>http://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL&gt;

</properties>

<repositories>

<repository>

<id>adobe-public-releases</id>

<name>Adobe Public Repository</name>

<url>http://repo.adobe.com/nexus/content/groups/public</url&gt;

<releases>

<enabled>true</enabled>

<updatePolicy>never</updatePolicy>

</releases>

<snapshots>

<enabled>false</enabled>

</snapshots>

</repository>

</repositories>

 

<pluginRepositories>

<pluginRepository>

<id>adobe-public-releases</id>

<name>Adobe Public Repository</name>

<url>http://repo.adobe.com/nexus/content/groups/public</url&gt;

<releases>

<enabled>true</enabled>

<updatePolicy>never</updatePolicy>

</releases>

<snapshots>

<enabled>false</enabled>

</snapshots>

</pluginRepository>

</pluginRepositories>

</profile>

</profiles>

Jcr Sql 2 vs Xpath queries comparison and point of view CQ5/AEM

I was quite fascinated by the world of XPath and the way i could configure a quick map and pass it to the queryBuilder interface to run a simple query and parse results. All my dreams shattered when i was told Adobe has deprecated the support of XPath queries and you are now required to use the JCR – SQL2 queries. The next search class that i ended up writing was for JCR and all was good until we really started pushing the content. The response time of the queries climbed up rapidly and we started feeling the pain of working with JCR queries.

JCR queries shouldn’t be used at all for multiple paths, by this i mean if you want to search under two different paths with one query you will end up with a very high response times. XPath queries or Query Builder seems to do that fine. For simple queries, you won’t find much difference between the response times of JcrSql queries and Xpath queries but as you build complex queries and adding multiple predicate you will soon start to find yourself in deeper and deeper holes.

For this very reason, i believe Adobe has not been able to deprecate Xpath or Query builder as everything is backwards compatible.

The performance of XPath isn’t very good, if you put it under heavy load but it has to be heavy load more than 500 concurrent search requests or something. The average response times for us for not so complex queries under load were approx 5 seconds under very heavy load for us. We then decided to use listChildren method of Resource interface as this is quite fast. 100x faster and it is not an exaggeration. If you are building such a system, i hope you will get your caching strategies right. Try to save your query results for easier retrieval afterwards and make less number of queries as you can offload a lot of that to the caching server.

So, build your systems with some of advice mentioned above and you should be ok.