You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2009/07/10 17:27:20 UTC

svn commit: r792981 - in /sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler: Scheduler.java impl/QuartzScheduler.java

Author: cziegeler
Date: Fri Jul 10 15:27:18 2009
New Revision: 792981

URL: http://svn.apache.org/viewvc?rev=792981&view=rev
Log:
SLING-1040 : Second attempt for cleanly handling lifecycle problems. As deactivate might happen during bind/unbind we should carefully check during bind/unbind. Clarify exception handling.

Modified:
    sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/Scheduler.java
    sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java

Modified: sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/Scheduler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/Scheduler.java?rev=792981&r1=792980&r2=792981&view=diff
==============================================================================
--- sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/Scheduler.java (original)
+++ sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/Scheduler.java Fri Jul 10 15:27:18 2009
@@ -53,6 +53,8 @@
      * @param config An optional configuration object - this configuration is only passed to the job the job implements {@link Job}.
      * @param schedulingExpression The time specification using a scheduling expression.
      * @param canRunConcurrently Whether this job can run even if previous scheduled runs are still running.
+     * @throws IllegalArgumentException If the scheduling expression can't be parsed or if the job has not the correct type.
+     * @throws Exception If the job can't be scheduled.
      */
     void addJob(String name, Object job, Map<String, Serializable> config, String schedulingExpression, boolean canRunConcurrently)
     throws Exception;
@@ -68,6 +70,8 @@
      * @param config An optional configuration object - this configuration is only passed to the job the job implements {@link Job}.
      * @param period Every period seconds this job is started.
      * @param canRunConcurrently Whether this job can run even if previous scheduled runs are still running.
+     * @throws IllegalArgumentException If the job has not the correct type.
+     * @throws Exception If the job can't be scheduled.
      */
     void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period, boolean canRunConcurrently)
     throws Exception;
@@ -77,6 +81,8 @@
      *
      * @param job The job to execute (either {@link Job} or {@link Runnable}).
      * @param config An optional configuration object - this configuration is only passed to the job the job implements {@link Job}.
+     * @throws IllegalArgumentException If the job has not the correct type.
+     * @throws Exception If the job can't be scheduled.
      */
     void fireJob(Object job, Map<String, Serializable> config)
     throws Exception;
@@ -90,6 +96,8 @@
      * @param job The job to execute (either {@link Job} or {@link Runnable}).
      * @param config An optional configuration object - this configuration is only passed to the job the job implements {@link Job}.
      * @param date The date this job should be run.
+     * @throws IllegalArgumentException If the job has not the correct type.
+     * @throws Exception If the job can't be scheduled.
      */
     void fireJobAt(String name, Object job, Map<String, Serializable> config, Date date)
     throws Exception;
@@ -98,6 +106,7 @@
      * Remove a scheduled job by name.
      *
      * @param name The name of the job.
+     * @throws NoSuchElementException If the job is not scheduled.
      */
     void removeJob(String name)
     throws NoSuchElementException;

Modified: sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java?rev=792981&r1=792980&r2=792981&view=diff
==============================================================================
--- sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java (original)
+++ sling/trunk/bundles/commons/scheduler/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java Fri Jul 10 15:27:18 2009
@@ -89,7 +89,7 @@
     protected final List<Registration> registeredJobs = new ArrayList<Registration>();
 
     /** The component context. */
-    protected ComponentContext context;
+    protected volatile ComponentContext context;
 
     /** @scr.reference */
     protected ThreadPoolManager threadPoolManager;
@@ -201,21 +201,28 @@
      * @param trigger a Trigger
      * @param canRunConcurrently whether this job can be run concurrently
      *
-     * @throws Exception thrown in case of errors
+     * @throws SchedulerException thrown in case of errors
      */
     protected void scheduleJob(String name,
                                final Object job,
                                final Map<String, Serializable>    config,
                                final Trigger trigger,
                                final boolean canRunConcurrently)
