polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [3/3] zest-java git commit: ZEST-130 - FIrst attempt at the Quartz integration issue. Doesn't work. Quartz is too complex and has not been able to separate its concerns well enough, forcing all new JobStore implementations to do a lot more work than shou
Date Sat, 05 Dec 2015 09:20:18 GMT
ZEST-130 - FIrst attempt at the Quartz integration issue. Doesn't work. Quartz is too complex and has not been able to separate its concerns well enough, forcing all new JobStore implementations to do a lot more work than should have been necessary.


Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/551c04d5
Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/551c04d5
Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/551c04d5

Branch: refs/heads/ZEST-130
Commit: 551c04d598e7279507018df2089dc70ca289549e
Parents: 725b616
Author: Niclas Hedhman <niclas@hedhman.org>
Authored: Sun Nov 22 14:05:16 2015 +0800
Committer: Niclas Hedhman <niclas@hedhman.org>
Committed: Sun Nov 22 14:05:16 2015 +0800

----------------------------------------------------------------------
 libraries.gradle                                |  44 +-
 libraries/scheduler/build.gradle                |   3 +-
 .../zest/library/scheduler/CalendarWrapper.java |  30 +
 .../zest/library/scheduler/Calendars.java       |  29 +
 .../zest/library/scheduler/CronSchedule.java    | 117 ---
 .../zest/library/scheduler/JobStoreMixin.java   | 710 +++++++++++++++++++
 .../zest/library/scheduler/JobWrapper.java      |  30 +
 .../zest/library/scheduler/JobsGroup.java       |  28 +
 .../zest/library/scheduler/JobsGroups.java      |  31 +
 .../zest/library/scheduler/OnceSchedule.java    |  68 --
 .../apache/zest/library/scheduler/Schedule.java | 131 ----
 .../zest/library/scheduler/ScheduleFactory.java |  42 --
 .../zest/library/scheduler/Scheduler.java       | 140 ----
 .../library/scheduler/SchedulerAssembler.java   |  66 ++
 .../scheduler/SchedulerConfiguration.java       |  66 +-
 .../library/scheduler/SchedulerService.java     | 188 ++++-
 .../library/scheduler/SchedulesHandler.java     |  89 ---
 .../org/apache/zest/library/scheduler/Task.java |  77 --
 .../zest/library/scheduler/TriggerWrapper.java  | 178 +++++
 .../zest/library/scheduler/TriggersGroup.java   |  29 +
 .../zest/library/scheduler/TriggersGroups.java  |  29 +
 .../apache/zest/library/scheduler/ZestJob.java  |  36 +
 .../zest/library/scheduler/ZestJobDetail.java   | 128 ++++
 .../zest/library/scheduler/ZestJobFactory.java  |  63 ++
 .../scheduler/bootstrap/SchedulerAssembler.java | 117 ---
 .../library/scheduler/bootstrap/package.html    |  21 -
 .../defaults/DefaultRejectionHandler.java       |  39 -
 .../defaults/DefaultScheduleFactoryMixin.java   |  91 ---
 .../defaults/DefaultThreadFactory.java          |  57 --
 .../library/scheduler/internal/Execution.java   | 275 -------
 .../scheduler/internal/ScheduleTime.java        |  61 --
 .../scheduler/internal/SchedulerMixin.java      | 199 ------
 .../library/scheduler/internal/Schedules.java   |  28 -
 .../library/scheduler/internal/TaskRunner.java  | 115 ---
 .../apache/zest/library/scheduler/package.html  |  21 -
 .../library/scheduler/schedule/package.html     |  21 -
 .../library/scheduler/timeline/Timeline.java    |  73 --
 .../timeline/TimelineForScheduleConcern.java    |  90 ---
 .../scheduler/timeline/TimelineRecord.java      |  79 ---
 .../scheduler/timeline/TimelineRecordStep.java  |  27 -
 .../timeline/TimelineScheduleMixin.java         | 136 ----
 .../timeline/TimelineScheduleState.java         |  26 -
 .../timeline/TimelineSchedulerServiceMixin.java | 105 ---
 .../library/scheduler/timeline/package.html     |  21 -
 .../apache/library/scheduler/SchedulerTest.java |  94 +++
 .../scheduler/AbstractSchedulerTest.java        |  74 --
 .../zest/library/scheduler/Constants.java       |  26 -
 .../library/scheduler/CronScheduleTest.java     |  83 ---
 .../apache/zest/library/scheduler/FooTask.java  |  75 --
 .../zest/library/scheduler/SchedulerTest.java   | 205 ------
 .../scheduler/docsupport/SchedulerDocs.java     |  98 ---
 .../src/test/resources/logback-test.xml         |  32 -
 52 files changed, 1707 insertions(+), 2934 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries.gradle
----------------------------------------------------------------------
diff --git a/libraries.gradle b/libraries.gradle
index 13c7525..87cac54 100644
--- a/libraries.gradle
+++ b/libraries.gradle
@@ -54,13 +54,13 @@ def osgiVersion = '4.2.0' // 4.3.0 Fails to compile! - 5.0.0 exists
 def pdfboxVersion = '1.8.5'
 def postgresqlVersion = '9.4-1201-jdbc41'
 def prefuseVersion = '0.21'
+def quartzVersion = '2.2.1'
 def restletVersion = '2.3.4'
 def rdfVersion = '2.7.9'
 def riakVersion = '1.4.4' // 2.0.x Fails to compile!
 def scalaVersion = '2.11.6'
 def servletVersion = '3.1.0'
 def shiroVersion = '1.2.3'
-def skedVersion = '2.1'
 def slf4jVersion = '1.7.12'
 def solrVersion = "1.4.1" // 4.8.1 Fails to compile!
 def springVersion = '4.1.7.RELEASE'
