Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id F129EF865 for ; Wed, 5 Nov 2014 08:52:12 +0000 (UTC) Received: (qmail 21810 invoked by uid 500); 5 Nov 2014 08:52:12 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 21737 invoked by uid 500); 5 Nov 2014 08:52:12 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 21728 invoked by uid 99); 5 Nov 2014 08:52:12 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Nov 2014 08:52:12 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Nov 2014 08:52:09 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id AFFF32388A74; Wed, 5 Nov 2014 08:50:37 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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... Date: Wed, 05 Nov 2014 08:50:36 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20141105085037.AFFF32388A74@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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 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[]) + * @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 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 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. - * + *

* If the job consumer needs more features like providing progress information or adding * more information of the processing, {@link JobExecutor} should be implemented instead. - * + *

* 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 + *

    + *
  • a job topic, or + *
  • a topic category ending with "/*" which means all topics in this category, or + *
  • a topic category ending with "/**" which means all topics in this category and all + * sub categories. This matching is new since version 1.2. + *
+ * A consumer registering for just "*" or "**" is not considered. + *

+ * 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}. + *

* 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. - * + *

    + *
  • 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. + *
  • 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. + *
+ *

* 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} + *

+ * 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} + *

+ * 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. - * + *

* 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. - * + *

* 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 + *

    + *
  • a job topic, or + *
  • a topic category ending with "/*" which means all topics in this category, or + *
  • a topic category ending with "/**" which means all topics in this category and all + * sub categories. This matching is new since version 1.2. + *
+ * A consumer registering for just "*" or "**" is not considered. + *

+ * 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}. + *

+ * 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. + *
  • 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. + *
+ *

* 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 JobExecutionContext.result().succeeded(). + * be generated by calling JobExecutionContext.result().succeeded() * * If the job has not been processed completely, but might be rescheduled "failed" should be returned. * This result can be generated by calling JobExecutionContext.result().failed(). 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