Expand my Community achievements bar.

SOLVED

Sling models and resource resolver- AutoClosable?

Avatar

Level 10

Hi all,

on  AEM 6.5.12

i May have asked this question but maybe to get a confirmation if I have a sling model and adapt to Resource.class , 

In it I have @inject for resourceresolver . 
i use it in one of the getter methods as resourceResolver.map(path) . I am not using post constructs 


do I have to close the resource resolver at any point in a sling model class ? Does it automatically close it at the end of the usage of model class ? Trying to avoid session leaks.

 

 I am not passing the resource resolver to any class but using it for map however I even have some logic for externalizing post mapping 

the customExternalizerService has another service resolver that opens where path is sent over. Model’s resolver is not passed 



 

@Model(adaptables = Resource.class)
public class PageModel {

@Self
private Resource resource 

 

@inject

private ResourceResolver resolver;

 

@inject

private customExternalizerService customExternalizerService;

 

private String extPageUrl;



public String getExtPageUrl() {
PageManager pageManager= resolver.adaptTo(PageManager.class);
Page currentPage = pageManager.getContainingPage(resource);
this. extPageUrl = customExternalizerService.externalize(resolver.map(currentPage.getPath());
return this.extPageUrl;
}

}

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @NitroHazeDev,

There is no need to close ResourceResolver injected that way into Sling Model, or retrieved via request.getResourceResolver(), request.adaptTo(ResourceResolver.class) or resource.getResourceResolver().

In above case you are not creating new instance of ResourceResolver this is why you do not have to close it explicitly.

However you will have to close ResourceResolver in Sling Model if you will create new instance of it using ResourceResolverFactory.

One remark to your implementation. I would suggest to use specific annotation/injector to get ResourceResolver object. It is also mentioned under Sling documentation

 

// use
@SlingObject
private ResourceResolver resourceResolver;

// instead of
@Inject
private ResourceResolver resourceResolver;

 

 This is recommended due to performance reasons, more can be found under:

View solution in original post

11 Replies

Avatar

Correct answer by
Community Advisor

Hi @NitroHazeDev,

There is no need to close ResourceResolver injected that way into Sling Model, or retrieved via request.getResourceResolver(), request.adaptTo(ResourceResolver.class) or resource.getResourceResolver().

In above case you are not creating new instance of ResourceResolver this is why you do not have to close it explicitly.

However you will have to close ResourceResolver in Sling Model if you will create new instance of it using ResourceResolverFactory.

One remark to your implementation. I would suggest to use specific annotation/injector to get ResourceResolver object. It is also mentioned under Sling documentation

 

// use
@SlingObject
private ResourceResolver resourceResolver;

// instead of
@Inject
private ResourceResolver resourceResolver;

 

 This is recommended due to performance reasons, more can be found under:

Avatar

Level 10

Thanks @lukasz-m  , glad to know I don’t need to close it , I was sure but wanted to confirm for sling models . Will work towards using slingobject for resource resolver. Do I  have to use slingobject vs inject for custom services written in our case the customExternalizerService? 

when you say “creating” resource resolver is it via the try block or service user accounts ? 

If there is a session leak it should be evident in the logs with the sling model name and unclosed session isn’t it ? 

Also, use of @slingObject , have you used it? Does it lead to troubles like this post ?
https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/open-sessions-jmx/m-p/2779...

Avatar

Community Advisor

Hello @NitroHazeDev 

 

Q. when you say “creating” resource resolver is it via the try block or service user accounts ? 

A. Please refer to https://cqdump.joerghoh.de/2018/11/14/try-with-resource-or-i-will-never-forget-to-close-a-resource-r... 

If a new resourceresolver has been created explicitly via "resourceResolverFactory" in any way, it should be closed.

 

Q. If there is a session leak it should be evident in the logs with the sling model name and unclosed session isn’t it ? 

A. For analysing unclosed sessions. Please refer to https://helpx.adobe.com/in/experience-manager/kb/AnalyzeUnclosedSessions.html 

https://experienceleague.adobe.com/docs/experience-cloud-kcs/kbarticles/KA-16548.html?lang=en 

 

 


Aanchal Sikka

Avatar

Level 10

Thanks @aanchal-sikka  but would it not be available in the logs with the model class name?
I might need some assistance when i try this, will update. if you have screenshots or so please do suggest for the debugging.

Avatar

Employee Advisor

if you don't explicitly open a ResourceResolver (by using one of the methods of the ResourceResolverFactory) you should not close a ResourceResolver.

See https://cqdump.joerghoh.de/2018/11/12/resourceresolvers-and-sessions-you-open-it-you-close-it/

Avatar

Level 10

@Jörg_Hoh 
Does below look ok to you overall wrt resource resolver and rest?
I only open the resource resolver in the custom externalizer class using service user account for additional processing etc

I put the methods in init class so as to avoid method(not init) twice if i just use the getter methods.We have a weird system where old page components may still be in use in terms of inheritance and wcmusepojo as well unfortunately, that is due for updates

 

@Model(adaptables = Resource.class)
public class PageModel{

@Self
private Resource resource;

 

@Inject
@Optional
@Named("image/fileReference")
private String thumbUrl;

 

@OSGiService
private ExternalizerService externalizerService; //custom service injected

@SlingObject
private ResourceResolver resolver;

private String extThumbnailUrl;
private String extPageUrl;


public String getThumbUrl) {
   return thumbUrl;
}

public void setThumbUrl(String thumbUrl){
     this.thumbUrl = thumbUrl;
}

@PostConstruct
protected void init() {
logger.info("in activate method");
if(StringUtils.isNotBlank(thumbUrl)) {
      this.extThumbnailUrl = externalizerService.externalizeUrl(thumbUrl);
}
PageManager pageManager= resolver.adaptTo(PageManager.class);
Page currentPage = pageManager.getContainingPage(resource);
if (externalizerService != null) {
     this.extPageUrl = externalizerService.externalizeUrl(resolver.map(currentPage.getPath())) + ".html";
}

}

public String getExternalizedThumbnailUrl() {
return externalizedThumbnailUrl;
}

public String getExternalizedPageUrl() {
return externalizedPageUrl;
}

}

