AEM6.2 sling models | Resource resolver is already closed | Adobe Higher Education
Skip to main content
Level 5
March 19, 2018
Resuelto

AEM6.2 sling models | Resource resolver is already closed

  • March 19, 2018
  • 19 respuestas
  • 14193 visualizaciones

Hi All,

I am  getting error in  sing model class saying resource resolver is already closed

Below is my code for reference.

@Model(adaptables = Resource.class)

public class SchedulerComponent {

private static Logger LOG = LoggerFactory.getLogger(SchedulerComponent.class);

@Inject

    private Date timer;

@Inject

private ResourceResolver resourceResolver;

@PostConstruct

public final void init() {

try {

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

} catch(Exception ex) {

}

}

}

Below is error stack trace.

java.lang.IllegalStateException: Resource resolver is already closed.

at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.checkClosed(ResourceResolverImpl.java:202)

at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.adaptTo(ResourceResolverImpl.java:826)

at com.test.core.models.SchedulerComponent$MyTimeTask.run(SchedulerComponent.java:69)

at java.util.TimerThread.mainLoop(Unknown Source)

at java.util.TimerThread.run(Unknown Source)

Please advise to fix the problem.

Thanks,

Pradeep

Este tema ha sido cerrado para respuestas.
Mejor respuesta de smacdonald2008

I found the Solution to you. Everything i wrote is applicable. You need to break the code into a Interface, Service and Model.

Notice the Run method.

//Define RUN

public void run() {

      try {

      //Is SESSION valid

      LOG.info("RUNNING IN THE RUN METHOD");

      ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

      session = resourceResolver.adaptTo(Session.class);

    LOG.info("SESSION ID is " +session);

     

     

     

     

      }

      catch (Exception e)

      {

      e.printStackTrace();

      }

  }

This logged a message showing it was successfully invoked:

20.03.2018 22:56:48.589 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml RUNNING IN THE RUN METHOD

20.03.2018 22:56:48.590 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml SESSION ID is com.adobe.granite.repository.impl.CRX3SessionImpl@1e6230e

This was broken into a Service that implements a Java interface and extends TimerTask

We broke the code into this Interface:

package com.adobe.community.time.core;

public interface Time {

   

   

      public String getTime() ;

}

This Implementation class

package com.adobe.community.time.core;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import java.nio.charset.Charset;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

import org.apache.felix.scr.annotations.Component;

import org.apache.felix.scr.annotations.Service;

import org.apache.felix.scr.annotations.Reference;

import javax.inject.Inject;

import javax.jcr.Node;

import javax.jcr.RepositoryException;

import javax.jcr.Session;

import java.util.HashMap;

import java.util.Map;

//Sling Imports

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

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

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

import org.apache.sling.models.annotations.Model;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.TimerTask;

@Component

@Service

public class TimeIml  extends TimerTask implements Time{

   

      //Inject a Sling ResourceResolverFactory

@Reference

private ResourceResolverFactory resolverFactory;

private static Logger LOG = LoggerFactory.getLogger(TimeIml.class);

private Session session;

   

//Define RUN

public void run() {

try {

//Is SESSION valid

LOG.info("RUNNING IN THE RUN METHOD");

ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

session = resourceResolver.adaptTo(Session.class);

LOG.info("SESSION ID is " +session);

}

catch (Exception e)

{

e.printStackTrace();

}

}

   

   

      public String getTime()

      {

try{

//Invoke the adaptTo method to create a Session

ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

session = resourceResolver.adaptTo(Session.class);

  LOG.info("Entering getCustData()");

  return "LAM22";

}

catch (Exception e)

{

e.printStackTrace();

}

return "Error" ;

      }

}

Model Class – we casted the 1st parameter for timer1.schedule – that was the KEY!!!!

timer1.schedule((TimerTask)time, timer);

   

Code for Model class – THis logges the message in the RUN METHOD – meaning it worked!


20.03.2018 22:56:48.589 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml RUNNING IN THE RUN METHOD

  1. 20.03.2018 22:56:48.590 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml SESSION ID is com.adobe.granite.repository.impl.CRX3SessionImpl@1e6230e

package com.adobe.community.time.core.models;

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import javax.inject.Named;

import com.adobe.community.time.core.Time;

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

import org.apache.sling.models.annotations.Default;

import org.apache.sling.models.annotations.Model;

import org.apache.sling.settings.SlingSettingsService;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Model(adaptables=Resource.class)

public class HelloWorldModel {

    @Inject

    private SlingSettingsService settings;

 

    @Inject

    private Time time;

    @Inject @Named("sling:resourceType") @Default(values="No resourceType")

    protected String resourceType;

    private String message;

 

    private static Logger LOG = LoggerFactory.getLogger(HelloWorldModel.class);

    @PostConstruct

    protected void init() {

message = "\tHello World!\n";

message += "\tThis is instance: " + settings.getSlingId() + "\n";

message += "\tTime is: " + time.getTime() + "\n";

     

        SetTimeInfo();

    }

    public String getMessage() {

return message;

    }

 

 

    public void SetTimeInfo() {

      try {

   

       Date timer = new Date();    

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    

      Timer timer1 = new Timer();

SimpleDateFormat inFormat = new  SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

SimpleDateFormat outFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

      LOG.info("Right format is :::: "+outFormat.format(timer));

    

      LOG.info("Current Time: " + df.format( new Date()));

//Date and time at which you want to execute

      //Date date = df.parse("2018-03-18 17:08:00");

    

   

      //MyTimeTask task = new MyTimeTask();

      //schedulerTask.setTimer(timer1);

timer1.schedule((TimerTask)time, timer);

   

      //String myVal33 = task.getCustData();

   

     

   

      //this.subject = text;

      } catch(Exception ex) {

ex.printStackTrace();

      }

      }

}

ALSO - I tested with ADMIN CALL - to run this - white list the bundle - see - https://forums.adobe.com/thread/2355506

19 respuestas

Level 5
March 20, 2018

@Inject

    private Date timer;

timer is the property in dialog of type Date.  This is needed to pass to schedule the task.

My requirement is to run  some piece  of code on  selected time. I am not using typical scheduler why because felix console access is not provided us, it is maintained and managed by Adobe, we can't ask them to run  scheduler as and when  needed. We have only author access. So in authoring dialog as soon as author is selecting particular date and time, my timer task code should execute. To accomplish this i am using java.util.TimerTask

Below code still throwing nullpointer for resourceresolver.

@SlingObject

private ResourceResolver resourceResolver;

smacdonald2008
Level 10
March 20, 2018

I sent you an email.

smacdonald2008
Level 10
March 20, 2018

I am going to figure this out - Many questions here - within a nest class - i do not think @Inject will work. But I will code this and see.

smacdonald2008
Level 10
March 21, 2018

IN AEM - to get a session - you use this typically in an OSGi bundle in a Service that is managed by AEM:

try {

          Map<String, Object> param = new HashMap<String, Object>();

          param.put(ResourceResolverFactory.SUBSERVICE, "datawrite");

          ResourceResolver resolver = null;

                                         

         

          resolver = resolverFactory.getServiceResourceResolver(param);

              session = resolver.adaptTo(Session.class);

However to get this to work - you need this:

@Reference

private ResourceResolverFactory resolverFactory;

This code will only work from an AEM Service. You can easily get to work from a Model.

For example - assume you have an interface ;

package com.adobe.community.time.core;

public interface Time {

public String getTime() ;

}

Then you have the Service that implements TImer:

package com.adobe.community.time.core;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import java.nio.charset.Charset;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

import org.apache.felix.scr.annotations.Component;

import org.apache.felix.scr.annotations.Service;

import org.apache.felix.scr.annotations.Reference;

import javax.inject.Inject;

import javax.jcr.Node;

import javax.jcr.RepositoryException;

import javax.jcr.Session;

import java.util.HashMap;

import java.util.Map;

//Sling Imports

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

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

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

import org.apache.sling.models.annotations.Model;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.TimerTask;

@Component

@Service

public class TimeIml  extends TimerTask implements Time{

//Inject a Sling ResourceResolverFactory

@Reference

private ResourceResolverFactory resolverFactory;

private static Logger LOG = LoggerFactory.getLogger(TimeIml.class);

private Session session;

//Define RUN

public void run() {

      try {

      String A = "tt";

      LOG.info(A);

      }

      catch (Exception e)

      {

      e.printStackTrace();

      }

  }

public String getTime()

{

try{

//Invoke the adaptTo method to create a Session

    ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

    session = resourceResolver.adaptTo(Session.class);

   

  LOG.info("Entering getCustData()");

  return "LAM22";

}

catch (Exception e)

{

e.printStackTrace();

}

return "Error" ;

}

}

In my model - I can get the getTime() method to be invoked by using @Inject.

@Inject

    private Time time;  // notice we are referencing the inteface - not the class

    @Inject @Named("sling:resourceType") @Default(values="No resourceType")

    protected String resourceType;

    private String message;

   

    private static Logger LOG = LoggerFactory.getLogger(HelloWorldModel.class);

    @PostConstruct

    protected void init() {

        message = "\tHello World!\n";

        message += "\tThis is instance: " + settings.getSlingId() + "\n";

        message += "\tTime is: " + time.getTime() + "\n";  // call getTime

This works fine in AEM.

This code will work fine when used in a Service - like TImeImp

@Reference

private ResourceResolverFactory resolverFactory;

You are trying to use ResourceResolverFactory  from a non-managed object -- this will not work

TimeIml tt = new TimeIml(); // ResourceResolverFactory  will be NULL!!!

ResourceResolverFactory  will be null in this case.

So you problem boils down to what to pass to the timer1.schedule(time, timer);

You cannot pass the @Inject instance as this is the interface - not the Object that extends TimerTask.

If you try and declare the object by using new:

TimeIml tt = new TimeIml()

ResourceResolverFactory is null.

Also - nested classes  from a model will not let you use @Inject either. . You cannot inject ResourceResolverFactory.

smacdonald2008
Level 10
March 21, 2018

My HTL component is showing the value returned from getTime method:

Ratna_Kumar
Level 10
March 21, 2018

Hi Pradeep,

I agree with Scott..

You cannot inject anything from the Inner class and It cannot be a model class. Also as Scott suggested better use Scheduler Service and not TimerTask

Thanks,

Ratna Kumar.

smacdonald2008
Level 10
March 21, 2018

I found the Solution to you. Everything i wrote is applicable. You need to break the code into a Interface, Service and Model.

Notice the Run method.

//Define RUN

public void run() {

      try {

      //Is SESSION valid

      LOG.info("RUNNING IN THE RUN METHOD");

      ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

      session = resourceResolver.adaptTo(Session.class);

    LOG.info("SESSION ID is " +session);

     

     

     

     

      }

      catch (Exception e)

      {

      e.printStackTrace();

      }

  }

This logged a message showing it was successfully invoked:

20.03.2018 22:56:48.589 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml RUNNING IN THE RUN METHOD

20.03.2018 22:56:48.590 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml SESSION ID is com.adobe.granite.repository.impl.CRX3SessionImpl@1e6230e

This was broken into a Service that implements a Java interface and extends TimerTask

We broke the code into this Interface:

package com.adobe.community.time.core;

public interface Time {

   

   

      public String getTime() ;

}

This Implementation class

package com.adobe.community.time.core;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import java.nio.charset.Charset;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

import org.apache.felix.scr.annotations.Component;

import org.apache.felix.scr.annotations.Service;

import org.apache.felix.scr.annotations.Reference;

import javax.inject.Inject;

import javax.jcr.Node;

import javax.jcr.RepositoryException;

import javax.jcr.Session;

import java.util.HashMap;

import java.util.Map;

//Sling Imports

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

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

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

import org.apache.sling.models.annotations.Model;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.TimerTask;

@Component

@Service

public class TimeIml  extends TimerTask implements Time{

   

      //Inject a Sling ResourceResolverFactory

@Reference

private ResourceResolverFactory resolverFactory;

private static Logger LOG = LoggerFactory.getLogger(TimeIml.class);

private Session session;

   

//Define RUN

public void run() {

try {

//Is SESSION valid

LOG.info("RUNNING IN THE RUN METHOD");

ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

session = resourceResolver.adaptTo(Session.class);

LOG.info("SESSION ID is " +session);

}

catch (Exception e)

{

e.printStackTrace();

}

}

   

   

      public String getTime()

      {

try{

//Invoke the adaptTo method to create a Session

ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);

session = resourceResolver.adaptTo(Session.class);

  LOG.info("Entering getCustData()");

  return "LAM22";

}

catch (Exception e)

{

e.printStackTrace();

}

return "Error" ;

      }

}

Model Class – we casted the 1st parameter for timer1.schedule – that was the KEY!!!!

timer1.schedule((TimerTask)time, timer);

   

Code for Model class – THis logges the message in the RUN METHOD – meaning it worked!


20.03.2018 22:56:48.589 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml RUNNING IN THE RUN METHOD

  1. 20.03.2018 22:56:48.590 *INFO* [Timer-23] com.adobe.community.time.core.TimeIml SESSION ID is com.adobe.granite.repository.impl.CRX3SessionImpl@1e6230e

package com.adobe.community.time.core.models;

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import javax.inject.Named;

import com.adobe.community.time.core.Time;

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

import org.apache.sling.models.annotations.Default;

import org.apache.sling.models.annotations.Model;

import org.apache.sling.settings.SlingSettingsService;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Model(adaptables=Resource.class)

public class HelloWorldModel {

    @Inject

    private SlingSettingsService settings;

 

    @Inject

    private Time time;

    @Inject @Named("sling:resourceType") @Default(values="No resourceType")

    protected String resourceType;

    private String message;

 

    private static Logger LOG = LoggerFactory.getLogger(HelloWorldModel.class);

    @PostConstruct

    protected void init() {

message = "\tHello World!\n";

message += "\tThis is instance: " + settings.getSlingId() + "\n";

message += "\tTime is: " + time.getTime() + "\n";

     

        SetTimeInfo();

    }

    public String getMessage() {

return message;

    }

 

 

    public void SetTimeInfo() {

      try {

   

       Date timer = new Date();    

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    

      Timer timer1 = new Timer();

SimpleDateFormat inFormat = new  SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

SimpleDateFormat outFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

      LOG.info("Right format is :::: "+outFormat.format(timer));

    

      LOG.info("Current Time: " + df.format( new Date()));

//Date and time at which you want to execute

      //Date date = df.parse("2018-03-18 17:08:00");

    

   

      //MyTimeTask task = new MyTimeTask();

      //schedulerTask.setTimer(timer1);

timer1.schedule((TimerTask)time, timer);

   

      //String myVal33 = task.getCustData();

   

     

   

      //this.subject = text;

      } catch(Exception ex) {

ex.printStackTrace();

      }

      }

}

ALSO - I tested with ADMIN CALL - to run this - white list the bundle - see - https://forums.adobe.com/thread/2355506

Ratna_Kumar
Level 10
March 21, 2018

Woow thats simply Awesome Scott!!

I will test this code in Maven 10 too!!

~Ratna Kumar.

smacdonald2008
Level 10
March 21, 2018

AN update - changed session id to :

LOG.info("SESSION ID is " +session.getUserID() );

Log message - 20.03.2018 23:21:02.626 *INFO* [Timer-25] com.adobe.community.time.core.TimeIml SESSION ID is admin