You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2014/11/05 09:50:36 UTC

svn commit: r1636824 - in /sling/trunk/bundles/extensions/event/src: main/java/org/apache/sling/event/impl/jobs/ main/java/org/apache/sling/event/impl/jobs/config/ main/java/org/apache/sling/event/impl/jobs/queues/ main/java/org/apache/sling/event/impl...

Author: cziegeler
Date: Wed Nov  5 08:50:36 2014
New Revision: 1636824

URL: http://svn.apache.org/r1636824
Log:
SLING-4133 : Allow job consumers to register for a topic and all subtopics

Added:
    sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java   (with props)
Modified:
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobConsumerManager.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobHandler.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobImpl.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobManagerImpl.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobSchedulerImpl.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/AbstractJobQueue.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueJobCache.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueManager.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/CheckTopologyTask.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/FindUnfinishedJobsTask.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/UpgradeTask.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/timed/TimedEventSender.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/JobBuilder.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobConsumer.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutionContext.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutor.java
    sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/package-info.java
    sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/EventUtilTest.java

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobConsumerManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobConsumerManager.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobConsumerManager.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobConsumerManager.java Wed Nov  5 08:50:36 2014
@@ -198,13 +198,23 @@ public class JobConsumerManager {
             if ( consumers != null ) {
                 return consumers.get(0).getExecutor(this.bundleContext);
             }
-            final int pos = topic.lastIndexOf('/');
+            int pos = topic.lastIndexOf('/');
             if ( pos > 0 ) {
                 final String category = topic.substring(0, pos + 1).concat("*");
                 final List<ConsumerInfo> categoryConsumers = this.topicToConsumerMap.get(category);
                 if ( categoryConsumers != null ) {
                     return categoryConsumers.get(0).getExecutor(this.bundleContext);
                 }
+
+                // search deep consumers (since 1.2 of the consumer package)
+                do {
+                    final String subCategory = topic.substring(0, pos + 1).concat("**");
+                    final List<ConsumerInfo> subCategoryConsumers = this.topicToConsumerMap.get(subCategory);
+                    if ( subCategoryConsumers != null ) {
+                        return subCategoryConsumers.get(0).getExecutor(this.bundleContext);
+                    }
+                    pos = topic.lastIndexOf('/', pos - 1);
+                } while ( pos > 0 );
             }
         }
         return null;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobHandler.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobHandler.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobHandler.java Wed Nov  5 08:50:36 2014
