package jeffaschenk.commons.frameworks.cnxidx.admin; import jeffaschenk.commons.frameworks.cnxidx.utility.commandlinearguments.CommandLinePrincipalCredentials; import jeffaschenk.commons.frameworks.cnxidx.utility.commandlinearguments.idxArgParser; import jeffaschenk.commons.frameworks.cnxidx.utility.commandlinearguments.idxArgVerificationRules; import jeffaschenk.commons.frameworks.cnxidx.utility.commandlinearguments.idxArgVerifier; import jeffaschenk.commons.frameworks.cnxidx.utility.ldap.idxCMDReturnCodes; import jeffaschenk.commons.frameworks.cnxidx.utility.ldap.idxElapsedTime; import jeffaschenk.commons.frameworks.cnxidx.utility.ldap.idxIRRException; import jeffaschenk.commons.frameworks.cnxidx.utility.ldap.idxTimeStamp; import java.util.*; import java.io.*; /** * Java Daemon Server utility, driven from properties and command * line parameters to obtain all incremental changes from the * IRR Directory tnd log those changes to an LDIF format output file on disk. * The Output conforms to the LDIF Specification: RFC2849. * <br> * <b>Usage:</b><br> * IRRChangeLogger <Required Parameters> <Optional Parameters> * <br> * <b>Required Parameters are:</b> * <pre> * --hosturl * Specify IRR(Directory) LDAP URL, ldap://hostname.acme.com * --irrid * Specify IRR(Directory) LDAP BIND DN, cn=irradmin,o=icosdsa * --irrpw * Specify IRR(Directory) LDAP BIND Password * --idu * Specify FRAMEWORK Keystore Alias to obtain IRRID and IRRPW. * --irrmltuid * Specify the IRR Unique MetaLink Trigger ID. * --outdir * Specify Full Output file system Directory Path for backups to be written. * </pre> * <b>Optional Parameters are:</b> * <pre> * --filetimespan * Specify Time in Minutes for new File Creations during incremental changes. * --outputbufsize * Specify Output Buffer Size, Default 128KB. * --append (DEPRECATED) * Specify to Append LDIF Existing Output File. * --version * Display Version information and exit. * --verbose * Output Additional Information. * --debug * Output Debugging Information. * --? * This Display. * * </pre> * * @author jeff.schenk * @version 2.0 $Revision * Developed 2001-2002 */ public class IRRChangeLogger implements idxCMDReturnCodes { private static String VERSION = "Version: 2.0 2002-09-30, " + "FRAMEWORK, Incorporated."; private static String MP = "IRRChangeLogger: "; private static String IRRHost = null; private static String IRRPrincipal = null; private static String IRRCredentials = null; private static String IRRMLTuid = null; private static String OUTPUT_DIRECTORY = null; private static boolean VERBOSE = false; private static boolean DEBUG = false; private static boolean APPEND = false; private static int OBUFSIZE = 0; private static long FILETIMESPAN = 0; private static idxTimeStamp CurrentTimeStamp = new idxTimeStamp(); private boolean ExitOnException = false; private PipedWriter BPQout; private PipedReader BPQin; /** * Usage * Class to print Usage parameters and simple exit. */ static void Usage() { System.err.println(MP + "Usage:"); System.err.println(MP + "IRRChangeLogger <Required Parameters> <Optional Parameters>"); System.err.println("\n" + MP + "Required Parameters are:"); System.err.println(MP + "--hosturl "); System.err.println("\tSpecify IRR(Directory) LDAP URL, ldap://hostname.acme.com"); System.err.println(MP + "--irrid "); System.err.println("\tSpecify IRR(Directory) LDAP BIND DN, cn=irradmin,o=icosdsa"); System.err.println(MP + "--irrpw "); System.err.println("\tSpecify IRR(Directory) LDAP BIND Password"); System.err.println(MP + "--idu "); System.err.println("\tSpecify FRAMEWORK Keystore Alias to obtain IRRID and IRRPW."); System.err.println(MP + "--irrmltuid "); System.err.println("\tSpecify IRR(Directory) MetaLink Trigger UID."); System.err.println(MP + "--outdir "); System.err.println("\tSpecify Full Output file system Directory Path for backups to be written."); System.err.println("\n" + MP + "Optional Parameters are:"); System.err.println(MP + "--filetimespan "); System.err.println("\tSpecify to Time in Minutes to create New Output Files."); System.err.println(MP + "--append "); System.err.println("\tSpecify to Append LDIF Output to Existing File."); System.err.println(MP + "--outputbufsize "); System.err.println("\tSpecify LDIF Output Buffer Size."); System.err.println(MP + "--version"); System.err.println("\tDisplay Version information and exit."); System.err.println(MP + "--debug"); System.err.println("\tDisplay Debugging Information."); System.err.println(MP + "--?"); System.err.println("\tThe Above Display."); System.exit(EXIT_USAGE); } // End of Subclass /** * IRRChangeLogger Contructor class driven from * Main or other Class Caller. * * @param _IRRHost Source IRR LDAP URL. * @param _IRRPrincipal Source IRR Principal. * @param _IRRCredentials Source IRR Credentials. * @param _IRRMLTuid Source IRR MetaLink Trigger UID. * @param _OUTPUT_DIRECTORY Destination Output Filename. * @param _OBUFSIZE BufferedWriter Output Buffer Size. * @param _FILETIMESPAN FileTimespan window. * @param _APPEND Indicate if Output Should be Appended. * @param _VERBOSE Indicate Verbosity. * @param _DEBUG Indicate DEBUGGING. * @param _ExitOnException Indicate Exit on Exceptions. */ public IRRChangeLogger(String _IRRHost, String _IRRPrincipal, String _IRRCredentials, String _IRRMLTuid, String _OUTPUT_DIRECTORY, int _OBUFSIZE, long _FILETIMESPAN, boolean _APPEND, boolean _VERBOSE, boolean _DEBUG, boolean _ExitOnException) { // **************************************** // Set My Incoming Parameters. // IRRHost = _IRRHost; IRRPrincipal = _IRRPrincipal; IRRCredentials = _IRRCredentials; IRRMLTuid = _IRRMLTuid; OUTPUT_DIRECTORY = _OUTPUT_DIRECTORY; OBUFSIZE = _OBUFSIZE; FILETIMESPAN = _FILETIMESPAN; APPEND = _APPEND; VERBOSE = _VERBOSE; DEBUG = _DEBUG; ExitOnException = _ExitOnException; } // End of Constructor for IRRChangeLogger. /** * perform Method class performs the requested IRR Function Utility. * * @throws Exception for any unrecoverable errors during function. * @throws idxIRRException for any unrecoverable errors during function. */ public void perform() throws Exception, idxIRRException { // ******************************************** // // We shall start two threads // A Poller Thread that will wait for changes // from the IRR Directory using the MetaLink Trigger // Facility. // // A Collector Thread which will receive Operation and // DN information over a pipe from the Poller thread. // The Collector Thread will then read the Entry // from the Directory and write the entry in LDIF // to the specified output file. // // ******************************************** CurrentTimeStamp.enableLocalTime(); // Show Local Time Not GMT. // ******************************************** // Establish Status Objects. IRRChangeStatus PollerStatus = new IRRChangeStatus(); IRRChangeStatus CollectorStatus = new IRRChangeStatus(); // ******************************************** // Set up a PIPE for Thread Communication. BPQout = new PipedWriter(); try { BPQin = new PipedReader(BPQout); } catch (IOException e) { if (ExitOnException) { System.err.println(MP + "Unable to Obtain PipedReader for Thread Communications, Terminating"); System.exit(EXIT_GENERIC_FAILURE); } else { throw new idxIRRException(MP + "Unable to Obtain PipeReader for Thread Communcations, Terminating."); } } // End of Exception. System.out.println(MP + CurrentTimeStamp.getFTS() + " Starting Change Collector LDIF Writer Thread..."); IRRChangeCollector CollectorThread; CollectorThread = new IRRChangeCollector(BPQin, CollectorStatus, IRRHost, IRRPrincipal, IRRCredentials, IRRMLTuid, OUTPUT_DIRECTORY, OBUFSIZE, FILETIMESPAN, APPEND, VERBOSE, DEBUG, ExitOnException); String IRRHostnonURI = IRRHost.substring(7); if (IRRHostnonURI.indexOf(":") > 0) { IRRHostnonURI = IRRHostnonURI.substring(0, IRRHostnonURI.indexOf(":")); } System.out.println(MP + CurrentTimeStamp.getFTS() + " Starting Changer Poller Thread..."); IRRChangePoller PollerThread; PollerThread = new IRRChangePoller(BPQout, PollerStatus, IRRHostnonURI, IRRPrincipal, IRRCredentials, IRRMLTuid, OUTPUT_DIRECTORY, VERBOSE, DEBUG, ExitOnException); // ****************************************** // Show Status. // if (CollectorThread.t.isAlive()) { System.out.println(MP + CurrentTimeStamp.getFTS() + " Entry Collector LDIF Output Thread is Running..."); } if (PollerThread.t.isAlive()) { System.out.println(MP + CurrentTimeStamp.getFTS() + " MetaLink Poller Thread is Running..."); } // ****************************************** // Now Join and Wait for Completion. // try { System.out.println(MP + CurrentTimeStamp.getFTS() + " Main Thread waiting for Worker Threads to Complete..."); CollectorThread.t.join(); PollerThread.t.join(); System.out.println(MP + CurrentTimeStamp.getFTS() + " MetaLink Poller Thread Running Status:[" + PollerThread.t.isAlive() + "]."); System.out.println(MP + CurrentTimeStamp.getFTS() + " Entry Collector LDIF Output Thread Running Status:[" + CollectorThread.t.isAlive() + "]."); } catch (InterruptedException e) { if (ExitOnException) { System.err.println(MP + "Main Thread Interrupted, Terminating."); System.exit(EXIT_IRR_BACKUP_FAILURE); } else { throw new idxIRRException(MP + "Main Thread Interrupted, Terminating."); } } // End of Exception. // ****************************************** // Determine if all went well? // if (PollerStatus.getError() != 0) { if (ExitOnException) { System.err.println(MP + "Exception in MetaLink Poller Thread, Error Code:[" + PollerStatus.getError() + "]"); System.exit(PollerStatus.getError()); } else { throw new idxIRRException(MP + "Exception in MetaLink Poller Thread, Error Code:[" + PollerStatus.getError() + "]"); } // End of Else. } // End of If. if (CollectorStatus.getError() != 0) { if (ExitOnException) { System.err.println(MP + "Exception in Collector LDIF Writer Thread, Error Code:[" + CollectorStatus.getError() + "]"); System.exit(CollectorStatus.getError()); } else { throw new idxIRRException(MP + "Exception in Collector LDFI Writer Thread, Error Code:[" + CollectorStatus.getError() + "]"); } // End of Else. } // End of If. // ******************** // Done. return; } // End of Performbackup /** * Main * * @param args Incoming Argument Array. * @see jeffaschenk.commons.frameworks.cnxidx.admin.IRRChangeLogger */ public static void main(String[] args) { // **************************************** // Send the Greeting. CurrentTimeStamp.enableLocalTime(); // Show Local Time Not GMT. System.out.println(MP + CurrentTimeStamp.getFTS() + " " + VERSION); // **************************************** // Parse the incoming Arguments and // create objects for each entity. // idxArgParser Zin = new idxArgParser(); Zin.parse(args); // *************************************** // Do I have any unnamed Values? if (!Zin.IsUnNamedEmpty()) { System.out.println(MP + "Unknown Values Encountered, Terminating Process."); Zin.showUnNamed(); Usage(); } // End of If. // *************************************** // Was Version Info Requested? if (Zin.doesNameExist("version")) { System.exit(EXIT_VERSION); } // *************************************** // Was Help Info Requested? if ((Zin.doesNameExist("?")) || (Zin.doesNameExist("usage"))) { Usage(); } // *************************************** // Was Verbosity Requested? if (Zin.doesNameExist("verbose")) { VERBOSE = true; } if (Zin.doesNameExist("debug")) { DEBUG = true; } // *************************************** // Show Arguments if Verbose Selected. if (DEBUG) { Zin.show(); } // *************************************** // Build our verification Rule Set. // // idxArgVerificationRules Parameters are: // String Name of argument name. // Boolean Required Argument Indicator. // Boolean StringObject Argument Indicator. // String Name of Value Verification Routine. // LinkedList<idxArgVerificationRules> VAR = new LinkedList<>(); VAR.add(new idxArgVerificationRules("hosturl", true, true)); VAR.add(new idxArgVerificationRules("irrid", false, true)); VAR.add(new idxArgVerificationRules("irrpw", false, true)); VAR.add(new idxArgVerificationRules("idu", false, true)); VAR.add(new idxArgVerificationRules("irrmltuid", true, true)); VAR.add(new idxArgVerificationRules("outdir", true, true)); VAR.add(new idxArgVerificationRules("append", false, false)); VAR.add(new idxArgVerificationRules("outputbufsize", false, true)); VAR.add(new idxArgVerificationRules("filetimespan", false, true)); VAR.add(new idxArgVerificationRules("debug", false, false)); // *************************************** // Run the Verification Rule Set. // If we do not have a positive return, // then an invalid argument was detected, // so show Usage and die. // idxArgVerifier AV = new idxArgVerifier(); AV.setVerbose(DEBUG); if (!AV.Verify(MP, Zin, VAR)) { Usage(); } // *************************************** // Obtain Authentication Principal and // Credentials from the KeyStore or // the command line. // CommandLinePrincipalCredentials clPC = new CommandLinePrincipalCredentials(Zin); // ************************************************** // Load up the Principal/Credentials. // if (clPC.wasObtained()) { IRRPrincipal = clPC.getPrincipal(); System.out.println(MP + CurrentTimeStamp.getFTS() + " IRR ID:[" + IRRPrincipal + "]"); IRRCredentials = clPC.getCredentials(); if (DEBUG) { System.out.println(MP + CurrentTimeStamp.getFTS() + " IRR Password:[" + IRRCredentials + "]"); } } else { System.out.println(MP + "Required Principal and Credentials not Specified, unable to continue."); Usage(); } // End of Else. // ***************************************** // For all Specified Boolean indicators, // set them appropreiately. // if (Zin.doesNameExist("append")) { APPEND = false; } // Never append, bad form.... // ************************************************** // Load up the RunTime Arguments. // IRRHost = (String) Zin.getValue("hosturl"); System.out.println(MP + CurrentTimeStamp.getFTS() + " IRR Host URL:[" + IRRHost + "]"); IRRMLTuid = (String) Zin.getValue("irrmltuid"); System.out.println(MP + CurrentTimeStamp.getFTS() + " IRR MetaLink UID:[" + IRRMLTuid + "]"); OUTPUT_DIRECTORY = ((String) Zin.getValue("outdir")).trim(); System.out.println(MP + CurrentTimeStamp.getFTS() + " Output Directory:[" + OUTPUT_DIRECTORY + "]"); if (Zin.doesNameExist("outputbufsize")) { try { OBUFSIZE = Integer.parseInt( (String) Zin.getValue("outputbufsize")); } catch (Exception e) { System.err.println(MP + "Output Buffer Size is Invalid, Unable to Continue,\n" + e); System.exit(EXIT_GENERIC_FAILURE); } // End of Exception. } // End of If. if (Zin.doesNameExist("filetimespan")) { try { FILETIMESPAN = Integer.parseInt( (String) Zin.getValue("filetimespan")); // ************************************* // Now Create the time in milliseconds. // System.out.println(MP + CurrentTimeStamp.getFTS() + " File Time Span Cycle Creation Window:[" + FILETIMESPAN + "] Minutes."); FILETIMESPAN = ((FILETIMESPAN * 60) * 1000); } catch (Exception e) { System.err.println(MP + "File Time Span is Invalid, Unable to Continue,\n" + e); System.exit(EXIT_GENERIC_FAILURE); } // End of Exception. } // End of If. // ************************************************ // Show Operational Parameters if (APPEND) { System.out.println(MP + CurrentTimeStamp.getFTS() + " Will Append LDIF Output to Existing Incremental File."); } else { System.out.println(MP + CurrentTimeStamp.getFTS() + " Will Create new Current LDIF Output Incremental File."); } // **************************************** // Note The Start Time. idxElapsedTime elt = new idxElapsedTime(); // **************************************** // Initailize Constructor. IRRChangeLogger FUNCTION = new IRRChangeLogger( IRRHost, IRRPrincipal, IRRCredentials, IRRMLTuid, OUTPUT_DIRECTORY, OBUFSIZE, FILETIMESPAN, APPEND, VERBOSE, DEBUG, true); // **************************************** // Perform Function. try { FUNCTION.perform(); } catch (Exception e) { System.err.println(MP + "IRR Exception Performing IRRChangeLogger.\n" + e); System.exit(EXIT_GENERIC_FAILURE); } // End of Exception. // **************************************** // Note The End Time. elt.setEnd(); // **************************************** // Exit System.out.println(MP + CurrentTimeStamp.getFTS() + " Done, Elapsed Time: " + elt.getElapsed()); System.exit(EXIT_SUCCESSFUL); } // End of Main } // End of Class IRRChangeLogger