SLING-7037 : Scheduler does not retain provided name. Fix handling of name and provided name, add tests including new test case from Marcel Reutegger

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1804434 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index cfe2787..e3ff731 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>30</version>
+        <version>31</version>
         <relativePath />
     </parent>
 
@@ -50,9 +50,6 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
-                        <Private-Package>
-                            org.apache.sling.commons.scheduler.impl
-                        </Private-Package>
                         <Import-Package>
                             !commonj.work,
                             !com.mchange.v2.c3p0,
diff --git a/src/main/java/org/apache/sling/commons/scheduler/impl/InternalScheduleOptions.java b/src/main/java/org/apache/sling/commons/scheduler/impl/InternalScheduleOptions.java
index cdf58f0..a5e67c9 100644
--- a/src/main/java/org/apache/sling/commons/scheduler/impl/InternalScheduleOptions.java
+++ b/src/main/java/org/apache/sling/commons/scheduler/impl/InternalScheduleOptions.java
@@ -30,6 +30,10 @@
  */
 public class InternalScheduleOptions implements ScheduleOptions {
 
+    public final TriggerBuilder<? extends Trigger> trigger;
+
+    public final IllegalArgumentException argumentException;
+
     public String providedName;
 
     public String name;
@@ -40,10 +44,6 @@
 
     public Map<String, Serializable> configuration;
 
-    public final TriggerBuilder<? extends Trigger> trigger;
-
-    public final IllegalArgumentException argumentException;
-
     public String[] runOn;
 
     public InternalScheduleOptions(final TriggerBuilder<? extends Trigger> trigger) {
@@ -71,6 +71,7 @@
     @Override
     public ScheduleOptions name(final String name) {
         this.name = name;
+        this.providedName = name;
         return this;
     }
 
diff --git a/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java b/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java
index 8e05f1c..795d530 100644
--- a/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java
+++ b/src/main/java/org/apache/sling/commons/scheduler/impl/QuartzScheduler.java
@@ -75,7 +75,7 @@
     static final String DATA_MAP_OBJECT = "QuartzJobScheduler.Object";
 
     /** Map key for the provided job name */
-    static final String DATA_MAP_PROVIDED_NAME = "QuartzJobScheduler.JobName";
+    static final String DATA_MAP_PROVIDED_NAME = "QuartzJobScheduler.ProvidedJobName";
 
     /** Map key for the job name */
     static final String DATA_MAP_NAME = "QuartzJobScheduler.JobName";
@@ -97,7 +97,7 @@
 
     /** Map key for the quartz scheduler */
     static final String DATA_MAP_QUARTZ_SCHEDULER = "QuartzJobScheduler.QuartzScheduler";
-    
+
     static final String DATA_MAP_THREAD_POOL_NAME = "QuartzJobScheduler.threadPoolName";
 
     static final String METRICS_NAME_RUNNING_JOBS = "commons.scheduler.running.jobs";
@@ -112,11 +112,11 @@
     @Reference
     private ThreadPoolManager threadPoolManager;
 
-    @Reference 
+    @Reference
     MetricsService metricsService;
-    
+
     ConfigHolder configHolder;
-    
+
     /** The quartz schedulers. */
     private final Map<String, SchedulerProxy> schedulers = new HashMap<>();
 
@@ -146,7 +146,7 @@
         ctx.addBundleListener(this);
 
         this.configHolder = new ConfigHolder(configuration);
-        
+
         this.active = true;
     }
 
@@ -615,7 +615,6 @@
         }
 
         synchronized ( proxy ) {
-            opts.providedName = opts.name;
             final String name;
             if ( opts.name != null ) {
                 // if there is already a job with the name, remove it first
diff --git a/src/main/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandler.java b/src/main/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandler.java
index ed02e48..4d7c5bb 100644
--- a/src/main/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandler.java
+++ b/src/main/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandler.java
@@ -247,7 +247,6 @@
     }
 
     private void scheduleJob(final ServiceReference<?> ref, final Object job, final ScheduleOptions scheduleOptions) {
-        ((InternalScheduleOptions)scheduleOptions).providedName = getStringProperty(ref, Scheduler.PROPERTY_SCHEDULER_NAME);
         final String name = getServiceIdentifier(ref);
         final Boolean concurrent = getBooleanProperty(ref, Scheduler.PROPERTY_SCHEDULER_CONCURRENT);
         final String[] runOnOpts = getRunOpts(ref);
@@ -265,6 +264,7 @@
                 .canRunConcurrently((concurrent != null ? concurrent : true))
                 .threadPoolName(poolName)
                 .onInstancesOnly(runOnOpts);
+        ((InternalScheduleOptions)scheduleOptions).providedName = getStringProperty(ref, Scheduler.PROPERTY_SCHEDULER_NAME);
 
         final long bundleId = ref.getBundle().getBundleId();
         final Long serviceId = getLongProperty(ref, Constants.SERVICE_ID);
diff --git a/src/test/java/org/apache/sling/commons/scheduler/impl/QuartzSchedulerTest.java b/src/test/java/org/apache/sling/commons/scheduler/impl/QuartzSchedulerTest.java
index e05e5ec..4905672 100644
--- a/src/test/java/org/apache/sling/commons/scheduler/impl/QuartzSchedulerTest.java
+++ b/src/test/java/org/apache/sling/commons/scheduler/impl/QuartzSchedulerTest.java
@@ -25,9 +25,12 @@
 
 import java.io.Serializable;
 import java.lang.reflect.Field;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.sling.commons.scheduler.Job;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
@@ -42,9 +45,11 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
+import org.quartz.JobDetail;
 import org.quartz.JobKey;
 import org.quartz.SchedulerException;
 import org.quartz.TriggerBuilder;
+import org.quartz.impl.matchers.GroupMatcher;
 
 @RunWith(MockitoJUnitRunner.class)
 public class QuartzSchedulerTest {
@@ -327,4 +332,39 @@
             sField.set(quartzScheduler, this.proxies);
         }
     }
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testNameAndProvidedName() throws SchedulerException {
+        final Date future = new Date(System.currentTimeMillis() + 1000 * 60 * 60);
+        quartzScheduler.schedule(1L, 1L, new Thread(), quartzScheduler.AT(future).name("j1").threadPoolName("tp1"));
+        quartzScheduler.schedule(1L, 1L, new Thread(), quartzScheduler.AT(future)
+                .config(Collections.singletonMap("key", (Serializable)"value")).threadPoolName("tp1"));
+        assertNull(proxies.get("tp1"));
+        // j1 is scheduled named, so both name and provided name should be set to j1
+        JobDetail jobDetail = proxies.get("testName").getScheduler().getJobDetail(JobKey.jobKey("j1"));
+        assertEquals("j1", jobDetail.getJobDataMap().get(QuartzScheduler.DATA_MAP_NAME));
+        assertEquals("j1", jobDetail.getJobDataMap().get(QuartzScheduler.DATA_MAP_PROVIDED_NAME));
+
+        // search job detail for job without name
+        jobDetail = null;
+        org.quartz.Scheduler scheduler = quartzScheduler.getSchedulers().get("testName").getScheduler();
+        final List<String> groups = scheduler.getJobGroupNames();
+        for(final String group : groups) {
+            final Set<JobKey> keys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group));
+            for(final JobKey key : keys) {
+                final JobDetail detail = scheduler.getJobDetail(key);
+                if ( detail != null
+                     && detail.getJobDataMap().get(QuartzScheduler.DATA_MAP_CONFIGURATION) != null
+                     && ((Map)detail.getJobDataMap().get(QuartzScheduler.DATA_MAP_CONFIGURATION)).get("key").equals("value")) {
+                    jobDetail = detail;
+                    break;
+                }
+            }
+        }
+        // provided name should be null, name is generated
+        assertNotNull(jobDetail);
+        assertNull(jobDetail.getJobDataMap().get(QuartzScheduler.DATA_MAP_PROVIDED_NAME));
+        assertNotNull(jobDetail.getJobDataMap().get(QuartzScheduler.DATA_MAP_NAME));
+    }
 }
diff --git a/src/test/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandlerTest.java b/src/test/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandlerTest.java
index d490d8a..742a73e 100644
--- a/src/test/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandlerTest.java
+++ b/src/test/java/org/apache/sling/commons/scheduler/impl/WhiteboardHandlerTest.java
@@ -16,12 +16,15 @@
  */
 package org.apache.sling.commons.scheduler.impl;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import java.lang.reflect.Field;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
 
 import org.apache.sling.commons.scheduler.Scheduler;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
@@ -32,8 +35,10 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
+import org.quartz.JobDetail;
 import org.quartz.JobKey;
 import org.quartz.SchedulerException;
+import org.quartz.impl.matchers.GroupMatcher;
 
 public class WhiteboardHandlerTest {
     private WhiteboardHandler handler;
@@ -113,6 +118,71 @@
         assertNull(quartzScheduler.getSchedulers().get("testName").getScheduler().getJobDetail(jobKey));
     }
 
+    // SLING-7037
+    @Test
+    public void testAddingServiceWithProvidedName() throws SchedulerException {
+        Thread service = new Thread();
+        String schedulerName = "testScheduler";
+        Long period = 1L;
+        Integer times = 2;
+
+        Dictionary<String, Object> serviceProps = new Hashtable<>();
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_RUN_ON, Scheduler.VALUE_RUN_ON_LEADER);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_CONCURRENT, Boolean.FALSE);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_IMMEDIATE, Boolean.FALSE);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_NAME, schedulerName);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_PERIOD, period);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_TIMES, times);
+        serviceProps.put(Constants.SERVICE_PID, "1");
+
+        final ServiceRegistration<?> reg = context.registerService(Runnable.class.getName(), service, serviceProps);
+        final ServiceReference<?> reference = reg.getReference();
+        handler.register(reference, service);
+        JobKey jobKey = JobKey.jobKey(schedulerName + "." + reference.getProperty(Constants.SERVICE_ID));
+
+        JobDetail jobDetail = quartzScheduler.getSchedulers().get("testName").getScheduler().getJobDetail(jobKey);
+        assertNotNull(jobDetail);
+        assertEquals(schedulerName, jobDetail.getJobDataMap().getString(QuartzScheduler.DATA_MAP_PROVIDED_NAME));
+        assertEquals(schedulerName + "." + reference.getProperty(Constants.SERVICE_ID),
+                jobDetail.getJobDataMap().getString(QuartzScheduler.DATA_MAP_NAME));
+    }
+
+    @Test
+    public void testAddingServiceWithoutProvidedName() throws SchedulerException {
+        Thread service = new Thread();
+        Long period = 1L;
+        Integer times = 2;
+
+        Dictionary<String, Object> serviceProps = new Hashtable<>();
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_RUN_ON, Scheduler.VALUE_RUN_ON_LEADER);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_CONCURRENT, Boolean.FALSE);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_IMMEDIATE, Boolean.FALSE);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_PERIOD, period);
+        serviceProps.put(Scheduler.PROPERTY_SCHEDULER_TIMES, times);
+        serviceProps.put(Constants.SERVICE_PID, "1");
+
+        final ServiceRegistration<?> reg = context.registerService(Runnable.class.getName(), service, serviceProps);
+        final ServiceReference<?> reference = reg.getReference();
+        handler.register(reference, service);
+
+        JobDetail jobDetail = null;
+        org.quartz.Scheduler scheduler = quartzScheduler.getSchedulers().get("testName").getScheduler();
+        final List<String> groups = scheduler.getJobGroupNames();
+        for(final String group : groups) {
+            final Set<JobKey> keys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group));
+            for(final JobKey key : keys) {
+                final JobDetail detail = scheduler.getJobDetail(key);
+                if ( detail != null && detail.getJobDataMap().get(QuartzScheduler.DATA_MAP_SERVICE_ID).equals(reg.getReference().getProperty(Constants.SERVICE_ID))) {
+                    jobDetail = detail;
+                    break;
+                }
+            }
+        }
+        assertNotNull(jobDetail);
+        assertNull(jobDetail.getJobDataMap().getString(QuartzScheduler.DATA_MAP_PROVIDED_NAME));
+        assertNotNull(jobDetail.getJobDataMap().getString(QuartzScheduler.DATA_MAP_NAME));
+    }
+
     @After
     public void deactivateScheduler() {
         quartzScheduler.deactivate(context);