Expand my Community achievements bar.

July 31st AEM Gems Webinar: Elevate your AEM development to master the integration of private GitHub repositories within AEM Cloud Manager.
SOLVED

JCR Query API Producing Unexpected XPath

Avatar

Level 4

We have built a REST API backed by the JCR Query API on AEM 5.6.1.  We're seeing a peculiar XPath expression being produced by the PredicateGroupEvaluator, when it uses the underlying JcrTagImpl.TagQueryExpressionBuilder via TagPredicateEvaluator.

Consider these Query Builder servlet request: 

  1. http://localhost:4502/bin/querybuilder.json?type=cq:Page&tagid=workflow:wcm/translation&tagid.proper...
  2. http://localhost:4502/bin/querybuilder.json?type=cq:Page&tagid=workflow:wcm&tagid.property=jcr:conte...
  3. http://localhost:4502/bin/querybuilder.json?type=cq:Page&group.p.or=false&group.1_tagid=workflow:wcm...
  4. http://localhost:4502/bin/querybuilder.json?type=cq:Page&group.p.or=false&group.1_tagid=workflow:dam...
  5. http://localhost:4502/bin/querybuilder.json?type=cq:Page&group.p.or=false&group.1_tagid=workflow:wcm...

Query #1 results in one hit (/etc/workflow/models/translation).  Query #2 filters for the more general workflow:wcm tag and results in four hits.  Query #3 uses a group to AND the previous two queries and should still result in only one hit, since the filter for workflow:wcm/translation still applies.  It actually returns the same four results as query #2.  This becomes even more obvious when you AND two disjoint tags, which should produce no hits, but will actually return the union of the two tags.

This becomes even more obvious when you AND two disjoint tags, which should produce no hits, but will actually return the union of the two tags: Queries #4 and #5 further demonstrate the incorrectness, as they should produce the same result, but they are different and both are incorrect.

 

 

Debugging the PredicateGroupEvaluator at line 104, we can verify that the group is formed correctly, but the multi-predicate expressions produced by the TagPredicateEvaluator get AND-ed without grouping parenthesis, producing the wrong query.

PredicateGroup group=group: or=false[ {1_tagid=tagid: tagid=workflow:wcm, property=jcr:content/cq:tags} {2_tagid=tagid: tagid=workflow:wcm/translation, property=jcr:content/cq:tags} ]
List<String> expressions = [     jcr:content/@cq:tags = 'workflow:wcm' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm' or         jcr:like(jcr:content/@cq:tags, 'workflow:wcm/%') or jcr:like(jcr:content/@cq:tags, '/etc/tags/workflow/wcm/%'),     jcr:content/@cq:tags = 'workflow:wcm/translation' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm/translation' or         jcr:like(jcr:content/@cq:tags, 'workflow:wcm/translation/%') or jcr:like(jcr:content/@cq:tags,         '/etc/tags/workflow/wcm/translation/%') ]
String xpath = "(jcr:content/@cq:tags = 'workflow:wcm' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm' or jcr:like(jcr:content/@cq:tags, 'workflow:wcm/%') or jcr:like(jcr:content/@cq:tags, '/etc/tags/workflow/wcm/%') and jcr:content/@cq:tags = 'workflow:wcm/translation' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm/translation' or jcr:like(jcr:content/@cq:tags, 'workflow:wcm/translation/%') or jcr:like(jcr:content/@cq:tags, '/etc/tags/workflow/wcm/translation/%'))";

Note the improper grouping of the expressions when they are conjoined in the xpath string.  The correct xpath should be:

String xpath = "((jcr:content/@cq:tags = 'workflow:wcm' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm' or jcr:like(jcr:content/@cq:tags, 'workflow:wcm/%') or jcr:like(jcr:content/@cq:tags, '/etc/tags/workflow/wcm/%')) and (jcr:content/@cq:tags = 'workflow:wcm/translation' or jcr:content/@cq:tags = '/etc/tags/workflow/wcm/translation' or jcr:like(jcr:content/@cq:tags, 'workflow:wcm/translation/%') or jcr:like(jcr:content/@cq:tags, '/etc/tags/workflow/wcm/translation/%)))";

Query #3 can also be produced in Java as:

PredicateGroup group = new PredicateGroup(); predicateGroup.setAllRequired(true); predicateGroup.add(new Predicate("tagid") .set("property", "cq:tags") .set("tagid", "example/a")); predicateGroup.add(new Predicate("tagid") .set("property", "cq:tags") .set("tagid", "example/b")); QueryBuilderImpl.createQuery(PredicateGroup, Session);

 

Is this a known issue?  Is there a patch for it?  Fixed in AEM 6?

We have worked around it by wrapping all tagid predicates in their own group, which then gets added to the outer predicateGroup.  The correct solution, however, is probably along the lines of:

// PredicateGroupEvaluator /*  94 */         xpath.append((String)exIter.next()); // Should be /*  -- */         xpath.append(getOpeningBracket()); /*  94 */         xpath.append((String)exIter.next()); /*  -- */         xpath.append(getClosingBracket());

Can you recommend a cleaner solution?

1 Accepted Solution

Avatar

Correct answer by
Level 4

We built this custom implementation over months of deciphering the poorly documented CQ Search API.  It is similar to the QueryBuilder servlet, but with better Predicate configuration and query language, and some custom domain logic.

I have raised the DayCare ticket #68923.  Is there a better channel to raise the issue on?

View solution in original post

3 Replies

Avatar

Level 10

This may be an unknown bug. I would recommend opening a ticket for this issue. 

Also - have you followed an online doc or article for this task or is this your own custom implementation?

Avatar

Correct answer by
Level 4

We built this custom implementation over months of deciphering the poorly documented CQ Search API.  It is similar to the QueryBuilder servlet, but with better Predicate configuration and query language, and some custom domain logic.

I have raised the DayCare ticket #68923.  Is there a better channel to raise the issue on?

Avatar

Level 10

I agree with the fact that we need to improve the Search API functionality content.  I will pass this information to the AEM docs team.

Also the community team will look at helping too by creating content and using an Ask the Experts session around this subject. 

Yeah - you used the correct channel to log the bug. 

Also - I'd recommend opening a bug against the AEM docs too. I would state that more information for Search API/examples is required. 

In meantime - i'd use your workaround. 

The community team will produce a community article around custom Predicates. Still a lot of community members do now know how to do this.