ZEST-128 - Chasing race condition problems.
Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/73b7f196 Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/73b7f196 Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/73b7f196 Branch: refs/heads/develop Commit: 73b7f196946f93be2805d4b5529924a5240baae9 Parents: 551f684 Author: Niclas Hedhman <[email protected]> Authored: Sun Nov 15 19:05:36 2015 +0800 Committer: Niclas Hedhman <[email protected]> Committed: Sun Nov 15 19:05:36 2015 +0800 ---------------------------------------------------------------------- .../association/AssociationAssignmentTest.java | 6 +- .../zest/library/scheduler/CronSchedule.java | 117 ++++++++ .../zest/library/scheduler/Execution.java | 231 --------------- .../zest/library/scheduler/OnceSchedule.java | 68 +++++ .../apache/zest/library/scheduler/Schedule.java | 131 +++++++++ .../zest/library/scheduler/ScheduleFactory.java | 42 +++ .../zest/library/scheduler/Scheduler.java | 11 +- .../zest/library/scheduler/SchedulerMixin.java | 187 ------------- .../library/scheduler/SchedulerService.java | 1 + .../library/scheduler/SchedulesHandler.java | 2 +- .../org/apache/zest/library/scheduler/Task.java | 2 +- .../zest/library/scheduler/TaskRunner.java | 115 -------- .../scheduler/bootstrap/SchedulerAssembler.java | 10 +- .../defaults/DefaultScheduleFactoryMixin.java | 8 +- .../defaults/DefaultThreadFactory.java | 3 +- .../library/scheduler/internal/Execution.java | 278 +++++++++++++++++++ .../scheduler/internal/ScheduleTime.java | 61 ++++ .../scheduler/internal/SchedulerMixin.java | 199 +++++++++++++ .../library/scheduler/internal/Schedules.java | 28 ++ .../library/scheduler/internal/TaskRunner.java | 115 ++++++++ .../library/scheduler/schedule/Schedule.java | 130 --------- .../scheduler/schedule/ScheduleFactory.java | 37 --- .../scheduler/schedule/ScheduleTime.java | 90 ------ .../library/scheduler/schedule/Schedules.java | 24 -- .../scheduler/schedule/cron/CronExpression.java | 36 --- .../schedule/cron/CronExpressionConstraint.java | 34 --- .../scheduler/schedule/cron/CronSchedule.java | 87 ------ .../scheduler/schedule/cron/package.html | 21 -- .../scheduler/schedule/once/OnceSchedule.java | 66 ----- .../scheduler/schedule/once/package.html | 21 -- .../timeline/TimelineForScheduleConcern.java | 2 +- .../timeline/TimelineScheduleMixin.java | 3 +- .../timeline/TimelineSchedulerServiceMixin.java | 4 +- .../library/scheduler/CronScheduleTest.java | 7 +- .../zest/library/scheduler/SchedulerTest.java | 1 - .../scheduler/docsupport/SchedulerDocs.java | 2 +- 36 files changed, 1071 insertions(+), 1109 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/core/runtime/src/test/java/org/apache/zest/runtime/association/AssociationAssignmentTest.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/test/java/org/apache/zest/runtime/association/AssociationAssignmentTest.java b/core/runtime/src/test/java/org/apache/zest/runtime/association/AssociationAssignmentTest.java index e224008..d0c7147 100644 --- a/core/runtime/src/test/java/org/apache/zest/runtime/association/AssociationAssignmentTest.java +++ b/core/runtime/src/test/java/org/apache/zest/runtime/association/AssociationAssignmentTest.java @@ -24,12 +24,13 @@ import org.apache.zest.api.association.Association; import org.apache.zest.api.entity.EntityBuilder; import org.apache.zest.api.entity.EntityComposite; import org.apache.zest.api.unitofwork.UnitOfWork; +import org.apache.zest.api.value.ValueSerialization; import org.apache.zest.bootstrap.AssemblyException; import org.apache.zest.bootstrap.ModuleAssembly; import org.apache.zest.entitystore.memory.MemoryEntityStoreService; import org.apache.zest.spi.uuid.UuidIdentityGeneratorService; import org.apache.zest.test.AbstractZestTest; -import org.apache.zest.valueserialization.orgjson.OrgJsonValueSerializationAssembler; +import org.apache.zest.valueserialization.orgjson.OrgJsonValueSerializationService; import org.junit.Test; import static org.hamcrest.core.IsEqual.equalTo; @@ -45,7 +46,8 @@ public class AssociationAssignmentTest extends AbstractZestTest { module.services( MemoryEntityStoreService.class ); module.services( UuidIdentityGeneratorService.class ); - new OrgJsonValueSerializationAssembler().assemble( module ); + module.services( OrgJsonValueSerializationService.class ) + .taggedWith( ValueSerialization.Formats.JSON ); module.entities( TheAssociatedType.class ); module.entities( TheMainType.class ); } http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CronSchedule.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CronSchedule.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CronSchedule.java new file mode 100644 index 0000000..9ee212d --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CronSchedule.java @@ -0,0 +1,117 @@ +/* + * 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.zest.library.scheduler; + +import java.lang.annotation.Retention; +import org.apache.zest.api.constraint.Constraint; +import org.apache.zest.api.constraint.ConstraintDeclaration; +import org.apache.zest.api.constraint.Constraints; +import org.apache.zest.api.mixin.Mixins; +import org.apache.zest.api.property.Immutable; +import org.apache.zest.api.property.Property; +import org.apache.zest.library.constraints.annotation.InstanceOf; +import org.apache.zest.library.constraints.annotation.NotEmpty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Mixins( CronSchedule.CronScheduleMixin.class ) +public interface CronSchedule + extends Schedule +{ + /** + * The Cron expression indicating when the Schedule is to be run. + * The Schedule can NOT be changed once it is set. If this is needed, delete this Schedule and attach the Task + * to a new Schedule. + * + * @return The cron expression that will be used on {@link org.apache.zest.api.unitofwork.UnitOfWork} completion to compute next run + */ + @CronExpression + @Immutable + Property<String> cronExpression(); + + abstract class CronScheduleMixin + implements CronSchedule + { + private static final Logger LOGGER = LoggerFactory.getLogger( Schedule.class ); + + @Override + public void taskStarting() + { + } + + @Override + public void taskCompletedSuccessfully() + { + } + + @Override + public void taskCompletedWithException( Throwable ex ) + { + } + + @Override + public String presentationString() + { + return cronExpression().get(); + } + + @Override + public long nextRun( long from ) + { + long actualFrom = from; + long firstRun = start().get().getMillis(); + if( firstRun > from ) + { + actualFrom = firstRun; + } + Long nextRun = createCron().firstRunAfter( actualFrom ); + LOGGER.info( "CronSchedule::nextRun({}) is {}", from, firstRun ); + return nextRun; + } + + private org.codeartisans.sked.cron.CronSchedule createCron() + { + return new org.codeartisans.sked.cron.CronSchedule( cronExpression().get() ); + } + } + + @ConstraintDeclaration + @Retention( RUNTIME ) + @NotEmpty + @InstanceOf( String.class ) + @Constraints( CronExpressionConstraint.class ) + @interface CronExpression + { + } + + class CronExpressionConstraint + implements Constraint<CronExpression, String> + { + private static final long serialVersionUID = 1L; + + @Override + public boolean isValid( CronExpression annotation, String cronExpression ) + { + return org.codeartisans.sked.cron.CronSchedule.isExpressionValid( cronExpression ); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Execution.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Execution.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Execution.java deleted file mode 100644 index d3a732b..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Execution.java +++ /dev/null @@ -1,231 +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.zest.library.scheduler; - -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.zest.api.concern.Concerns; -import org.apache.zest.api.configuration.Configuration; -import org.apache.zest.api.injection.scope.Structure; -import org.apache.zest.api.injection.scope.This; -import org.apache.zest.api.mixin.Mixins; -import org.apache.zest.api.structure.Module; -import org.apache.zest.api.unitofwork.NoSuchEntityException; -import org.apache.zest.api.unitofwork.UnitOfWork; -import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern; -import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; -import org.apache.zest.api.unitofwork.concern.UnitOfWorkRetry; -import org.apache.zest.library.scheduler.schedule.Schedule; -import org.apache.zest.library.scheduler.schedule.ScheduleTime; - -@Mixins( Execution.ExecutionMixin.class ) -@Concerns( UnitOfWorkConcern.class ) -public interface Execution -{ - - void dispatchForExecution( Schedule schedule ); - - void start() - throws Exception; - - void stop() - throws Exception; - - @UnitOfWorkPropagation - @UnitOfWorkRetry( retries = 3 ) - void updateNextTime( ScheduleTime schedule ); - - class ExecutionMixin - implements Execution, Runnable - { - private static final ThreadGroup TG = new ThreadGroup( "Zest Scheduling" ); - - @Structure - private Module module; - - @This - private Scheduler scheduler; - - @This - private Configuration<SchedulerConfiguration> config; - - @This - private ThreadFactory threadFactory; - - @This - private RejectedExecutionHandler rejectionHandler; - - private final SortedSet<ScheduleTime> timingQueue = new TreeSet<>(); - private volatile boolean running; - private ThreadPoolExecutor taskExecutor; - private volatile Thread scheduleThread; - - @Override - @UnitOfWorkPropagation - public void run() - { - synchronized( this ) - { - running = true; - while( running ) - { - try - { - if( timingQueue.size() > 0 ) - { - ScheduleTime scheduleTime = timingQueue.first(); - waitFor( scheduleTime ); - timingQueue.remove( scheduleTime ); - updateNextTime( scheduleTime ); - submitTaskForExecution( scheduleTime ); - } - else - { - this.wait( 100 ); - } - } - catch( InterruptedException e ) - { - // Ignore. Used to signal "Hey, wake up. Time to work..." - } - catch( Throwable e ) - { - e.printStackTrace(); - } - } - } - } - - private void waitFor( ScheduleTime scheduleTime ) - throws InterruptedException - { - long now = System.currentTimeMillis(); - long waitingTime = scheduleTime.nextTime() - now; - if( waitingTime > 0 ) - { - this.wait( waitingTime ); - } - } - - @Override - public void updateNextTime( ScheduleTime scheduleTime ) - { - long now = System.currentTimeMillis(); - UnitOfWork uow = module.currentUnitOfWork(); - try - { - Schedule schedule = uow.get( Schedule.class, scheduleTime.scheduleIdentity() ); - long nextTime = schedule.nextRun( now + 1000 ); - if( nextTime != Long.MIN_VALUE ) - { - scheduleTime = new ScheduleTime( schedule.identity().get(), nextTime ); - timingQueue.add( scheduleTime ); - } - } - catch( NoSuchEntityException e ) - { - // Schedule has been removed. - scheduler.cancelSchedule( scheduleTime.scheduleIdentity() ); - } - } - - private void submitTaskForExecution( ScheduleTime scheduleTime ) - { - Runnable taskRunner = module.newTransient( Runnable.class, scheduleTime ); - this.taskExecutor.submit( taskRunner ); - } - - public void dispatchForExecution( Schedule schedule ) - { - long now = System.currentTimeMillis(); - synchronized( this ) - { - long nextRun = schedule.nextRun( now ); - if( nextRun > 0 ) - { - timingQueue.add( new ScheduleTime( schedule.identity().get(), nextRun ) ); - scheduleThread.interrupt(); - } - } - } - - @Override - public void start() - throws Exception - { - SchedulerConfiguration configuration = config.get(); - Integer workersCount = configuration.workersCount().get(); - Integer workQueueSize = configuration.workQueueSize().get(); - createThreadPoolExecutor( workersCount, workQueueSize ); - taskExecutor.prestartAllCoreThreads(); - - scheduleThread = new Thread( TG, this, "Scheduler" ); - scheduleThread.start(); - } - - private void createThreadPoolExecutor( Integer workersCount, Integer workQueueSize ) - { - int corePoolSize = 2; - if( workersCount > 4 ) - { - corePoolSize = workersCount / 4 + 1; - } - if( corePoolSize > 50 ) - { - corePoolSize = 20; - } - if( workersCount > 200 ) - { - workersCount = 200; - } - taskExecutor = new ThreadPoolExecutor( corePoolSize, workersCount, - 0, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>( workQueueSize ), - threadFactory, rejectionHandler ); - } - - @Override - public void stop() - throws Exception - { - running = false; - synchronized( this ) - { - scheduleThread.interrupt(); - } - taskExecutor.shutdown(); - try - { - taskExecutor.awaitTermination( 5, TimeUnit.SECONDS ); - } - catch( InterruptedException e ) - { - e.printStackTrace(); - } - taskExecutor.shutdownNow(); - } - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/OnceSchedule.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/OnceSchedule.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/OnceSchedule.java new file mode 100644 index 0000000..299c2be --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/OnceSchedule.java @@ -0,0 +1,68 @@ +/* + * 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.zest.library.scheduler; + +import org.apache.zest.api.mixin.Mixins; + +@Mixins( OnceSchedule.OnceScheduleMixin.class ) +public interface OnceSchedule + extends Schedule +{ + abstract class OnceScheduleMixin + implements OnceSchedule + { + @Override + public void taskStarting() + { + } + + @Override + public void taskCompletedSuccessfully() + { + } + + @Override + public void taskCompletedWithException( Throwable ex ) + { + } + + @Override + public long nextRun( long from ) + { + if( done().get() ) + { + return Long.MIN_VALUE; + } + done().set( true ); + long runAt = start().get().getMillis(); + if( runAt >= from ) + { + return runAt; + } + return from; + } + + @Override + public String presentationString() + { + return start().get().toString(); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Schedule.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Schedule.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Schedule.java new file mode 100644 index 0000000..a0f8a6e --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Schedule.java @@ -0,0 +1,131 @@ +/* + * 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.zest.library.scheduler; + +import org.apache.zest.api.association.Association; +import org.apache.zest.api.common.UseDefaults; +import org.apache.zest.api.entity.EntityComposite; +import org.apache.zest.api.property.Immutable; +import org.apache.zest.api.property.Property; +import org.apache.zest.library.scheduler.Task; +import org.joda.time.DateTime; + +/** + * Represent the scheduling of a {@link Task}. + */ +public interface Schedule extends EntityComposite +{ + /** + * @return The Association to the Task to be executed when it is time. + */ + Association<Task> task(); + + /** The first run of this Schedule. + * + * @return The property containing the first time this Schedule will be run. + */ + @Immutable + Property<DateTime> start(); + + /** Returns true if the Schedule has been cancelled. + * + * @return true if the Schedule has been cancelled. + */ + @UseDefaults + Property<Boolean> cancelled(); + + /** Returns true if the Schedule is currently running. + * + * @return true if the Schedule is currently running. + */ + @UseDefaults + Property<Boolean> running(); + + /** Returns the number of times the {@link Task} has been executed. + * <p> + * Each time the {@link Task#run} method completes, with or without an {@link Exception}, this + * counter is incremented by 1. + * </p> + * + * @return true the number of Exception that has occurred when running the {@link Task}. + */ + @UseDefaults + Property<Long> executionCounter(); + + /** Returns the number of Exception that has occurred when running the {@link Task}. + * <p> + * Each time the {@link Task#run} method throws a {@link RuntimeException}, this property + * is incremenented by 1, + * </p> + * + * @return true the number of Exception that has occurred when running the {@link Task}. + */ + @UseDefaults + Property<Long> exceptionCounter(); + + /** Returns true if the Schedule is done and will not be executed any more times. + * + * @return true if the Schedule is done and will not be executed any more times. + */ + @UseDefaults + Property<Boolean> done(); + + /** Returns the number of times the Schedule has been skipped, due to the Task was still running. + * + * @return the number of times the Schedule has been skipped, due to the Task was still running. + */ + @UseDefaults + Property<Long> overrun(); + + /** + * Called just before the {@link org.apache.zest.library.scheduler.Task#run()} method is called. + */ + void taskStarting(); + + /** + * Called directly after the {@link org.apache.zest.library.scheduler.Task#run()} method has been completed and + * returned from the method normally. + */ + void taskCompletedSuccessfully(); + + /** + * Called directly after the {@link org.apache.zest.library.scheduler.Task#run()} method has been completed but + * threw a RuntimeException. + * @param ex The execption that was thrown in the Task. If the thrown Exception was an + * {@link java.lang.reflect.UndeclaredThrowableException} then the underlying exception is passed here. + */ + void taskCompletedWithException( Throwable ex ); + + /** + * Compute the next time this schedule is to be run. + * + * @param from The starting time when to look for the next time it will run. + * + * @return The exact absolute time when this Schedule is to be run next time, or -1 if never + */ + long nextRun( long from ); + + /** + * Return a representation of the Schedule in a human understandable format. + * + * @return A String representing this schedule. + */ + String presentationString(); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/ScheduleFactory.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/ScheduleFactory.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/ScheduleFactory.java new file mode 100644 index 0000000..e891814 --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/ScheduleFactory.java @@ -0,0 +1,42 @@ +/* + * 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.zest.library.scheduler; + +import org.apache.zest.api.concern.Concerns; +import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern; +import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; +import org.apache.zest.library.scheduler.Schedule; +import org.apache.zest.library.scheduler.defaults.DefaultScheduleFactoryMixin; +import org.joda.time.DateTime; +import org.apache.zest.api.mixin.Mixins; +import org.apache.zest.library.scheduler.Task; + +import static org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propagation.MANDATORY; + +@Mixins( DefaultScheduleFactoryMixin.class ) +@Concerns( UnitOfWorkConcern.class ) +public interface ScheduleFactory +{ + @UnitOfWorkPropagation( MANDATORY) + Schedule newCronSchedule( Task task, String cronExpression, DateTime start ); + + @UnitOfWorkPropagation( MANDATORY) + Schedule newOnceSchedule( Task task, DateTime runAt ); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java index f8aae19..8510645 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java @@ -18,14 +18,13 @@ */ package org.apache.zest.library.scheduler; +import org.apache.zest.library.scheduler.internal.Schedules; import org.joda.time.DateTime; import org.apache.zest.api.concern.Concerns; import org.apache.zest.api.structure.Application; import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern; import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; import org.apache.zest.library.scheduler.bootstrap.SchedulerAssembler; -import org.apache.zest.library.scheduler.schedule.Schedule; -import org.apache.zest.library.scheduler.schedule.cron.CronExpression; import org.apache.zest.library.scheduler.timeline.Timeline; import static org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propagation.MANDATORY; @@ -46,7 +45,7 @@ import static org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propa * </p> * <p> * All {@link Schedule}s are durable and stored in the visible {@link org.apache.zest.spi.entitystore.EntityStore} like - * any ordinary {@link org.apache.zest.api.entity.EntityComposite}. There is also a {@link org.apache.zest.library.scheduler.schedule.Schedules} + * any ordinary {@link org.apache.zest.api.entity.EntityComposite}. There is also a {@link Schedules} * entity composite that has Associations to all active, completed and cancelled schedules. * </p> * <p> @@ -87,7 +86,7 @@ public interface Scheduler * @return The newly created Schedule */ @UnitOfWorkPropagation( MANDATORY ) - Schedule scheduleCron( Task task, @CronExpression String cronExpression ); + Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression ); /** * Schedule a Task using a CronExpression with a given initial delay in milliseconds. @@ -99,7 +98,7 @@ public interface Scheduler * @return The newly created Schedule */ @UnitOfWorkPropagation( MANDATORY ) - Schedule scheduleCron( Task task, @CronExpression String cronExpression, long initialDelay ); + Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression, long initialDelay ); /** * Schedule a Task using a CronExpression starting at a given date. @@ -111,7 +110,7 @@ public interface Scheduler * @return The newly created Schedule */ @UnitOfWorkPropagation( MANDATORY ) - Schedule scheduleCron( Task task, @CronExpression String cronExpression, DateTime start ); + Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression, DateTime start ); /** Schedules a custom Schedule. * http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerMixin.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerMixin.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerMixin.java deleted file mode 100644 index 9f7423c..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerMixin.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2010-2012, Paul Merlin. - * Copyright (c) 2012, Niclas Hedhman. - * - * Licensed 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.zest.library.scheduler; - -import org.apache.zest.api.configuration.Configuration; -import org.apache.zest.api.injection.scope.Service; -import org.apache.zest.api.injection.scope.Structure; -import org.apache.zest.api.injection.scope.This; -import org.apache.zest.api.service.ServiceActivation; -import org.apache.zest.api.structure.Module; -import org.apache.zest.api.unitofwork.NoSuchEntityException; -import org.apache.zest.api.unitofwork.UnitOfWork; -import org.apache.zest.api.unitofwork.UnitOfWorkCompletionException; -import org.apache.zest.api.usecase.UsecaseBuilder; -import org.apache.zest.library.scheduler.schedule.Schedule; -import org.apache.zest.library.scheduler.schedule.ScheduleFactory; -import org.apache.zest.library.scheduler.schedule.Schedules; -import org.apache.zest.library.scheduler.schedule.cron.CronExpression; -import org.joda.time.DateTime; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SchedulerMixin - implements Scheduler, ServiceActivation -{ - private static final Logger LOGGER = LoggerFactory.getLogger( Scheduler.class ); - - @Service - private ScheduleFactory scheduleFactory; - - @Structure - private Module module; - - @This - private SchedulerService me; - - @This - private SchedulesHandler schedulesHandler; - - @This - private Execution execution; - - @This - private Configuration<SchedulerConfiguration> config; - - public SchedulerMixin() - { - } - - @Override - public Schedule scheduleOnce( Task task, int initialSecondsDelay ) - { - long now = System.currentTimeMillis(); - Schedule schedule = scheduleFactory.newOnceSchedule( task, new DateTime( now + initialSecondsDelay * 1000 ) ); - saveAndDispatch( schedule ); - return schedule; - } - - @Override - public Schedule scheduleOnce( Task task, DateTime runAt ) - { - Schedule schedule = scheduleFactory.newOnceSchedule( task, runAt ); - saveAndDispatch( schedule ); - return schedule; - } - - @Override - public Schedule scheduleCron( Task task, String cronExpression ) - { - DateTime now = new DateTime(); - Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, now ); - saveAndDispatch( schedule ); - return schedule; - } - - @Override - public Schedule scheduleCron( Task task, @CronExpression String cronExpression, DateTime start ) - { - Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, start ); - saveAndDispatch( schedule ); - return schedule; - } - - @Override - public void scheduleCron( Schedule schedule ) - { - saveAndDispatch( schedule ); - } - - @Override - public Schedule scheduleCron( Task task, String cronExpression, long initialDelay ) - { - DateTime start = new DateTime( System.currentTimeMillis() + initialDelay ); - Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, start ); - saveAndDispatch( schedule ); - return schedule; - } - - @Override - public void cancelSchedule( String scheduleId ) - { - UnitOfWork uow = module.currentUnitOfWork(); - Schedule schedule = null; - try - { - schedule = uow.get( Schedule.class, scheduleId ); - } - catch( NoSuchEntityException e ) - { - return; - } - cancelSchedule( schedule ); - } - - @Override - public void cancelSchedule( Schedule schedule ) - { - Schedules active = schedulesHandler.getActiveSchedules(); - if( active.schedules().remove( schedule ) ) - { - schedule.cancelled().set( true ); - } - } - - private void saveAndDispatch( Schedule schedule ) - { - Schedules schedules = schedulesHandler.getActiveSchedules(); - schedules.schedules().add( schedule ); - execution.dispatchForExecution( schedule ); - } - - private void loadSchedules() - throws UnitOfWorkCompletionException - { - try (UnitOfWork ignored = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Initialize Schedules" ) )) - { - Schedules schedules = schedulesHandler.getActiveSchedules(); - for( Schedule schedule : schedules.schedules() ) - { - if( schedule.cancelled().get() || schedule.done().get() ) - { - schedules.schedules().remove( schedule ); - } - else - { - execution.dispatchForExecution( schedule ); - } - } - } - } - - @Override - public void activateService() - throws Exception - { - // Throws IllegalArgument if corePoolSize or keepAliveTime less than zero, - // or if workersCount less than or equal to zero, - // or if corePoolSize greater than workersCount. - execution.start(); - loadSchedules(); - LOGGER.debug( "Activated" ); - } - - @Override - public void passivateService() - throws Exception - { - execution.stop(); - LOGGER.debug( "Passivated" ); - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerService.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerService.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerService.java index 0d1ef4c..ade3d1e 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerService.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerService.java @@ -23,6 +23,7 @@ import org.apache.zest.api.mixin.Mixins; import org.apache.zest.api.service.ServiceActivation; import org.apache.zest.library.scheduler.defaults.DefaultRejectionHandler; import org.apache.zest.library.scheduler.defaults.DefaultThreadFactory; +import org.apache.zest.library.scheduler.internal.SchedulerMixin; @Mixins( { SchedulerMixin.class, DefaultThreadFactory.class, DefaultRejectionHandler.class } ) public interface SchedulerService http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java index b76ef96..b4a2b4d 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java @@ -28,7 +28,7 @@ import org.apache.zest.api.structure.Module; import org.apache.zest.api.unitofwork.NoSuchEntityException; import org.apache.zest.api.unitofwork.UnitOfWork; import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; -import org.apache.zest.library.scheduler.schedule.Schedules; +import org.apache.zest.library.scheduler.internal.Schedules; @Mixins(SchedulesHandler.SchedulesHandlerMixin.class) public interface SchedulesHandler http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java index 6cc284c..9cce9ce 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java @@ -29,7 +29,7 @@ import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; /** * Compose an Entity using this type to be able to Schedule it. *<p> - * A Task is associated from a {@link org.apache.zest.library.scheduler.schedule.Schedule}, and upon time to execute + * A Task is associated from a {@link Schedule}, and upon time to execute * the SchedulerService will dispatch a TaskRunner in a new thread, and establish a UnitOfWork (Usecase name of "Task Runner"). *</p> *<p> http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/TaskRunner.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/TaskRunner.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/TaskRunner.java deleted file mode 100644 index 3e0e975..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/TaskRunner.java +++ /dev/null @@ -1,115 +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.zest.library.scheduler; - -import java.lang.reflect.UndeclaredThrowableException; -import java.util.concurrent.locks.ReentrantLock; -import org.apache.zest.api.injection.scope.Structure; -import org.apache.zest.api.injection.scope.Uses; -import org.apache.zest.api.structure.Module; -import org.apache.zest.api.unitofwork.UnitOfWork; -import org.apache.zest.api.usecase.UsecaseBuilder; -import org.apache.zest.library.scheduler.schedule.Schedule; -import org.apache.zest.library.scheduler.schedule.ScheduleTime; - -public class TaskRunner - implements Runnable -{ - private static ReentrantLock lock = new ReentrantLock(); - - @Structure - private Module module; - - @Uses - private ScheduleTime schedule; - - @Override - public void run() - { - // TODO: (niclas) I am NOT happy with this implementation, requiring 3 UnitOfWorks to be created. 15-20 milliseconds on my MacBook. If there is a better way to detect overrun, two of those might not be needed. - UnitOfWork uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner initialize" ) ); - try - { - lock.lock(); - Schedule schedule = uow.get( Schedule.class, this.schedule.scheduleIdentity() ); - if( !schedule.running().get() ) // check for overrun. - { - try - { - schedule.taskStarting(); - schedule.running().set( true ); - uow.complete(); // This completion is needed to detect overrun - lock.unlock(); - - uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner" ) ); - schedule = uow.get( schedule ); // re-attach the entity to the new UnitOfWork - Task task = schedule.task().get(); - task.run(); - uow.complete(); - lock.lock(); - uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner conclude" ) ); - schedule = uow.get( schedule ); // re-attach the entity to the new UnitOfWork - schedule.running().set( false ); - schedule.taskCompletedSuccessfully(); - schedule.executionCounter().set( schedule.executionCounter().get() + 1 ); - } - catch( RuntimeException ex ) - { - schedule.running().set( false ); - processException( schedule, ex ); - } - } - else - { - schedule.overrun().set( schedule.overrun().get() + 1 ); - } - uow.complete(); - } - catch( Exception e ) - { - e.printStackTrace(); - throw new UndeclaredThrowableException( e ); - } - finally - { - uow.discard(); - try - { - lock.unlock(); - } - catch( IllegalMonitorStateException e ) - { - // ignore, as it may happen on certain exceptions. - } - } - } - - private void processException( Schedule schedule, RuntimeException ex ) - { - Throwable exception = ex; - while( exception instanceof UndeclaredThrowableException ) - { - exception = ( (UndeclaredThrowableException) ex ).getUndeclaredThrowable(); - } - schedule.taskCompletedWithException( exception ); - schedule.exceptionCounter().set( schedule.exceptionCounter().get() + 1 ); - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/bootstrap/SchedulerAssembler.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/bootstrap/SchedulerAssembler.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/bootstrap/SchedulerAssembler.java index af5f475..317abd1 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/bootstrap/SchedulerAssembler.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/bootstrap/SchedulerAssembler.java @@ -27,11 +27,11 @@ import org.apache.zest.bootstrap.ServiceDeclaration; import org.apache.zest.bootstrap.ValueDeclaration; import org.apache.zest.library.scheduler.SchedulerConfiguration; import org.apache.zest.library.scheduler.SchedulerService; -import org.apache.zest.library.scheduler.TaskRunner; -import org.apache.zest.library.scheduler.schedule.ScheduleFactory; -import org.apache.zest.library.scheduler.schedule.Schedules; -import org.apache.zest.library.scheduler.schedule.cron.CronSchedule; -import org.apache.zest.library.scheduler.schedule.once.OnceSchedule; +import org.apache.zest.library.scheduler.internal.TaskRunner; +import org.apache.zest.library.scheduler.ScheduleFactory; +import org.apache.zest.library.scheduler.internal.Schedules; +import org.apache.zest.library.scheduler.CronSchedule; +import org.apache.zest.library.scheduler.OnceSchedule; import org.apache.zest.library.scheduler.timeline.Timeline; import org.apache.zest.library.scheduler.timeline.TimelineForScheduleConcern; import org.apache.zest.library.scheduler.timeline.TimelineRecord; http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultScheduleFactoryMixin.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultScheduleFactoryMixin.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultScheduleFactoryMixin.java index f05c041..27c7125 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultScheduleFactoryMixin.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultScheduleFactoryMixin.java @@ -27,10 +27,10 @@ import org.apache.zest.api.structure.Module; import org.apache.zest.api.unitofwork.UnitOfWork; import org.apache.zest.library.scheduler.SchedulerService; import org.apache.zest.library.scheduler.Task; -import org.apache.zest.library.scheduler.schedule.Schedule; -import org.apache.zest.library.scheduler.schedule.ScheduleFactory; -import org.apache.zest.library.scheduler.schedule.cron.CronSchedule; -import org.apache.zest.library.scheduler.schedule.once.OnceSchedule; +import org.apache.zest.library.scheduler.Schedule; +import org.apache.zest.library.scheduler.ScheduleFactory; +import org.apache.zest.library.scheduler.CronSchedule; +import org.apache.zest.library.scheduler.OnceSchedule; import org.apache.zest.spi.uuid.UuidIdentityGeneratorService; import org.joda.time.DateTime; import org.slf4j.Logger; http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultThreadFactory.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultThreadFactory.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultThreadFactory.java index c834f50..43520bd 100644 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultThreadFactory.java +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/defaults/DefaultThreadFactory.java @@ -22,6 +22,7 @@ package org.apache.zest.library.scheduler.defaults; import java.util.concurrent.atomic.AtomicInteger; import org.apache.zest.api.injection.scope.This; +import org.apache.zest.library.scheduler.internal.Execution; import org.apache.zest.library.scheduler.SchedulerService; public class DefaultThreadFactory @@ -35,7 +36,7 @@ public class DefaultThreadFactory protected DefaultThreadFactory( @This SchedulerService me ) { SecurityManager sm = System.getSecurityManager(); - group = ( sm != null ) ? sm.getThreadGroup() : Thread.currentThread().getThreadGroup(); + group = ( sm != null ) ? sm.getThreadGroup() : Execution.ExecutionMixin.TG; namePrefix = me.identity().get() + "-P" + POOL_NUMBER.getAndIncrement() + "W"; } http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Execution.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Execution.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Execution.java new file mode 100644 index 0000000..a92ee2b --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Execution.java @@ -0,0 +1,278 @@ +/* + * 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.zest.library.scheduler.internal; + +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.zest.api.concern.Concerns; +import org.apache.zest.api.configuration.Configuration; +import org.apache.zest.api.injection.scope.Structure; +import org.apache.zest.api.injection.scope.This; +import org.apache.zest.api.mixin.Mixins; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.unitofwork.NoSuchEntityException; +import org.apache.zest.api.unitofwork.UnitOfWork; +import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern; +import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; +import org.apache.zest.library.scheduler.Schedule; +import org.apache.zest.library.scheduler.Scheduler; +import org.apache.zest.library.scheduler.SchedulerConfiguration; + +/** + * This composite handles the Execution of Schedules. + * + * The composite is internal and should never be used by clients. + */ +@Mixins( Execution.ExecutionMixin.class ) +@Concerns( UnitOfWorkConcern.class ) +public interface Execution +{ + void dispatchForExecution( Schedule schedule ); + + void start() + throws Exception; + + void stop() + throws Exception; + + @UnitOfWorkPropagation( usecase = "Schedule Next Time Update" ) + void updateNextTime( ScheduleTime schedule ); // This method is public, only because the UnitOfWorkConcern is wanted. + + class ExecutionMixin + implements Execution, Runnable + { + public static final ThreadGroup TG = new ThreadGroup( "Zest Scheduling" ); + + private final Object lock = new Object(); + + @Structure + private Module module; + + @This + private Scheduler scheduler; + + @This + private Configuration<SchedulerConfiguration> config; + + @This + private ThreadFactory threadFactory; + + @This + private RejectedExecutionHandler rejectionHandler; + + private final SortedSet<ScheduleTime> timingQueue = new TreeSet<>(); + private volatile boolean running; + private ThreadPoolExecutor taskExecutor; + private volatile Thread scheduleThread; + + @Override + public void run() + { + running = true; + while( running ) + { + try + { + ScheduleTime scheduleTime = timing(); + if( scheduleTime != null ) + { + waitFor( scheduleTime ); + + if( isTime( scheduleTime ) ) // We might have been awakened to reschedule + { + updateNextTime( scheduleTime ); + } + } + else + { + waitFor( 100 ); + } + } + catch( Throwable e ) + { + e.printStackTrace(); + } + } + } + + private ScheduleTime timing() + { + synchronized( lock ) + { + if( timingQueue.size() == 0 ) + { + return null; + } + return timingQueue.first(); + } + } + + private boolean isTime( ScheduleTime scheduleTime ) + { + long now = System.currentTimeMillis(); + return scheduleTime.nextTime() <= now; + } + + private void waitFor( ScheduleTime scheduleTime ) + throws InterruptedException + { + long now = System.currentTimeMillis(); + long waitingTime = scheduleTime.nextTime() - now; + waitFor( waitingTime ); + } + + private void waitFor( long waitingTime ) + { + if( waitingTime > 0 ) + { + synchronized( lock ) + { + try + { + lock.wait( waitingTime ); + } + catch( InterruptedException e ) + { + // should be ignored. + } + } + } + } + + @Override + public void updateNextTime( ScheduleTime oldScheduleTime ) + { + long now = System.currentTimeMillis(); + UnitOfWork uow = module.currentUnitOfWork(); + try + { + submitTaskForExecution( oldScheduleTime ); + Schedule schedule = uow.get( Schedule.class, oldScheduleTime.scheduleIdentity() ); + long nextTime = schedule.nextRun( now + 1000 ); + if( nextTime != Long.MIN_VALUE ) + { + ScheduleTime newScheduleTime = new ScheduleTime( schedule.identity().get(), nextTime ); + synchronized( lock ) + { + // Re-add to the Timing Queue, to re-position the sorting. + timingQueue.remove( oldScheduleTime ); + timingQueue.add( newScheduleTime ); + } + } + else + { + synchronized( lock ) + { + timingQueue.remove( oldScheduleTime ); + } + } + } + catch( NoSuchEntityException e ) + { + e.printStackTrace(); +// scheduler.cancelSchedule( oldScheduleTime.scheduleIdentity() ); + } + } + + private void submitTaskForExecution( ScheduleTime scheduleTime ) + { + Runnable taskRunner = module.newTransient( Runnable.class, scheduleTime ); + this.taskExecutor.submit( taskRunner ); + } + + public void dispatchForExecution( Schedule schedule ) + { + long now = System.currentTimeMillis(); + long nextRun = schedule.nextRun( now + 1000 ); + if( nextRun > 0 ) + { + synchronized( lock ) + { + timingQueue.add( new ScheduleTime( schedule.identity().get(), nextRun ) ); + lock.notifyAll(); + } + } + } + + @Override + public void start() + throws Exception + { + SchedulerConfiguration configuration = config.get(); + Integer workersCount = configuration.workersCount().get(); + Integer workQueueSize = configuration.workQueueSize().get(); + createThreadPoolExecutor( workersCount, workQueueSize ); + taskExecutor.prestartAllCoreThreads(); + + SecurityManager sm = System.getSecurityManager(); + ThreadGroup threadGroup = sm != null ? sm.getThreadGroup() : TG; + scheduleThread = new Thread( threadGroup, this, "Scheduler" ); + scheduleThread.start(); + } + + private void createThreadPoolExecutor( Integer workersCount, Integer workQueueSize ) + { + int corePoolSize = 2; + if( workersCount > 4 ) + { + corePoolSize = workersCount / 4 + 1; + } + if( corePoolSize > 50 ) + { + corePoolSize = 20; + } + if( workersCount > 200 ) + { + workersCount = 200; + } + taskExecutor = new ThreadPoolExecutor( corePoolSize, workersCount, + 0, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>( workQueueSize ), + threadFactory, rejectionHandler ); + } + + @Override + public void stop() + throws Exception + { + running = false; + synchronized( this ) + { + scheduleThread.interrupt(); + } + taskExecutor.shutdown(); + try + { + taskExecutor.awaitTermination( 5, TimeUnit.SECONDS ); + } + catch( InterruptedException e ) + { + e.printStackTrace(); + } + taskExecutor.shutdownNow(); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/ScheduleTime.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/ScheduleTime.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/ScheduleTime.java new file mode 100644 index 0000000..b008de7 --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/ScheduleTime.java @@ -0,0 +1,61 @@ +/* + * 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.zest.library.scheduler.internal; + +import org.apache.zest.api.util.NullArgumentException; + +public final class ScheduleTime + implements Comparable<ScheduleTime> +{ + private String scheduleIdentity; + private long nextTime; + + public ScheduleTime( String scheduleIdentity, long nextTime ) + { + NullArgumentException.validateNotEmpty( "scheduleIdentity", scheduleIdentity ); + this.scheduleIdentity = scheduleIdentity; + this.nextTime = nextTime; + } + + public long nextTime() + { + return nextTime; + } + + public String scheduleIdentity() + { + return scheduleIdentity; + } + + @Override + public int compareTo( ScheduleTime another ) + { + if( this.scheduleIdentity.equals( another.scheduleIdentity ) ) + { + return 0; + } + + if( this.nextTime < another.nextTime ) + { + return -1; + } + return 1; + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/SchedulerMixin.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/SchedulerMixin.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/SchedulerMixin.java new file mode 100644 index 0000000..3afafa5 --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/SchedulerMixin.java @@ -0,0 +1,199 @@ +/* + * 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.zest.library.scheduler.internal; + +import org.apache.zest.api.configuration.Configuration; +import org.apache.zest.api.injection.scope.Service; +import org.apache.zest.api.injection.scope.Structure; +import org.apache.zest.api.injection.scope.This; +import org.apache.zest.api.service.ServiceActivation; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.unitofwork.NoSuchEntityException; +import org.apache.zest.api.unitofwork.UnitOfWork; +import org.apache.zest.api.unitofwork.UnitOfWorkCompletionException; +import org.apache.zest.api.usecase.UsecaseBuilder; +import org.apache.zest.library.scheduler.Scheduler; +import org.apache.zest.library.scheduler.SchedulerConfiguration; +import org.apache.zest.library.scheduler.SchedulerService; +import org.apache.zest.library.scheduler.SchedulesHandler; +import org.apache.zest.library.scheduler.Task; +import org.apache.zest.library.scheduler.CronSchedule; +import org.apache.zest.library.scheduler.Schedule; +import org.apache.zest.library.scheduler.ScheduleFactory; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SchedulerMixin + implements Scheduler, ServiceActivation +{ + private static final Logger LOGGER = LoggerFactory.getLogger( Scheduler.class ); + + @Service + private ScheduleFactory scheduleFactory; + + @Structure + private Module module; + + @This + private SchedulerService me; + + @This + private SchedulesHandler schedulesHandler; + + @This + private Execution execution; + + @This + private Configuration<SchedulerConfiguration> config; + + public SchedulerMixin() + { + } + + @Override + public Schedule scheduleOnce( Task task, int initialSecondsDelay ) + { + long now = System.currentTimeMillis(); + Schedule schedule = scheduleFactory.newOnceSchedule( task, new DateTime( now + initialSecondsDelay * 1000 ) ); + saveAndDispatch( schedule ); + return schedule; + } + + @Override + public Schedule scheduleOnce( Task task, DateTime runAt ) + { + Schedule schedule = scheduleFactory.newOnceSchedule( task, runAt ); + saveAndDispatch( schedule ); + return schedule; + } + + @Override + public Schedule scheduleCron( Task task, String cronExpression ) + { + DateTime now = new DateTime(); + Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, now ); + saveAndDispatch( schedule ); + return schedule; + } + + @Override + public Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression, DateTime start ) + { + Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, start ); + saveAndDispatch( schedule ); + return schedule; + } + + @Override + public void scheduleCron( Schedule schedule ) + { + saveAndDispatch( schedule ); + } + + @Override + public Schedule scheduleCron( Task task, String cronExpression, long initialDelay ) + { + DateTime start = new DateTime( System.currentTimeMillis() + initialDelay ); + Schedule schedule = scheduleFactory.newCronSchedule( task, cronExpression, start ); + saveAndDispatch( schedule ); + return schedule; + } + + @Override + public void cancelSchedule( String scheduleId ) + { + UnitOfWork uow = module.currentUnitOfWork(); + Schedule schedule = null; + try + { + schedule = uow.get( Schedule.class, scheduleId ); + } + catch( NoSuchEntityException e ) + { + return; + } + cancelSchedule( schedule ); + } + + @Override + public void cancelSchedule( Schedule schedule ) + { + Schedules active = schedulesHandler.getActiveSchedules(); + if( active.schedules().remove( schedule ) ) + { + schedule.cancelled().set( true ); + } + } + + private void saveAndDispatch( Schedule schedule ) + { + Schedules schedules = schedulesHandler.getActiveSchedules(); + schedules.schedules().add( schedule ); + execution.dispatchForExecution( schedule ); + } + + private void loadSchedules() + throws UnitOfWorkCompletionException + { + try (UnitOfWork ignored = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Initialize Schedules" ) )) + { + Schedules schedules = schedulesHandler.getActiveSchedules(); + for( Schedule schedule : schedules.schedules() ) + { + dispatch( schedule ); + } + } + } + + private void dispatch( Schedule schedule ) + { + try + { + if( !schedule.cancelled().get() && !schedule.done().get() ) + { + execution.dispatchForExecution( schedule ); + } + } catch( Exception e ) + { + e.printStackTrace(); + } + } + + @Override + public void activateService() + throws Exception + { + // Throws IllegalArgument if corePoolSize or keepAliveTime less than zero, + // or if workersCount less than or equal to zero, + // or if corePoolSize greater than workersCount. + execution.start(); + loadSchedules(); + LOGGER.debug( "Activated" ); + } + + @Override + public void passivateService() + throws Exception + { + execution.stop(); + LOGGER.debug( "Passivated" ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Schedules.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Schedules.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Schedules.java new file mode 100644 index 0000000..95563c1 --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/Schedules.java @@ -0,0 +1,28 @@ +/* + * 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.zest.library.scheduler.internal; + +import org.apache.zest.api.association.ManyAssociation; +import org.apache.zest.library.scheduler.Schedule; + +public interface Schedules +{ + ManyAssociation<Schedule> schedules(); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/TaskRunner.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/TaskRunner.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/TaskRunner.java new file mode 100644 index 0000000..fa52d73 --- /dev/null +++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/internal/TaskRunner.java @@ -0,0 +1,115 @@ +/* + * 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.zest.library.scheduler.internal; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.zest.api.injection.scope.Structure; +import org.apache.zest.api.injection.scope.Uses; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.unitofwork.UnitOfWork; +import org.apache.zest.api.usecase.UsecaseBuilder; +import org.apache.zest.library.scheduler.Task; +import org.apache.zest.library.scheduler.Schedule; + +public class TaskRunner + implements Runnable +{ + private static ReentrantLock lock = new ReentrantLock(); + + @Structure + private Module module; + + @Uses + private ScheduleTime schedule; + + @Override + public void run() + { + // TODO: (niclas) I am NOT happy with this implementation, requiring 3 UnitOfWorks to be created. 15-20 milliseconds on my MacBook. If there is a better way to detect overrun, two of those might not be needed. + UnitOfWork uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner initialize" ) ); + try + { + lock.lock(); + Schedule schedule = uow.get( Schedule.class, this.schedule.scheduleIdentity() ); + if( !schedule.running().get() ) // check for overrun. + { + try + { + schedule.taskStarting(); + schedule.running().set( true ); + uow.complete(); // This completion is needed to detect overrun + + uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner" ) ); + schedule = uow.get( schedule ); // re-attach the entity to the new UnitOfWork + Task task = schedule.task().get(); + lock.unlock(); + task.run(); + lock.lock(); + uow.complete(); + uow = module.newUnitOfWork( UsecaseBuilder.newUsecase( "Task Runner conclude" ) ); + schedule = uow.get( schedule ); // re-attach the entity to the new UnitOfWork + schedule.running().set( false ); + schedule.taskCompletedSuccessfully(); + schedule.executionCounter().set( schedule.executionCounter().get() + 1 ); + } + catch( RuntimeException ex ) + { + schedule.running().set( false ); + processException( schedule, ex ); + } + } + else + { + schedule.overrun().set( schedule.overrun().get() + 1 ); + } + uow.complete(); + } + catch( Exception e ) + { + e.printStackTrace(); + throw new UndeclaredThrowableException( e ); + } + finally + { + uow.discard(); + try + { + lock.unlock(); + } + catch( IllegalMonitorStateException e ) + { + // ignore, as it may happen on certain exceptions. + } + } + } + + private void processException( Schedule schedule, RuntimeException ex ) + { + Throwable exception = ex; + while( exception instanceof UndeclaredThrowableException ) + { + exception = ( (UndeclaredThrowableException) ex ).getUndeclaredThrowable(); + } + schedule.taskCompletedWithException( exception ); + schedule.exceptionCounter().set( schedule.exceptionCounter().get() + 1 ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedule.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedule.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedule.java deleted file mode 100644 index 48f2e6f..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedule.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2010-2012, Paul Merlin. - * Copyright (c) 2012, Niclas Hedhman. - * - * Licensed 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.zest.library.scheduler.schedule; - -import org.apache.zest.api.association.Association; -import org.apache.zest.api.common.UseDefaults; -import org.apache.zest.api.entity.EntityComposite; -import org.apache.zest.api.property.Immutable; -import org.apache.zest.api.property.Property; -import org.apache.zest.library.scheduler.Task; -import org.joda.time.DateTime; - -/** - * Represent the scheduling of a {@link Task}. - */ -public interface Schedule extends EntityComposite -{ - /** - * @return The Association to the Task to be executed when it is time. - */ - Association<Task> task(); - - /** The first run of this Schedule. - * - * @return The property containing the first time this Schedule will be run. - */ - @Immutable - Property<DateTime> start(); - - /** Returns true if the Schedule has been cancelled. - * - * @return true if the Schedule has been cancelled. - */ - @UseDefaults - Property<Boolean> cancelled(); - - /** Returns true if the Schedule is currently running. - * - * @return true if the Schedule is currently running. - */ - @UseDefaults - Property<Boolean> running(); - - /** Returns the number of times the {@link Task} has been executed. - * <p> - * Each time the {@link Task#run} method completes, with or without an {@link Exception}, this - * counter is incremented by 1. - * </p> - * - * @return true the number of Exception that has occurred when running the {@link Task}. - */ - @UseDefaults - Property<Long> executionCounter(); - - /** Returns the number of Exception that has occurred when running the {@link Task}. - * <p> - * Each time the {@link Task#run} method throws a {@link RuntimeException}, this property - * is incremenented by 1, - * </p> - * - * @return true the number of Exception that has occurred when running the {@link Task}. - */ - @UseDefaults - Property<Long> exceptionCounter(); - - /** Returns true if the Schedule is done and will not be executed any more times. - * - * @return true if the Schedule is done and will not be executed any more times. - */ - @UseDefaults - Property<Boolean> done(); - - /** Returns the number of times the Schedule has been skipped, due to the Task was still running. - * - * @return the number of times the Schedule has been skipped, due to the Task was still running. - */ - @UseDefaults - Property<Long> overrun(); - - /** - * Called just before the {@link org.apache.zest.library.scheduler.Task#run()} method is called. - */ - void taskStarting(); - - /** - * Called directly after the {@link org.apache.zest.library.scheduler.Task#run()} method has been completed and - * returned from the method normally. - */ - void taskCompletedSuccessfully(); - - /** - * Called directly after the {@link org.apache.zest.library.scheduler.Task#run()} method has been completed but - * threw a RuntimeException. - * @param ex The execption that was thrown in the Task. If the thrown Exception was an - * {@link java.lang.reflect.UndeclaredThrowableException} then the underlying exception is passed here. - */ - void taskCompletedWithException( Throwable ex ); - - /** - * Compute the next time this schedule is to be run. - * - * @param from The starting time when to look for the next time it will run. - * - * @return The exact absolute time when this Schedule is to be run next time, or -1 if never - */ - long nextRun( long from ); - - /** - * Return a representation of the Schedule in a human understandable format. - * - * @return A String representing this schedule. - */ - String presentationString(); -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleFactory.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleFactory.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleFactory.java deleted file mode 100644 index 133ec1c..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. - * - * Licensed 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.zest.library.scheduler.schedule; - -import org.apache.zest.api.concern.Concerns; -import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern; -import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation; -import org.apache.zest.library.scheduler.defaults.DefaultScheduleFactoryMixin; -import org.joda.time.DateTime; -import org.apache.zest.api.mixin.Mixins; -import org.apache.zest.library.scheduler.Task; - -import static org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propagation.MANDATORY; - -@Mixins( DefaultScheduleFactoryMixin.class ) -@Concerns( UnitOfWorkConcern.class ) -public interface ScheduleFactory -{ - @UnitOfWorkPropagation( MANDATORY) - Schedule newCronSchedule( Task task, String cronExpression, DateTime start ); - - @UnitOfWorkPropagation( MANDATORY) - Schedule newOnceSchedule( Task task, DateTime runAt ); -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleTime.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleTime.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleTime.java deleted file mode 100644 index ed38cd6..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/ScheduleTime.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2010-2012, Paul Merlin. All Rights Reserved. - * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. - * - * Licensed 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.zest.library.scheduler.schedule; - -import org.apache.zest.api.util.NullArgumentException; - -public final class ScheduleTime - implements Comparable<ScheduleTime> -{ - private String scheduleIdentity; - private long nextTime; - - public ScheduleTime( String scheduleIdentity, long nextTime ) - { - NullArgumentException.validateNotEmpty( "scheduleIdentity", scheduleIdentity ); - this.scheduleIdentity = scheduleIdentity; - this.nextTime = nextTime; - } - - @Override - public boolean equals( Object o ) - { - if( this == o ) - { - return true; - } - if( o == null || getClass() != o.getClass() ) - { - return false; - } - ScheduleTime that = (ScheduleTime) o; - if( nextTime != that.nextTime ) - { - return false; - } - return scheduleIdentity.equals( that.scheduleIdentity ); - } - - @Override - public int hashCode() - { - int result = scheduleIdentity.hashCode(); - result = 31 * result + (int) ( nextTime ^ ( nextTime >>> 32 ) ); - return result; - } - - public long nextTime() - { - return nextTime; - } - - public String scheduleIdentity() - { - return scheduleIdentity; - } - - @Override - public int compareTo( ScheduleTime another ) - { - if( this.nextTime < another.nextTime ) - { - return -1; - } - else - { - if( this.nextTime == another.nextTime ) - { - return 0; - } - else - { - return 1; - } - } - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/73b7f196/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedules.java ---------------------------------------------------------------------- diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedules.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedules.java deleted file mode 100644 index ac65da3..0000000 --- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/schedule/Schedules.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2010-2012, Paul Merlin. All Rights Reserved. - * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. - * - * Licensed 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.zest.library.scheduler.schedule; - -import org.apache.zest.api.association.ManyAssociation; - -public interface Schedules -{ - ManyAssociation<Schedule> schedules(); -}