@@ -97,9 +97,10 @@ public class JobHandler {
     }
 
     /**
-     * Finish a job
-     * @param info  The job handler
+     * Finish a job.
      * @param state The state of the processing
+     * @param keepJobInHistory whether to keep the job in the job history.
+     * @param duration the duration of the processing.
      */
     public void finished(final Job.JobState state,
                           final boolean keepJobInHistory,

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobImpl.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobImpl.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobImpl.java Wed Nov  5 08:50:36 2014
@@ -367,7 +367,7 @@ public class JobImpl implements Job, Com
     }
 
     /**
-     * @see org.apache.sling.event.jobs.Job#getCurrentProgressStep()
+     * @see org.apache.sling.event.jobs.Job#getFinishedProgressStep()
      */
     @Override
     public int getFinishedProgressStep() {

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobManagerImpl.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobManagerImpl.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobManagerImpl.java Wed Nov  5 08:50:36 2014
@@ -501,7 +501,7 @@ public class JobManagerImpl
     }
 
     /**
-     * @see org.apache.sling.event.jobs.JobManager#findJobs(org.apache.sling.event.jobs.JobManager.QueryType, java.lang.String, long, java.util.Map<java.lang.String,java.lang.Object>[])
+     * @see org.apache.sling.event.jobs.JobManager#findJobs(org.apache.sling.event.jobs.JobManager.QueryType, java.lang.String, long, java.util.Map[])
      */
     @Override
     public Collection<Job> findJobs(final QueryType type,

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobSchedulerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobSchedulerImpl.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobSchedulerImpl.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/JobSchedulerImpl.java Wed Nov  5 08:50:36 2014
@@ -165,7 +165,7 @@ public class JobSchedulerImpl
     }
 
     /**
-     * @see org.apache.sling.event.impl.AbstractRepositoryEventHandler#runInBackground()
+     * This is the background thread processing new scheduled jobs.
      */
     protected void runInBackground() {
         Event event = null;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java Wed Nov  5 08:50:36 2014
@@ -231,7 +231,7 @@ public class JobManagerConfiguration imp
      * Create a new resource resolver for reading and writing the resource tree.
      * The resolver needs to be closed by the client.
      * @return A resource resolver
-     * @throw RuntimeException if the resolver can't be created.
+     * @throws RuntimeException if the resolver can't be created.
      */
     public ResourceResolver createResourceResolver() {
         ResourceResolver resolver = null;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/AbstractJobQueue.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/AbstractJobQueue.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/AbstractJobQueue.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/AbstractJobQueue.java Wed Nov  5 08:50:36 2014
@@ -380,8 +380,8 @@ public abstract class AbstractJobQueue
     }
 
     /**
-     * Inform the queue about a job for the topic
-     * @param topic A new topic.
+     * Inform the queue about new job for the given topics.
+     * @param topics the new topics
      */
     public void wakeUpQueue(final Set<String> topics) {
         this.cache.handleNewTopics(topics);

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueJobCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueJobCache.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueJobCache.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueJobCache.java Wed Nov  5 08:50:36 2014
@@ -69,7 +69,7 @@ public class QueueJobCache {
     /**
      * Create a new queue job cache
      * @param configuration Current job manager configuration
-     * @param info The queue info
+     * @param queueType The queue type
      * @param topics The topics handled by this queue.
      */
     public QueueJobCache(final JobManagerConfiguration configuration,
@@ -109,7 +109,7 @@ public class QueueJobCache {
     /**
      * Get the next job.
      * This method is not called concurrently, however
-     * {@link #reschedule(JobImpl)} and {@link #handleNewTopics(String)}
+     * {@link #reschedule(JobHandler)} and {@link #handleNewTopics(Set)}
      * can be called concurrently.
      */
     public JobImpl getNextJob(final boolean doFull) {

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueManager.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueManager.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/queues/QueueManager.java Wed Nov  5 08:50:36 2014
@@ -337,7 +337,7 @@ public class QueueManager
 
     /**
      * This method is called whenever the topology or queue configurations change.
-     * @param caps The new topology capabilities or {@code null} if currently unknown.
+     * @param active Whether the job handling is active atm.
      */
     @Override
     public void configurationChanged(final boolean active) {

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/CheckTopologyTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/CheckTopologyTask.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/CheckTopologyTask.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/CheckTopologyTask.java Wed Nov  5 08:50:36 2014
@@ -60,7 +60,7 @@ public class CheckTopologyTask {
 
     /**
      * Constructor
-     * @param The configuration
+     * @param config The configuration
      */
     public CheckTopologyTask(final JobManagerConfiguration config) {
         this.configuration = config;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/FindUnfinishedJobsTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/FindUnfinishedJobsTask.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/FindUnfinishedJobsTask.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/FindUnfinishedJobsTask.java Wed Nov  5 08:50:36 2014
@@ -45,7 +45,7 @@ public class FindUnfinishedJobsTask {
 
     /**
      * Constructor
-     * @param The configuration
+     * @param config the configuration
      */
     public FindUnfinishedJobsTask(final JobManagerConfiguration config) {
         this.configuration = config;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/UpgradeTask.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/UpgradeTask.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/UpgradeTask.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/tasks/UpgradeTask.java Wed Nov  5 08:50:36 2014
@@ -58,7 +58,7 @@ public class UpgradeTask {
 
     /**
      * Constructor
-     * @param The configuration
+     * @param config the configuration
      */
     public UpgradeTask(final JobManagerConfiguration config) {
         this.configuration = config;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/timed/TimedEventSender.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/timed/TimedEventSender.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/timed/TimedEventSender.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/timed/TimedEventSender.java Wed Nov  5 08:50:36 2014
@@ -182,7 +182,7 @@ public class TimedEventSender
     }
 
     /**
-     * @see org.apache.sling.event.impl.AbstractRepositoryEventHandler#runInBackground()
+     * The background thread for the timed events.
      */
     protected void runInBackground() {
         Event event = null;
@@ -273,7 +273,7 @@ public class TimedEventSender
      * Process the event.
      * If a scheduler is available, a job is scheduled or stopped.
      * @param event The incoming event.
-     * @return
+     * @return {@code true} if the event could be processed.
      */
     protected boolean processEvent(final Event event, final ScheduleInfo scheduleInfo) {
         final Scheduler localScheduler = this.scheduler;

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/JobBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/JobBuilder.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/JobBuilder.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/JobBuilder.java Wed Nov  5 08:50:36 2014
@@ -131,7 +131,7 @@ public interface JobBuilder {
         /**
          * Schedule the job for according to the cron expression.
          * If no expression is specified, the job can't be scheduled.
-         * @param date The date
+         * @param expression The cron expression
          */
         ScheduleBuilder cron(final String expression);
 

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobConsumer.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobConsumer.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobConsumer.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobConsumer.java Wed Nov  5 08:50:36 2014
@@ -26,29 +26,43 @@ import aQute.bnd.annotation.ConsumerType
 
 /**
  * A job consumer consumes a job.
- *
+ * <p>
  * If the job consumer needs more features like providing progress information or adding
  * more information of the processing, {@link JobExecutor} should be implemented instead.
- *
+ * <p>
  * A job consumer registers itself with the {@link #PROPERTY_TOPICS} service registration
  * property. The value of this property defines which topics a consumer is able to process.
- * Each string value of this property is either a job topic or a topic category ending
- * with "/*" which means all topics in this category.
- * For example, the value "org/apache/sling/jobs/*" matches the topics
- * "org/apache/sling/jobs/a" and "org/apache/sling/jobs/b" but neither
- * "org/apache/sling/jobs" nor "org/apache/sling/jobs/subcategory/a"
- *
+ * Each string value of this property is either
+ * <ul>
+ * <li>a job topic, or
+ * <li>a topic category ending with "/*" which means all topics in this category, or
+ * <li>a topic category ending with "/**" which means all topics in this category and all
+ *     sub categories. This matching is new since version 1.2.
+ * </ul>
+ * A consumer registering for just "*" or "**" is not considered.
+ * <p>
+ * For example, the value {@code org/apache/sling/jobs/*} matches the topics
+ * {@code org/apache/sling/jobs/a} and {@code org/apache/sling/jobs/b} but neither
+ * {@code org/apache/sling/jobs} nor {@code org/apache/sling/jobs/subcategory/a}. A value of
+ * {@code org/apache/sling/jobs/**} matches the same topics but also all sub topics
+ * like {@code org/apache/sling/jobs/subcategory/a} or {@code org/apache/sling/jobs/subcategory/a/c/d}.
+ * <p>
  * If there is more than one job consumer or executor registered for a job topic, the selection is as
  * follows:
- * - If there is a single consumer registering for the exact topic, this one is used
- * - If there is more than a single consumer registering for the exact topic, the one
- *   with the highest service ranking is used. If the ranking is equal, the one with
- *   the lowest service ID is used.
- * - If there is a single consumer registered for the category, it is used
- * - If there is more than a single consumer registered for the category, the service
- *   with the highest service ranking is used. If the ranking is equal, the one with
- *   the lowest service ID is used.
- *
+ * <ul>
+ * <li>If there is a single consumer registering for the exact topic, this one is used.
+ * <li>If there is more than a single consumer registering for the exact topic, the one
+ *     with the highest service ranking is used. If the ranking is equal, the one with
+ *     the lowest service ID is used.
+ * <li>If there is a single consumer registered for the category, it is used.
+ * <li>If there is more than a single consumer registered for the category, the service
+ *     with the highest service ranking is used. If the ranking is equal, the one with
+ *     the lowest service ID is used.
+ * <li>The search continues with consumer registered for deep categories. The nearest one
+ *     is tried next. If there are several, the one with the highest service ranking is
+ *     used. If the ranking is equal, the one with the lowest service ID is used.
+ * </ul>
+ * <p>
  * If the consumer decides to process the job asynchronously, the processing must finish
  * within the current lifetime of the job consumer. If the consumer (or the instance
  * of the consumer) dies, the job processing will mark this processing as failed and
@@ -59,11 +73,18 @@ import aQute.bnd.annotation.ConsumerType
 @ConsumerType
 public interface JobConsumer {
 
+    /**
+     * The result of the job processing.
+     */
     enum JobResult {
-        OK,      // processing finished
-        FAILED,  // processing failed, can be retried
-        CANCEL,  // processing failed permanently
-        ASYNC    // processing will be done async
+        /** Processing finished successfully. */
+        OK,
+        /** Processing failed but might be retried. */
+        FAILED,
+        /** Processing failed permanently and must not be retried. */
+        CANCEL,
+        /** Processing will be done asynchronously. */
+        ASYNC
     }
 
     /** Job property containing an asynchronous handler. */
@@ -92,18 +113,18 @@ public interface JobConsumer {
 
     /**
      * Execute the job.
-     *
-     * If the job has been processed successfully, {@link JobResult.OK} should be returned.
-     * If the job has not been processed completely, but might be rescheduled {@link JobResult.FAILED}
+     * <p>
+     * If the job has been processed successfully, {@link JobResult#OK} should be returned.
+     * If the job has not been processed completely, but might be rescheduled {@link JobResult#FAILED}
      * should be returned.
-     * If the job processing failed and should not be rescheduled, {@link JobResult.CANCEL} should
+     * If the job processing failed and should not be rescheduled, {@link JobResult#CANCEL} should
      * be returned.
-     *
-     * If the consumer decides to process the job asynchronously it should return {@link JobResult.ASYNC}
+     * <p>
+     * If the consumer decides to process the job asynchronously it should return {@link JobResult#ASYNC}
      * and notify the job manager by using the {@link AsyncHandler} interface.
-     *
+     * <p>
      * If the processing fails with throwing an exception/throwable, the process will not be rescheduled
-     * and treated like the method would have returned {@link JobResult.CANCEL}.
+     * and treated like the method would have returned {@link JobResult#CANCEL}.
      *
      * @param job The job
      * @return The job result

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutionContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutionContext.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutionContext.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutionContext.java Wed Nov  5 08:50:36 2014
@@ -71,7 +71,7 @@ public interface JobExecutionContext {
      * job progress is assumed to be 100%.
      * This method has only effect if {@link #initProgress(int, long)}
      * has been called first with a positive number for steps
-     * @param step The number of finished steps since the last call.
+     * @param steps The number of finished steps since the last call.
      */
     void incrementProgressCount(final int steps);
 

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutor.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutor.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutor.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/JobExecutor.java Wed Nov  5 08:50:36 2014
@@ -24,26 +24,40 @@ import aQute.bnd.annotation.ConsumerType
 
 /**
  * A job executor consumes a job.
- *
+ * <p>
  * A job executor registers itself with the {@link #PROPERTY_TOPICS} service registration
  * property. The value of this property defines which topics an executor is able to process.
- * Each string value of this property is either a job topic or a topic category ending
- * with "/*" which means all topics in this category.
- * For example, the value "org/apache/sling/jobs/*" matches the topics
- * "org/apache/sling/jobs/a" and "org/apache/sling/jobs/b" but neither
- * "org/apache/sling/jobs" nor "org/apache/sling/jobs/subcategory/a"
- *
- * If there is more than one job executor or consumer registered for a job topic,
- * the selection is as follows:
- * - If there is a single consumer registering for the exact topic, this one is used
- * - If there is more than a single consumer registering for the exact topic, the one
- *   with the highest service ranking is used. If the ranking is equal, the one with
- *   the lowest service ID is used.
- * - If there is a single consumer registered for the category, it is used
- * - If there is more than a single consumer registered for the category, the service
- *   with the highest service ranking is used. If the ranking is equal, the one with
- *   the lowest service ID is used.
- *
+ * Each string value of this property is either
+ * <ul>
+ * <li>a job topic, or
+ * <li>a topic category ending with "/*" which means all topics in this category, or
+ * <li>a topic category ending with "/**" which means all topics in this category and all
+ *     sub categories. This matching is new since version 1.2.
+ * </ul>
+ * A consumer registering for just "*" or "**" is not considered.
+ * <p>
+ * For example, the value {@code org/apache/sling/jobs/*} matches the topics
+ * {@code org/apache/sling/jobs/a} and {@code org/apache/sling/jobs/b} but neither
+ * {@code org/apache/sling/jobs} nor {@code org/apache/sling/jobs/subcategory/a}. A value of
+ * {@code org/apache/sling/jobs/**} matches the same topics but also all sub topics
+ * like {@code org/apache/sling/jobs/subcategory/a} or {@code org/apache/sling/jobs/subcategory/a/c/d}.
+ * <p>
+ * If there is more than one job consumer or executor registered for a job topic, the selection is as
+ * follows:
+ * <ul>
+ * <li>If there is a single consumer registering for the exact topic, this one is used.
+ * <li>If there is more than a single consumer registering for the exact topic, the one
+ *     with the highest service ranking is used. If the ranking is equal, the one with
+ *     the lowest service ID is used.
+ * <li>If there is a single consumer registered for the category, it is used.
+ * <li>If there is more than a single consumer registered for the category, the service
+ *     with the highest service ranking is used. If the ranking is equal, the one with
+ *     the lowest service ID is used.
+ * <li>The search continues with consumer registered for deep categories. The nearest one
+ *     is tried next. If there are several, the one with the highest service ranking is
+ *     used. If the ranking is equal, the one with the lowest service ID is used.
+ * </ul>
+ * <p>
  * If the executor decides to process the job asynchronously, the processing must finish
  * within the current lifetime of the job executor. If the executor (or the instance
  * of the executor) dies, the job processing will mark this processing as failed and
@@ -64,7 +78,7 @@ public interface JobExecutor {
      * Execute the job.
      *
      * If the job has been processed successfully, a job result of "succeeded" should be returned. This result can
-     * be generated by calling <code>JobExecutionContext.result().succeeded()</code>.
+     * be generated by calling <code>JobExecutionContext.result().succeeded()</code>
      *
      * If the job has not been processed completely, but might be rescheduled "failed" should be returned.
      * This result can be generated by calling <code>JobExecutionContext.result().failed()</code>.

Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/package-info.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/package-info.java (original)
+++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/jobs/consumer/package-info.java Wed Nov  5 08:50:36 2014
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("1.1.0")
+@Version("1.2.0")
 package org.apache.sling.event.jobs.consumer;
 
 import aQute.bnd.annotation.Version;

Modified: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/EventUtilTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/EventUtilTest.java?rev=1636824&r1=1636823&r2=1636824&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/EventUtilTest.java (original)
+++ sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/EventUtilTest.java Wed Nov  5 08:50:36 2014
@@ -25,25 +25,14 @@ import static org.junit.Assert.assertTru
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.jmock.Mockery;
-import org.jmock.integration.junit4.JMock;
-import org.jmock.integration.junit4.JUnit4Mockery;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.osgi.service.event.Event;
 
 /**
  * Tests for the EventUtil utility methods.
  */
-@RunWith(JMock.class)
 public class EventUtilTest {
 
-    protected Mockery context;
-
-    public EventUtilTest() {
-        this.context = new JUnit4Mockery();
-    }
-
     @Test public void testDistributeFlag() {
         final Event distributableEvent = EventUtil.createDistributableEvent("some/topic", null);
         assertTrue(EventUtil.shouldDistribute(distributableEvent));

Added: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java?rev=1636824&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java (added)
+++ sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java Wed Nov  5 08:50:36 2014
@@ -0,0 +1,198 @@
+/*
+ * 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.sling.event.impl.jobs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Collections;
+
+import org.apache.sling.event.jobs.consumer.JobConsumer;
+import org.apache.sling.event.jobs.consumer.JobExecutor;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class JobConsumerManagerTest {
+
+    @Test public void testSimpleMappingConsumer() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobConsumer jc1 = Mockito.mock(JobConsumer.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobConsumer.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobConsumer(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNull(jcs.getExecutor("a/c"));
+        assertNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testCategoryMappingConsumer() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobConsumer jc1 = Mockito.mock(JobConsumer.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobConsumer.PROPERTY_TOPICS)).thenReturn("a/*");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobConsumer(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNotNull(jcs.getExecutor("a/c"));
+        assertNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testSubCategoryMappingConsumer() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobConsumer jc1 = Mockito.mock(JobConsumer.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobConsumer.PROPERTY_TOPICS)).thenReturn("a/**");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobConsumer(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNotNull(jcs.getExecutor("a/c"));
+        assertNotNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testSimpleMappingExecutor() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobExecutor jc1 = Mockito.mock(JobExecutor.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobConsumer.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobExecutor(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNull(jcs.getExecutor("a/c"));
+        assertNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testCategoryMappingExecutor() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobExecutor jc1 = Mockito.mock(JobExecutor.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/*");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobExecutor(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNotNull(jcs.getExecutor("a/c"));
+        assertNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testSubCategoryMappingExecutor() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobExecutor jc1 = Mockito.mock(JobExecutor.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/**");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobExecutor(ref1);
+
+        assertNotNull(jcs.getExecutor("a/b"));
+        assertNull(jcs.getExecutor("a"));
+        assertNotNull(jcs.getExecutor("a/c"));
+        assertNotNull(jcs.getExecutor("a/b/a"));
+    }
+
+    @Test public void testRanking() {
+        final BundleContext bc = Mockito.mock(BundleContext.class);
+        final JobConsumerManager jcs = new JobConsumerManager();
+        jcs.activate(bc, Collections.EMPTY_MAP);
+
+        final JobExecutor jc1 = Mockito.mock(JobExecutor.class);
+        final JobExecutor jc2 = Mockito.mock(JobExecutor.class);
+        final JobExecutor jc3 = Mockito.mock(JobExecutor.class);
+        final JobExecutor jc4 = Mockito.mock(JobExecutor.class);
+        final ServiceReference ref1 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref1.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref1.getProperty(Constants.SERVICE_RANKING)).thenReturn(1);
+        Mockito.when(ref1.getProperty(Constants.SERVICE_ID)).thenReturn(1L);
+        Mockito.when(bc.getService(ref1)).thenReturn(jc1);
+        jcs.bindJobExecutor(ref1);
+        assertEquals(jc1, jcs.getExecutor("a/b"));
+
+        final ServiceReference ref2 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref2.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref2.getProperty(Constants.SERVICE_RANKING)).thenReturn(10);
+        Mockito.when(ref2.getProperty(Constants.SERVICE_ID)).thenReturn(2L);
+        Mockito.when(bc.getService(ref2)).thenReturn(jc2);
+        jcs.bindJobExecutor(ref2);
+        assertEquals(jc2, jcs.getExecutor("a/b"));
+
+        final ServiceReference ref3 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref3.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref3.getProperty(Constants.SERVICE_RANKING)).thenReturn(5);
+        Mockito.when(ref3.getProperty(Constants.SERVICE_ID)).thenReturn(3L);
+        Mockito.when(bc.getService(ref3)).thenReturn(jc3);
+        jcs.bindJobExecutor(ref3);
+        assertEquals(jc2, jcs.getExecutor("a/b"));
+
+        final ServiceReference ref4 = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref4.getProperty(JobExecutor.PROPERTY_TOPICS)).thenReturn("a/b");
+        Mockito.when(ref4.getProperty(Constants.SERVICE_RANKING)).thenReturn(5);
+        Mockito.when(ref4.getProperty(Constants.SERVICE_ID)).thenReturn(4L);
+        Mockito.when(bc.getService(ref4)).thenReturn(jc4);
+        jcs.bindJobExecutor(ref4);
+        assertEquals(jc2, jcs.getExecutor("a/b"));
+
+        jcs.unbindJobExecutor(ref2);
+        assertEquals(jc3, jcs.getExecutor("a/b"));
+
+        jcs.unbindJobExecutor(ref3);
+        assertEquals(jc4, jcs.getExecutor("a/b"));
+    }
+}

Propchange: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/JobConsumerManagerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain