Expand my Community achievements bar.

SOLVED

How to create jcr based resourceresolver instance?

Avatar

Level 7

Hi I want to use resource resolver in jcr session to call querybuilder api.

Please help in creating resourceresolver instance using jcr session.

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

Is there any specific reason you want to follow that approach as you have mentioned in your problem statement?

You can call or inject QueryBuilder API using @ Reference annotation as shown below -

 

/**
 * 
 */
package com.aem.demo.core.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

import javax.jcr.Session;
import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.demo.core.services.WriteDataToFile;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.google.common.base.Strings;

/**
 * @author debal
 * 
 *         This servlet is used to generate report associated with activated
 *         page or activated assets only Report will be generated for AEM sites
 *         under specific content path
 */
@Component(service = Servlet.class, property = { "sling.servlet.paths=" + "/bin/reports/resource",
		"sling.servlet.methods=" + HttpConstants.METHOD_POST })
public class ResourceResportServlet extends SlingAllMethodsServlet {

	private final Logger logger = LoggerFactory.getLogger(ResourceResportServlet.class);

	private static final long serialVersionUID = 8383266648883534070L;
	@Reference
	private QueryBuilder queryBuilder;

	@Reference
	WriteDataToFile writeDataToFile;

	protected void doPost(SlingHttpServletRequest slingHttpServletRequest,
			SlingHttpServletResponse slingHttpServletResponse) {

		int rowNumber = 0;
		Map<String, String> map = new HashMap<String, String>();
		Map<Integer, String> resourceMap = new TreeMap<>();
		String resourceSearchPath = slingHttpServletRequest.getParameter("searchPath");
		String lastReplicatedDate = slingHttpServletRequest.getParameter("lastPublishedDate");
		logger.info("**** Report generation has been initiated under {}" + resourceSearchPath);
		logger.info("**** Report generation has been generated from {}" + lastReplicatedDate);

		String rseourceType = null;

		if (!Strings.isNullOrEmpty(resourceSearchPath) && !Strings.isNullOrEmpty(lastReplicatedDate)) {

			try (ResourceResolver resourceResolver = slingHttpServletRequest.getResourceResolver()) {

				Session session = resourceResolver.adaptTo(Session.class);

				Resource resource = resourceResolver.getResource(resourceSearchPath);

				if (Objects.nonNull(resource)) {

					String resourcepath = resource.getPath();
					if (resource.isResourceType("cq:Page")) {
						rseourceType = "cq:Page";
					} else if (resourcepath.contains("/dam/")) {
						rseourceType = "dam:Asset";
					}

					logger.info("**** Resource Type {}" + rseourceType);
					/*
					 * create query description as hash map (simplest way, same as form post)
					 */
					map.put("path", resourceSearchPath.trim());
					map.put("type", rseourceType.trim());

					map.put("1_property", "jcr:content/cq:lastReplicationAction");
					map.put("1_property.value", "Activate");
					map.put("2_daterange.property", "jcr:content/cq:lastReplicated");
					map.put("2_daterange.lowerBound", lastReplicatedDate);
					map.put("p.limit", "-1");

					Query searchquery = queryBuilder.createQuery(PredicateGroup.create(map), session);

					

					SearchResult searchResult = searchquery.getResult();
					logger.info("**** Number of Total Matches {}" + searchResult.getTotalMatches());
					Iterator<Resource> resources = searchResult.getResources();
					while (resources.hasNext()) {

						Resource searchResultResource = resources.next();

						String searchrseourcePath = searchResultResource.getPath();
						slingHttpServletResponse.getWriter().write(searchrseourcePath);
						resourceMap.put(rowNumber++, searchrseourcePath);

					}
					writeDataToFile.addDataToFile(resourceMap, slingHttpServletResponse);
				}

			} catch (IOException e) {

				e.printStackTrace();
			}
			;
		}

	}

 

 You could follow below steps also -

 

1. Create ResourceResover using ResourceResolverFactory and service user as shown below and define the entire logic in a separate utility interface and implementation class as shown below  -

/**
 * 
 */
package com.aem.demo.core.services;

import org.apache.sling.api.resource.ResourceResolver;

/**
 * @author debal
 * 
 *         This service will be used as a utility and it will help us to get
 *         resource resolver object , JCR session and close resource resolver
 *
 */
public interface JcrUtility {

	public ResourceResolver getResourceResolver();

