2

I have a Singleton class in Java and I have a timer using the @Schedule annotation. I wish to change the property of the Schedule at runtime. Below is the code:

@Startup
@Singleton
public class Listener {

   public void setProperty() {
       Method[] methods = this.getClass().getDeclaredMethods();
       Method method = methods[0];
       Annotation[] annotations = method.getDeclaredAnnotations();
       Annotation annotation = annotations[0];
       if(annotation instanceof Schedule) {
            Schedule schedule = (Schedule) annotation;
            System.out.println(schedule.second());
       }
   }

    @PostConstruct
    public void runAtStartUp() {
         setProperty();
    }

   @Schedule(second = "3")
   public void run() {
       // do something
   }
}

I wish to change the value at runtime of Schedule second based on the information from a Property file. Is this actually possibe? The Property file contains the configuration information. I tried to do @Schedule(second = SOME_VARIABLE) where private static String SOME_VARIABLE = readFromConfigFile(); This does not work. It expects a constant meaning a final and I don't want to set final.

I also saw this post: Modifying annotation attribute value at runtime in java

It shows this is not possible to do.

Any ideas?

EDIT:

@Startup
@Singleton
public class Listener {
    javax.annotation.@Resource // the issue is this
    private javax.ejb.TimerService timerService;
    private static String SOME_VARIABLE = null;

    @PostConstruct
    public void runAtStartUp() {
         SOME_VARIABLE = readFromFile();
         timerService.createTimer(new Date(), TimeUnit.SECONDS.toMillis(Long.parse(SOME_VARIABLE)), null);
    }

    @Timeout
    public void check(Timer timer) {
        // some code runs every SOME_VARIABLE as seconds
    }
}

The issue is injecting using @Resource. How can this be fixed?

The Exception is shown below:

No EJBContainer provider available The following providers: org.glassfish.ejb.embedded.EJBContainerProviderImpl Returned null from createEJBContainer call
javax.ejb.EJBException
org.glassfish.ejb.embedded.EJBContainerProviderImpl
at javax.ejb.embeddable.EJBContainer.reportError(EJBContainer.java:186)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:121)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:78)

@BeforeClass
public void setUpClass() throws Exception {
    Container container = EJBContainer.createEJBContainer();
}

This occurs during unit testing using the Embeddable EJB Container. Some of the Apache Maven code is located on this post: Java EJB JNDI Beans Lookup Failed

Community
  • 1
  • 1
user3189663
  • 211
  • 4
  • 18

2 Answers2

0

Maybe you could use the TimerService. I have written some code but on my Wildfly 8 it seems to run multiple times even if its a Singleton. Documentation http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html

Hope this helps:

@javax.ejb.Singleton
@javax.ejb.Startup
public class VariableEjbTimer {

    @javax.annotation.Resource
    javax.ejb.TimerService timerService;

    @javax.annotation.PostConstruct
    public void runAtStartUp() {
        createTimer(2000L);
    }

    private void createTimer(long millis) {
        //timerService.createSingleActionTimer(millis, new javax.ejb.TimerConfig());
        timerService.createTimer(millis, millis, null);
    }

    @javax.ejb.Timeout
    public void run(javax.ejb.Timer timer) {
        long timeout = readFromConfigFile();
        System.out.println("Timeout in " + timeout);
        createTimer(timeout);
    }