@@ -189,46 +189,46 @@ rootProject.ext {
           wicket_stateless: "com.jolira:wicket-stateless:$wicketStatelessVersion",
 
           // Library & Extension dependencies
-          jackson_mapper: "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
-          jodamoney: "org.joda:joda-money:$jodaMoneyVersion",
-          jodatime: "joda-time:joda-time:$jodaTimeVersion",
+          bonecp: "com.jolbox:bonecp:$bonecpVersion",
+          bouncy_castle: "org.bouncycastle:bcprov-jdk15on:$bouncyVersion",
+          commons_dbcp: "commons-dbcp:commons-dbcp:$commonsDbcpVersion",
+          commons_lang: "commons-lang:commons-lang:$commonsLangVersion",
+          dnsjava: "dnsjava:dnsjava:$dnsJavaVersion",
           ehcache: "net.sf.ehcache:ehcache:$ehcacheVersion",
           elasticsearch: "org.elasticsearch:elasticsearch:$elasticsearchVersion",
+          freemarker: "org.freemarker:freemarker:$freemarkerVersion",
           h2: "com.h2database:h2:$h2Version",
           hazelcast: "com.hazelcast:hazelcast:$hazelcastVersion",
+          http_client: "org.apache.httpcomponents:httpclient:$httpClientVersion",
+          jackson_mapper: "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion",
+          javaSqlGenerator: "org.java-sql-generator:org.java-sql-generator.api:$javasqlgeneratorVersion",
+          javaSqlGeneratorImpl: "org.java-sql-generator:org.java-sql-generator.implementation:$javasqlgeneratorVersion",
           jclouds_core: "org.apache.jclouds:jclouds-core:$jcloudsVersion",
           jclouds_blobstore: "org.apache.jclouds:jclouds-allblobstore:$jcloudsVersion",
           jclouds_filesystem: "org.apache.jclouds.api:filesystem:$jcloudsVersion",
           jdbm: "jdbm:jdbm:$jdbmVersion",
           jedis: "redis.clients:jedis:$jedisVersion",
           jgoodies_looks: "com.jgoodies:jgoodies-looks:$jgoodiesLooksVersion",
+          jodamoney: "org.joda:joda-money:$jodaMoneyVersion",
+          jodatime: "joda-time:joda-time:$jodaTimeVersion",
+          jta: "javax.transaction:jta:$jtaVersion",
           leveldb_api: "org.iq80.leveldb:leveldb-api:$leveldbVersion",
           leveldb_java: "org.iq80.leveldb:leveldb:$leveldbVersion",
           leveldb_jni_all: "org.fusesource.leveldbjni:leveldbjni-all:$leveldbJniVersion",
+          liquibase: "org.liquibase:liquibase-core:$liquibaseVersion",
           mongodb: "org.mongodb:mongo-java-driver:$mongodbVersion",
+          pdfbox: "org.apache.pdfbox:pdfbox:$pdfboxVersion",
+          prefuse: "de.sciss:prefuse-core:$prefuseVersion",
+          quartz: "org.quartz-scheduler:quartz:$quartzVersion",
+          restlet_xml: "org.restlet.jee:org.restlet.ext.xml:$restletVersion",
           riak: "com.basho.riak:riak-client:$riakVersion",
-          jta: "javax.transaction:jta:$jtaVersion",
-          javaSqlGenerator: "org.java-sql-generator:org.java-sql-generator.api:$javasqlgeneratorVersion",
-          javaSqlGeneratorImpl: "org.java-sql-generator:org.java-sql-generator.implementation:$javasqlgeneratorVersion",
-          velocity: "org.apache.velocity:velocity:$velocityVersion",
-          commons_dbcp: "commons-dbcp:commons-dbcp:$commonsDbcpVersion",
-          commons_lang: "commons-lang:commons-lang:$commonsLangVersion",
           servlet_api: "javax.servlet:javax.servlet-api:$servletVersion",
-          http_client: "org.apache.httpcomponents:httpclient:$httpClientVersion",
-          woodstox: "org.codehaus.woodstox:woodstox-core-asl:$woodstoxVersion",
-          restlet_xml: "org.restlet.jee:org.restlet.ext.xml:$restletVersion",
-          bouncy_castle: "org.bouncycastle:bcprov-jdk15on:$bouncyVersion",
-          dnsjava: "dnsjava:dnsjava:$dnsJavaVersion",
-          freemarker: "org.freemarker:freemarker:$freemarkerVersion",
           shiro: "org.apache.shiro:shiro-core:$shiroVersion",
           shiro_web: "org.apache.shiro:shiro-web:$shiroVersion",
-          bonecp: "com.jolbox:bonecp:$bonecpVersion",
-          liquibase: "org.liquibase:liquibase-core:$liquibaseVersion",
-          sked: "org.codeartisans:sked:$skedVersion",
-          yammer_metrics: "com.yammer.metrics:metrics-core:$yammerMetricsVersion",
-          pdfbox: "org.apache.pdfbox:pdfbox:$pdfboxVersion",
-          prefuse: "de.sciss:prefuse-core:$prefuseVersion",
           spymemcached: "net.spy:spymemcached:$spymemcachedVersion",
+          velocity: "org.apache.velocity:velocity:$velocityVersion",
+          woodstox: "org.codehaus.woodstox:woodstox-core-asl:$woodstoxVersion",
+          yammer_metrics: "com.yammer.metrics:metrics-core:$yammerMetricsVersion",
 
           // Testing
           junit: "junit:junit:$junitVersion",

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/build.gradle
----------------------------------------------------------------------
diff --git a/libraries/scheduler/build.gradle b/libraries/scheduler/build.gradle
index 37b63d0..29f691c 100644
--- a/libraries/scheduler/build.gradle
+++ b/libraries/scheduler/build.gradle
@@ -25,8 +25,7 @@ jar { manifest { name = "Apache Zestâ„¢ Library - Scheduler" }}
 dependencies {
     compile project( ":org.apache.zest.core:org.apache.zest.core.bootstrap" )
     compile project( ':org.apache.zest.libraries:org.apache.zest.library.constraints' )
-    compile libraries.sked
-    compile libraries.slf4j_api
+    compile libraries.quartz
 
     testCompile project( ":org.apache.zest.core:org.apache.zest.core.testsupport" )
     testCompile project( ":org.apache.zest.extensions:org.apache.zest.extension.indexing-rdf" )

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CalendarWrapper.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CalendarWrapper.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CalendarWrapper.java
new file mode 100644
index 0000000..4d6a394
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CalendarWrapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.entity.EntityComposite;
+import org.apache.zest.api.property.Property;
+import org.quartz.Calendar;
+
+public interface CalendarWrapper extends EntityComposite
+{
+    Property<Calendar> calendar();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Calendars.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Calendars.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Calendars.java
new file mode 100644
index 0000000..9e38d8a
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Calendars.java
@@ -0,0 +1,29 @@
+/*
+ * 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.NamedAssociation;
+import org.apache.zest.api.entity.EntityComposite;
+
+public interface Calendars extends EntityComposite
+{
+    NamedAssociation<CalendarWrapper> calendars();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/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
deleted file mode 100644
index 9ee212d..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/CronSchedule.java
+++ /dev/null
@@ -1,117 +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.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/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobStoreMixin.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobStoreMixin.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobStoreMixin.java
new file mode 100644
index 0000000..269b393
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobStoreMixin.java
@@ -0,0 +1,710 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.apache.zest.api.entity.EntityBuilder;
+import org.apache.zest.api.entity.LifecycleException;
+import org.apache.zest.api.injection.scope.Structure;
+import org.apache.zest.api.query.Query;
+import org.apache.zest.api.query.QueryBuilder;
+import org.apache.zest.api.query.QueryBuilderFactory;
+import org.apache.zest.api.unitofwork.EntityTypeNotFoundException;
+import org.apache.zest.api.unitofwork.NoSuchEntityException;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.api.unitofwork.UnitOfWorkFactory;
+import org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation;
+import org.quartz.Calendar;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.JobPersistenceException;
+import org.quartz.ObjectAlreadyExistsException;
+import org.quartz.SchedulerConfigException;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.quartz.impl.matchers.GroupMatcher;
+import org.quartz.spi.ClassLoadHelper;
+import org.quartz.spi.JobStore;
+import org.quartz.spi.OperableTrigger;
+import org.quartz.spi.SchedulerSignaler;
+import org.quartz.spi.TriggerFiredResult;
+
+import static org.apache.zest.api.query.QueryExpressions.and;
+import static org.apache.zest.api.query.QueryExpressions.eq;
+import static org.apache.zest.api.query.QueryExpressions.lt;
+import static org.apache.zest.api.query.QueryExpressions.not;
+import static org.apache.zest.api.query.QueryExpressions.templateFor;
+
+public class JobStoreMixin
+    implements JobStore
+{
+    @Structure
+    UnitOfWorkFactory uowf;
+
+    @Structure
+    QueryBuilderFactory qbf;
+    private String instanceId;
+    private String instanceName;
+    private int threadPoolSize;
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "store quartz job" )
+    public void storeJob( JobDetail newJob, boolean replaceExisting )
+        throws ObjectAlreadyExistsException
+    {
+        JobKey key = newJob.getKey();
+        JobsGroup group = getJobsGroup( key );
+        JobWrapper job = group.jobs().get( key.getName() );
+        if( job != null )
+        {
+            if( !replaceExisting )
+            {
+                throw new ObjectAlreadyExistsException( newJob );
+            }
+            job.jobDetail().set( newJob );
+        }
+        else
+        {
+            UnitOfWork uow = uowf.currentUnitOfWork();
+            EntityBuilder<JobWrapper> builder = uow.newEntityBuilder( JobWrapper.class );
+            builder.instance().jobDetail().set( newJob );
+            job = builder.newInstance();
+            group.jobs().put( key.getName(), job );
+        }
+    }
+
+    @Override
+    public void storeJobsAndTriggers( Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace )
+        throws ObjectAlreadyExistsException, JobPersistenceException
+    {
+        // make sure there are no collisions...
+        if( !replace )
+        {
+            for( Map.Entry<JobDetail, Set<? extends Trigger>> e : triggersAndJobs.entrySet() )
+            {
+                if( checkExists( e.getKey().getKey() ) )
+                {
+                    throw new ObjectAlreadyExistsException( e.getKey() );
+                }
+                for( Trigger trigger : e.getValue() )
+                {
+                    if( checkExists( trigger.getKey() ) )
+                    {
+                        throw new ObjectAlreadyExistsException( trigger );
+                    }
+                }
+            }
+        }
+        // do bulk add...
+        for( Map.Entry<JobDetail, Set<? extends Trigger>> e : triggersAndJobs.entrySet() )
+        {
+            storeJob( e.getKey(), true );
+            for( Trigger trigger : e.getValue() )
+            {
+                storeTrigger( (OperableTrigger) trigger, true );
+            }
+        }
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "store quartz trigger" )
+    public void storeTrigger( OperableTrigger newTrigger, boolean replaceExisting )
+        throws ObjectAlreadyExistsException
+    {
+        TriggerKey key = newTrigger.getKey();
+        TriggersGroup group = getTriggersGroup( key );
+        TriggerWrapper trigger = group.triggers().get( key.getName() );
+        if( trigger != null )
+        {
+            if( !replaceExisting )
+            {
+                throw new ObjectAlreadyExistsException( newTrigger );
+            }
+            trigger.trigger().set( newTrigger );
+        }
+        else
+        {
+            UnitOfWork uow = uowf.currentUnitOfWork();
+            EntityBuilder<TriggerWrapper> builder = uow.newEntityBuilder( TriggerWrapper.class );
+            builder.instance().trigger().set( newTrigger );
+            trigger = builder.newInstance();
+            group.triggers().put( key.getName(), trigger );
+        }
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "store quartz calendar" )
+    public void storeCalendar( String name, Calendar newCalendar, boolean replaceExisting, boolean updateTriggers )
+        throws ObjectAlreadyExistsException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        Calendars calendars = uow.get( Calendars.class, Calendars.class.getName() );
+        try
+        {
+            CalendarWrapper calendar = calendars.calendars().get( name );
+            if( !replaceExisting )
+            {
+                throw new ObjectAlreadyExistsException( "Calendar " + name + " already exists." );
+            }
+            calendar.calendar().set( newCalendar );
+        }
+        catch( NoSuchEntityException e )
+        {
+            EntityBuilder<CalendarWrapper> builder = uow.newEntityBuilder( CalendarWrapper.class );
+            builder.instance().calendar().set( newCalendar );
+            CalendarWrapper calendar = builder.newInstance();
+            calendars.calendars().put( name, calendar );
+        }
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "remove quartz job" )
+    public boolean removeJob( JobKey jobKey )
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        JobsGroups groups = uow.get( JobsGroups.class, JobsGroups.class.getName() );
+        JobsGroup group = groups.groups().get( jobKey.getGroup() );
+        group.jobs().remove( jobKey.getName() );
+        return remove( JobWrapper.class, getIdentity( jobKey ) );
+    }
+
+    @Override
+    public boolean removeJobs( List<JobKey> jobKeys )
+        throws JobPersistenceException
+    {
+        return jobKeys.stream().map( this::removeJobWithSuccessIndicator ).allMatch( v -> v );
+    }
+
+    private Boolean removeJobWithSuccessIndicator( JobKey key )
+    {
+        try
+        {
+            return removeJob( key );
+        }
+        catch( JobPersistenceException e )
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public JobDetail retrieveJob( JobKey key )
+        throws JobPersistenceException
+    {
+        JobsGroup group = getJobsGroup( key );
+        JobWrapper job = group.jobs().get( key.getName() );
+        if( job != null )
+        {
+            return job.jobDetail().get();
+        }
+        return null;
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "remove quartz trigger" )
+    public boolean removeTrigger( TriggerKey triggerKey )
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroups groups = uow.get( TriggersGroups.class, TriggersGroups.class.getName() );
+        TriggersGroup group = groups.groups().get( triggerKey.getGroup() );
+        group.triggers().remove( triggerKey.getName() );
+        return remove( TriggerWrapper.class, getIdentity( triggerKey ) );
+    }
+
+    @Override
+    public boolean removeTriggers( List<TriggerKey> triggerKeys )
+        throws JobPersistenceException
+    {
+        return triggerKeys.stream().map( this::removeTriggerWithSuccessIndicator ).allMatch( v -> v );
+    }
+
+    private boolean removeTriggerWithSuccessIndicator( TriggerKey triggerKey )
+    {
+        try
+        {
+            return removeTrigger( triggerKey );
+        }
+        catch( JobPersistenceException e )
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean replaceTrigger( TriggerKey triggerKey, OperableTrigger newTrigger )
+        throws JobPersistenceException
+    {
+        TriggerWrapper existing = (TriggerWrapper) retrieveTrigger( triggerKey );
+        if( existing.trigger().get().getJobKey().equals( newTrigger.getJobKey() ))
+        {
+            removeTrigger( triggerKey );
+            storeTrigger( newTrigger, true );
+        }
+        return false;
+    }
+
+    private Stream<TriggerWrapper> allTriggers()
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroups groups = uow.get( TriggersGroups.class, TriggersGroups.class.getName() );
+        return groups.groups().toMap().values().stream().flatMap( group -> group.triggers().toMap().values().stream() );
+    }
+
+    @Override
+    public OperableTrigger retrieveTrigger( TriggerKey key )
+        throws JobPersistenceException
+    {
+        TriggersGroup group = getTriggersGroup( key );
+        return group.triggers().get( key.getName() );
+    }
+
+    @Override
+    public boolean checkExists( JobKey key )
+        throws JobPersistenceException
+    {
+        JobsGroup group = getJobsGroup( key );
+        JobWrapper job = group.jobs().get( key.getName() );
+        return job != null;
+    }
+
+    @Override
+    public boolean checkExists( TriggerKey key )
+        throws JobPersistenceException
+    {
+        TriggersGroup group = getTriggersGroup( key );
+        return group.triggers().get( key.getName() ) != null;
+    }
+
+    @Override
+    public void clearAllSchedulingData()
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "remove quartz calendar" )
+    public boolean removeCalendar( String calName )
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        Calendars calendars = uow.get( Calendars.class, Calendars.class.getName() );
+        calendars.calendars().remove( calName );
+        return remove( CalendarWrapper.class, calName );
+    }
+
+    @Override
+    public Calendar retrieveCalendar( String calName )
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        Calendars calendars = uow.get( Calendars.class, Calendars.class.getName() );
+        return calendars.calendars().get( calName ).calendar().get();
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get number of quartz calendars" )
+    public int getNumberOfCalendars()
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        Calendars calendars = uow.get( Calendars.class, Calendars.class.getName() );
+        return calendars.calendars().count();
+    }
+
+    @Override
+    public Set<JobKey> getJobKeys( GroupMatcher<JobKey> matcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Set<TriggerKey> getTriggerKeys( GroupMatcher<TriggerKey> matcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get number of quartz triggers" )
+    public int getNumberOfTriggers()
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroups groups = uow.get( TriggersGroups.class, TriggersGroups.class.getName() );
+        return (int) groups
+            .groups()
+            .toMap()
+            .values()
+            .stream()
+            .flatMap(
+                triggers -> triggers
+                    .triggers()
+                    .toMap()
+                    .values()
+                    .stream()
+            ).count();
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get number of quartz jobs" )
+    public int getNumberOfJobs()
+        throws JobPersistenceException
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        JobsGroup jobs = uow.get( JobsGroup.class, JobsGroup.class.getName() );
+        return jobs.jobs().count();
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get quartz job group names" )
+    public List<String> getJobGroupNames()
+        throws JobPersistenceException
+    {
+        List<String> result = new ArrayList<>();
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        JobsGroup jobs = uow.get( JobsGroup.class, JobsGroup.class.getName() );
+        jobs.jobs().forEach( name -> result.add( getGroupName( name ) ) );
+        return result;
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get quartz trigger group names" )
+    public List<String> getTriggerGroupNames()
+        throws JobPersistenceException
+    {
+        List<String> result = new ArrayList<>();
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroup triggersGroup = uow.get( TriggersGroup.class, TriggersGroup.class.getName() );
+        triggersGroup.triggers().forEach( name -> result.add( getGroupName( name ) ) );
+        return result;
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get quartz calendar names" )
+    public List<String> getCalendarNames()
+        throws JobPersistenceException
+    {
+        List<String> result = new ArrayList<>();
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        Calendars calendars = uow.get( Calendars.class, Calendars.class.getName() );
+        calendars.calendars().forEach( result::add );
+        return result;
+    }
+
+    @Override
+    @UnitOfWorkPropagation( usecase = "get quartz triggers for job" )
+    public List<OperableTrigger> getTriggersForJob( JobKey jobKey )
+        throws JobPersistenceException
+    {
+        List<OperableTrigger> result = new ArrayList<>();
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroup triggersGroup = uow.get( TriggersGroup.class, TriggersGroup.class.getName() );
+        triggersGroup.triggers().toMap().values().stream()
+            .map( triggerWrapper -> (OperableTrigger) triggerWrapper.trigger().get() )
+            .filter( trigger -> trigger.getJobKey().equals( jobKey ) )
+            .forEach( result::add );
+        return result;
+    }
+
+    @Override
+    public Trigger.TriggerState getTriggerState( TriggerKey triggerKey )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void pauseTrigger( TriggerKey triggerKey )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Collection<String> pauseTriggers( GroupMatcher<TriggerKey> matcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void pauseJob( JobKey jobKey )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Collection<String> pauseJobs( GroupMatcher<JobKey> groupMatcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void resumeTrigger( TriggerKey triggerKey )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Collection<String> resumeTriggers( GroupMatcher<TriggerKey> matcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Set<String> getPausedTriggerGroups()
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void resumeJob( JobKey jobKey )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public Collection<String> resumeJobs( GroupMatcher<JobKey> matcher )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void pauseAll()
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void resumeAll()
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public List<OperableTrigger> acquireNextTriggers( long noLaterThan, int maxCount, long timeWindow )
+        throws JobPersistenceException
+    {
+        List<OperableTrigger> result = new ArrayList<>();
+        Query<TriggerWrapper> query = createNextTriggersQuery( noLaterThan, timeWindow );
+        query.maxResults( maxCount );
+        for( TriggerWrapper wrapper : query )
+        {
+            wrapper.state().set( TriggerWrapper.State.aquired );
+            result.add( wrapper );
+        }
+        return result;
+    }
+
+    private Query<TriggerWrapper> createNextTriggersQuery( long noLaterThan, long timeWindow )
+    {
+        QueryBuilder<TriggerWrapper> qb = qbf.newQueryBuilder( TriggerWrapper.class );
+        TriggerWrapper template = templateFor( TriggerWrapper.class );
+        qb = qb.where(
+            and(
+                lt( template.nextTime(), noLaterThan + timeWindow ),
+                not( eq( template.state(), TriggerWrapper.State.aquired ) )
+            )
+        );
+        return uowf.currentUnitOfWork().newQuery( qb );
+    }
+
+    @Override
+    public void releaseAcquiredTrigger( OperableTrigger trigger )
+    {
+        ( (TriggerWrapper) trigger ).state().set( TriggerWrapper.State.waiting );
+    }
+
+    @Override
+    public List<TriggerFiredResult> triggersFired( List<OperableTrigger> triggers )
+        throws JobPersistenceException
+    {
+        throw new UnsupportedOperationException( "This operation is not yet supported." );
+    }
+
+    @Override
+    public void triggeredJobComplete( OperableTrigger trigger,
+                                      JobDetail jobDetail,
+                                      Trigger.CompletedExecutionInstruction triggerInstCode
+    )
+    {
+        System.out.println("Job completed: " + jobDetail);
+    }
+
+    @Override
+    public void setInstanceId( String schedInstId )
+    {
+        instanceId = schedInstId;
+    }
+
+    @Override
+    public void setInstanceName( String schedName )
+    {
+        instanceName = schedName;
+    }
+
+    @Override
+    public void setThreadPoolSize( int poolSize )
+    {
+        threadPoolSize = poolSize;
+    }
+
+    @Override
+    public void initialize( ClassLoadHelper loadHelper, SchedulerSignaler signaler )
+        throws SchedulerConfigException
+    {
+
+    }
+
+    @Override
+    public void schedulerStarted()
+        throws SchedulerException
+    {
+
+    }
+
+    @Override
+    public void schedulerPaused()
+    {
+
+    }
+
+    @Override
+    public void schedulerResumed()
+    {
+
+    }
+
+    @Override
+    public void shutdown()
+    {
+
+    }
+
+    @Override
+    public boolean supportsPersistence()
+    {
+        return true;
+    }
+
+    @Override
+    public long getEstimatedTimeToReleaseAndAcquireTrigger()
+    {
+        return 0;
+    }
+
+    @Override
+    public boolean isClustered()
+    {
+        return false;
+    }
+
+    @Override
+    public void storeJobAndTrigger( JobDetail newJob, OperableTrigger newTrigger )
+        throws ObjectAlreadyExistsException, JobPersistenceException
+    {
+        storeJob( newJob, false );
+        storeTrigger( newTrigger, false );
+    }
+
+    private String getIdentity( JobKey key )
+    {
+        return key.getGroup() + ":" + key.getName();
+    }
+
+    private String getIdentity( TriggerKey key )
+    {
+        return key.getGroup() + ":" + key.getName();
+    }
+
+    private String getGroupName( String name )
+    {
+        return name.split( ":" )[ 0 ];
+    }
+
+    private JobsGroup getJobsGroup( JobKey key )
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        JobsGroups groups = uow.get( JobsGroups.class, JobsGroups.class.getName() );
+        JobsGroup jobsGroup = groups.groups().get( jobsGroupIdentity( key ) );
+        if( jobsGroup == null )
+        {
+            jobsGroup = uow.newEntity( JobsGroup.class, jobsGroupIdentity( key ) );
+        }
+        return jobsGroup;
+    }
+
+    private String jobsGroupIdentity( JobKey key )
+    {
+        return "jobsGroup://" + key.getGroup() + "." + key.getName();
+    }
+
+    private TriggersGroup getTriggersGroup( TriggerKey key )
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        TriggersGroups groups = uow.get( TriggersGroups.class, TriggersGroups.class.getName() );
+        TriggersGroup triggersGroup = groups.groups().get( triggersGroupIdentity( key ) );
+        if( triggersGroup == null )
+        {
+            triggersGroup = uow.newEntity( TriggersGroup.class, triggersGroupIdentity( key ) );
+        }
+        return triggersGroup;
+    }
+
+    private String triggersGroupIdentity( TriggerKey key )
+    {
+        return "triggersGroup://" + key.getGroup() + "." + key.getName();
+    }
+
+    private <T> boolean remove( Class<T> type, String identity )
+    {
+        UnitOfWork uow = uowf.currentUnitOfWork();
+        try
+        {
+            T wrapper = uow.get( type, identity );
+            uow.remove( wrapper );
+            return true;
+        }
+        catch( EntityTypeNotFoundException | NoSuchEntityException | LifecycleException e )
+        {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobWrapper.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobWrapper.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobWrapper.java
new file mode 100644
index 0000000..7d766e5
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobWrapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.entity.EntityComposite;
+import org.apache.zest.api.property.Property;
+import org.quartz.JobDetail;
+
+public interface JobWrapper extends EntityComposite
+{
+    Property<JobDetail> jobDetail();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroup.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroup.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroup.java
new file mode 100644
index 0000000..b2fdb24
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroup.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;
+
+import org.apache.zest.api.association.NamedAssociation;
+
+public interface JobsGroup
+{
+    NamedAssociation<JobWrapper> jobs();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroups.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroups.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroups.java
new file mode 100644
index 0000000..8fad7a8
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/JobsGroups.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.zest.library.scheduler;
+
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.common.UseDefaults;
+import org.apache.zest.api.entity.EntityComposite;
+
+public interface JobsGroups extends EntityComposite
+{
+    @UseDefaults
+    NamedAssociation<JobsGroup> groups();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/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
deleted file mode 100644
index 299c2be..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/OnceSchedule.java
+++ /dev/null
@@ -1,68 +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 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/551c04d5/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
deleted file mode 100644
index a0f8a6e..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Schedule.java
+++ /dev/null
@@ -1,131 +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 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/551c04d5/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
deleted file mode 100644
index e891814..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/ScheduleFactory.java
+++ /dev/null
@@ -1,42 +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 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/551c04d5/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
deleted file mode 100644
index 8510645..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Scheduler.java
+++ /dev/null
@@ -1,140 +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.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.timeline.Timeline;
-
-import static org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propagation.MANDATORY;
-
-/**
- * Scheduler.
- * <p>
- * This is the only interface you should use in your application for scheduling tasks.
- * </p>
- * <p>
- * See {@link SchedulerConfiguration} for configuration properties.
- * </p>
- * <p>
- * See in {@link SchedulerAssembler} how to assemble a {@link Scheduler} and optional {@link Timeline}.
- * </p>
- * <p>
- * By default, a {@link Schedule} is not durable. In other words, it do not survive an {@link Application} restart.
- * </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 Schedules}
- * entity composite that has Associations to all active, completed and cancelled schedules.
- * </p>
- * <p>
- *
- * </p>
- */
-@Concerns( UnitOfWorkConcern.class )
-public interface Scheduler
-{
-    /**
-     * Schedule a Task to be run after a given initial delay in seconds.
-     *
-     * @param task                Task to be scheduled once
-     * @param initialSecondsDelay Initial delay the Task will be run after, in seconds
-     *
-     * @return The newly created Schedule
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    Schedule scheduleOnce( Task task, int initialSecondsDelay );
-
-    /**
-     * Schedule a Task to be run after a given initial delay in seconds.
-     *
-     * @param task  Task to be scheduled once
-     * @param runAt The future point in time when the Schedule will be run.
-     *
-     * @return The newly created Schedule
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    Schedule scheduleOnce( Task task, DateTime runAt );
-
-    /**
-     * Schedule a Task using a CronExpression.
-     *
-     * @param task           Task to be scheduled once
-     * @param cronExpression CronExpression for creating the Schedule for the given Task
-     *
-     * @return The newly created Schedule
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression );
-
-    /**
-     * Schedule a Task using a CronExpression with a given initial delay in milliseconds.
-     *
-     * @param task           Task to be scheduled once
-     * @param cronExpression CronExpression for creating the Schedule for the given Task
-     * @param initialDelay   Initial delay the Schedule will be active after, in milliseconds
-     *
-     * @return The newly created Schedule
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression, long initialDelay );
-
-    /**
-     * Schedule a Task using a CronExpression starting at a given date.
-     *
-     * @param task           Task to be scheduled once
-     * @param cronExpression CronExpression for creating the Schedule for the given Task
-     * @param start          Date from which the Schedule will become active
-     *
-     * @return The newly created Schedule
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    Schedule scheduleCron( Task task, @CronSchedule.CronExpression String cronExpression, DateTime start );
-
-    /** Schedules a custom Schedule.
-     *
-     *
-     * @param schedule The Schedule instance to be scheduled.
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    void scheduleCron( Schedule schedule );
-
-    /** Cancels a Schedule.
-     * Reads the Schedule from the EntityStore and calls {@link #cancelSchedule(Schedule)}.
-     *
-     * @param scheduleId The identity of the Schedule to be cancelled.
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    void cancelSchedule( String scheduleId );
-
-    /** Cancels the provided Schedule.
-     *
-     * Cancellation can be done before, while and after execution of the Schedule. If the execution
-     * is in progress, it will not be interrupted.
-     *
-     * @param schedule The schedule to be cancelled.
-     */
-    @UnitOfWorkPropagation( MANDATORY )
-    public void cancelSchedule( Schedule schedule );
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerAssembler.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerAssembler.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerAssembler.java
new file mode 100644
index 0000000..48aa871
--- /dev/null
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerAssembler.java
@@ -0,0 +1,66 @@
+/*
+ * 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.unitofwork.concern.UnitOfWorkConcern;
+import org.apache.zest.bootstrap.Assembler;
+import org.apache.zest.bootstrap.AssemblyException;
+import org.apache.zest.bootstrap.ModuleAssembly;
+import org.quartz.simpl.RAMJobStore;
+import org.quartz.spi.JobStore;
+import org.quartz.spi.OperableTrigger;
+
+public class SchedulerAssembler
+    implements Assembler
+{
+
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.services( JobStore.class ).withMixins( JobStoreMixin.class ).withConcerns( UnitOfWorkConcern.class );
+        module.services( SchedulerService.class ).instantiateOnStartup();
+        module.entities( JobWrapper.class );
+        module.entities( SchedulerConfiguration.class );
+        defineDefaults( module );
+        module.entities( TriggerWrapper.class );
+        module.entities( CalendarWrapper.class );
+        module.entities( Calendars.class );
+        module.entities( TriggersGroup.class );
+        module.entities( TriggersGroups.class );
+        module.entities( JobsGroup.class );
+        module.entities( JobsGroups.class );
+        module.values( ZestJobDetail.class );
+        module.objects( ZestJobFactory.class );
+    }
+
+    private void defineDefaults( ModuleAssembly module )
+    {
+        SchedulerConfiguration defaults = module.forMixin( SchedulerConfiguration.class ).declareDefaults();
+
+        defaults.idleWaitTime().set( 1000L );
+        defaults.interrupOnShutdown().set( true );
+        defaults.interrupOnShutdownWithWait().set( true );
+        defaults.batchTimeWindow().set( 15000L );
+        defaults.threadCount().set( 2 );
+        defaults.threadPriority().set( Thread.NORM_PRIORITY );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java
----------------------------------------------------------------------
diff --git a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java
index 66d7769..2569c1d 100644
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java
+++ b/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java
@@ -1,46 +1,48 @@
 /*
- * 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
+ * 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.
+ * 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.
  *
- * 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.common.Optional;
 import org.apache.zest.api.common.UseDefaults;
 import org.apache.zest.api.property.Property;
 
-/**
- * Configuration for the {@link Scheduler}.
- *
- * Every property has a default value, you can use a {@link Scheduler} without providing any.
- */
 public interface SchedulerConfiguration
 {
-// START SNIPPET: configuration
-    /**
-     * @return Number of worker threads, optional and defaults to the number of available cores.
-     */
-    @Optional @UseDefaults
-    Property<Integer> workersCount();
-
-    /**
-     * @return Size of the queue to use for holding tasks before they are run, optional and defaults to 10.
-     */
-    @Optional @UseDefaults
-    Property<Integer> workQueueSize();
-
-// END SNIPPET: configuration
+    @UseDefaults
+    Property<Long> batchTimeWindow();
+
+    @UseDefaults
+    Property<Boolean> interrupOnShutdown();
+
+    @UseDefaults
+    Property<Boolean> interrupOnShutdownWithWait();
+
+    @UseDefaults
+    Property<Integer> maxBatchSize();
+
+    @UseDefaults
+    Property<Long> idleWaitTime();
+
+    @UseDefaults
+    Property<Integer> threadCount();
+
+    @UseDefaults
+    Property<Integer> threadPriority();
 }

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/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 ade3d1e..54ea1bf 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
@@ -1,32 +1,182 @@
 /*
- * Copyright (c) 2010-2014, 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
+ * 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.
+ * 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.
  *
- * 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.entity.Identity;
+import java.util.Collection;
+import org.apache.zest.api.ZestAPI;
+import org.apache.zest.api.configuration.Configuration;
+import org.apache.zest.api.entity.EntityBuilder;
+import org.apache.zest.api.entity.EntityComposite;
+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.mixin.Mixins;
+import org.apache.zest.api.object.ObjectFactory;
 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;
+import org.apache.zest.api.service.ServiceComposite;
+import org.apache.zest.api.unitofwork.NoSuchEntityException;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.api.unitofwork.UnitOfWorkFactory;
+import org.apache.zest.api.usecase.UsecaseBuilder;
+import org.apache.zest.api.value.ValueBuilder;
+import org.apache.zest.api.value.ValueBuilderFactory;
+import org.apache.zest.spi.ZestSPI;
+import org.apache.zest.spi.uuid.UuidIdentityGeneratorService;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.SchedulerFactory;
+import org.quartz.impl.DirectSchedulerFactory;
+import org.quartz.impl.SchedulerRepository;
+import org.quartz.simpl.SimpleThreadPool;
+import org.quartz.spi.JobFactory;
+import org.quartz.spi.JobStore;
 
-@Mixins( { SchedulerMixin.class, DefaultThreadFactory.class, DefaultRejectionHandler.class } )
-public interface SchedulerService
-    extends Scheduler, ServiceActivation, Identity
+@Mixins( { SchedulerService.SchedulerActivationMixin.class } )
+public interface SchedulerService extends SchedulerFactory, ServiceActivation, ServiceComposite
 {
+    ZestJobDetail createJobDetails(ZestJob jobEntity);
+
+    abstract class SchedulerActivationMixin
+        implements SchedulerService
+    {
+
+        @This
+        private Configuration<SchedulerConfiguration> conf;
+
+        @Service
+        UuidIdentityGeneratorService uuid;
+
+        @Service
+        JobStore jobStore;
+
+        @Structure
+        ZestAPI api;
+
+        @Structure
+        ObjectFactory objectFactory;
+
+        @Structure
+        UnitOfWorkFactory uowf;
+
+        @Structure
+        ValueBuilderFactory vbf;
+
+        @Override
+        public void activateService()
+            throws Exception
+        {
+            initializeRoots();
+            SchedulerConfiguration config = conf.get();
+            DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
+            SimpleThreadPool threadPool = new SimpleThreadPool();
+            threadPool.setThreadCount( config.threadCount().get() );
+            threadPool.setThreadPriority( config.threadPriority().get() );
+            threadPool.setInstanceName( identity().get() );
+            threadPool.setThreadNamePrefix( identity().get() );
+            factory.createScheduler( identity().get(), uuid.generate( Scheduler.class ), threadPool, jobStore );
+
+            JobFactory jobFactory = objectFactory.newObject( ZestJobFactory.class );
+            getScheduler().setJobFactory( jobFactory );
+            getScheduler().start();
+        }
+
+        @Override
+        public void passivateService()
+            throws Exception
+        {
+            getScheduler().shutdown();
+            SchedulerRepository schedRep = SchedulerRepository.getInstance();
+            schedRep.remove( identity().get() );
+        }
+
+        @Override
+        public Scheduler getScheduler()
+            throws SchedulerException
+        {
+            SchedulerRepository schedRep = SchedulerRepository.getInstance();
+            String schedulerIdentity = identity().get();
+            return schedRep.lookup( schedulerIdentity );
+        }
+
+        @Override
+        public Scheduler getScheduler( String schedName )
+            throws SchedulerException
+        {
+            throw new UnsupportedOperationException( "Quartz in Apache Zest doesn't facilitate the Quartz Repository concept, as the Zest service mechanism can replace it that.\nRegister an additional SchedulerService in your bootstrap and look it up using normal Zest @Service injection or via ServiceFinder." );
+        }
+
+        @Override
+        public Collection<Scheduler> getAllSchedulers()
+            throws SchedulerException
+        {
+            throw new UnsupportedOperationException( "Quartz in Apache Zest doesn't facilitate the Quartz Repository concept, as the Zest service mechanism can replace it that.\nAll SchedulerServices can be looked up with @Service List<ServiceReference<SchedulerService>>" );
+        }
+
+        @Override
+        public ZestJobDetail createJobDetails( ZestJob jobEntity )
+        {
+            ValueBuilder<ZestJobDetail> builder = vbf.newValueBuilder( ZestJobDetail.class );
+            ZestJobDetail.State proto = builder.prototypeFor(ZestJobDetail.State.class);
+            proto.description().set( jobEntity.description().get() );
+            proto.jobClass().set( api.entityDescriptorFor( jobEntity ).primaryType().getName() );
+            proto.jobIdentity().set( jobEntity.identity().get() );
+            return builder.newInstance();
+        }
+
+        private void initializeRoots()
+        {
+            try( UnitOfWork uow = uowf.newUnitOfWork( UsecaseBuilder.newUsecase( "initialize quartz root entities" ) ) )
+            {
+                createJobsGroups();
+                createTriggersGroups();
+                createCalendars();
+                uow.complete();
+            }
+        }
+
+        private void createJobsGroups()
+        {
+            createContainer( JobsGroups.class );
+        }
+
+        private void createTriggersGroups()
+        {
+            createContainer( TriggersGroups.class );
+        }
+
+        private void createCalendars()
+        {
+            createContainer( Calendars.class );
+        }
+
+        private void createContainer( Class<? extends EntityComposite> type )
+        {
+            UnitOfWork uow = uowf.currentUnitOfWork();
+            try
+            {
+                uow.get( type, type.getName() );
+            } catch( NoSuchEntityException e)
+            {
+                uow.newEntity( type, type.getName() );
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/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
deleted file mode 100644
index b4a2b4d..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulesHandler.java
+++ /dev/null
@@ -1,89 +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 org.apache.zest.api.entity.Identity;
-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.UnitOfWorkPropagation;
-import org.apache.zest.library.scheduler.internal.Schedules;
-
-@Mixins(SchedulesHandler.SchedulesHandlerMixin.class)
-public interface SchedulesHandler
-{
-    @UnitOfWorkPropagation( UnitOfWorkPropagation.Propagation.MANDATORY)
-    Schedules getActiveSchedules();
-
-    @UnitOfWorkPropagation( UnitOfWorkPropagation.Propagation.MANDATORY)
-    Schedules getCancelledSchedules();
-
-    class SchedulesHandlerMixin implements SchedulesHandler
-    {
-        @This
-        private Identity me;
-
-        @Structure
-        private Module module;
-
-        @Override
-        public Schedules getActiveSchedules()
-        {
-            return getOrCreateSchedules(getActiveSchedulesIdentity());
-        }
-
-        @Override
-        public Schedules getCancelledSchedules()
-        {
-            return getOrCreateSchedules(getCancelledSchedulesIdentity());
-        }
-
-        public String getActiveSchedulesIdentity()
-        {
-            return "Schedules-Active:" + me.identity().get();
-        }
-
-        public String getCancelledSchedulesIdentity()
-        {
-            return "Schedules-Cancelled:" + me.identity().get();
-        }
-
-        private Schedules getOrCreateSchedules( String identity ){
-            UnitOfWork uow = module.currentUnitOfWork();
-            Schedules schedules;
-            try
-            {
-                schedules = uow.get( Schedules.class, identity );
-            }
-            catch( NoSuchEntityException e )
-            {
-                // Create a new Schedules entity for keeping track of them all.
-                schedules = uow.newEntity( Schedules.class, identity );
-            }
-            return schedules;
-
-        }
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/551c04d5/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
deleted file mode 100644
index 9cce9ce..0000000
--- a/libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java
+++ /dev/null
@@ -1,77 +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 java.util.List;
-import org.apache.zest.api.common.UseDefaults;
-import org.apache.zest.api.concern.Concerns;
-import org.apache.zest.api.property.Property;
-import org.apache.zest.api.unitofwork.UnitOfWork;
-import org.apache.zest.api.unitofwork.concern.UnitOfWorkConcern;
-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 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>
- * The {@code Task} type declares the {@link UnitOfWorkConcern} and therefor the {@code Task} implementation may
- * declare the {@link UnitOfWorkPropagation} annotation with the
- * {@link org.apache.zest.api.unitofwork.concern.UnitOfWorkPropagation.Propagation#REQUIRES_NEW} and a different
- * {@link UnitOfWork} strategy, such as {@code Retries} and {@code DiscardOn}.
- *
- *</p>
- *
- * Here is a simple example:
- * <pre><code>
- *  interface MyTask
- *      extends Task
- *  {
- *      Property&lt;String customState();
- *      Association&lt;AnotherEntity&gt; anotherEntity();
- *  }
- *
- *  class MyTaskMixin
- *      implements Runnable
- *  {
- *      &#64;This MyTaskEntity me;
- *
- *      public void run()
- *      {
- *          me.customState().set( me.anotherEntity().get().doSomeStuff( me.customState().get() ) );
- *      }
- *  }
- * </code></pre>
- *
- * Finaly, {@literal MyTask} must be assembled into an {@literal EntityComposite}.
- */
-// START SNIPPET: task
-@Concerns( UnitOfWorkConcern.class )
-public interface Task
-    extends Runnable
-{
-    Property<String> name();
-
-    @UseDefaults
-    Property<List<String>> tags();
-
-}
-// END SNIPPET: task


Mime
View raw message