From 443b3676302e7861180802784d8a1ebc43d07ea3 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Thu, 19 May 2016 00:08:20 -0400
Subject: [PATCH 304/306] Add parameters to purge old published files

Ticket 2254
---
 .../cms/publish/publishers/FileBasedPublisher.java | 85 +++++++++++++++++++++-
 1 file changed, 81 insertions(+), 4 deletions(-)

diff --git a/base/server/cms/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java b/base/server/cms/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java
index c48aa2db44163850d34f99e146ba6505926d2389..d2f6d39127b312f2b9ac51d70f44c162f24e9d96 100644
--- a/base/server/cms/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java
+++ b/base/server/cms/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java
@@ -28,14 +28,14 @@ import java.security.cert.CRLException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509CRL;
 import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Locale;
 import java.util.TimeZone;
 import java.util.Vector;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import netscape.ldap.LDAPConnection;
-
 import org.mozilla.jss.util.Base64OutputStream;
 
 import com.netscape.certsrv.apps.CMS;
@@ -47,6 +47,8 @@ import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.publish.ILdapPublisher;
 import com.netscape.cmsutil.util.Utils;
 
+import netscape.ldap.LDAPConnection;
+
 /**
  * This publisher writes certificate and CRL into
  * a directory.
@@ -62,6 +64,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
     private static final String PROP_EXT = "crlLinkExt";
     private static final String PROP_ZIP = "zipCRLs";
     private static final String PROP_LEV = "zipLevel";
+    private static final String PROP_MAX_AGE = "maxAge";
+    private static final String PROP_MAX_FILES = "maxFiles";
     private IConfigStore mConfig = null;
     private String mDir = null;
     private ILogger mLogger = CMS.getLogger();
@@ -73,6 +77,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
     protected String mTimeStamp = null;
     protected String mLinkExt = null;
     protected int mZipLevel = 9;
+    protected int maxAge = 0;
+    protected int maxFiles = 0;
 
     public void setIssuingPointId(String crlIssuingPointId) {
         mCrlIssuingPointId = crlIssuingPointId;
@@ -108,6 +114,10 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
                         + ";string;Name extension used by link to the latest CRL. Default name extension is 'der'.",
                 PROP_ZIP + ";boolean;Generate compressed CRLs.",
                 PROP_LEV + ";choice(0,1,2,3,4,5,6,7,8,9);Set compression level from 0 to 9.",
+                PROP_MAX_AGE
+                    + ";integer;Number of hours after which files should expire and be purged. Default is 0, which means to never expire.",
+                PROP_MAX_FILES
+                    + ";integer;Maximum number of files to be kept.  Once new files are published, the oldest files will be purged.  Default is 0 (no limit)",
                 IExtendedPluginInfo.HELP_TOKEN +
                         ";configuration-ldappublish-publisher-filepublisher",
                 IExtendedPluginInfo.HELP_TEXT
@@ -143,6 +153,14 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
         } catch (EBaseException e) {
         }
         try {
+            maxFiles = mConfig.getInteger(PROP_MAX_FILES, 0);
+        } catch (EBaseException e) {
+        }
+        try {
+            maxAge = mConfig.getInteger(PROP_MAX_AGE, 0);
+        } catch (EBaseException e) {
+        }
+        try {
             if (mTimeStamp == null || (!mTimeStamp.equals("GMT")))
                 mTimeStamp = "LocalTime";
             v.addElement(PROP_DIR + "=" + dir);
@@ -153,6 +171,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
             v.addElement(PROP_EXT + "=" + ext);
             v.addElement(PROP_ZIP + "=" + mConfig.getBoolean(PROP_ZIP, false));
             v.addElement(PROP_LEV + "=" + mZipLevel);
+            v.addElement(PROP_MAX_FILES +"=" + maxFiles);
+            v.addElement(PROP_MAX_AGE + "=" + maxAge);
         } catch (Exception e) {
         }
         return v;
@@ -172,6 +192,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
         v.addElement(PROP_EXT + "=");
         v.addElement(PROP_ZIP + "=false");
         v.addElement(PROP_LEV + "=9");
+        v.addElement(PROP_MAX_FILES + "=0");
+        v.addElement(PROP_MAX_AGE + "=0");
         return v;
     }
 
@@ -191,6 +213,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
             mLinkExt = mConfig.getString(PROP_EXT, null);
             mZipCRL = mConfig.getBoolean(PROP_ZIP, false);
             mZipLevel = mConfig.getInteger(PROP_LEV, 9);
+            maxFiles = mConfig.getInteger(PROP_MAX_FILES, 0);
+            maxAge = mConfig.getInteger(PROP_MAX_AGE, 0);
         } catch (EBaseException e) {
         }
         if (dir == null) {
@@ -274,7 +298,7 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
     }
 
     /**
-     * Publishs a object to the ldap directory.
+     * Publishes a object to the ldap directory.
      *
      * @param conn a Ldap connection
      *            (null if LDAP publishing is not enabled)
@@ -410,6 +434,8 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
                     renameFile.renameTo(destFile);
                 }
             }
+            purgeExpiredFiles();
+            purgeExcessFiles();
         } catch (IOException e) {
             mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
                     ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString()));
@@ -422,8 +448,59 @@ public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
         }
     }
 
+    public void purgeExpiredFiles() {
+        File dir = new File(mDir);
+
+        if (!dir.isDirectory()) return;
+
+        if (maxAge != 0) {
+            long now = System.currentTimeMillis();
+            long duration = 60 * 1000 * 60 * maxAge;
+            long expiration = now - duration;
+
+            // purge any files older than maxAge hours
+            File[] files = dir.listFiles();
+            for (File file : files) {
+                if (file.lastModified() < expiration) {
+                    CMS.debug("Expiring and deleting file older than " + maxAge + " hours: " +
+                            file.getName());
+                    if (file.isFile()) file.delete();
+                }
+            }
+        }
+    }
+
+    public void purgeExcessFiles() {
+        File dir = new File(mDir);
+
+        if (!dir.isDirectory()) return;
+
+        if (maxFiles != 0) {
+            // purge any files over maxFiles limit
+            if (dir.listFiles().length <= maxFiles) return;
+
+            File[] files = dir.listFiles();
+            Arrays.sort(files, new Comparator<File>() {
+                public int compare(File f1, File f2) {
+                    return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
+                }
+                }
+            );
+
+            for (File file: files) {
+                if (dir.listFiles().length > maxFiles) {
+                    CMS.debug("Deleting file as publishing directory has more than " + maxFiles
+                            + " files: " + file);
+                    if (file.isFile()) file.delete();
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
     /**
-     * Unpublishs a object to the ldap directory.
+     * Unpublishes a object to the ldap directory.
      *
      * @param conn the Ldap connection
      *            (null if LDAP publishing is not enabled)
-- 
2.7.3

