Expand my Community achievements bar.

SOLVED

AEM 6.4.8.3 Unclosed resourceResolver from custom service in logs

Avatar

Level 2

We are closing the service RR in the finally block still we get the unclosed RR in logs for below method.
This post has additional logic as a workaround to manually close the ResourceResolver after processing the query result. 
Ques1) Do I need to do this extra workaround code for my method below.

Please find method below with additional workaround, currently stuck with converting node to a resource. 
Ques2) Do we know how we can convert node to a resource 
 Resource closeableResource = adapterManager.getAdapter(closeableNode, Resource.class); // gives null resource

Sample code from method below:

import javax.jcr.query.Query; import javax.jcr.query.QueryResult;

ResourceResolver resolver = null;
try { resolver = getResourceResolver(ServiceUser.READ_ONLY_SERVICE.toString());
final Session session = resolver.adaptTo(Session.class);
final Query query = session.getWorkspace().getQueryManager().createQuery("/jcr:root" + nodePath + "/element(*,nt:base)[sling:resourceType='proj/components/page'] order by @" + PROPERTY_PUBDATE_NAME + " descending", Query.XPATH);
query.setLimit(75);
final QueryResult result = query.execute();
if (result != null && result.getNodes() != null) {
final NodeIterator nodeIterator = result.getNodes();
while (nodeIterator.hasNext()) {
pagePath = null; templateTitle = null; Calendar releaseDate = null;
final Node node = nodeIterator.nextNode();
if (node != null) {
final Map<String, Object> nodePropertyMap = new HashMap<String, Object>();
if (node.hasProperty(PROPERTY_JCR_TITLE)) {
templateTitle = node.getProperty(PROPERTY_JCR_TITLE).getString(); nodePropertyMap.put(PROPERTY_JCR_TITLE, templateTitle);
} if (node.hasProperty(PROPERTY_PUBDATE_NAME)) {
releaseDate = node.getProperty(PROPERTY_PUBDATE_NAME).getDate(); nodePropertyMap.put(PROPERTY_PUBDATE_NAME, releaseDate);
} pagePath = node.getPath();
nodePropertyMap.put("path", pagePath);
dataList.add(nodePropertyMap); } }

//workaround added below https://helpx.adobe.com/au/experience-manager/kb/Unclosed-ResourceResolver-warnng-at-com-day-cq-sear...
final NodeIterator closeableNodeIterator = result.getNodes();
if(Objects.nonNull(closeableNodeIterator)){
while (closeableNodeIterator.hasNext()) {
final Node closeableNode = closeableNodeIterator.nextNode();
if(Objects.nonNull(adapterManager)){
// https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/how-to-convert-a-node-to-a...
Resource closeableResource = adapterManager.getAdapter(closeableNode, Resource.class); 

if(Objects.nonNull(closeableResource)){ 
closeableResource.getResourceResolver().close(); } } } } }
} catch (final RepositoryException e) { logger.error(e.getMessage());
} finally { if (null != resolver) { resolver.close(); }
} return dataList;

@Jörg_Hoh 

 
1 Accepted Solution

Avatar

Correct answer by
Employee

The linked post is specific to the QueryBuilder. This code does not use QueryBuilder and thus does not apply here. The code is a bit hard to read due to lack of formatting, but this is what this code should look like (making a few guesses):

 

 

