From 76677d6e5deb43a3d7703b26f50cc3f8a9e88880 Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Mon, 27 Feb 2012 14:58:24 -0600
Subject: [PATCH] Refactored JobsScheduler.

The JobsScheduler has been modified to stop all jobs on shutdown.
This is done by setting a flag in each job instead of stopping the
job thread abruptly. Long running jobs should check this flag
periodically and then exit gracefully. None of the existing jobs
need to do this since they do not run very long.

Other threads that run background services have been converted into
daemons such that they will terminate automatically when the JVM
exits.

Ticket #73
---
 .../common/src/com/netscape/certsrv/jobs/IJob.java |   12 +++++
 .../common/src/com/netscape/cms/jobs/AJobBase.java |   22 +++++++---
 .../src/com/netscape/cms/jobs/PublishCertsJob.java |    9 ++--
 .../netscape/cms/jobs/RenewalNotificationJob.java  |    2 +-
 .../com/netscape/cms/jobs/RequestInQueueJob.java   |    2 +-
 .../com/netscape/cms/jobs/UnpublishExpiredJob.java |    2 +-
 .../src/com/netscape/cmscore/apps/CMSEngine.java   |    2 -
 .../cmscore/dbs/CertificateRepository.java         |    7 +--
 .../com/netscape/cmscore/jobs/JobsScheduler.java   |   48 ++++++--------------
 9 files changed, 51 insertions(+), 55 deletions(-)

diff --git a/pki/base/common/src/com/netscape/certsrv/jobs/IJob.java b/pki/base/common/src/com/netscape/certsrv/jobs/IJob.java
index 3683b1f09c98cf0a26dced254c44396a281be787..5584d68ff61991855c99fb45fb25a82faef27381 100644
--- a/pki/base/common/src/com/netscape/certsrv/jobs/IJob.java
+++ b/pki/base/common/src/com/netscape/certsrv/jobs/IJob.java
@@ -91,4 +91,16 @@ public interface IJob {
      * @return configuration store
      */
     public IConfigStore getConfigStore();
+
+    /**
+     * Request the job to stop gracefully. The job may not stop immediately.
+     */
+    public void stop();
+
+    /**
+     * Check whether the job has been asked to stop. Long running jobs should call
+     * this method occasionally inside the run() method and exit gracefully if it
+     * returns true.
+     */
+    public boolean isStopped();
 }
diff --git a/pki/base/common/src/com/netscape/cms/jobs/AJobBase.java b/pki/base/common/src/com/netscape/cms/jobs/AJobBase.java
index 4a70147de474c1a9d71850a97d1696213f05f4ab..0da5d20287dc7b5358ab53899639f82b3a31a94c 100644
--- a/pki/base/common/src/com/netscape/cms/jobs/AJobBase.java
+++ b/pki/base/common/src/com/netscape/cms/jobs/AJobBase.java
@@ -74,6 +74,8 @@ public abstract class AJobBase implements IJob, Runnable {
     protected Hashtable<String, Object> mContentParams = new Hashtable<String, Object>();
     protected Hashtable<String, Object> mItemParams = new Hashtable<String, Object>();
 
+    boolean stopped;
+
     public AJobBase() {
     }
 
@@ -209,17 +211,17 @@ public abstract class AJobBase implements IJob, Runnable {
 
     protected void buildItemParams(X509CertImpl cert) {
         mItemParams.put(IEmailFormProcessor.TOKEN_SERIAL_NUM,
-                (Object) cert.getSerialNumber().toString());
+                cert.getSerialNumber().toString());
         mItemParams.put(IEmailFormProcessor.TOKEN_HEX_SERIAL_NUM,
-                (Object) cert.getSerialNumber().toString(16));
+                cert.getSerialNumber().toString(16));
         mItemParams.put(IEmailFormProcessor.TOKEN_ISSUER_DN,
-                (Object) cert.getIssuerDN().toString());
+                cert.getIssuerDN().toString());
         mItemParams.put(IEmailFormProcessor.TOKEN_SUBJECT_DN,
-                (Object) cert.getSubjectDN().toString());
+                cert.getSubjectDN().toString());
         mItemParams.put(IEmailFormProcessor.TOKEN_NOT_AFTER,
-                (Object) cert.getNotAfter().toString());
+                cert.getNotAfter().toString());
         mItemParams.put(IEmailFormProcessor.TOKEN_NOT_BEFORE,
-                (Object) cert.getNotBefore().toString());
+                cert.getNotBefore().toString());
         // ... and more
     }
 
@@ -288,4 +290,12 @@ public abstract class AJobBase implements IJob, Runnable {
         mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_OTHER,
                 level, mId + ": " + msg, multiline);
     }
+
+    public void stop() {
+        stopped = true;
+    }
+
+    public boolean isStopped() {
+        return stopped;
+    }
 }
diff --git a/pki/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java b/pki/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java
index 903f83691e54a41ae8fb814ac935112a06646754..2289d7255db50aae41e913af124b3b006ee6193a 100644
--- a/pki/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java
+++ b/pki/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java
@@ -17,7 +17,6 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.jobs;
 
