You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by an...@apache.org on 2013/02/06 12:23:14 UTC

svn commit: r1442913 - in /tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz: JobSpec.java QuartzResourceAdapter.java

Author: andygumbrecht
Date: Wed Feb  6 11:23:13 2013
New Revision: 1442913

URL: http://svn.apache.org/viewvc?rev=1442913&view=rev
Log:
Fix https://issues.apache.org/jira/browse/OPENEJB-1996
Fix https://issues.apache.org/jira/browse/OPENEJB-1995

Modified:
    tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/JobSpec.java
    tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/QuartzResourceAdapter.java

Modified: tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/JobSpec.java
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/JobSpec.java?rev=1442913&r1=1442912&r2=1442913&view=diff
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/JobSpec.java (original)
+++ tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/JobSpec.java Wed Feb  6 11:23:13 2013
@@ -38,7 +38,7 @@ import java.util.TimeZone;
 
 /**
  * @version $Rev$ $Date$
-*/
+ */
 public final class JobSpec implements ActivationSpec {
 
     private MessageEndpoint endpoint;
@@ -67,7 +67,7 @@ public final class JobSpec implements Ac
         return triggerName;
     }
 
-    public void setTriggerName(String s) {
+    public void setTriggerName(final String s) {
         triggerName = s;
     }
 
@@ -75,7 +75,7 @@ public final class JobSpec implements Ac
         return triggerGroup;
     }
 
-    public void setTriggerGroup(String s) {
+    public void setTriggerGroup(final String s) {
         triggerGroup = s;
     }
 
@@ -85,13 +85,13 @@ public final class JobSpec implements Ac
         return jobName;
     }
 
