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

AEM6.2 sling models | Resource resolver is already closed

  • March 19, 2018
  • 19 replies
  • 14193 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

joerghoh
Adobe Employee
Adobe 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?

Level 5
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);

}

}

}

smacdonald2008
Level 10
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.

smacdonald2008
Level 10
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.

Level 5
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
Level 10
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.

joerghoh
Adobe Employee
Adobe 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

Level 5
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);

}

}

}

smacdonald2008
Level 10
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)

BrijeshYadav
Level 5
March 20, 2018

Hi Pradeep,

It's problem with injecting Date object which breaks and encounters exception. Here is working code for your sling models.

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

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

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

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

import org.apache.sling.models.annotations.injectorspecific.SlingObject;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;

import javax.inject.Inject;

import javax.jcr.Session;

import java.util.Date;

@Model(adaptables = Resource.class)

public class SchedulerComponent {

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

   @Inject
  @Optional
   private Date timer;

   @SlingObject
   private ResourceResolver resourceResolver;

   private String userName = "default user";

   @PostConstruct
   public final void init() {

   try {

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

   userName = session.getUserID();

  } catch (Exception ex) {

   LOG.error(ex.getMessage());

  }

  }

   public String getUserName() {

   return userName;

  }

}