	public void closeResourceResolver(ResourceResolver resourceResolver);
}

 

/**
 * 
 */
package com.aem.demo.core.services.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.demo.core.services.JcrUtility;

/**
 * @author debal
 *
 */
@Component(service = JcrUtility.class, immediate = true) 
public class JcrUtilityImpl implements JcrUtility {

	private final Logger logger = LoggerFactory.getLogger(JcrUtilityImpl.class);

	@Reference
	ResourceResolverFactory resourceResolverFactory;

	@Override
	public ResourceResolver getResourceResolver() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(resourceResolverFactory.SUBSERVICE, "readWriteService");
		ResourceResolver serviceResourceResolver = null;
		try {

			serviceResourceResolver = resourceResolverFactory.getServiceResourceResolver(map);
		} catch (LoginException e) {
			logger.error("Could not get service user [ {} ]", "demoSystemUser", e.getMessage());
		}
		return serviceResourceResolver;

	}

	@Override
	public void closeResourceResolver(ResourceResolver resourceResolver) {
		if (Objects.nonNull(resourceResolver)) {
			resourceResolver.close();
		}

	}

}

This will be an OSGi service.

2. Create a service user and assign requisite permission to that service user and do a service mapping as shown below -

 

DEBAL_DAS_0-1658048944810.png

3.   Get the ResourceResolver instance via that OSGi service [created in step:1] like 

      @ Reference

       JcrUtility jcrUtility;

       ResourceResolver resourceResolver = jcrUtility.getResourceResolver();

 

      Get the Session using ResourceResolver as shown below -

      Session session = resourceResolver.adaptTo(Session.class); 

     

       Now inject QueryBuilder API using @ Reference annotation as shown below -

       @ Reference
       private QueryBuilder queryBuilder;

 

      Finally your query part something like below one -

 

     

map.put("path", resourceSearchPath.trim());
map.put("type", rseourceType.trim());

map.put("1_property", "jcr:content/cq:lastReplicationAction");
map.put("1_property.value", "Activate");
map.put("2_daterange.property", "jcr:content/cq:lastReplicated");
map.put("2_daterange.lowerBound", lastReplicatedDate);
map.put("p.limit", "-1");

Query searchquery = queryBuilder.createQuery(PredicateGroup.create(map), session);

View solution in original post

2 Replies

Avatar

Community Advisor

Hi @akshaybhujbale 

 

Session and ResourceResolver objects that are obtained via the SlingRequest or WorkflowSession do not close by your application.  For example:

slingRequest.getResourceResolver().adaptTo(Session.class);
//Or
workflowSession.getSession();

That resolver or session closes automatically after the request has been processed.

 

https://helpx.adobe.com/experience-manager/kb/Random-Resource-resolver-is-already-closed-in-the-logs...

 

Avatar

Correct answer by
Employee Advisor

Is there any specific reason you want to follow that approach as you have mentioned in your problem statement?

You can call or inject QueryBuilder API using @ Reference annotation as shown below -

 

/**
 * 
 */
package com.aem.demo.core.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

import javax.jcr.Session;
import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.demo.core.services.WriteDataToFile;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;
import com.google.common.base.Strings;

/**
 * @author debal
 * 
 *         This servlet is used to generate report associated with activated
 *         page or activated assets only Report will be generated for AEM sites
 *         under specific content path
 */
@Component(service = Servlet.class, property = { "sling.servlet.paths=" + "/bin/reports/resource",
		"sling.servlet.methods=" + HttpConstants.METHOD_POST })
public class ResourceResportServlet extends SlingAllMethodsServlet {

	private final Logger logger = LoggerFactory.getLogger(ResourceResportServlet.class);

	private static final long serialVersionUID = 8383266648883534070L;
	@Reference
	private QueryBuilder queryBuilder;

	@Reference
	WriteDataToFile writeDataToFile;