Avatar

Employee Advisor

That java code looks ok from a ResourceResolver perspective. 

 

On a related note, I would just recommend to switch from the @inject annotation to a more specific one, see https://cqdump.joerghoh.de/2022/11/28/sling-model-performance/

Avatar

Level 10

Thanks @Jörg_Hoh , Used OSGiService as well as SlingObject, will attempt refactoring here. Refered to the doc you shared , it does not add to the latency right?

  • "The OsgiInjector is queried as well, which tries to access the OSGI ServiceRegistry; ..., which also adds latency."


Regarding @inject used - How do you suggest I use @Jörg_Hoh .. I was wondering since it is a property at child resource .. so it is child node , “image” that holds a property of importance ..I thought of childresource 

Also, does the init method look ok to to do the mapping to a url with resource resolver? 
     this.extPageUrl = externalizerService.externalizeUrl(resolver.map(currentPage.getPath())) + ".html";


my custom externalizer class injected into the model has below code which i am closing just as a reference.Please let me know if you see something here from resource resolver perspective, missed adding it earlier. The run mode bit is to evade sling settings issue, by using custom config

Again i very much appreciate your response .. puts me at ease to know i am following the best practices , thanks to you and  the folks here...

 


@Component(immediate = true)
@Service(value = ExternalizerService.class)
public class ExternalizerServiceImpl implements ExternalizerService {


@Reference
private  ResourceResolverFactory resourceResolverFactory;

@Reference
private RunModeConfigService runModeConfigService;

private static final String INSTANCE_CONFIG_PATH = "instance";

@Override
public String externalizeUrl(String path) {
       String externalizedThumbnailURL = null;
         try (ResourceResolver resourceResolver = ResourceResolverUtils
.getUserSystemResourceResolver(resourceResolverFactory)) {
           if (resourceResolver != null) {
              Externalizer externalizer =                resourceResolver.adaptTo(Externalizer.class);
          LOGGER.debug("image path: {}" , path);
         if (externalizer != null) {
         if (isRunModePublish()) {
           externalizedThumbnailURL = externalizer.publishLink(resourceResolver, path);
          LOGGER.debug("Run mode pub {}" ,externalizedThumbnailURL);
      } else {
           externalizedThumbnailURL = externalizer.authorLink(resourceResolver, path);
           LOGGER.debug("Run mode auth {}" ,externalizedThumbnailURL);
   }
 }
}
}
return externalizedThumbnailURL;
}


public boolean isRunModePublish() {
if (runModeConfigService != null && !runModeConfigService.getRunModeConfig().isEmpty()) {
       Map<String, String> map = runModeConfigService.getRunModeConfig();
      String instance = map.get(INSTANCE_CONFIG_PATH);
      if (StringUtils.equalsIgnoreCase(instance, "author")) {
            return false;
        }
}
return true;
}
}




Avatar

Employee Advisor

Looks ok as well. I just wonder ... do you really need this new ResourceResolver in the externalizerService at all? It is invoked on the thumbUrl parameter of the Sling Model, and is this really not readable by "normal users"?

 

I doubt it on publish, and I think that for the same reason it's not necessary on author as well; meaning that this path should be readable by the ResourceResolver which is used to render the Sling Model.

 

Avatar

Level 10

There is additional processing needed that i planned to segregate for run mode based and reuse across the board. Hence opening one there for externalizing purposes. If i pass it from sling model, it might close unexpectedly is what i was thinking.

 

referred to your comment in the below and avoided passing resolver from model to externalizer service , unless I am missing something are you suggesting I pass resolver from model to be used in externalizer service clsss ? 

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/aem6-2-sling-models-resour... 

Apologies , did not understand "I doubt it on publish, and I think that for the same reason it's not necessary on author as well; meaning that this path should be readable by the ResourceResolver which is used to render the Sling Model."

btw i just updated the original question to avoid clutter, might have missed your eyes, 

Used OSGiService as well as SlingObject, will attempt refactoring here. Refered to the doc you shared , it does not add to the latency right?

  • "The OsgiInjector is queried as well, which tries to access the OSGI ServiceRegistry; ..., which also adds latency."


 

 

Regarding @inject used - How do you suggest I use @Jörg_Hoh .. I was wondering since it is a property at child resource .. so it is child node , “image” that holds a property of importance ..I thought of childresource 

Also, does the init method look ok to to do the mapping to a url with resource resolver? 
     this.extPageUrl = externalizerService.externalizeUrl(resolver.map(currentPage.getPath())) + ".html";

Avatar

Level 10

Offline discussions to avoid clutter, obtained resourceresolver using getResourceresolver- while no harm getting via a service. Does not need closing. Also, used @slingObject and @osgiservice and no performance issues were noted. Closing this .
Also, if any issues, the model would throw an error in the error log if unclosed resource resolver logging is checked in the config. it would be in the info status thanks to @Jörg_Hoh  for this..
Thanks  all, @Jörg_Hoh  @aanchal-sikka @lukasz-m