deltaspike-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gpetra...@apache.org
Subject deltaspike git commit: DELTASPIKE-1054 optional mode for switching from org.quartz.Job to java.lang.Runnable
Date Wed, 30 Dec 2015 17:36:54 GMT
Repository: deltaspike
Updated Branches:
  refs/heads/master e79b665a4 -> aa1893f71


DELTASPIKE-1054 optional mode for switching from org.quartz.Job to java.lang.Runnable


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/aa1893f7
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/aa1893f7
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/aa1893f7

Branch: refs/heads/master
Commit: aa1893f71d1658b4f052600453d89e83728b5233
Parents: e79b665
Author: gpetracek <gpetracek@apache.org>
Authored: Wed Dec 30 16:50:53 2015 +0100
Committer: gpetracek <gpetracek@apache.org>
Committed: Wed Dec 30 18:34:41 2015 +0100

----------------------------------------------------------------------
 .../scheduler/impl/AbstractQuartzScheduler.java | 474 +++++++++++++++++++
 .../scheduler/impl/JobQuartzScheduler.java      |  31 ++
 .../scheduler/impl/JobRunnableAdapter.java      |  41 ++
 .../scheduler/impl/QuartzScheduler.java         | 466 ------------------
 .../scheduler/impl/RunnableQuartzScheduler.java |  37 ++
 .../scheduler/impl/SchedulerExtension.java      |  14 +
 ...rg.apache.deltaspike.scheduler.spi.Scheduler |  10 +-
 .../scheduler/custom/QuartzDeactivator.java     |   3 +-
 8 files changed, 608 insertions(+), 468 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/AbstractQuartzScheduler.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/AbstractQuartzScheduler.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/AbstractQuartzScheduler.java
