DELTASPIKE-475 @Scheduled (first draft)
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/edbdaa8e Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/edbdaa8e Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/edbdaa8e Branch: refs/heads/master Commit: edbdaa8e6fac4686b407086c8f6d48c9ced892ab Parents: f216f03 Author: gpetracek <[email protected]> Authored: Fri Dec 20 14:43:57 2013 +0100 Committer: gpetracek <[email protected]> Committed: Fri Dec 20 15:47:41 2013 +0100 ---------------------------------------------------------------------- deltaspike/modules/pom.xml | 1 + deltaspike/modules/scheduler/api/pom.xml | 78 +++++ .../deltaspike/scheduler/api/Scheduled.java | 45 +++ .../deltaspike/scheduler/spi/Scheduler.java | 40 +++ .../api/src/main/resources/META-INF/beans.xml | 23 ++ deltaspike/modules/scheduler/impl/pom.xml | 147 ++++++++++ .../scheduler/impl/QuartzScheduler.java | 287 +++++++++++++++++++ .../scheduler/impl/SchedulerExtension.java | 192 +++++++++++++ .../scheduler/impl/SchedulerProducer.java | 39 +++ .../impl/src/main/resources/META-INF/beans.xml | 23 ++ .../javax.enterprise.inject.spi.Extension | 20 ++ ...rg.apache.deltaspike.scheduler.spi.Scheduler | 20 ++ deltaspike/modules/scheduler/pom.xml | 40 +++ deltaspike/parent/pom.xml | 14 + 14 files changed, 969 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/pom.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/pom.xml b/deltaspike/modules/pom.xml index 3049707..9755231 100644 --- a/deltaspike/modules/pom.xml +++ b/deltaspike/modules/pom.xml @@ -42,6 +42,7 @@ <module>partial-bean</module> <module>bean-validation</module> <module>data</module> + <module>scheduler</module> <module>test-control</module> </modules> </project> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/api/pom.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/api/pom.xml b/deltaspike/modules/scheduler/api/pom.xml new file mode 100644 index 0000000..93af6e0 --- /dev/null +++ b/deltaspike/modules/scheduler/api/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>scheduler-module-project</artifactId> + <version>0.6-SNAPSHOT</version> + </parent> + + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>deltaspike-scheduler-module-api</artifactId> + <packaging>bundle</packaging> + + <name>Apache DeltaSpike Scheduler-Module API</name> + + <properties> + <deltaspike.osgi.export.pkg> + org.apache.deltaspike.scheduler.* + </deltaspike.osgi.export.pkg> + <deltaspike.osgi.import> + javax.enterprise.inject, + !org.apache.deltaspike.scheduler.*, + * + </deltaspike.osgi.import> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.deltaspike.core</groupId> + <artifactId>deltaspike-core-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.deltaspike.cdictrl</groupId> + <artifactId>deltaspike-cdictrl-api</artifactId> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/api/Scheduled.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/api/Scheduled.java b/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/api/Scheduled.java new file mode 100644 index 0000000..6732e5a --- /dev/null +++ b/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/api/Scheduled.java @@ -0,0 +1,45 @@ +/* + * 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.api; + +import javax.enterprise.context.RequestScoped; +import javax.enterprise.context.SessionScoped; +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({ TYPE }) +@Retention(RUNTIME) +@Documented +public @interface Scheduled +{ + String cronExpression(); + + Class<? extends Annotation>[] startScopes() default { SessionScoped.class, RequestScoped.class }; + + Class group() default Scheduled.class; //type-safe group + + String description() default ""; + + boolean onStartup() default true; //use false to schedule it manually (after the bootstrapping-process) +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/spi/Scheduler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/spi/Scheduler.java b/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/spi/Scheduler.java new file mode 100644 index 0000000..11560ac --- /dev/null +++ b/deltaspike/modules/scheduler/api/src/main/java/org/apache/deltaspike/scheduler/spi/Scheduler.java @@ -0,0 +1,40 @@ +/* + * 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.spi; + +import org.apache.deltaspike.core.spi.activation.Deactivatable; + +public interface Scheduler<T> extends Deactivatable +{ + void start(); + + void stop(); + + void pauseJob(Class<? extends T> jobClass); + + void resumeJob(Class<? extends T> jobClass); + + void interruptJob(Class<? extends T> jobClass); + + boolean isExecutingJob(Class<? extends T> jobClass); + + void registerNewJob(Class<? extends T> jobClass); + + void startJobManually(Class<? extends T> jobClass); +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/api/src/main/resources/META-INF/beans.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/api/src/main/resources/META-INF/beans.xml b/deltaspike/modules/scheduler/api/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..4070730 --- /dev/null +++ b/deltaspike/modules/scheduler/api/src/main/resources/META-INF/beans.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> +</beans> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/impl/pom.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/impl/pom.xml b/deltaspike/modules/scheduler/impl/pom.xml new file mode 100644 index 0000000..83bb92e --- /dev/null +++ b/deltaspike/modules/scheduler/impl/pom.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>scheduler-module-project</artifactId> + <version>0.6-SNAPSHOT</version> + </parent> + + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>deltaspike-scheduler-module-impl</artifactId> + <packaging>bundle</packaging> + + <name>Apache DeltaSpike Scheduler-Module Impl</name> + + <properties> + <deltaspike.osgi.export.pkg> + org.apache.deltaspike.scheduler.impl.* + </deltaspike.osgi.export.pkg> + <deltaspike.osgi.import> + !org.apache.deltaspike.scheduler.impl.*, + * + </deltaspike.osgi.import> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>deltaspike-scheduler-module-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.deltaspike.cdictrl</groupId> + <artifactId>deltaspike-cdictrl-api</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + <version>[2.0.0,)</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-el_2.2_spec</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-servlet_2.5_spec</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>OWB</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <dependencies> + <dependency> + <groupId>org.apache.openwebbeans</groupId> + <artifactId>openwebbeans-impl</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.openwebbeans</groupId> + <artifactId>openwebbeans-spi</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.deltaspike.cdictrl</groupId> + <artifactId>deltaspike-cdictrl-owb</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + <profile> + <id>Weld</id> + <dependencies> + <dependency> + <groupId>org.apache.deltaspike.cdictrl</groupId> + <artifactId>deltaspike-cdictrl-weld</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.jboss.weld.se</groupId> + <artifactId>weld-se</artifactId> + <version>${weld.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + </profiles> + +</project> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/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 new file mode 100644 index 0000000..8507d71 --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/QuartzScheduler.java @@ -0,0 +1,287 @@ +/* + * 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.config.ConfigResolver; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.apache.deltaspike.core.util.ExceptionUtils; +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.lang.annotation.Annotation; +import java.util.Collections; +import java.util.Stack; + +//vetoed class (see SchedulerExtension) +public class QuartzScheduler implements Scheduler<Job> +{ + private org.quartz.Scheduler scheduler; + + @Override + public void start() + { + if (this.scheduler != null) + { + throw new UnsupportedOperationException("the scheduler is started already"); + } + + SchedulerFactory schedulerFactory; + try + { + String configFile = + ConfigResolver.getPropertyValue("deltaspike.scheduler.quartz_config-file", "quartz.properties"); + schedulerFactory = new StdSchedulerFactory(configFile); + } + catch (SchedulerException e) + { + schedulerFactory = new StdSchedulerFactory(); + } + + try + { + this.scheduler = schedulerFactory.getScheduler(); + this.scheduler.getListenerManager().addJobListener(new InjectionAwareJobListener()); + + if (!this.scheduler.isStarted()) + { + String delayedStart = + ConfigResolver.getPropertyValue("deltaspike.scheduler.delayed_start_in_seconds", "1"); + this.scheduler.startDelayed(Integer.parseInt(delayedStart)); + } + } + catch (SchedulerException e) + { + throw ExceptionUtils.throwAsRuntimeException(e); + } + } + + @Override + public void stop() + { + try + { + if (this.scheduler != null && this.scheduler.isStarted()) + { + String forceStop = ConfigResolver.getPropertyValue("deltaspike.scheduler.force_stop", "true"); + + this.scheduler.shutdown(Boolean.parseBoolean(forceStop)); + 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 = JobBuilder.newJob(jobClass) + .withDescription(description) + .withIdentity(jobKey) + .build(); + Trigger trigger = TriggerBuilder.newTrigger() + .withSchedule(CronScheduleBuilder.cronSchedule(scheduled.cronExpression())) + .build(); + + this.scheduler.scheduleJob(jobDetail, trigger); + } + 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 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 + { + private Stack<Class<? extends Annotation>> scopes = new Stack<Class<? extends Annotation>>(); + private ContextControl contextControl; + + @Override + public String getName() + { + return getClass().getName(); + } + + @Override + public void jobToBeExecuted(JobExecutionContext context) + { + Scheduled scheduled = context.getJobInstance().getClass().getAnnotation(Scheduled.class); + + Collections.addAll(this.scopes, scheduled.startScopes()); + + this.contextControl = BeanProvider.getContextualReference(ContextControl.class); + + for (Class<? extends Annotation> scopeAnnotation : this.scopes) + { + contextControl.startContext(scopeAnnotation); + } + + BeanProvider.injectFields(context.getJobInstance()); + } + + @Override + public void jobExecutionVetoed(JobExecutionContext context) + { + stopStartedScopes(); + } + + @Override + public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) + { + stopStartedScopes(); + } + + private void stopStartedScopes() + { + while (!this.scopes.empty()) + { + this.contextControl.stopContext(this.scopes.pop()); + } + } + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/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 new file mode 100644 index 0000000..bb1bcc9 --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerExtension.java @@ -0,0 +1,192 @@ +/* + * 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.config.ConfigResolver; +import org.apache.deltaspike.core.spi.activation.Deactivatable; +import org.apache.deltaspike.core.util.ClassDeactivationUtils; +import org.apache.deltaspike.core.util.ClassUtils; +import org.apache.deltaspike.core.util.ServiceUtils; +import org.apache.deltaspike.scheduler.api.Scheduled; +import org.apache.deltaspike.scheduler.spi.Scheduler; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeBeanDiscovery; +import javax.enterprise.inject.spi.BeforeShutdown; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +public class SchedulerExtension implements Extension, Deactivatable +{ + private static final Logger LOG = Logger.getLogger(SchedulerExtension.class.getName()); + + private Boolean isActivated = true; + + private List<Class> foundManagedJobClasses = new ArrayList<Class>(); + + private Scheduler scheduler; + + private Class jobClass; + + protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery) + { + this.isActivated = ClassDeactivationUtils.isActivated(getClass()); + + if (this.isActivated) + { + String jobClassName = ConfigResolver.getPropertyValue("deltaspike.scheduler.job-class", "org.quartz.Job"); + + this.jobClass = ClassUtils.tryToLoadClassForName(jobClassName); + + if (this.jobClass == null) + { + this.isActivated = false; + } + } + } + + public <X> void findScheduledJobs(@Observes ProcessAnnotatedType<X> pat, BeanManager beanManager) + { + if (!this.isActivated) + { + return; + } + + Class<X> beanClass = pat.getAnnotatedType().getJavaClass(); + + //see SchedulerProducer + if (Scheduler.class.isAssignableFrom(beanClass)) + { + pat.veto(); + return; + } + + if (!jobClass.isAssignableFrom(beanClass)) + { + return; + } + + Scheduled scheduled = pat.getAnnotatedType().getAnnotation(Scheduled.class); + if (scheduled != null && scheduled.onStartup()) + { + this.foundManagedJobClasses.add(beanClass); + } + } + + public <X> void scheduleJobs(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) + { + if (!this.isActivated) + { + return; + } + + initScheduler(afterBeanDiscovery); + + if (this.scheduler == null) + { + return; + } + + + List<String> foundJobNames = new ArrayList<String>(); + + for (Class jobClass : this.foundManagedJobClasses) + { + if (foundJobNames.contains(jobClass.getSimpleName())) + { + afterBeanDiscovery.addDefinitionError( + new IllegalStateException("Multiple Job-Classes found with name " + jobClass.getSimpleName())); + } + + foundJobNames.add(jobClass.getSimpleName()); + this.scheduler.registerNewJob(jobClass); + } + } + + public <X> void stopScheduler(@Observes BeforeShutdown beforeShutdown) + { + if (!this.isActivated) + { + return; + } + + if (this.scheduler != null) + { + this.scheduler.stop(); + this.scheduler = null; + } + } + + private void initScheduler(AfterBeanDiscovery afterBeanDiscovery) + { + List<Scheduler> availableSchedulers = ServiceUtils.loadServiceImplementations(Scheduler.class, true); + + this.scheduler = findScheduler(availableSchedulers, this.jobClass); + + if (this.scheduler != null) + { + try + { + this.scheduler.start(); + } + catch (Throwable t) + { + afterBeanDiscovery.addDefinitionError(t); + } + } + else if (this.foundManagedJobClasses.size() > 0) + { + LOG.warning( + this.foundManagedJobClasses.size() + " scheduling-jobs found, but there is no configured scheduler"); + } + } + + private static Scheduler findScheduler(List<Scheduler> availableSchedulers, Class jobClass) + { + for (Scheduler scheduler : availableSchedulers) + { + for (Type interfaceClass : scheduler.getClass().getGenericInterfaces()) + { + if (!(interfaceClass instanceof ParameterizedType) || + !Scheduler.class.isAssignableFrom((Class)((ParameterizedType)interfaceClass).getRawType())) + { + continue; + } + + if (jobClass.isAssignableFrom(((Class)((ParameterizedType)interfaceClass).getActualTypeArguments()[0]))) + { + return scheduler; + } + } + } + return null; + } + + Scheduler getScheduler() + { + return scheduler; + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerProducer.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerProducer.java b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerProducer.java new file mode 100644 index 0000000..9b2bed0 --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/java/org/apache/deltaspike/scheduler/impl/SchedulerProducer.java @@ -0,0 +1,39 @@ +/* + * 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.scheduler.spi.Scheduler; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; + +@ApplicationScoped +public class SchedulerProducer +{ + @Inject + private SchedulerExtension schedulerExtension; + + @Produces + @ApplicationScoped + protected Scheduler produceScheduler() + { + return this.schedulerExtension.getScheduler(); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/beans.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/beans.xml b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..4070730 --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/beans.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> +</beans> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 0000000..b2ad72a --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1,20 @@ +##################################################################################### +# 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. +##################################################################################### + +org.apache.deltaspike.scheduler.impl.SchedulerExtension \ No newline at end of file http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/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 new file mode 100644 index 0000000..cd752de --- /dev/null +++ b/deltaspike/modules/scheduler/impl/src/main/resources/META-INF/services/org.apache.deltaspike.scheduler.spi.Scheduler @@ -0,0 +1,20 @@ +##################################################################################### +# 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. +##################################################################################### + +org.apache.deltaspike.scheduler.impl.QuartzScheduler \ No newline at end of file http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/modules/scheduler/pom.xml ---------------------------------------------------------------------- diff --git a/deltaspike/modules/scheduler/pom.xml b/deltaspike/modules/scheduler/pom.xml new file mode 100644 index 0000000..6bddcc3 --- /dev/null +++ b/deltaspike/modules/scheduler/pom.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>modules-project</artifactId> + <version>0.6-SNAPSHOT</version> + </parent> + + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>scheduler-module-project</artifactId> + <version>0.6-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>Apache DeltaSpike Scheduler-Module</name> + + <modules> + <module>api</module> + <module>impl</module> + </modules> +</project> http://git-wip-us.apache.org/repos/asf/deltaspike/blob/edbdaa8e/deltaspike/parent/pom.xml ---------------------------------------------------------------------- diff --git a/deltaspike/parent/pom.xml b/deltaspike/parent/pom.xml index 12b69a3..d63dd09 100644 --- a/deltaspike/parent/pom.xml +++ b/deltaspike/parent/pom.xml @@ -564,6 +564,20 @@ <dependency> <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>deltaspike-scheduler-module-api</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.apache.deltaspike.modules</groupId> + <artifactId>deltaspike-scheduler-module-impl</artifactId> + <version>${project.version}</version> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.apache.deltaspike.modules</groupId> <artifactId>deltaspike-bean-validation-module-api</artifactId> <version>${project.version}</version> <scope>compile</scope>
