6
votes

I read a lot of articles like JCR vs Apache Sling and I'm confused about what to use. Some authors advise to use JCR API like more performance optimized and the rest are on the side of Apache Sling because it's faster to write and far more readable and maintainable in the long run. And I had some questions:

  • What practice is better from your point of view?
  • What is more often used in production projects?
2

2 Answers

6
votes

I think Maciej Matuszewski exhausted this subject enough in his presentation JCR, Sling or AEM? Which API should I use and when?.

In most of the cases, it is recommended to use Apache Sling as a higher API whereas JCR is required when performance needs to be taken into account. It is then important however to know the border between these two scenarios.

Maciej notices it is around 1ms difference for opening the regular AEM page without taking any caching into account. Taking care of the performance is totally unnecessary in that case. We should instead focus on writing code that is readable, understandable, reduced to the minimum and reusing already existing APIs, frameworks, util classes that are covered already by proper unit tests and peer reviewed, rather than reinventing the wheel from the beginning. Base on that, we should also prefer AEM layer over Sling layer.

From my experience, I would say that JCR should be utilized in few scenarios, mainly when traversing of a large amount of data of CRX database and it cannot be achieved by any searching API.

So that the difference is like between using C# or C++ as a programming language for computer games development - in some of the cases it is enough to stay higher API for development convenience however for some cases it is required to get lower and start using C++ pointers.

However, the most important thing is to not mix both abstract layers in your implementation.

1
votes

To start with a very typical answer, 'IT DEPENDS'.

Consider the following scenarios for your understanding:

Scenario 1: Read the title of the page which is containing the current resource.

Approach 1: Leverage the awesome Sling API's to work upon all the available context objects like currentPage, resource, pageManager, wcmmode and many more in your Java controller (Sling Model/ WCMUSe class).

// get the page that contains this resource.
// If the resource is a page the resource is returned. Otherwise it 
// walks up the parent resources until a page is found.
Page page = pageManager.getContainingPage(resource);

// Check if the returned page object isn't null
if(page != null){
    return page.getTitle();
}

Approach 2: Use the JCR API's:

// assign the current resource node to parent Node to check 
// if the current resoure in itself is a page
Node parentNode = currentNode;
while (parentNode.getProperty("jcr:PrimaryTpe").getString() != "cq:Page" ){
    parentNode = parentNode.getParent();
}
// The page Title
String pageTitle = null;

// find the jcr:content node of the page and return the 
// jcr:title property of that node
if(parentNode.hasNode("jcr:content"){
    Node jcrContentNode = parentNode.getNode("jcr:Content");
    pageTitle = jcrContentNode.getProperty("jcr:title").getValue().getString();
} 
 return pageTitle;

In this scenario, obviously the Sling API's win by a huge margin on the ease of access and usability. I have never experienced any performance issue with the Sling APIs in comparison to the JCR APIs.

Scenario 2: Change the title of the first level page nodes (considering /content/mywebsite/en to be level ZERO) of your website to Upper Case letters.

Approach: In such a requirement where you need to do certain one-time changes to your JCR repository, you should use the JCR APIs by creating a Standalone Java Application to perform such tasks instead of creating an unnecessary component, its controller, an unnecessary page to put this component and then using the Sling API's in the controller to perform these tasks.

//Create a connection to the CQ repository running on local host 
Repository repository = JcrUtils.getRepository("http://localhost:4502/crx/server");

//Create a Session
Session session = repository.login( new SimpleCredentials("username", "password".toCharArray()),"crx.default");

//Create a node that represents the root node
Node root = session.getRootNode(); 

// Get the level ZERO node
Node homepageNode = root.getNode("/content/mywebsite/en");

NodeIterator iter = homePageNode.getNodes;
while(iter.hasNext){
    // if next node is of primarty type cq:Page
    // get its jcr:content node and 
    // set its jcr:title property to uppercase letters.
}

Rule of Thumb:

If you want access to your AEM repository from within the AEM application use Sling APIs over JCR APIs they are:

  1. higher APIs than JCR (have a lot of predefined methods to do a lot of work)
  2. provide access to all the Global Context objects inside the controller
  3. very easy to use

but in case if you need to accces your repository for large scale opertaions, (generally one time changes) choose to work with a standalone Java application using the JCR APIs.