Expand my Community achievements bar.

SOLVED

AEM6.2 sling models | Resource resolver is already closed

Avatar

Level 6

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

1 Accepted Solution

Avatar

Correct answer by
Level 10

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

View solution in original post

19 Replies

Avatar

Employee Advisor

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?

Avatar

Level 6

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

}

}

}

Avatar

Level 10

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.

Avatar

Level 10

Setup your project like this:

APIC.png

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.

Avatar

Level 6

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;

Avatar

Level 10

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.

Avatar

Employee Advisor

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

Avatar

Level 6

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

}

}

}

Avatar

Level 10

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)

Avatar

Community Advisor

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;

  }

}

Avatar

Level 6

@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;

Avatar

Level 10

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.

Avatar

Level 10

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.

Avatar

Level 10

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

AAA.png

Avatar

Level 10

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.

Avatar

Correct answer by
Level 10

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

Avatar

Level 10

Woow thats simply Awesome Scott!!

I will test this code in Maven 10 too!!

~Ratna Kumar.

Avatar

Level 10

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