-    throws Exception {
+    throws SchedulerException {
+        // this method is also called from bind - as deactivate might have been
+        // called in the meantime, we just check
+        final org.quartz.Scheduler s = this.scheduler;
+        if ( s == null ) {
+            throw new IllegalStateException("Scheduler is not available anymore.");
+        }
+
         // check if the supplied object is valid
         this.checkJob(job);
 
         // if there is already a job with the name, remove it first
         if ( name != null ) {
             try {
-                final JobDetail jobdetail = this.scheduler.getJobDetail(name, DEFAULT_QUARTZ_JOB_GROUP);
+                final JobDetail jobdetail = s.getJobDetail(name, DEFAULT_QUARTZ_JOB_GROUP);
                 if (jobdetail != null) {
                     this.removeJob(name);
                 }
@@ -231,7 +238,7 @@
         final JobDetail detail = this.createJobDetail(name, jobDataMap);
 
         this.logger.debug("Scheduling job {} with name {} and trigger {}", new Object[] {job, name, trigger});
-        this.scheduler.scheduleJob(detail, trigger);
+        s.scheduleJob(detail, trigger);
     }
 
     /**
@@ -278,9 +285,9 @@
      * Check the job object, either runnable or job is allowed
      */
     protected void checkJob(Object job)
-    throws Exception {
+    throws IllegalArgumentException {
         if (!(job instanceof Runnable) && !(job instanceof Job)) {
-            throw new Exception("Job object is neither an instance of " + Runnable.class.getName() + " nor " + Job.class.getName());
+            throw new IllegalArgumentException("Job object is neither an instance of " + Runnable.class.getName() + " nor " + Job.class.getName());
         }
     }
 
@@ -292,13 +299,13 @@
                        Map<String, Serializable>    config,
                        String schedulingExpression,
                        boolean canRunConcurrently)
-    throws Exception {
+    throws SchedulerException {
         final CronTrigger cronJobEntry = new CronTrigger(name, DEFAULT_QUARTZ_JOB_GROUP);
 
         try {
             cronJobEntry.setCronExpression(schedulingExpression);
         } catch (final ParseException pe) {
-            throw new Exception(pe.getMessage(), pe);
+            throw new IllegalArgumentException("Error during parsing of cron '" + schedulingExpression + "' : " + pe.getMessage(), pe);
         }
         this.scheduleJob(name, job, config, cronJobEntry, canRunConcurrently);
     }
@@ -307,7 +314,7 @@
      * @see org.apache.sling.commons.scheduler.Scheduler#addPeriodicJob(java.lang.String, java.lang.Object, java.util.Map, long, boolean)
      */
     public void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period, boolean canRunConcurrently)
-    throws Exception {
+    throws SchedulerException {
         final long ms = period * 1000;
         if ( name == null ) {
             name = PREFIX + UUID.randomUUID().toString();
@@ -323,7 +330,7 @@
      * @see org.apache.sling.commons.scheduler.Scheduler#fireJob(java.lang.Object, java.util.Map)
      */
     public void fireJob(Object job, Map<String, Serializable> config)
-    throws Exception {
+    throws SchedulerException {
         this.checkJob(job);
         final String name = job.getClass().getName();
         final JobDataMap dataMap = this.initDataMap(name, job, config, true);
@@ -337,7 +344,8 @@
     /**
      * @see org.apache.sling.commons.scheduler.Scheduler#fireJobAt(java.lang.String, java.lang.Object, java.util.Map, java.util.Date)
      */
-    public void fireJobAt(String name, Object job, Map<String, Serializable> config, Date date) throws Exception {
+    public void fireJobAt(String name, Object job, Map<String, Serializable> config, Date date)
+    throws SchedulerException {
         if ( name == null ) {
             name = PREFIX + UUID.randomUUID().toString();
         }
@@ -349,11 +357,16 @@
      * @see org.apache.sling.commons.scheduler.Scheduler#removeJob(java.lang.String)
      */
     public void removeJob(String name) throws NoSuchElementException {
-        try {
-            this.scheduler.deleteJob(name, DEFAULT_QUARTZ_JOB_GROUP);
-            this.logger.debug("Unscheduling job with name {}", name);
-        } catch (final SchedulerException se) {
-            throw new NoSuchElementException(se.getMessage());
+        // as this method might be called from unbind and during
+        // unbind a deactivate could happen, we check the scheduler first
+        final org.quartz.Scheduler s = this.scheduler;
+        if ( s != null ) {
+            try {
+                this.scheduler.deleteJob(name, DEFAULT_QUARTZ_JOB_GROUP);
+                this.logger.debug("Unscheduling job with name {}", name);
+            } catch (final SchedulerException se) {
+                throw new NoSuchElementException(se.getMessage());
+            }
         }
     }
 
@@ -380,23 +393,32 @@
      * Register a job or task
      * @param type The type (job or task)
      * @param ref The service reference
-     * @throws Exception If the registration can't be performed
      */
-    private void register(String type, ServiceReference ref)
-    throws Exception {
-        final Object job = this.context.locateService(type, ref);
-        if ( ref != null ) {
-            this.checkJob(job);
-            final String name = getServiceIdentifier(ref);
-            final Boolean concurrent = (Boolean)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_CONCURRENT);
-            final String expression = (String)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_EXPRESSION);
-            if ( expression != null ) {
-                this.addJob(name, job, null, expression, (concurrent != null ? concurrent : true));
-            } else {
-                final Long period = (Long)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_PERIOD);
-                if ( period != null ) {
-                    this.addPeriodicJob(name, job, null, period, (concurrent != null ? concurrent : true));
+    private void register(String type, ServiceReference ref) {
+        // we called from bind, it might be that deactivate has been
+        // called in the meantime
+        final ComponentContext ctx = this.context;
+        if ( ctx != null ) {
+            try {
+                final Object job = ctx.locateService(type, ref);
+                if ( ref != null ) {
+                    this.checkJob(job);
+                    final String name = getServiceIdentifier(ref);
+                    final Boolean concurrent = (Boolean)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_CONCURRENT);
+                    final String expression = (String)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_EXPRESSION);
+                    if ( expression != null ) {
+                        this.addJob(name, job, null, expression, (concurrent != null ? concurrent : true));
+                    } else {
+                        final Long period = (Long)ref.getProperty(Scheduler.PROPERTY_SCHEDULER_PERIOD);
+                        if ( period != null ) {
+                            this.addPeriodicJob(name, job, null, period, (concurrent != null ? concurrent : true));
+                        }
+                    }
                 }
+            } catch (IllegalStateException e) {
+                // this can happen if deactivate has been called - therefore ignoring
+            } catch (SchedulerException e) {
+                // this can happen if deactivate has been called - therefore ignoring
             }
         }
     }
@@ -406,8 +428,12 @@
      * @param ref The service reference.
      */
     private void unregister(ServiceReference ref) {
-        final String name = getServiceIdentifier(ref);
-        this.removeJob(name);
+        try {
+            final String name = getServiceIdentifier(ref);
+            this.removeJob(name);
+        } catch (NoSuchElementException nsee) {
+            // we ignore this
+        }
     }
 
     /**
@@ -415,8 +441,7 @@
      * @param ref
      * @throws Exception
      */
-    protected void bindJob(ServiceReference ref)
-    throws Exception {
+    protected void bindJob(ServiceReference ref) {
         if ( this.scheduler != null ) {
             this.register(Registration.JOB, ref);
         } else {
@@ -445,8 +470,7 @@
      * @param ref
      * @throws Exception
      */
-    protected void bindTask(ServiceReference ref)
-    throws Exception {
+    protected void bindTask(ServiceReference ref) {
         if ( this.scheduler != null ) {
             this.register(Registration.TASK, ref);
         } else {