AEM6.2 sling models | Resource resolver is already closed | Community
Skip to main content
New Participant
March 19, 2018
Solved

AEM6.2 sling models | Resource resolver is already closed

  • March 19, 2018
  • 19 replies
  • 14191 views

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

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by 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 replies

smacdonald2008
New Participant
March 20, 2018

What exactly are you trying to accomplish. Looks like you are trying to implement Java logic that fires off jobs on a timer.

When most ppl want to implement a time based scheduler solution, they are writing a Sling Scheduler Service. Apache Sling :: Scheduler Service (commons scheduler)

New Participant
March 20, 2018

now i am getting nullpointer for resourceresolver

package com.test.core.models;

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 javax.annotation.PostConstruct;

import javax.inject.Inject;

import javax.jcr.Node;

import javax.jcr.RepositoryException;

import javax.jcr.Session;

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

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

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

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Model(adaptables = Resource.class)

public class SchedulerComponent {

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

@Inject

    private Date timer;

/*@Inject

    private String classification;

*/

/*@Inject

private ResourceResolver resourceResolver;

*/

/*@Inject

private Session session;

*/

/*@Inject

private SchedulerTask schedulerTask;

*/

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

Timer timer1 = new Timer();

   private class MyTimeTask extends TimerTask {

   @Inject

   private ResourceResolver resourceResolver;

  

      public void run() {

      try {

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

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

      ResourceResolver resolver = null;

      resolver = resolverFactory.getServiceResourceResolver(param);

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

      LOG.info("Entering to run method");

// write custom code  here

      LOG.info("0000000");

      String classification = "hindi";

      Node classificationNode = session.getNode("/content/myapp/api-data/"+classification);

      LOG.info("111111");

     

  //System.setProperty("https.proxyHost", "proxy.global.dish.com");

  //System.setProperty("https.proxyPort", "8080");

  URL url = new URL("https://teamtreehouse.com/matthew.json");

      LOG.info("2222222");

  URLConnection con = url.openConnection();

  LOG.info("connection opened");

  BufferedReader br  = new BufferedReader(new InputStreamReader(con.getInputStream(), Charset.forName("UTF-8")));

  StringBuilder sb = new StringBuilder();

  String line;

  while ((line = br.readLine()) != null) {

  sb.append(line);

  }

  System.out.println(sb.toString());

 

  Node fileNode = classificationNode.addNode("twelve-month-pre-pay", "nt:file");

  fileNode.setProperty("jcr:date", sb.toString());

  session.save();

  LOG.info("Original data saved in repository");

  /*

  File jsonFile = new File("api-call-hindi.json");

  BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(jsonFile));

 

  // Read json content from repository 

String content = new String(Files.readAllBytes(Paths.get("api-call.json")));

LOG.info("Content is ::: "+content);

JSONObject apiJson =  new JSONObject(content);

JSONArray base_linear_packages = apiJson.getJSONArray("base_linear_packages");

for(int i=0; i< base_linear_packages.length(); i++) {

JSONObject base_linear_package = base_linear_packages.getJSONObject(i);

// assuming all channels are present in  classification_name:Hindi identifier:hindi-gold

if(base_linear_package.get("classification_name").equals("Hindi") && base_linear_package.get("identifier").equals("hindi-gold")) {

JSONArray channels = base_linear_package.getJSONArray("channels");

File channelsFile = new File("channels.json");

BufferedWriter channelsWriter = new BufferedWriter(new FileWriter(channelsFile));

ObjectMapper mapper1 = new ObjectMapper();

Object jsonObject1 = mapper.readValue(channels.toString(), Object.class);

String prettyString1 = mapper1.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject1);

channelsWriter.write(prettyString1);

System.out.println("Channles written!!!");

channelsWriter.close();

break;

}

}*/

LOG.info("Running Task");

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

timer1.cancel();

} catch (RepositoryException e) {

LOG.info("RepositoryException is :::: ", e);

} catch (MalformedURLException e) {

LOG.info("MalformedURLException is :::: ", e);

} catch (IOException e) {

e.printStackTrace();

} catch(Exception e) {

LOG.info("Exception is :::: ", e);

}

      }

   }

@PostConstruct

public final void init() {

try {

LOG.info("Time is :::: "+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(task, timer);

} catch(Exception ex) {

LOG.error("Error in init :::: ", ex);

}

}

}

joerghoh
Employee
March 19, 2018

Hi,

the formating is a bit unfortunate, so I hope I did not get the code wrong.

For me it looks like that you have a sling model, and that you pass the resourceResolver (which is injected into it) to a TimerTask. And then this TimerTask throws the mentioned stacktrace.

That's what I would expect in this case. Because the request (which invokes the Sling Model) "owns" the resourceResolver, that means it is responsible for opening and closing it. If you start a new asynchronous thread and pass this resourceResolver to this new thread, the request does not know about it and closes the resourceResolver; and then you get the exception you posted.

The solution is to open a new ResourceResolver in the TimerThread.

Jörg

smacdonald2008
New Participant
March 19, 2018

This is an interesting use case. Something that i have not tried. Can you see if you can get that code to work in your service class.

New Participant
March 19, 2018

Not solved the issue even  after placed timertask logic in separate class

Nw below is my timertask class code

@Component

public class SchedulerTask extends TimerTask {

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

@Reference

private ResourceResolver resourceResolver;

Timer timer = new Timer();

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

public void run() {

    try {

}

}

}

Below error i am getting

org.apache.sling.api.scripting.ScriptEvaluationException: org.apache.sling.scripting.sightly.SightlyException: Identifier com.test.core.models.SchedulerComponent cannot be correctly instantiated by the Use API

I am  injecting timertask like below in main model class

@Inject

private SchedulerTask schedulerTask;

smacdonald2008
New Participant
March 19, 2018

Setup your project like this:

Also - to get a Session in your Service - use this code:

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

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