-import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.util.Date;
 import java.util.Enumeration;
@@ -135,7 +134,7 @@ public class PublishCertsJob extends AJobBase
         }
 
         mReqQ = mCa.getRequestQueue();
-        mRepository = (ICertificateRepository) mCa.getCertificateRepository();
+        mRepository = mCa.getCertificateRepository();
         mPublisherProcessor = mCa.getPublisherProcessor();
 
         // read from the configuration file
@@ -299,7 +298,7 @@ public class PublishCertsJob extends AJobBase
                 try {
                     if ((mPublisherProcessor != null) &&
                             mPublisherProcessor.enabled()) {
-                        mPublisherProcessor.publishCert((X509Certificate) cert, req);
+                        mPublisherProcessor.publishCert(cert, req);
                         if (mSummary == true)
                             buildItemParams(IEmailFormProcessor.TOKEN_STATUS,
                                     STATUS_SUCCESS);
@@ -322,7 +321,7 @@ public class PublishCertsJob extends AJobBase
                 try {
                     if ((mPublisherProcessor != null) &&
                             mPublisherProcessor.enabled()) {
-                        mPublisherProcessor.publishCert((X509Certificate) cert, null);
+                        mPublisherProcessor.publishCert(cert, null);
 
                         if (mSummary == true)
                             buildItemParams(IEmailFormProcessor.TOKEN_STATUS,
@@ -396,6 +395,6 @@ public class PublishCertsJob extends AJobBase
      * @return String array of configuration parameter names.
      */
     public String[] getConfigParams() {
-        return (mConfigParams);
+        return mConfigParams;
     }
 }
diff --git a/pki/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java b/pki/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java
index 621d987febb8020d11acb9d68513a7628cb5a6fe..5a14c6278fd2feef2f1b888d09c667c6a8fbde3d 100644
--- a/pki/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java
+++ b/pki/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java
@@ -275,7 +275,7 @@ public class RenewalNotificationJob
             return;
         }
 
-        mCertDB = (ICertificateRepository) mCA.getCertificateRepository();
+        mCertDB = mCA.getCertificateRepository();
 
         mCron = mConfig.getString(IJobCron.PROP_CRON);
         if (mCron == null) {
diff --git a/pki/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java b/pki/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java
index adddc9755bc9f2a2cc499305fe525f8779a822d2..775845ca7552186666f6d03f9ab3af01855e8235 100644
--- a/pki/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java
+++ b/pki/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java
@@ -213,6 +213,6 @@ public class RequestInQueueJob extends AJobBase
      * @return String array of configuration parameter names.
      */
     public String[] getConfigParams() {
-        return (mConfigParams);
+        return mConfigParams;
     }
 }
diff --git a/pki/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java b/pki/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java
index c61d953ebab380263a19c43b87e950ef5fd74524..63cae7f30713db50f2cc72316b058ca0d8892059 100644
--- a/pki/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java
+++ b/pki/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java
@@ -135,7 +135,7 @@ public class UnpublishExpiredJob extends AJobBase
         }
 
         mReqQ = mCa.getRequestQueue();
-        mRepository = (ICertificateRepository) mCa.getCertificateRepository();
+        mRepository = mCa.getCertificateRepository();
         mPublisherProcessor = mCa.getPublisherProcessor();
 
         // read from the configuration file
diff --git a/pki/base/common/src/com/netscape/cmscore/apps/CMSEngine.java b/pki/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
index 5fdcaece06b73fa23bfbc9b4ea50833b582b53c1..b9f9bd393911ef985941b90243ecc805af1222de 100644
--- a/pki/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/pki/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -1620,8 +1620,6 @@ public class CMSEngine implements ICMSEngine {
         shutdownSubsystems(mFinalSubsystems);
         shutdownSubsystems(mDynSubsystems);
         shutdownSubsystems(mStaticSubsystems);
-
-        System.exit(0);
     }
 
     /**
diff --git a/pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java b/pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java
index 0d004d3357bc818b11dd03c3d10b9f133e548c70..c563a3a4504f8dfae892df0ebf32ac6c66afdb08 100644
--- a/pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java
+++ b/pki/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java
@@ -245,6 +245,7 @@ public class CertificateRepository extends Repository
             }
             if (mResults != null) {
                 mRetrieveModificationsThread.setResults(mResults);
+                mRetrieveModificationsThread.setDaemon(true);
                 mRetrieveModificationsThread.start();
             }
         }
@@ -254,6 +255,7 @@ public class CertificateRepository extends Repository
             CMS.debug("In setCertStatusUpdateInterval about to create CertStatusUpdateThread ");
             mCertStatusUpdateThread = new CertStatusUpdateThread(this, requestRepo, "CertStatusUpdateThread");
             mCertStatusUpdateThread.setInterval(interval);
+            mCertStatusUpdateThread.setDaemon(true);
             mCertStatusUpdateThread.start();
         } else {
             CMS.debug("In setCertStatusUpdateInterval it thinks the thread is up already ");
@@ -1903,11 +1905,6 @@ public class CertificateRepository extends Repository
     }
 
     public void shutdown() {
-        //if (mCertStatusUpdateThread != null) 
-        //        mCertStatusUpdateThread.destroy();
-
-        //if (mRetrieveModificationsThread != null) 
-        //        mRetrieveModificationsThread.destroy();
     }
 }
 
diff --git a/pki/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java b/pki/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java
index 79225a13f860563689fe907d30d47c2e0e2d7fd8..b35f8c340eaeab92028a188bf1f2ea747da2cba1 100644
--- a/pki/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java
+++ b/pki/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java
@@ -118,7 +118,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
 
         // register all job plugins
         while (mImpls.hasMoreElements()) {
-            String id = (String) mImpls.nextElement();
+            String id = mImpls.nextElement();
             String pluginPath = c.getString(id + "." + PROP_CLASS);
 
             JobPlugin plugin = new JobPlugin(id, pluginPath);
@@ -131,10 +131,9 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
         Enumeration<String> jobs = c.getSubStoreNames();
 
         while (jobs.hasMoreElements()) {
-            String jobName = (String) jobs.nextElement();
+            String jobName = jobs.nextElement();
             String implName = c.getString(jobName + "." + PROP_PLUGIN);
-            JobPlugin plugin =
-                    (JobPlugin) mJobPlugins.get(implName);
+            JobPlugin plugin = mJobPlugins.get(implName);
 
             if (plugin == null) {
                 log(ILogger.LL_FAILURE,
@@ -145,10 +144,8 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
             String classPath = plugin.getClassPath();
 
             // instantiate and init the job
-            IJob job = null;
-
             try {
-                job = (IJob)
+                IJob job = (IJob)
                         Class.forName(classPath).newInstance();
                 IConfigStore jconfig = c.getSubStore(jobName);
 
@@ -205,7 +202,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
             // get time now
             Calendar cal = Calendar.getInstance();
             long rightNow = cal.getTime().getTime();
-            long duration = 0;
+            long duration;
             long second = cal.get(Calendar.SECOND);
 
             if (second != 1) { // scheduler needs adjustment
@@ -238,6 +235,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
                     System.out.println(e);
                 }
             }
+
             // if (duration == 0), it's time
 
             // woke up...
@@ -262,10 +260,8 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
              */
             wokeupTime = cal.getTime().getTime();
 
-            IJob job = null;
-
-            for (Enumeration<IJob> e = mJobs.elements(); e.hasMoreElements();) {
-                job = e.nextElement();
+            for (Enumeration<IJob> e = mJobs.elements(); e.hasMoreElements(); ) {
+                IJob job = e.nextElement();
 
                 // is it enabled?
                 IConfigStore cs = job.getConfigStore();
@@ -285,7 +281,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
                     //	log(ILogger.LL_INFO, "show time for: "+job.getId());
 
                     // if previous thread still alive, skip
-                    Thread jthread = (Thread) mJobThreads.get(job.getId());
+                    Thread jthread = mJobThreads.get(job.getId());
 
                     if ((jthread == null) || (!jthread.isAlive())) {
                         Thread jobThread = new Thread((Runnable) job, job.getId());
@@ -381,7 +377,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
      * @return name of the Jobs Scheduler subsystem
      */
     public String getId() {
-        return (mId);
+        return mId;
     }
 
     /**
@@ -419,24 +415,9 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
      * <P>
      */
     public void shutdown() {
-        mJobPlugins.clear();
-        mJobPlugins = null;
-        mJobs.clear();
-        mJobs = null;
-
-        Enumeration<String> enums = mJobThreads.keys();
-        while (enums.hasMoreElements()) {
-            String id = (String) enums.nextElement();
-            Thread currthread = (Thread) mJobThreads.get(id);
-            //if (currthread != null) 
-            //  currthread.destroy();
+        for (IJob job : mJobs.values()) {
+            job.stop();
         }
-
-        mJobThreads.clear();
-        mJobThreads = null;
-
-        //if (mScheduleThread != null) 
-        //  mScheduleThread.destroy();
     }
 
     /**
@@ -462,7 +443,7 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
             Debug.trace("in getCofigParams()");
 
         // is this a registered implname?
-        JobPlugin plugin = (JobPlugin) mJobPlugins.get(implName);
+        JobPlugin plugin = mJobPlugins.get(implName);
 
         if (plugin == null) {
             log(ILogger.LL_FAILURE,
@@ -477,13 +458,12 @@ public class JobsScheduler implements Runnable, IJobsScheduler {
         // auth manager instantces to avoid instantiation just for this.
 
         // a temporary instance
-        IJob jobInst = null;
         String className = plugin.getClassPath();
 
         if (Debug.ON)
             Debug.trace("className = " + className);
         try {
-            jobInst = (IJob)
+            IJob jobInst = (IJob)
                     Class.forName(className).newInstance();
             if (Debug.ON)
                 Debug.trace("class instantiated");
-- 
1.7.7.4