    private long readFromConfigFile() {
        return new java.util.Random().nextInt(5) * 1000L;
    }
}
TomasZ.
  • 449
  • 1
  • 5
  • 10
  • How can this approach be used to inject the value of the @Schedule(second = SOME_VARIABLE) at runtime? – user3189663 Apr 08 '14 at 13:14
  • From the docs: `@Schedule` is an Automatic timer and for programmatic timer (your case) you use the `TimerService`. The first timer is set to 2000 milliseconds and the others are read from the config file (random number in this code for simplicity). If your SOME_VARIABLE comes from a config file, than you read that value in the `readFromConfigFile()` method. I hope this answers your question. – TomasZ. Apr 08 '14 at 13:30
  • The SOME_VARIABLE is a static variable that needs to be injected into the @Schedule(seconds = SOME_VARIABLE) or in some other way. Will your solution work for this? – user3189663 Apr 08 '14 at 13:39
  • You would use `@Schedule` for static values. But you want the values to change at runtime. So you need to use the `TimerService`. I forgot to mention that instead of the `@Schedule` annotatted method the `@Timeout` annotated method will be called. I rename the methods. There is always a new timer created, because you can't change the timing of existing timers. – TomasZ. Apr 08 '14 at 13:47
  • Yes, I want the values to change at runtime but only to change once. I want to initialise the value read from a file and some how inject the value into the annotation. Is this actually possible? Are there other approaches. The SOME_VARIABLE approach requires it be a a constant and I don't want to set it to constant at compile time. – user3189663 Apr 08 '14 at 13:51
  • Don't worry got it. Thank you. – user3189663 Apr 08 '14 at 14:18
  • I receive No runnable methods Exception. – user3189663 Apr 08 '14 at 14:33
  • Please see EDIT above. – user3189663 Apr 08 '14 at 14:38
  • Could you please post the first few lines of the Exception? Maybe that will help. Please also check that you used the proper packages @javax.annotation.Resource and javax.ejb.TimerService. What application server are you using? – TomasZ. Apr 08 '14 at 17:42
  • I am using Glassfish server and I have added the Exception stacktrace above. The correct annotations are being used and are shown above. – user3189663 Apr 09 '14 at 08:20
  • It's getting complicated :) Does the timer service code work when you run it in normal server mode? Maybe this thread helps https://www.java.net/forum/topic/glassfish/glassfish/timer-service-not-available-embedded-mode – TomasZ. Apr 09 '14 at 11:13
  • Sorry for coming late back to you. I am in a situation where I am not allowed to use the TimerService. How else can this be implemented? – user3189663 Apr 11 '14 at 11:12
0

I think the solution you are looking for was discussed here.

TomasZ is right you should use programmatic timers with TimerService for the situations when you want dynamically change schedule in run time.

Community
  • 1
  • 1
jjd
  • 2,158
  • 2
  • 18
  • 31
  • Sorry for coming late back to you. I am in a situation where I am not allowed to use the TimerService. How else can this be implemented? – user3189663 Apr 11 '14 at 11:10
  • What do you mean by 'not allowed to use TimeService'? As far as I understand, when you use automatic timers utilizing @Schedule annotation, you still use timeService. The only difference is the way you create timer. – jjd Apr 11 '14 at 12:40
  • Okay, what does the real job under he water when you use '@Schedule' annotation? Could you please explain why you are allowed to use '@Schedule' and not allowed to use TimerService? – jjd Apr 11 '14 at 12:58
  • Unless you have a definitive answer, you should not think of some weird solutions whereas a standard solutions for what you have to do exists. It is the same way like you would try to feed yourself not through your mouth. Can you do it? Yes you can, but it would be really inconvenient. No I am not aware of any other standard way to do it in EJB framework. And yes you have plenty third party tools that you can integrate and utilize somehow in your application. THe only question here is why. – jjd Apr 11 '14 at 14:11
  • The team don't seem to give the answer. I have to implement in another way. I have no choice. Is there any other way of doing this. The aim is that there is a Singleton class and this class does two things. The first thing is to keeping checking every so often for some resource is running and the other thing is to keep receiving data when it arrives so a schedule setup every 2 seconds or something. Could you please help here? – user3189663 Apr 11 '14 at 14:26
  • If I may, nobody here owes you an answer. You cannot describe your problem clear enough. That is not a problem of community. For the problem you described, you received an answer. The vague explanation of yours about impossibility of using it does not make it a correct solution for the problem. You are the one who should think of the better explanation if you want to receive help. Now back to the question: Have I understood correctly, that your problem related to fact that you already have another programmatic timer defined for your singleton and you already have a @Timeout method defined? – jjd Apr 11 '14 at 15:01
  • I agree with jjd. The comments will be confusing for future users. Do you need 2 different timers for 2 different things? Or your team has a bug with the TimerService? – TomasZ. Apr 12 '14 at 08:29