new file mode 100644
index 0000000..bd85f93
--- /dev/null
+++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/AbstractQuartzScheduler.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.scheduler.impl;
+
+import org.apache.deltaspike.cdise.api.ContextControl;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.api.provider.DependentProvider;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+import org.apache.deltaspike.core.util.PropertyFileUtils;
+import org.apache.deltaspike.core.util.ProxyUtils;
+import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
+import org.apache.deltaspike.scheduler.api.Scheduled;
+import org.apache.deltaspike.scheduler.spi.Scheduler;
+import org.quartz.CronScheduleBuilder;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.JobKey;
+import org.quartz.JobListener;
+import org.quartz.SchedulerException;
+import org.quartz.SchedulerFactory;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+import org.quartz.impl.StdSchedulerFactory;
+
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public abstract class AbstractQuartzScheduler<T> implements Scheduler<T>
+{
+    private static final Logger LOG = Logger.getLogger(AbstractQuartzScheduler.class.getName());
+    private static final Scheduled DEFAULT_SCHEDULED_LITERAL = AnnotationInstanceProvider.of(Scheduled.class);
+
+    private static ThreadLocal<JobListenerContext> currentJobListenerContext = new
ThreadLocal<JobListenerContext>();
+
+    protected org.quartz.Scheduler scheduler;
+
+    @Override
+    public void start()
+    {
+        if (this.scheduler != null)
+        {
+            throw new UnsupportedOperationException("the scheduler is started already");
+        }
+
+        SchedulerFactory schedulerFactory = null;
+        try
+        {
+            Properties properties = new Properties();
+            properties.put(StdSchedulerFactory.PROP_SCHED_JOB_FACTORY_CLASS, CdiAwareJobFactory.class.getName());
+
+            try
+            {
+                ResourceBundle config = loadCustomQuartzConfig();
+
+                Enumeration<String> keys = config.getKeys();
+                String key;
+                while (keys.hasMoreElements())
+                {
+                    key = keys.nextElement();
+                    properties.put(key, config.getString(key));
+                }
+            }
+            catch (Exception e1)
+            {
+                LOG.info("no custom quartz-config file found. falling back to the default
config provided by quartz.");
+
+                InputStream inputStream = null;
+                try
+                {
+                    inputStream = ClassUtils.getClassLoader(null).getResourceAsStream("org/quartz/quartz.properties");
+                    properties.load(inputStream);
+                }
+                catch (Exception e2)
+                {
+                    LOG.warning("failed to load quartz default-config");
+                    schedulerFactory = new StdSchedulerFactory();
+                }
+                finally
+                {
+                    if (inputStream != null)
+                    {
+                        inputStream.close();
+                    }
+                }
+            }
+            if (schedulerFactory == null)
+            {
+                schedulerFactory = new StdSchedulerFactory(properties);
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.log(Level.WARNING, "fallback to default scheduler-factory", e);
+            schedulerFactory = new StdSchedulerFactory();
+        }
+
+        try
+        {
+            this.scheduler = schedulerFactory.getScheduler();
+            if (SchedulerBaseConfig.LifecycleIntegration.START_SCOPES_PER_JOB)
+            {
+                this.scheduler.getListenerManager().addJobListener(new InjectionAwareJobListener());
+            }
+            if (!this.scheduler.isStarted())
+            {
+                this.scheduler.startDelayed(SchedulerBaseConfig.LifecycleIntegration.DELAYED_START_IN_SECONDS);
+            }
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    protected ResourceBundle loadCustomQuartzConfig()
+    {
+        //don't use quartz.properties as default-value
+        String configFile = SchedulerBaseConfig.SCHEDULER_CONFIG_FILE;
+        return PropertyFileUtils.getResourceBundle(configFile);
+    }
+
+    @Override
+    public void stop()
+    {
+        try
+        {
+            if (this.scheduler != null && this.scheduler.isStarted())
+            {
+                this.scheduler.shutdown(SchedulerBaseConfig.LifecycleIntegration.FORCE_STOP);
+                this.scheduler = null;
+            }
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void registerNewJob(Class<? extends T> jobClass)
+    {
+        JobKey jobKey = createJobKey(jobClass);
+
+        try
+        {
+            Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
+
+            String description = scheduled.description();
+
+            if ("".equals(scheduled.description()))
+            {
+                description = jobClass.getName();
+            }
+
+            JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
+            Trigger trigger;
+
+            if (jobDetail == null)
+            {
+                Class<? extends Job> jobClassToAdd = createFinalJobClass(jobClass);
+                jobDetail = JobBuilder.newJob(jobClassToAdd)
+                        .withDescription(description)
+                        .withIdentity(jobKey)
+                        .build();
+
+                trigger = TriggerBuilder.newTrigger()
+                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
+                        .build();
+
+                this.scheduler.scheduleJob(jobDetail, trigger);
+            }
+            else if (scheduled.overrideOnStartup())
+            {
+                List<? extends Trigger> existingTriggers = this.scheduler.getTriggersOfJob(jobKey);
+
+                if (existingTriggers == null || existingTriggers.isEmpty())
+                {
+                    //TODO re-visit it
+                    trigger = TriggerBuilder.newTrigger()
+                            .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
+                            .build();
+
+                    this.scheduler.scheduleJob(jobDetail, trigger);
+                    return;
+                }
+
+                if (existingTriggers.size() > 1)
+                {
+                    throw new IllegalStateException("multiple triggers found for " + jobKey
+ " ('" + jobDetail + "')" +
+                        ", but aren't supported by @" + Scheduled.class.getName() + "#overrideOnStartup");
+                }
+
+                trigger = existingTriggers.iterator().next();
+
+                trigger = TriggerBuilder.newTrigger()
+                        .withIdentity(trigger.getKey())
+                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
+                        .build();
+
+                this.scheduler.rescheduleJob(trigger.getKey(), trigger);
+            }
+            else
+            {
+                Logger.getLogger(AbstractQuartzScheduler.class.getName()).info(
+                    jobKey + " exists already and will be ignored.");
+            }
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    protected abstract Class<? extends Job> createFinalJobClass(Class<? extends
T> jobClass);
+
+    @Override
+    public void startJobManually(Class<? extends T> jobClass)
+    {
+        try
+        {
+            this.scheduler.triggerJob(createJobKey(jobClass));
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void interruptJob(Class<? extends T> jobClass)
+    {
+        try
+        {
+            this.scheduler.interrupt(createJobKey(jobClass));
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean deleteJob(Class<? extends T> jobClass)
+    {
+        try
+        {
+            return this.scheduler.deleteJob(createJobKey(jobClass));
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void pauseJob(Class<? extends T> jobClass)
+    {
+        try
+        {
+            this.scheduler.pauseJob(createJobKey(jobClass));
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void resumeJob(Class<? extends T> jobClass)
+    {
+        try
+        {
+            this.scheduler.resumeJob(createJobKey(jobClass));
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean isExecutingJob(Class<? extends T> jobClass)
+    {
+        try
+        {
+            JobKey jobKey = createJobKey(jobClass);
+            JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
+
+            if (jobDetail == null)
+            {
+                return false;
+            }
+
+            for (JobExecutionContext jobExecutionContext : this.scheduler.getCurrentlyExecutingJobs())
+            {
+                if (jobKey.equals(jobExecutionContext.getJobDetail().getKey()))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+        catch (SchedulerException e)
+        {
+            throw ExceptionUtils.throwAsRuntimeException(e);
+        }
+    }
+
+    private JobKey createJobKey(Class<?> jobClass)
+    {
+        Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
+
+        if (scheduled == null)
+        {
+            throw new IllegalStateException("@" + Scheduled.class.getName() + " is missing
on " + jobClass.getName());
+        }
+
+        String groupName = scheduled.group().getSimpleName();
+        String jobName = getJobName(jobClass);
+
+        if (!Scheduled.class.getSimpleName().equals(groupName))
+        {
+            return new JobKey(jobName, groupName);
+        }
+        return new JobKey(jobName);
+    }
+
+    protected String getJobName(Class<?> jobClass)
+    {
+        return jobClass.getSimpleName();
+    }
+
+    private class InjectionAwareJobListener implements JobListener
+    {
+        @Override
+        public String getName()
+        {
+            return getClass().getName();
+        }
+
+        @Override
+        public void jobToBeExecuted(JobExecutionContext jobExecutionContext)
+        {
+            Class<?> jobClass = ProxyUtils.getUnproxiedClass(jobExecutionContext.getJobInstance().getClass());
+            Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
+
+            //can happen with manually registered job-instances (via #unwrap)
+            if (scheduled == null)
+            {
+                scheduled = DEFAULT_SCHEDULED_LITERAL;
+            }
+
+            JobListenerContext jobListenerContext = new JobListenerContext();
+            currentJobListenerContext.set(jobListenerContext);
+            jobListenerContext.startContexts(scheduled);
+
+            boolean jobInstanceIsBean;
+
+            try
+            {
+                jobInstanceIsBean =
+                    Boolean.TRUE.equals(jobExecutionContext.getScheduler().getContext().get(jobClass.getName()));
+            }
+            catch (SchedulerException e)
+            {
+                jobInstanceIsBean = false;
+            }
+
+            if (!jobInstanceIsBean)
+            {
+                BeanProvider.injectFields(jobExecutionContext.getJobInstance());
+            }
+        }
+
+        @Override
+        public void jobExecutionVetoed(JobExecutionContext context)
+        {
+            stopStartedScopes();
+        }
+
+        @Override
+        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException)
+        {
+            stopStartedScopes();
+        }
+
+        private void stopStartedScopes()
+        {
+            JobListenerContext jobListenerContext = currentJobListenerContext.get();
+            if (jobListenerContext != null)
+            {
+                jobListenerContext.stopStartedScopes();
+                currentJobListenerContext.set(null);
+                currentJobListenerContext.remove();
+            }
+        }
+    }
+
+    private static class JobListenerContext
+    {
+        private Stack<Class<? extends Annotation>> scopes = new Stack<Class<?
extends Annotation>>();
+        private DependentProvider<ContextControl> contextControl;
+
+        public void startContexts(Scheduled scheduled)
+        {
+            Collections.addAll(this.scopes, scheduled.startScopes());
+
+            if (!this.scopes.isEmpty())
+            {
+                this.contextControl = BeanProvider.getDependent(ContextControl.class);
+
+                for (Class<? extends Annotation> scopeAnnotation : this.scopes)
+                {
+                    contextControl.get().startContext(scopeAnnotation);
+                }
+            }
+        }
+
+        private void stopStartedScopes()
+        {
+            if (this.contextControl == null)
+            {
+                return;
+            }
+
+            while (!this.scopes.empty())
+            {
+                this.contextControl.get().stopContext(this.scopes.pop());
+            }
+            this.contextControl.destroy();
+        }
+    }
+
+    @Override
+    public <S> S unwrap(Class<? extends S> schedulerClass)
+    {
+        if (schedulerClass.isAssignableFrom(this.scheduler.getClass()))
+        {
+            return (S)this.scheduler;
+        }
+
+        throw new IllegalArgumentException(schedulerClass.getName() +
+            " isn't compatible with " + this.scheduler.getClass().getName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobQuartzScheduler.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobQuartzScheduler.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobQuartzScheduler.java
new file mode 100644
index 0000000..785026e
--- /dev/null
+++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobQuartzScheduler.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.scheduler.impl;
+
+import org.quartz.Job;
+
+//vetoed class (see SchedulerExtension)
+public class JobQuartzScheduler extends AbstractQuartzScheduler<Job>
+{
+    @Override
+    protected Class<? extends Job> createFinalJobClass(Class<? extends Job> jobClass)
+    {
+        return jobClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobRunnableAdapter.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobRunnableAdapter.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobRunnableAdapter.java
new file mode 100644
index 0000000..ab03f27
--- /dev/null
+++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/JobRunnableAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.scheduler.impl;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+import javax.enterprise.inject.Typed;
+
+@Typed()
+public class JobRunnableAdapter implements Job
+{
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException
+    {
+        Class<? extends Runnable> jobClass =
+            ClassUtils.tryToLoadClassForName(context.getJobDetail().getKey().getName(), Runnable.class);
+
+        Runnable runnableBean = BeanProvider.getContextualReference(jobClass);
+        runnableBean.run();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/QuartzScheduler.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/QuartzScheduler.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/QuartzScheduler.java
deleted file mode 100644
index 44e6417..0000000
--- a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/QuartzScheduler.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.deltaspike.scheduler.impl;
-
-import org.apache.deltaspike.cdise.api.ContextControl;
-import org.apache.deltaspike.core.api.provider.BeanProvider;
-import org.apache.deltaspike.core.api.provider.DependentProvider;
-import org.apache.deltaspike.core.util.ClassUtils;
-import org.apache.deltaspike.core.util.ExceptionUtils;
-import org.apache.deltaspike.core.util.PropertyFileUtils;
-import org.apache.deltaspike.core.util.ProxyUtils;
-import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
-import org.apache.deltaspike.scheduler.api.Scheduled;
-import org.apache.deltaspike.scheduler.spi.Scheduler;
-import org.quartz.CronScheduleBuilder;
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDetail;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.quartz.JobKey;
-import org.quartz.JobListener;
-import org.quartz.SchedulerException;
-import org.quartz.SchedulerFactory;
-import org.quartz.Trigger;
-import org.quartz.TriggerBuilder;
-import org.quartz.impl.StdSchedulerFactory;
-
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-import java.util.ResourceBundle;
-import java.util.Stack;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-//vetoed class (see SchedulerExtension)
-public class QuartzScheduler implements Scheduler<Job>
-{
-    private static final Logger LOG = Logger.getLogger(QuartzScheduler.class.getName());
-    private static final Scheduled DEFAULT_SCHEDULED_LITERAL = AnnotationInstanceProvider.of(Scheduled.class);
-
-    private static ThreadLocal<JobListenerContext> currentJobListenerContext = new
ThreadLocal<JobListenerContext>();
-
-    protected org.quartz.Scheduler scheduler;
-
-    @Override
-    public void start()
-    {
-        if (this.scheduler != null)
-        {
-            throw new UnsupportedOperationException("the scheduler is started already");
-        }
-
-        SchedulerFactory schedulerFactory = null;
-        try
-        {
-            Properties properties = new Properties();
-            properties.put(StdSchedulerFactory.PROP_SCHED_JOB_FACTORY_CLASS, CdiAwareJobFactory.class.getName());
-
-            try
-            {
-                ResourceBundle config = loadCustomQuartzConfig();
-
-                Enumeration<String> keys = config.getKeys();
-                String key;
-                while (keys.hasMoreElements())
-                {
-                    key = keys.nextElement();
-                    properties.put(key, config.getString(key));
-                }
-            }
-            catch (Exception e1)
-            {
-                LOG.info("no custom quartz-config file found. falling back to the default
config provided by quartz.");
-
-                InputStream inputStream = null;
-                try
-                {
-                    inputStream = ClassUtils.getClassLoader(null).getResourceAsStream("org/quartz/quartz.properties");
-                    properties.load(inputStream);
-                }
-                catch (Exception e2)
-                {
-                    LOG.warning("failed to load quartz default-config");
-                    schedulerFactory = new StdSchedulerFactory();
-                }
-                finally
-                {
-                    if (inputStream != null)
-                    {
-                        inputStream.close();
-                    }
-                }
-            }
-            if (schedulerFactory == null)
-            {
-                schedulerFactory = new StdSchedulerFactory(properties);
-            }
-        }
-        catch (Exception e)
-        {
-            LOG.log(Level.WARNING, "fallback to default scheduler-factory", e);
-            schedulerFactory = new StdSchedulerFactory();
-        }
-
-        try
-        {
-            this.scheduler = schedulerFactory.getScheduler();
-            if (SchedulerBaseConfig.LifecycleIntegration.START_SCOPES_PER_JOB)
-            {
-                this.scheduler.getListenerManager().addJobListener(new InjectionAwareJobListener());
-            }
-            if (!this.scheduler.isStarted())
-            {
-                this.scheduler.startDelayed(SchedulerBaseConfig.LifecycleIntegration.DELAYED_START_IN_SECONDS);
-            }
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    protected ResourceBundle loadCustomQuartzConfig()
-    {
-        //don't use quartz.properties as default-value
-        String configFile = SchedulerBaseConfig.SCHEDULER_CONFIG_FILE;
-        return PropertyFileUtils.getResourceBundle(configFile);
-    }
-
-    @Override
-    public void stop()
-    {
-        try
-        {
-            if (this.scheduler != null && this.scheduler.isStarted())
-            {
-                this.scheduler.shutdown(SchedulerBaseConfig.LifecycleIntegration.FORCE_STOP);
-                this.scheduler = null;
-            }
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public void registerNewJob(Class<? extends Job> jobClass)
-    {
-        JobKey jobKey = createJobKey(jobClass);
-
-        try
-        {
-            Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
-
-            String description = scheduled.description();
-
-            if ("".equals(scheduled.description()))
-            {
-                description = jobClass.getName();
-            }
-
-            JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
-            Trigger trigger;
-
-            if (jobDetail == null)
-            {
-                jobDetail = JobBuilder.newJob(jobClass)
-                        .withDescription(description)
-                        .withIdentity(jobKey)
-                        .build();
-
-                trigger = TriggerBuilder.newTrigger()
-                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
-                        .build();
-
-                this.scheduler.scheduleJob(jobDetail, trigger);
-            }
-            else if (scheduled.overrideOnStartup())
-            {
-                List<? extends Trigger> existingTriggers = this.scheduler.getTriggersOfJob(jobKey);
-
-                if (existingTriggers == null || existingTriggers.isEmpty())
-                {
-                    //TODO re-visit it
-                    trigger = TriggerBuilder.newTrigger()
-                            .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
-                            .build();
-
-                    this.scheduler.scheduleJob(jobDetail, trigger);
-                    return;
-                }
-
-                if (existingTriggers.size() > 1)
-                {
-                    throw new IllegalStateException("multiple triggers found for " + jobKey
+ " ('" + jobDetail + "')" +
-                        ", but aren't supported by @" + Scheduled.class.getName() + "#overrideOnStartup");
-                }
-
-                trigger = existingTriggers.iterator().next();
-
-                trigger = TriggerBuilder.newTrigger()
-                        .withIdentity(trigger.getKey())
-                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression()))
-                        .build();
-
-                this.scheduler.rescheduleJob(trigger.getKey(), trigger);
-            }
-            else
-            {
-                Logger.getLogger(QuartzScheduler.class.getName()).info(jobKey + " exists
already and will be ignored.");
-            }
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public void startJobManually(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            this.scheduler.triggerJob(createJobKey(jobClass));
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public void interruptJob(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            this.scheduler.interrupt(createJobKey(jobClass));
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public boolean deleteJob(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            return this.scheduler.deleteJob(createJobKey(jobClass));
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public void pauseJob(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            this.scheduler.pauseJob(createJobKey(jobClass));
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public void resumeJob(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            this.scheduler.resumeJob(createJobKey(jobClass));
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    @Override
-    public boolean isExecutingJob(Class<? extends Job> jobClass)
-    {
-        try
-        {
-            JobKey jobKey = createJobKey(jobClass);
-            JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
-
-            if (jobDetail == null)
-            {
-                return false;
-            }
-
-            for (JobExecutionContext jobExecutionContext : this.scheduler.getCurrentlyExecutingJobs())
-            {
-                if (jobKey.equals(jobExecutionContext.getJobDetail().getKey()))
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-        catch (SchedulerException e)
-        {
-            throw ExceptionUtils.throwAsRuntimeException(e);
-        }
-    }
-
-    private static JobKey createJobKey(Class<?> jobClass)
-    {
-        Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
-
-        if (scheduled == null)
-        {
-            throw new IllegalStateException("@" + Scheduled.class.getName() + " is missing
on " + jobClass.getName());
-        }
-
-        String groupName = scheduled.group().getSimpleName();
-        String jobName = jobClass.getSimpleName();
-
-        if (!Scheduled.class.getSimpleName().equals(groupName))
-        {
-            return new JobKey(jobName, groupName);
-        }
-        return new JobKey(jobName);
-    }
-
-    private class InjectionAwareJobListener implements JobListener
-    {
-        @Override
-        public String getName()
-        {
-            return getClass().getName();
-        }
-
-        @Override
-        public void jobToBeExecuted(JobExecutionContext jobExecutionContext)
-        {
-            Class<?> jobClass = ProxyUtils.getUnproxiedClass(jobExecutionContext.getJobInstance().getClass());
-            Scheduled scheduled = jobClass.getAnnotation(Scheduled.class);
-
-            //can happen with manually registered job-instances (via #unwrap)
-            if (scheduled == null)
-            {
-                scheduled = DEFAULT_SCHEDULED_LITERAL;
-            }
-
-            JobListenerContext jobListenerContext = new JobListenerContext();
-            currentJobListenerContext.set(jobListenerContext);
-            jobListenerContext.startContexts(scheduled);
-
-            boolean jobInstanceIsBean;
-
-            try
-            {
-                jobInstanceIsBean =
-                    Boolean.TRUE.equals(jobExecutionContext.getScheduler().getContext().get(jobClass.getName()));
-            }
-            catch (SchedulerException e)
-            {
-                jobInstanceIsBean = false;
-            }
-
-            if (!jobInstanceIsBean)
-            {
-                BeanProvider.injectFields(jobExecutionContext.getJobInstance());
-            }
-        }
-
-        @Override
-        public void jobExecutionVetoed(JobExecutionContext context)
-        {
-            stopStartedScopes();
-        }
-
-        @Override
-        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException)
-        {
-            stopStartedScopes();
-        }
-
-        private void stopStartedScopes()
-        {
-            JobListenerContext jobListenerContext = currentJobListenerContext.get();
-            if (jobListenerContext != null)
-            {
-                jobListenerContext.stopStartedScopes();
-                currentJobListenerContext.set(null);
-                currentJobListenerContext.remove();
-            }
-        }
-    }
-
-    private class JobListenerContext
-    {
-        private Stack<Class<? extends Annotation>> scopes = new Stack<Class<?
extends Annotation>>();
-        private DependentProvider<ContextControl> contextControl;
-
-        public void startContexts(Scheduled scheduled)
-        {
-            Collections.addAll(this.scopes, scheduled.startScopes());
-
-            if (!this.scopes.isEmpty())
-            {
-                this.contextControl = BeanProvider.getDependent(ContextControl.class);
-
-                for (Class<? extends Annotation> scopeAnnotation : this.scopes)
-                {
-                    contextControl.get().startContext(scopeAnnotation);
-                }
-            }
-        }
-
-        private void stopStartedScopes()
-        {
-            if (this.contextControl == null)
-            {
-                return;
-            }
-
-            while (!this.scopes.empty())
-            {
-                this.contextControl.get().stopContext(this.scopes.pop());
-            }
-            this.contextControl.destroy();
-        }
-    }
-
-    @Override
-    public <S> S unwrap(Class<? extends S> schedulerClass)
-    {
-        if (schedulerClass.isAssignableFrom(this.scheduler.getClass()))
-        {
-            return (S)this.scheduler;
-        }
-
-        throw new IllegalArgumentException(schedulerClass.getName() +
-            " isn't compatible with " + this.scheduler.getClass().getName());
-    }
-}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/RunnableQuartzScheduler.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/RunnableQuartzScheduler.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/RunnableQuartzScheduler.java
new file mode 100644
index 0000000..9d11f29
--- /dev/null
+++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/RunnableQuartzScheduler.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.deltaspike.scheduler.impl;
+
+import org.quartz.Job;
+
+//vetoed class (see SchedulerExtension)
+public class RunnableQuartzScheduler extends AbstractQuartzScheduler<Runnable>
+{
+    @Override
+    protected String getJobName(Class<?> jobClass)
+    {
+        return jobClass.getName();
+    }
+
+    @Override
+    protected Class<? extends Job> createFinalJobClass(Class<? extends Runnable>
jobClass)
+    {
+        return JobRunnableAdapter.class;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java
b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java
index ea113bc..907d2c0 100644
--- a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java
+++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java
@@ -170,6 +170,7 @@ public class SchedulerExtension implements Extension, Deactivatable
     {
         for (Scheduler scheduler : availableSchedulers)
         {
+            //in case of implementing the Scheduler interface directly
             for (Type interfaceClass : scheduler.getClass().getGenericInterfaces())
             {
                 if (!(interfaceClass instanceof ParameterizedType) ||
@@ -183,6 +184,19 @@ public class SchedulerExtension implements Extension, Deactivatable
                     return scheduler;
                 }
             }
+
+            //in case of extending e.g. AbstractQuartzScheduler
+            if (scheduler.getClass().getGenericSuperclass() instanceof ParameterizedType)
+            {
+                ParameterizedType parameterizedType = (ParameterizedType) scheduler.getClass().getGenericSuperclass();
+                for (Type typeArgument : parameterizedType.getActualTypeArguments())
+                {
+                    if (jobClass.isAssignableFrom((Class)typeArgument))
+                    {
+                        return scheduler;
+                    }
+                }
+            }
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler
b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler
index f8883a7..3e03601 100644
--- a/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler
+++ b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler
@@ -93,4 +93,12 @@
 # under the License.
 #####################################################################################
 
-org.apache.deltaspike.scheduler.impl.QuartzScheduler
\ No newline at end of file
+#only one of the following schedulers will get active
+
+#default scheduler:
+org.apache.deltaspike.scheduler.impl.JobQuartzScheduler
+
+#alternative scheduler - add
+# deltaspike.scheduler.job-class=java.lang.Runnable
+#to META-INF/apache-deltaspike.properties
+org.apache.deltaspike.scheduler.impl.RunnableQuartzScheduler
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/aa1893f7/deltaspike/modules/scheduler/impl/src/test/java/org/apache/deltaspike/test/scheduler/custom/QuartzDeactivator.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/scheduler/impl/src/test/java/org/apache/deltaspike/test/scheduler/custom/QuartzDeactivator.java
b/deltaspike/modules/scheduler/impl/src/test/java/org/apache/deltaspike/test/scheduler/custom/QuartzDeactivator.java
index 0a929bf..f370789 100644
--- a/deltaspike/modules/scheduler/impl/src/test/java/org/apache/deltaspike/test/scheduler/custom/QuartzDeactivator.java
+++ b/deltaspike/modules/scheduler/impl/src/test/java/org/apache/deltaspike/test/scheduler/custom/QuartzDeactivator.java
@@ -28,6 +28,7 @@ public class QuartzDeactivator implements ClassDeactivator
     @Override
     public Boolean isActivated(Class<? extends Deactivatable> targetClass)
     {
-        return !"QuartzScheduler".equals(targetClass.getSimpleName());
+        return !"QuartzScheduler".equals(targetClass.getSimpleName()) &&
+                !"RunnableQuartzScheduler".equals(targetClass.getSimpleName());
     }
 }


Mime
View raw message