	protected void doPost(SlingHttpServletRequest slingHttpServletRequest,
			SlingHttpServletResponse slingHttpServletResponse) {

		int rowNumber = 0;
		Map<String, String> map = new HashMap<String, String>();
		Map<Integer, String> resourceMap = new TreeMap<>();
		String resourceSearchPath = slingHttpServletRequest.getParameter("searchPath");
		String lastReplicatedDate = slingHttpServletRequest.getParameter("lastPublishedDate");
		logger.info("**** Report generation has been initiated under {}" + resourceSearchPath);
		logger.info("**** Report generation has been generated from {}" + lastReplicatedDate);

		String rseourceType = null;

		if (!Strings.isNullOrEmpty(resourceSearchPath) && !Strings.isNullOrEmpty(lastReplicatedDate)) {

			try (ResourceResolver resourceResolver = slingHttpServletRequest.getResourceResolver()) {

				Session session = resourceResolver.adaptTo(Session.class);

				Resource resource = resourceResolver.getResource(resourceSearchPath);

				if (Objects.nonNull(resource)) {

					String resourcepath = resource.getPath();
					if (resource.isResourceType("cq:Page")) {
						rseourceType = "cq:Page";
					} else if (resourcepath.contains("/dam/")) {
						rseourceType = "dam:Asset";
					}

					logger.info("**** Resource Type {}" + rseourceType);
					/*
					 * create query description as hash map (simplest way, same as form post)
					 */
					map.put("path", resourceSearchPath.trim());
					map.put("type", rseourceType.trim());

					map.put("1_property", "jcr:content/cq:lastReplicationAction");
					map.put("1_property.value", "Activate");
					map.put("2_daterange.property", "jcr:content/cq:lastReplicated");
					map.put("2_daterange.lowerBound", lastReplicatedDate);
					map.put("p.limit", "-1");

					Query searchquery = queryBuilder.createQuery(PredicateGroup.create(map), session);

					

					SearchResult searchResult = searchquery.getResult();
					logger.info("**** Number of Total Matches {}" + searchResult.getTotalMatches());
					Iterator<Resource> resources = searchResult.getResources();
					while (resources.hasNext()) {

						Resource searchResultResource = resources.next();

						String searchrseourcePath = searchResultResource.getPath();
						slingHttpServletResponse.getWriter().write(searchrseourcePath);
						resourceMap.put(rowNumber++, searchrseourcePath);

					}
					writeDataToFile.addDataToFile(resourceMap, slingHttpServletResponse);
				}

			} catch (IOException e) {

				e.printStackTrace();
			}
			;
		}

	}

 

 You could follow below steps also -

 

1. Create ResourceResover using ResourceResolverFactory and service user as shown below and define the entire logic in a separate utility interface and implementation class as shown below  -

/**
 * 
 */
package com.aem.demo.core.services;

import org.apache.sling.api.resource.ResourceResolver;

/**
 * @author debal
 * 
 *         This service will be used as a utility and it will help us to get
 *         resource resolver object , JCR session and close resource resolver
 *
 */
public interface JcrUtility {

	public ResourceResolver getResourceResolver();

	public void closeResourceResolver(ResourceResolver resourceResolver);
}

 

/**
 * 
 */
package com.aem.demo.core.services.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aem.demo.core.services.JcrUtility;

/**
 * @author debal
 *
 */
@Component(service = JcrUtility.class, immediate = true) 
public class JcrUtilityImpl implements JcrUtility {

	private final Logger logger = LoggerFactory.getLogger(JcrUtilityImpl.class);

	@Reference
	ResourceResolverFactory resourceResolverFactory;

	@Override
	public ResourceResolver getResourceResolver() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(resourceResolverFactory.SUBSERVICE, "readWriteService");
		ResourceResolver serviceResourceResolver = null;
		try {

			serviceResourceResolver = resourceResolverFactory.getServiceResourceResolver(map);
		} catch (LoginException e) {
			logger.error("Could not get service user [ {} ]", "demoSystemUser", e.getMessage());
		}
		return serviceResourceResolver;

	}

	@Override
	public void closeResourceResolver(ResourceResolver resourceResolver) {
		if (Objects.nonNull(resourceResolver)) {
			resourceResolver.close();
		}

	}

}

This will be an OSGi service.

2. Create a service user and assign requisite permission to that service user and do a service mapping as shown below -

 

DEBAL_DAS_0-1658048944810.png

3.   Get the ResourceResolver instance via that OSGi service [created in step:1] like 

      @ Reference

       JcrUtility jcrUtility;

       ResourceResolver resourceResolver = jcrUtility.getResourceResolver();

 

      Get the Session using ResourceResolver as shown below -

      Session session = resourceResolver.adaptTo(Session.class); 

     

       Now inject QueryBuilder API using @ Reference annotation as shown below -

       @ Reference
       private QueryBuilder queryBuilder;

 

      Finally your query part something like below one -

 

     

map.put("path", resourceSearchPath.trim());
map.put("type", rseourceType.trim());

map.put("1_property", "jcr:content/cq:lastReplicationAction");
map.put("1_property.value", "Activate");
map.put("2_daterange.property", "jcr:content/cq:lastReplicated");
map.put("2_daterange.lowerBound", lastReplicatedDate);
map.put("p.limit", "-1");

Query searchquery = queryBuilder.createQuery(PredicateGroup.create(map), session);