List<Map<String, Object> dataList = new ArrayList<>();
ResourceResolver resolver = null;
try {
    resolver = resourceResolverFactory.getServiceResourceResolver(Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, ServiceUser.READ_ONLY_SERVICE.toString());
    final Session session = resolver.adaptTo(Session.class);
    final Query query = session.getWorkspace().getQueryManager().createQuery("/jcr:root" + nodePath + "/element(*,nt:base)[sling:resourceType='proj/components/page'] order by @" + PROPERTY_PUBDATE_NAME + " descending", Query.XPATH);
    query.setLimit(75);
    final QueryResult result = query.execute();
    if (result != null && result.getNodes() != null) {
        final NodeIterator nodeIterator = result.getNodes();
        while (nodeIterator.hasNext()) {
            final Node node = nodeIterator.nextNode();
            if (node != null) {
                final Map<String, Object> nodePropertyMap = new HashMap<>();
                if (node.hasProperty(PROPERTY_JCR_TITLE)) {
                    nodePropertyMap.put(PROPERTY_JCR_TITLE, node.getProperty(PROPERTY_JCR_TITLE).getString());
                }
                if (node.hasProperty(PROPERTY_PUBDATE_NAME)) {
                    nodePropertyMap.put(PROPERTY_PUBDATE_NAME, node.getProperty(PROPERTY_PUBDATE_NAME).getDate());
                }
                nodePropertyMap.put("path", node.getPath());
                dataList.add(nodePropertyMap);
            }
        }
    }
} catch (final RepositoryException e) {
    logger.error(e.getMessage());
} finally {
    if (null != resolver) {
        resolver.close();
    }
}
return dataList;

 

 

It would, of course, be better to use try-with-resources, but I didn't do that in this example because I wasn't sure that was available in 6.4.8, but per @Jörg_Hoh 's comment it is.

 

When a ResourceResolver is left unclosed, the logged stack trace will point to exactly where the ResourceResolver was created (which you can actually see an example of in the linked post about the QueryBuilder). 

View solution in original post

2 Replies

Avatar

Correct answer by
Employee

The linked post is specific to the QueryBuilder. This code does not use QueryBuilder and thus does not apply here. The code is a bit hard to read due to lack of formatting, but this is what this code should look like (making a few guesses):

 

 

List<Map<String, Object> dataList = new ArrayList<>();
ResourceResolver resolver = null;
try {
    resolver = resourceResolverFactory.getServiceResourceResolver(Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, ServiceUser.READ_ONLY_SERVICE.toString());
    final Session session = resolver.adaptTo(Session.class);
    final Query query = session.getWorkspace().getQueryManager().createQuery("/jcr:root" + nodePath + "/element(*,nt:base)[sling:resourceType='proj/components/page'] order by @" + PROPERTY_PUBDATE_NAME + " descending", Query.XPATH);
    query.setLimit(75);
    final QueryResult result = query.execute();
    if (result != null && result.getNodes() != null) {
        final NodeIterator nodeIterator = result.getNodes();
        while (nodeIterator.hasNext()) {
            final Node node = nodeIterator.nextNode();
            if (node != null) {
                final Map<String, Object> nodePropertyMap = new HashMap<>();
                if (node.hasProperty(PROPERTY_JCR_TITLE)) {
                    nodePropertyMap.put(PROPERTY_JCR_TITLE, node.getProperty(PROPERTY_JCR_TITLE).getString());
                }
                if (node.hasProperty(PROPERTY_PUBDATE_NAME)) {
                    nodePropertyMap.put(PROPERTY_PUBDATE_NAME, node.getProperty(PROPERTY_PUBDATE_NAME).getDate());
                }
                nodePropertyMap.put("path", node.getPath());
                dataList.add(nodePropertyMap);
            }
        }
    }
} catch (final RepositoryException e) {
    logger.error(e.getMessage());
} finally {
    if (null != resolver) {
        resolver.close();
    }
}
return dataList;

 

 

It would, of course, be better to use try-with-resources, but I didn't do that in this example because I wasn't sure that was available in 6.4.8, but per @Jörg_Hoh 's comment it is.

 

When a ResourceResolver is left unclosed, the logged stack trace will point to exactly where the ResourceResolver was created (which you can actually see an example of in the linked post about the QueryBuilder). 

Avatar

Employee Advisor
The ResourceResolver implements AutoClosable for quite some time, and the AEM 6.4 definitely ships with that ability.