Hello Developers, In this article you will learn all about Resource Resolver & Query Builder in AEM. At the end of this article you can answer these questions: 1) What is Resource Resolver ? 2) What is Query Builder ? 3) What is Resource Resolver Factory ? 4) How can we actually code resource resolver and query builder ? and also we will use these concepts to explain our example.
Resource Resolver In AEM
Resource Resolver is used to resolve Resource
objects and work with such resources like viewing, creating, editing or updating them.
So to understand resource resolver first we need to understand the resolver factory and to understand resolver factory you should have basic understanding of factory design pattern. refer this article to know about factory design pattern.
Basically Resource Resolver Factory is creates Resolver on of basis of AEM configuration, and in AEM case it create JCR. Resource Resolver can easily created by resource.getResourceResolver and from other methods too which is already instantiated during starting of the AEM. And after getting Resource Resolver, we can do further operations like start and stop JCR sessions, osgi services, in servlets and runs our query. We can create/destroy own user service based Resource Resolver.
So when we start our AEM instance Resource resolver factory create resource resolver so that we can adapt and further process our program from that resolver.
How to Get Resource Resolver ( In Sling Model, In Servlet, In OSGI Services and what are the way )
Here I have mention three way to get or create resource resolver in deferent places like in model in servlet or in OSGI service and component.
In Sling Model
1) First way
// what model we are using it takes same resource by the help of Self annotation
@Self
Resource resource;
// after getting resource simply we can take resolver from the by the help of getResourceResolver method
ResourceResolver resolver = resource.getResourceResolver();
2) Second Way
If you are using Resource.class and SlingHttpServletRequest in @Model annotation then we don’t get resolver as other injected values from the dialog.
@Inject
@Source("sling-object")
private ResourceResolver resourceResolver;
@Inject = This annotation is used to inject a property, resource, request, OSGi service.
@Source explicitly tie an injected field or method to a particular injector (by name). can also be on other annotations.
In Servlet
3) Second Way
We can use request variable which is define in doGet and doPost (SlingHttpServletRequest req) and use getResourceResolver method.
private ResourceResolver resourceResolver = req.getResourceResolver();
In OSGI
4) Second Way
Getting Resolver in AEM little different way to restrict user. It means creating resource resolver on the basis of system user. So, we need to do these steps:-
1) Create user and give the permissions as below picture.
system user creation link: http://localhost:4502/crx/explorer/index.jsp
Now assign permission to the user which is created just now and for setting permission you go here: http://localhost:4502/useradmin
now search user and select and then gives permissions and then save it. (Like I have given content access to read, modify, create etc)
2) Map these user in the “Apache Sling Service User Mapper Service”. http://localhost:4502/system/console/configMgr
search User Mapper and configure : <bundle symbolic name>:<any name of service>=<system user id>
and then run this below code, but it is better to create separate class and method for resolver creation and whenever required the resolver simply call the method by pass reference of the FactoryResourceResolver.
@Reference
private ResourceResolverFactory resourceResolverFactory;
public static final String RESOURCE_USER = "demoshahidtest";
final Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put(ResourceResolverFactory.SUBSERVICE, RESOURCE_USER);
// fetches the admin service resolver using service user.
ResourceResolver resolver = resourceResolverFactory.getServiceResourceResolver(paramMap);
Now after getting Resource Resolver we can do our query related task easily.
Query Builder In AEM
Query Builder is highly recommended over simple SQL / XPATH query statements. In AEM, information is stored in a structural format as resource, attributes, and values. Query Builder API is like SQL Query where queries are executed to fetch structural data. Query Builder consists of a statement that includes predicates, expression, and clauses similar to SQL statements. The best way to create predicates is using the Query Builder Debugging Tool : /libs/cq/search/content/querydebug.html. Here you can Try to implement your Business use case in the Predicate form using this debugger, Optimize the query and then implement it in the code.
The above query builder UI is used to test our query and then we can use it in our code.
Some Standard Predicates
path=/ here we can define path which is use to search under a particular hierarchy only
type It is used for searching for a particular nodetype only.
property This is used to search for a specific property only.
p.limit : Limits the number of search results fetched.
p.offset : Sets the offset for the search results
and so on. refer this for more predicates
Required Services, Classes, Interfaces For Query Builder
ResourceResolver as we read above to perform any task related resource we need resolver.
@Reference
QueryBuilder queryBuilder; QueryBuilder is a service for building Queries
searching the Java Content Repository and which are easily extensible. and Used Reference annotation defines references to other services made available to the component by the Service Component Runtime. If you are using it in model please use adapt method with resource resolver and remove reference annotation.
Session Session; It is an Interface. The Session
object provides read and (in level 2) write access to the content of a particular workspace in the repository. and need to adapt class with resource resolver.
Map<String, String> predicate = new HashMap<>(); For creating predicates(xpath query)
Query query; A Query
represents a JCR repository query that can be created programmatically, with a list of so-called Predicates
.
SearchResult SearchResult
represents a search result of a JCR query, returned by Query
and SimpleSearch
.
getHits() method return a List of Hit
s to display on the result page.
Page Defines the interface of a CQ WCM Page. to more understand
These are essential requirements for getting details from page type resources. Please see below example and look at explanation that how can we create query builder in aem which return page details(title, des, link etc).
Use Case Example For Query Builder
Creating a servlet which return page( title, description, and path link ) in JSON format with the help of Query Builder
look at the below code and explanations:
package com.adobe.aem.guides.wknd.core.servlets; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import com.day.cq.wcm.api.Page; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.apache.sling.servlets.annotations.SlingServletPaths; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import javax.servlet.Servlet; import javax.servlet.ServletException; import java.io.IOException; import com.day.cq.search.PredicateGroup; import com.day.cq.search.Query; import com.day.cq.search.QueryBuilder; import com.day.cq.search.result.Hit; import com.day.cq.search.result.SearchResult; import java.util.HashMap; import java.util.Map; import javax.jcr.RepositoryException; import javax.jcr.Session; @Component(service = Servlet.class) @SlingServletPaths(value = { "/bin/pagesloader" }) public class MyPageLoader extends SlingAllMethodsServlet { @Reference QueryBuilder queryBuilder; Session session; JsonArray jsonArray = new JsonArray(); JsonObject jsonObject = new JsonObject(); @Override protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws ServletException, IOException { String id = req.getParameter("apikey"); if (id != null) { if (id.equals("shahidaem")) { ResourceResolver resourceResolver = req.getResourceResolver(); session = resourceResolver.adaptTo(Session.class); // predicates which is refer to our query Map<String, String> predicate = new HashMap<>(); predicate.put("path", "/content/wknd/us/en/blogs"); predicate.put("type", "cq:Page"); Query query = null; try { query = queryBuilder.createQuery(PredicateGroup.create(predicate), session); } catch (Exception e) { // LOGGER.error("Error in Query Check kr le bhai try block me: Shahid bhai bol // rha"); } SearchResult searchResult = query.getResult(); for (Hit hit : searchResult.getHits()) { String path = null; JsonObject tempObj = new JsonObject(); try { path = hit.getPath(); Resource articlResource = resourceResolver.getResource(path); Page articlPage = articlResource.adaptTo(Page.class); String title = articlPage.getTitle(); String description = articlPage.getDescription(); tempObj.addProperty("title", title); tempObj.addProperty("description", description); tempObj.addProperty("link", path + ".html"); jsonArray.add(tempObj); } catch (RepositoryException e) { throw new RuntimeException(e); } } jsonObject.add("data", jsonArray); } else { jsonObject.addProperty("data", "Invalid parameter! please ask to admin for apikey value=" + id); } } else { jsonObject.addProperty("data", "Invalid URL and Key & Parameter! Please Check "); } resp.setContentType("application/json"); resp.getWriter().print(jsonObject); } }
Lets Understand above code line by line:
If you don not know about servlet in AEM, please first read servlet first then only you will understand
We have created predicate for page details and provide path. Under this path we have pages.
We have used SlingHttpServletRequest req, for getting resource resolver and adapt session class with the help resolver then created our query with predicates and session and build with querybuilder and then used searchresult for getting result from the query then with the help of for-each loop method and Hit we are able to go one by one resources. Again with getPath method we have specified path and then take that path resource Page type and finally get their properties value. After all the processes we have used JsonObject and JsonArray to make all result in JSON format and then simply print that JSON as responses. we have used parameter also to verify
Links and their conditions blocks(result)
http://localhost:4502/bin/pagesloader?apikey=shahidaem : here we will show result as below correct output picture
pass wrong parameter http://localhost:4502/bin/pagesloader?apikey=shahidaemfghj then we have simply printed: Invalid parameter! please ask to admin for apikey value=shahidaemfghj
and if URL is wrong or name(apikey) is wrong: http://localhost:4502/bin/pagesloader?adpidxckey=shahidaem
These all are optional we can simple write our query builder code without any if else blocks, as I have created for good practice for creating api’s
Any Question? Feel free to ask
Thankyou
Happy Coding