6 Replies Latest reply on Sep 1, 2009 11:24 AM by Nikolay Elenkov

    JobName annotation?

    Nikolay Elenkov Master

      I've been using the @Asynchrounous/@Expiration/@IntervalDuration annotations to schedule repeatable Quartz jobs, and that has worked pretty well.
      However, the jobs/triggers have auto-generated names like -6a5e40e8:11b717f63c3:-7f7d and that is not very readable.


      I need to reschedule jobs if some parameters are changed in my app, hence the need to now a job's associated trigger name. QuartzTriggerHandle has a
      'triggerName' field, but it is private, and QuartzTriggerHandle offers only cancel/pause/resume methods. I guess a solution would be to make
      QuartzTriggerHandle's triggerName publicly accessible (as already requested in JBSEAM-2695), but that would still give random job names. I would prefer to be able to specify the job/trigger names. To that end being able to add a @JobName/@TriggerName annotation to @Asynchronous methods would be nice.


      In case it helps someone with a similar problem, I currently use the following code as a workaround. It schedules jobs, executed in a Seam context, with the specified job/trigger name (mimics what QuartzDispatcher.java does sans the auto-generated names).


      QuartzDispatcher dispatcher = QuartzDispatcher.instance();
      Scheduler scheduler = dispatcher.getScheduler();
      
      Method method = clazz.getMethod(methodName, (Class[]) null);
      Asynchronous async = new AsynchronousInvocation(method, componentName, null);
      JobDetail job = new JobDetail(jobName, JOB_GROUP, QuartzDispatcher.QuartzJob.class);
      job.setRequestsRecovery(true);
      job.getJobDataMap().put("async", async);
      SimpleTrigger trigger = new SimpleTrigger(triggerName, TRIGGER_GROUP, when, null,
                                                SimpleTrigger.REPEAT_INDEFINITELY, interval);
      scheduler.scheduleJob(job, trigger);
      



      BTW, using a job/trigger group other than DEFAULT (say 'seam') or being able to specify one would also be nice.


        • 1. Re: JobName annotation?
          Alexander Torstling Newbie

          I felt like Seam did not quite cover cron-type jobs, so I just used a completely separate Quartz scheduler for those jobs. This requires some stanza to hook the job-running thread into Seam, but is quite easy. If you'd like I can paste some code here.

          • 2. Re: JobName annotation?
            Pete Muir Master

            File a feature request in JIRA with a patch.

            • 3. Re: JobName annotation?
              Nikolay Elenkov Master

              Alexander T wrote on Jul 30, 2008 11:27:


              I felt like Seam did not quite cover cron-type jobs, so I just used a completely separate Quartz scheduler for those jobs. This requires some stanza to hook the job-running thread into Seam, but is quite easy. If you'd like I can paste some code here.


              I have a working solution (for now), but I'd like to see how you hooked the job-running thread into Seam. So, yes, please post some code.

              • 4. Re: JobName annotation?
                Alexander Torstling Newbie

                Ok! I created my scheduler in an MBean to get a cluster singleton, and I'm using EL
                expressions saved in the jobs to express what is to be done. Here is the worker class.
                It is slightly incomplete, but you'll get the idea


                public class TaskWorker implements Job {
                
                     private Log log;
                
                     /**
                      * @see RootInterceptor#invoke() 
                      */
                     public void execute(JobExecutionContext jec) throws JobExecutionException {
                          // More about this in the org.jboss.seam.Seam sourcecode
                          // and http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4126662#4126662
                          boolean createContexts = !Contexts.isEventContextActive() && !Contexts.isApplicationContextActive();
                          if (createContexts) {
                               Lifecycle.beginCall();
                          }
                          try {
                
                               log = Logging.getLog(getClass());
                
                               JobDetail jobDetail = jec.getJobDetail();
                               CronTrigger cronTrigger = (CronTrigger) jec.getTrigger();
                
                               String methodBindingExpression = (String) jobDetail.getJobDataMap().get(
                                         TaskDataTypes.METHOD_BINDING_EXPRESSION.name());
                
                               // Taken from org.jboss.seam.Event 
                
                               MethodExpression<Object> invocationTarget = Expressions.instance().createMethodExpression(
                                         methodBindingExpression);
                
                               log.debug("Executing job '#0', calling '#1', scheduled at '#2'", jobDetail.getName(),
                                         invocationTarget.getExpressionString(), cronTrigger.getCronExpression());
                
                               invocationTarget.invoke();
                          } finally {
                               if (createContexts) {
                                    Lifecycle.endCall();
                               }
                          }
                     }
                }


                • 5. Re: JobName annotation?
                  Joseph Nusairat Newbie

                  I had the same problem as well.


                  According to the seam doco you can persist the QuartzTrigerHandler to the datbase. But i didn't like that either.


                  So i thought of some wrappers ... in the end i just used reflections to get the private field ... and i save that to the DB .... and then call the schedulers automatically.


                  here's the code i used to get the private field


                  public static Object getPrivateField(Object o, String fieldName) {
                            // Check we have valid arguments...
                            assert o != null;
                            assert fieldName != null;
                  
                            // Go and find the private field...
                            final Field fields[] = o.getClass().getDeclaredFields();
                            for (int i = 0; i < fields.length; ++i) {
                                 if (fieldName.equals(fields[i].getName())) {
                                      try {
                                           fields[i].setAccessible(true);
                                           return fields[i].get(o);
                                      } catch (IllegalAccessException ex) {
                                           return null;
                                      }
                                 }
                            }
                            return null;
                       }
                  

                  • 6. Re: JobName annotation?
                    Nikolay Elenkov Master

                    Pete Muir wrote on Jul 30, 2008 11:33:


                    File a feature request in JIRA with a patch.


                    Better late then never: JBSEAM-4399


                    The patch adds a @JobName annotation, so you can write:


                    public QuartzTriggerHandle scheduleJob(@Expiration Date when, @IntervalDuration Long interval, @JobName String jobName) 
                    {
                    ...
                    }
                    



                    And call it like this:


                    QuartzTriggerHandle handle = processor.scheduleJob(new Date(), 60 * 60 * 1000, "myJob");