     ResourceResolver resolver = null;

      resolver = resolverFactory.getServiceResourceResolver(param);

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

This will work. IN your model - you will get an instance using @Inject, Once you enter the Service, you are getting a session using a system user and you will be able to perform JCR operations like reading and writing node props.

smacdonald2008
New Participant
March 19, 2018

Instead of using an inner class, why not create MyTimeTask  as an AEM Servce (use @Component). Then you can get an instance of this Service by using @inject.

You can use @inject to get an instance of AEM services when using Sling Models.

I ahve not seen inner classes used with SLing Models and would think it would make more sense to break your code into a Model and a Service.

New Participant
March 19, 2018

Hi Jorg,

Please find the full class code below

package com.test.core.models;

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 javax.annotation.PostConstruct;

import javax.inject.Inject;

import javax.jcr.Node;

import javax.jcr.RepositoryException;

import javax.jcr.Session;

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

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

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

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Model(adaptables = Resource.class)

public class SchedulerComponent {

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

@Inject

    private Date timer;

@Inject

private ResourceResolver resourceResolver;

/*@Inject

    private String classification;

*/

/*@Inject

private ResourceResolver resourceResolver;

*/

/*@Inject

private Session session;

*/

 

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

private boolean taskOver;

public boolean isTaskOver() {

return taskOver;

}

Timer timer1 = new Timer();

   private class MyTimeTask extends TimerTask {

   private ResourceResolver resourceResolver;

  

   public MyTimeTask(ResourceResolver resourceResolver) {

   this.resourceResolver = resourceResolver;

}

      public void run() {

      try {

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

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

      ResourceResolver resolver = null;

      resolver = resolverFactory.getServiceResourceResolver(param);

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

      LOG.info("Entering to run method");

// write custom code  here

      LOG.info("0000000");

      String classification = "english";

      Node classificationNode = session.getNode("/content/myapp/api-data/"+classification);

      LOG.info("111111");

     

  //System.setProperty("https.proxyHost", "proxy.global.dish.com");

  //System.setProperty("https.proxyPort", "8080");

  URL url = new URL("https://teamtreehouse.com/matthew.json");

      LOG.info("2222222");

  URLConnection con = url.openConnection();

  LOG.info("connection opened");

  BufferedReader br  = new BufferedReader(new InputStreamReader(con.getInputStream(), Charset.forName("UTF-8")));

  StringBuilder sb = new StringBuilder();

  String line;

  while ((line = br.readLine()) != null) {

  sb.append(line);

  }

  System.out.println(sb.toString());

 

  Node fileNode = classificationNode.addNode("twelve-month-pre-pay", "nt:file");

  fileNode.setProperty("jcr:date", sb.toString());

  session.save();

  LOG.info("Original data saved in repository");

  /*

  File jsonFile = new File("api-call-hindi.json");

  BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(jsonFile));

 

  // Read json content from repository 

String content = new String(Files.readAllBytes(Paths.get("api-call.json")));

LOG.info("Content is ::: "+content);

JSONObject apiJson =  new JSONObject(content);

JSONArray base_linear_packages = apiJson.getJSONArray("base_linear_packages");

for(int i=0; i< base_linear_packages.length(); i++) {

JSONObject base_linear_package = base_linear_packages.getJSONObject(i);

// assuming all channels are present in  classification_name:Hindi identifier:hindi-gold

if(base_linear_package.get("classification_name").equals("Hindi") && base_linear_package.get("identifier").equals("hindi-gold")) {

JSONArray channels = base_linear_package.getJSONArray("channels");

File channelsFile = new File("channels.json");

BufferedWriter channelsWriter = new BufferedWriter(new FileWriter(channelsFile));

ObjectMapper mapper1 = new ObjectMapper();

Object jsonObject1 = mapper.readValue(channels.toString(), Object.class);

String prettyString1 = mapper1.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject1);

channelsWriter.write(prettyString1);

System.out.println("Channles written!!!");

channelsWriter.close();

break;

}

}*/

LOG.info("Running Task");

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

timer1.cancel();

taskOver = true;

} catch (RepositoryException e) {

LOG.info("RepositoryException is :::: ", e);

} catch (MalformedURLException e) {

LOG.info("MalformedURLException is :::: ", e);

} catch (IOException e) {

e.printStackTrace();

} catch(Exception e) {

LOG.info("Exception is :::: ", e);

}

      }

   }

@PostConstruct

public final void init() {

try {

LOG.info("Time is :::: "+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(resourceResolver);

timer1.schedule(task, timer);

} catch(Exception ex) {

LOG.error("Error in init :::: ", ex);

}

}

}

joerghoh
Employee
March 19, 2018

How are you invoking this model? The stacktrace indicates that you have an inner class "MyTimeTask" which is a runnable and invoked from a timer. Can you share the complete code?