-    public void setJobName(String s) {
+    public void setJobName(final String s) {
         jobName = s;
     }
 
     // -- Job Group
 
-    public void setJobGroup(String s) {
+    public void setJobGroup(final String s) {
         jobGroup = s;
     }
 
@@ -105,13 +105,13 @@ public final class JobSpec implements Ac
         return description;
     }
 
-    public void setDescription(String s) {
+    public void setDescription(final String s) {
         description = s;
     }
 
     // -- Recoverable
 
-    public void setRequestsRecovery(boolean b) {
+    public void setRequestsRecovery(final boolean b) {
         recoverable = b;
     }
 
@@ -125,13 +125,13 @@ public final class JobSpec implements Ac
         return durable;
     }
 
-    public void setDurable(boolean b) {
+    public void setDurable(final boolean b) {
         durable = b;
     }
 
     // -- Calendar name
 
-    public void setCalendarName(String s) {
+    public void setCalendarName(final String s) {
         calendarName = s;
     }
 
@@ -141,7 +141,7 @@ public final class JobSpec implements Ac
 
     // -- Expression
 
-    public void setCronExpression(String s) {
+    public void setCronExpression(final String s) {
         cronExpression = s;
     }
 
@@ -151,60 +151,60 @@ public final class JobSpec implements Ac
 
     /**
      * An alias for CronExpression
+     * See http://quartz-scheduler.org/api/2.0.0/org/quartz/CronExpression.html
      *
-     * @param s
+     * @param s Valid cron expression
      */
-    public void setCronTrigger(String s) {
+    public void setCronTrigger(final String s) {
         setCronExpression(s);
     }
 
     // --
 
-    public void setTimeZone(String timeZone) {
+    public void setTimeZone(final String timeZone) {
         this.timeZone = timeZone;
     }
 
     // --
 
-    public void setStartTime(String startTime) {
-        Date date = parse(startTime);
+    public void setStartTime(final String startTime) {
+        final Date date = parse(startTime);
         if (date != null) {
             this.startTime = startTime;
         }
     }
 
-    public void setEndTime(String endTime) {
-        Date date = parse(endTime);
+    public void setEndTime(final String endTime) {
+        final Date date = parse(endTime);
         if (date != null) {
             this.endTime = endTime;
         }
     }
 
+    private Date parse(final String value) {
 
-    private Date parse(String value) {
-
-        String[] formats = {
-                "EEE MMM d HH:mm:ss z yyyy",
-                "EEE, d MMM yyyy HH:mm:ss Z",
-                "yyyy-MM-dd HH:mm:ss.S",
-                "yyyy-MM-dd HH:mm:ss.SZ",
-                "yyyy-MM-dd HH:mm:ss.S",
-                "yyyy-MM-dd HH:mm:ssZ",
-                "yyyy-MM-dd HH:mm:ss",
-                "yyyy-MM-dd HH:mmZ",
-                "yyyy-MM-dd HH:mm",
-                "yyyy-MM-dd'T'HH:mm:ss.SZ",
-                "yyyy-MM-dd'T'HH:mm:ss.S",
-                "yyyy-MM-dd'T'HH:mm:ssZ",
-                "yyyy-MM-dd'T'HH:mm:ss",
-                "yyyy-MM-dd'T'HH:mmZ",
-                "yyyy-MM-dd'T'HH:mm",
-                "yyyy-MM-dd",
-                "yyyyMMdd"
+        final String[] formats = {
+                                     "EEE MMM d HH:mm:ss z yyyy",
+                                     "EEE, d MMM yyyy HH:mm:ss Z",
+                                     "yyyy-MM-dd HH:mm:ss.S",
+                                     "yyyy-MM-dd HH:mm:ss.SZ",
+                                     "yyyy-MM-dd HH:mm:ss.S",
+                                     "yyyy-MM-dd HH:mm:ssZ",
+                                     "yyyy-MM-dd HH:mm:ss",
+                                     "yyyy-MM-dd HH:mmZ",
+                                     "yyyy-MM-dd HH:mm",
+                                     "yyyy-MM-dd'T'HH:mm:ss.SZ",
+                                     "yyyy-MM-dd'T'HH:mm:ss.S",
+                                     "yyyy-MM-dd'T'HH:mm:ssZ",
+                                     "yyyy-MM-dd'T'HH:mm:ss",
+                                     "yyyy-MM-dd'T'HH:mmZ",
+                                     "yyyy-MM-dd'T'HH:mm",
+                                     "yyyy-MM-dd",
+                                     "yyyyMMdd"
         };
 
-        for (String format : formats) {
-            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        for (final String format : formats) {
+            final SimpleDateFormat dateFormat = new SimpleDateFormat(format);
             try {
                 return dateFormat.parse(value);
             } catch (ParseException e) {
@@ -218,36 +218,41 @@ public final class JobSpec implements Ac
 
     // -- ActivationSpec methods
 
+    @SuppressWarnings("unchecked")
+    @Override
     public void validate() throws InvalidPropertyException {
-        if (invalidProperty != null) throw invalidProperty;
+        if (invalidProperty != null)
+            throw invalidProperty;
 
-        int i = hashCode();
+        final int i = hashCode();
         detail = JobBuilder.newJob(QuartzResourceAdapter.JobEndpoint.class)
-                .withIdentity("Job" + i, Scheduler.DEFAULT_GROUP)
-                .withDescription(description)
-                .requestRecovery(recoverable)
-                .storeDurably(durable)
-                .build();
+                           .withIdentity("Job" + i, Scheduler.DEFAULT_GROUP)
+                           .withDescription(description)
+                           .requestRecovery(recoverable)
+                           .storeDurably(durable)
+                           .build();
         final TriggerBuilder tb = TriggerBuilder.newTrigger()
-                .forJob(detail)
-                .withIdentity("Trigger" + i, Scheduler.DEFAULT_GROUP)
-                .withDescription(description);
+                                                .forJob(detail)
+                                                .withIdentity("Trigger" + i, Scheduler.DEFAULT_GROUP)
+                                                .withDescription(description);
         if (startTime != null) {
-                tb.startAt(parse(startTime));
+            tb.startAt(parse(startTime));
         }
+
         if (endTime != null) {
-                tb.endAt(parse(endTime));
+            tb.endAt(parse(endTime));
         }
+
         if (calendarName != null) {
-                tb.modifiedByCalendar(calendarName);
+            tb.modifiedByCalendar(calendarName);
         }
+
         final CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule(getCronExpression());
         if (timeZone != null) {
             csb.inTimeZone(TimeZone.getTimeZone(timeZone));
         }
-        tb.withSchedule(CronScheduleBuilder.cronSchedule(getCronExpression()));
-        trigger = tb.build();
-        
+
+        trigger = tb.withSchedule(csb).build();
 
         try {
             ((CronTriggerImpl) trigger).validate();
@@ -256,11 +261,13 @@ public final class JobSpec implements Ac
         }
     }
 
+    @Override
     public ResourceAdapter getResourceAdapter() {
         return resourceAdapter;
     }
 
-    public void setResourceAdapter(ResourceAdapter resourceAdapter) {
+    @Override
+    public void setResourceAdapter(final ResourceAdapter resourceAdapter) {
         this.resourceAdapter = resourceAdapter;
     }
 
@@ -268,7 +275,7 @@ public final class JobSpec implements Ac
         return endpoint;
     }
 
-    void setEndpoint(MessageEndpoint endpoint) {
+    void setEndpoint(final MessageEndpoint endpoint) {
         this.endpoint = endpoint;
     }
 

Modified: tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/QuartzResourceAdapter.java
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/QuartzResourceAdapter.java?rev=1442913&r1=1442912&r2=1442913&view=diff
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/QuartzResourceAdapter.java (original)
+++ tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/resource/quartz/QuartzResourceAdapter.java Wed Feb  6 11:23:13 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.openejb.resource.quartz;
 
+import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.util.LogCategory;
 import org.quartz.Job;
 import org.quartz.JobDataMap;
@@ -24,6 +25,7 @@ import org.quartz.JobExecutionException;
 import org.quartz.Scheduler;
 import org.quartz.SchedulerException;
 import org.quartz.impl.StdSchedulerFactory;
+import org.quartz.listeners.SchedulerListenerSupport;
 
 import javax.resource.ResourceException;
 import javax.resource.spi.ActivationSpec;
@@ -33,166 +35,236 @@ import javax.resource.spi.endpoint.Messa
 import javax.resource.spi.endpoint.MessageEndpointFactory;
 import javax.transaction.xa.XAResource;
 import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * @version $Rev$ $Date$
  */
 public class QuartzResourceAdapter implements javax.resource.spi.ResourceAdapter {
 
-    private static Exception ex = null;
-    private Scheduler scheduler;
-    private BootstrapContext bootstrapContext;
-    private Thread startThread;
+    public static final String OPENEJB_QUARTZ_TIMEOUT = "openejb.quartz.timeout";
 
-    public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException {
+    //Start and stop may be called from different threads so use atomics
+    private final AtomicReference<Exception> ex = new AtomicReference<Exception>();
+    private final AtomicReference<Scheduler> scheduler = new AtomicReference<Scheduler>();
+    private final AtomicReference<BootstrapContext> bootstrapContext = new AtomicReference<BootstrapContext>();
+    private final AtomicReference<Thread> startThread = new AtomicReference<Thread>();
 
-        this.bootstrapContext = bootstrapContext;
+    @Override
+    public void start(final BootstrapContext bootstrapContext) throws ResourceAdapterInternalException {
 
-        startThread = new Thread("Quartz Scheduler Start") {
+        if (null != this.bootstrapContext.getAndSet(bootstrapContext)) {
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("QuartzResourceAdapter is already starting");
+            return;
+        }
 
-            @Override
-            public void run() {
+        final CountDownLatch signal = new CountDownLatch(1);
+        long timeout = SystemInstance.get().getOptions().get(QuartzResourceAdapter.OPENEJB_QUARTZ_TIMEOUT, 10000L);
 
-                Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+        if (timeout < 1000L) {
+            timeout = 1000L;
+        }
 
-                synchronized (QuartzResourceAdapter.this) {
+        if (timeout > 60000L) {
+            timeout = 60000L;
+        }
 
-                    try {
-                        scheduler = StdSchedulerFactory.getDefaultScheduler();
-                    } catch (Exception e) {
-                        ex = e;
-                        return;
-                    }
+        //Allow org.quartz.InterruptableJob implementors to be interrupted on shutdown
+        System.setProperty(StdSchedulerFactory.PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN
+                              , System.getProperty(StdSchedulerFactory.PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN, "true"));
+        System.setProperty(StdSchedulerFactory.PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT
+                              , System.getProperty(StdSchedulerFactory.PROP_SCHED_INTERRUPT_JOBS_ON_SHUTDOWN_WITH_WAIT, "true"));
+
+        startThread.set(new Thread("Quartz Scheduler Start") {
+
+            @Override
+            public void run() {
+
+                try {
+                    QuartzResourceAdapter.this.scheduler.set(StdSchedulerFactory.getDefaultScheduler());
+                } catch (Exception e) {
+                    QuartzResourceAdapter.this.ex.set(e);
+                    return;
                 }
 
                 try {
-                    scheduler.start();
+                    QuartzResourceAdapter.this.scheduler.get().getListenerManager().addSchedulerListener(new SchedulerListenerSupport() {
+                        @Override
+                        public void schedulerStarted() {
+                            signal.countDown();
+                        }
+                    });
+
+                    QuartzResourceAdapter.this.scheduler.get().start();
+
                 } catch (Exception e) {
-                    ex = e;
+                    QuartzResourceAdapter.this.ex.set(e);
+                    signal.countDown();
                 }
             }
-        };
+        });
 
-        startThread.setDaemon(true);
-        startThread.start();
+        startThread.get().setDaemon(true);
+        startThread.get().start();
 
+        boolean started = false;
         try {
-            startThread.join(5000);
+            started = signal.await(timeout, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
+            //Ignore
         }
 
-
-        if (null != ex) {
-            throw new ResourceAdapterInternalException("Failed to create Quartz Scheduler", ex);
+        final Exception exception = ex.get();
+        if (null != exception) {
+            final String err = "Error creating Quartz Scheduler";
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").error(err, exception);
+            throw new ResourceAdapterInternalException(err, exception);
         }
 
-        org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").info("Started Quartz Scheduler");
+        if (started) {
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").info("Started Quartz Scheduler");
+        } else {
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("Failed to start Quartz Scheduler within defined timeout, status unknown");
+        }
     }
 
     public Scheduler getScheduler() {
-        return scheduler;
+        return scheduler.get();
     }
 
     public BootstrapContext getBootstrapContext() {
-        return bootstrapContext;
+        return bootstrapContext.get();
     }
 
+    @Override
     public void stop() {
 
-        synchronized (this) {
+        final Scheduler s = scheduler.getAndSet(null);
 
-            if (null != scheduler) {
+        if (null != s) {
 
-                if (startThread.isAlive()) {
-                    startThread.interrupt();
-                }
+            if (null != startThread.get()) {
+                startThread.get().interrupt();
+            }
 
-                Thread stopThread = new Thread("Quartz Scheduler Requested Stop") {
+            long timeout = SystemInstance.get().getOptions().get(QuartzResourceAdapter.OPENEJB_QUARTZ_TIMEOUT, 10000L);
 
-                    @Override
-                    public void run() {
-                        try {
-                            scheduler.shutdown(true);
-                        } catch (Exception e) {
-                            ex = e;
-                        }
-                    }
-                };
+            if (timeout < 1000L) {
+                timeout = 1000L;
+            }
 
-                stopThread.setDaemon(true);
-                stopThread.start();
+            if (timeout > 60000L) {
+                timeout = 60000L;
+            }
 
-                try {
-                    //Block for a maximum of 5 seconds waiting for this thread to die.
-                    stopThread.join(5000);
-                } catch (InterruptedException ie) {
-                    //Ignore
-                }
+            final CountDownLatch shutdownWait = new CountDownLatch(1);
 
-                try {
-                    if (!scheduler.isShutdown()) {
+            Thread stopThread = new Thread("Quartz Scheduler Requested Stop") {
 
-                        stopThread = new Thread("Quartz Scheduler Forced Stop") {
+                @Override
+                public void run() {
+                    try {
+                        s.getListenerManager().addSchedulerListener(new SchedulerListenerSupport() {
 
                             @Override
-                            public void run() {
-                                try {
-                                    //Try to force a shutdown
-                                    scheduler.shutdown(false);
-                                    org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("Forced Quartz stop - Jobs may be incomplete");
-                                } catch (Exception e) {
-                                    ex = e;
-                                }
+                            public void schedulerShutdown() {
+                                shutdownWait.countDown();
                             }
-                        };
+                        });
 
-                        stopThread.setDaemon(true);
-                        stopThread.start();
+                        //Shutdown, but give running jobs a chance to complete.
+                        //User scheduled jobs should really implement InterruptableJob
+                        s.shutdown(true);
+                    } catch (Exception e) {
+                        QuartzResourceAdapter.this.ex.set(e);
                     }
-                } catch (Exception e) {
-                    ex = e;
                 }
+            };
+
+            stopThread.setDaemon(true);
+            stopThread.start();
+
+            boolean stopped = false;
+            try {
+                stopped = shutdownWait.await(timeout, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                //Ignore
             }
-        }
 
-        this.bootstrapContext = null;
+            try {
+                if (!stopped || !s.isShutdown()) {
 
-        if (null != ex) {
-            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("Error stopping Quartz Scheduler", ex);
-            return;
+                    stopThread = new Thread("Quartz Scheduler Forced Stop") {
+
+                        @Override
+                        public void run() {
+                            try {
+                                //Force a shutdown without waiting for jobs to complete.
+                                s.shutdown(false);
+                                org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("Forced Quartz stop - Jobs may be incomplete");
+                            } catch (Exception e) {
+                                QuartzResourceAdapter.this.ex.set(e);
+                            }
+                        }
+                    };
+
+                    stopThread.setDaemon(true);
+                    stopThread.start();
+
+                    try {
+                        //Give the forced shutdown a chance to complete
+                        stopThread.join(timeout);
+                    } catch (InterruptedException e) {
+                        //Ignore
+                    }
+                }
+            } catch (Exception e) {
+                ex.set(e);
+            }
         }
 
-        org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").info("Stopped Quartz Scheduler");
+        this.bootstrapContext.set(null);
+
+        if (null != ex.get()) {
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").warning("Error stopping Quartz Scheduler", ex.get());
+        } else {
+            org.apache.openejb.util.Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources").info("Stopped Quartz Scheduler");
+        }
     }
 
-    public void endpointActivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) throws ResourceException {
+    @Override
+    public void endpointActivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) throws ResourceException {
 
-        if (null == scheduler) {
+        final Scheduler s = scheduler.get();
+        if (null == s) {
             throw new ResourceException("Quartz Scheduler is not available");
         }
 
         try {
 
-            JobSpec spec = (JobSpec) activationSpec;
+            final JobSpec spec = (JobSpec) activationSpec;
 
-            MessageEndpoint endpoint = messageEndpointFactory.createEndpoint(null);
+            final MessageEndpoint endpoint = messageEndpointFactory.createEndpoint(null);
             spec.setEndpoint(endpoint);
 
-            Job job = (Job) endpoint;
+            final Job job = (Job) endpoint;
 
-            JobDataMap jobDataMap = spec.getDetail().getJobDataMap();
+            final JobDataMap jobDataMap = spec.getDetail().getJobDataMap();
             jobDataMap.put(Data.class.getName(), new Data(job));
 
-            scheduler.scheduleJob(spec.getDetail(), spec.getTrigger());
+            s.scheduleJob(spec.getDetail(), spec.getTrigger());
         } catch (SchedulerException e) {
             throw new ResourceException("Failed to schedule job", e);
         }
     }
 
-    public void endpointDeactivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec) {
+    @Override
+    public void endpointDeactivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) {
 
-        if (null == scheduler) {
+        final Scheduler s = scheduler.get();
+        if (null == s) {
             throw new IllegalStateException("Quartz Scheduler is not available");
         }
 
@@ -200,7 +272,7 @@ public class QuartzResourceAdapter imple
 
         try {
             spec = (JobSpec) activationSpec;
-            scheduler.deleteJob(spec.jobKey());
+            s.deleteJob(spec.jobKey());
 
         } catch (SchedulerException e) {
             throw new IllegalStateException("Failed to delete job", e);
@@ -215,24 +287,25 @@ public class QuartzResourceAdapter imple
 
         private static Method method = null;
 
-        public void execute(JobExecutionContext execution) throws JobExecutionException {
+        @Override
+        public void execute(final JobExecutionContext execution) throws JobExecutionException {
 
             MessageEndpoint endpoint = null;
+            JobExecutionException ex = null;
 
             try {
 
-                JobDataMap jobDataMap = execution.getJobDetail().getJobDataMap();
-
-                Data data = Data.class.cast(jobDataMap.get(Data.class.getName()));
+                final JobDataMap jobDataMap = execution.getJobDetail().getJobDataMap();
 
-                Job job = data.job;
+                final Data data = Data.class.cast(jobDataMap.get(Data.class.getName()));
 
-                endpoint = (MessageEndpoint) job;
+                final Job job = data.job;
 
                 if (null == method) {
-                    method = Job.class.getMethod("execute", JobExecutionContext.class);
+                    method = job.getClass().getMethod("execute", JobExecutionContext.class);
                 }
 
+                endpoint = (MessageEndpoint) job;
                 endpoint.beforeDelivery(method);
 
                 job.execute(execution);
@@ -240,19 +313,23 @@ public class QuartzResourceAdapter imple
             } catch (NoSuchMethodException e) {
                 throw new IllegalStateException(e);
             } catch (ResourceException e) {
-                throw new JobExecutionException(e);
+                ex = new JobExecutionException(e);
             } catch (Throwable t) {
-                throw new JobExecutionException(new Exception(t));
+                ex = new JobExecutionException(new Exception(t));
             } finally {
 
                 if (null != endpoint) {
                     try {
                         endpoint.afterDelivery();
                     } catch (ResourceException e) {
-                        throw new JobExecutionException(e);
+                        ex = new JobExecutionException(e);
                     }
                 }
             }
+
+            if (null != ex) {
+                throw ex;
+            }
         }
     }
 
@@ -265,12 +342,13 @@ public class QuartzResourceAdapter imple
 
         private final Job job;
 
-        private Data(Job job) {
+        private Data(final Job job) {
             this.job = job;
         }
     }
 
-    public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException {
+    @Override
+    public XAResource[] getXAResources(final ActivationSpec[] activationSpecs) throws ResourceException {
         return new XAResource[0];
     }
 }