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.idxLogger;
import jeffaschenk.commons.frameworks.cnxidx.utility.ldap.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
/**
* Java Command line utility, driven from properties and command
* line parameters to Restore the Entire, a portion (container) or even
* a single entry and optionally all of its children to
* the IRR Directory from a LDIF format input file on disk.
* Backup input conforms to the LDIF Specification: RFC2849.
* However the Input Change Log fil must have been produced from the
* IRRChangeLogger utility.
* <br>
* <b>Usage:</b><br>
* IRRChangeLogRestore <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.
* --infile
* Specify Full Input file Path of Change Log to be read.
* </pre>
* <b>Optional Parameters are:</b>
* <pre>
* --jar
* Specify LDIF infile specifies a JAR path.
* --restoreonlyDN
* Specify to restore only current DN.
* --withchildren
* Specify to restore specified restoreonlyDN and all it's children.
* --version
* Display Version information and exit.
* --?
* This Display.
*
* </pre>
*
* @author jeff.schenk
* @version 3.0 $Revision
* Developed 2003
*/
public class IRRChangeLogRestore implements idxCMDReturnCodes {
public static String VERSION = "Version: 3.0 2003-09-12, " +
"FRAMEWORK, Incorporated.";
// *******************************
// Common Logging Facility.
public static final String CLASSNAME = IRRChangeLogRestore.class.getName();
public static idxLogger IDXLOG = new idxLogger();
public static String MP = CLASSNAME + ": ";
// ****************************
// Runtime Statistics
private int entries_exceptions = 0;
private int entries_skipped = 0;
private int entries_processed = 0;
private int entries_modified = 0;
private int entries_renamed = 0;
private int entries_deleted = 0;
private int entries_added = 0;
/**
* Usage
* Class to print Usage parameters and simple exit.
*/
static void Usage() {
System.err.println(MP + "Usage:");
System.err.println(MP + "IRRChangeLogRestore <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 + "--infile ");
System.err.println("\tSpecify Full Input file Path of Change Logfile to be read and restored.");
System.err.println("\n" + MP + "Optional Parameters are:");
System.err.println(MP + "--jar ");
System.err.println("\tSpecify LDIF Input is located in a JAR.");
System.err.println(MP + "--restoreonlyDN ");
System.err.println("\tSpecify to restore only current DN.");
System.err.println(MP + "--withchildren ");
System.err.println("\tSpecify to restore specified restoreonlyDN and all it's children.");
System.err.println(MP + "--version");
System.err.println("\tDisplay Version information and exit.");
System.err.println(MP + "--?");
System.err.println("\tThe Above Display.");
System.exit(EXIT_USAGE);
} // End of Subclass
/**
* IRRChangeLogRestore Contructor class driven from
* Main or other Class Caller.
*/
public IRRChangeLogRestore() {
} // End of Constructor for IRRChangeLogRestore.
/**
* clearStats Method resets all statistics for this utility classs.
*/
public void clearStats() {
entries_exceptions = 0;
entries_skipped = 0;
entries_processed = 0;
entries_modified = 0;
entries_renamed = 0;
entries_deleted = 0;
entries_added = 0;
} // End of clearStats Method.
/**
* obtainStats Method to obtain all statistics for this utility classs.
*/
public int[] obtainStats() {
int[] stats = new int[7];
stats[0] = entries_exceptions;
stats[1] = entries_skipped;
stats[2] = entries_processed;
stats[3] = entries_modified;
stats[4] = entries_renamed;
stats[5] = entries_deleted;
stats[6] = entries_added;
return (stats);
} // End of clearStats Method.
/**
* dumpStats Method displays all statistics for this utility.
*/
public void dumpStats() {
String METHODNAME = "dumpStats";
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Processed: [" + entries_processed + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entry Exceptions: [" + entries_exceptions + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Skipped: [" + entries_skipped + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Added: [" + entries_added + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Deleted: [" + entries_deleted + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Renamed: [" + entries_renamed + "]");
IDXLOG.info(CLASSNAME, METHODNAME, "Entries Modified: [" + entries_modified + "]");
} // End of dumpStats Method.
/**
* perform Method class performs the requested IRR Function Utility.
*
* @throws idxIRRException for any specific IRR unrecoverable errors during function.
* @throws Exception for any unrecoverable errors during function.
*/
public void perform(DirContext irrctx, String INPUT_FILENAME)
throws Exception, idxIRRException {
perform(irrctx, INPUT_FILENAME, "", false, false, false);
} // End of Perform Method.
/**
* perform Method class performs the requested IRR Function Utility.
*
* @throws idxIRRException for any specific IRR unrecoverable errors during function.
* @throws Exception for any unrecoverable errors during function.
*/
public void perform(DirContext irrctx,
String INPUT_FILENAME,
String RESTOREONLY_SOURCEDN,
boolean INJAR,
boolean RESTOREONLY_WITH_CHILDREN,
boolean RESTOREONLY)
throws Exception, idxIRRException {
String METHODNAME = "perform";
IDXLOG.finer(CLASSNAME, METHODNAME, "Entering to Restore LDIF from Input File:[" +
INPUT_FILENAME + "].");
// ****************************************
// Note The Start Time.
idxElapsedTime elt = new idxElapsedTime();
// *******************************************
// Initialize.
CompoundName RESTOREONLY_Name = null;
CompoundName Incoming_Name = null;
CompoundName Control_Name = null;
// *******************************************
// Acquire a Name Parser.
idxNameParser myParser = new idxNameParser();
// ********************************************
// Create a Compound Name for our SourceDN
//
if (RESTOREONLY) {
try {
// ***********************************************
// Now determine if SourceDN is Valid.
idxParseDN zSdn = new idxParseDN(RESTOREONLY_SOURCEDN);
if (!zSdn.isValid()) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Restore Only Source DN [" +
RESTOREONLY_SOURCEDN +
"] is Invalid, unable to continue.");
throw new idxIRRException(MP + "Restore Only Source DN [" +
RESTOREONLY_SOURCEDN +
"] is Invalid, unable to continue.",
EXIT_IRR_RESTORE_FAILURE);
} // End of If.
RESTOREONLY_Name = myParser.parse(RESTOREONLY_SOURCEDN);
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Restore Only Source DN [" +
RESTOREONLY_SOURCEDN +
"] is Invalid, unable to continue.");
throw new idxIRRException(MP + "Restore Only Source DN [" +
RESTOREONLY_SOURCEDN +
"] is Invalid, unable to continue.",
EXIT_IRR_RESTORE_FAILURE);
} // End of exception
} // End of If.
// *****************************************
// Open Input File and Start Restore Process
if (INJAR) {
IDXLOG.finer(CLASSNAME, METHODNAME, "Starting Directory Restore using LDIF JAR Class:[" + INPUT_FILENAME + "]");
} else {
IDXLOG.finer(CLASSNAME, METHODNAME, "Starting Directory Restore using LDIF Input File:[" + INPUT_FILENAME + "]");
} // End of Else.
// *****************************************
// Initialize.
BufferedReader LDIFIN = null;
clearStats();
Attributes current_entry_attributes = null;
String current_dn = null;
String LDIFVersion = null;
String IDXCHANGETYPE = null;
String IDXCHANGETYPEDN = null;
String IDXCHANGETYPEOLDDN = null;
boolean IDXCHANGEBYPASS = false;
// *****************************************
// Open up Input.
try {
if (INJAR) {
// ******************************************
// Open up the Input Stream from a JAR.
LDIFIN = new BufferedReader(
new InputStreamReader(
ClassLoader.getSystemResourceAsStream(INPUT_FILENAME)), 16384);
} else {
// ******************************************
// Open up the Input Stream from a File.
LDIFIN = new BufferedReader(
new FileReader(INPUT_FILENAME), 16384);
} // End of Else.
// ******************************************
// Obtain our Reader Instance with our Input.
idxChangeLogLDIFReader ldif = new idxChangeLogLDIFReader(LDIFIN);
Incoming_Name = null;
while (ldif.hasMore()) {
current_entry_attributes = ldif.getNextEntry();
current_dn = ldif.getCurrentDN();
if ((current_dn == null) ||
(current_dn.equals(""))) {
continue;
}
// *************************************
// Detect the Version, if possible.
if ((LDIFVersion == null) ||
(LDIFVersion.equals(""))) {
LDIFVersion = ldif.getVersion();
if ((LDIFVersion != null) &&
(!LDIFVersion.equals(""))) {
IDXLOG.finer(CLASSNAME, METHODNAME, "LDIF VERSION Detected:[" +
LDIFVersion + "]");
}
} // End of LDIF Version Detection.
// *********************************************
// Obtain Change Control Information for Entry.
//
Attribute myattr = current_entry_attributes.get("IDXCHANGETYPE");
if (myattr != null) {
Object myValue = myattr.get();
IDXCHANGETYPE = ((String) myValue).trim();
current_entry_attributes.remove("IDXCHANGETYPE");
// *******************************
// Obtain the DN.
myattr = current_entry_attributes.get("IDXCHANGETYPEDN");
if (myattr == null) {
IDXCHANGETYPEOLDDN = null;
} else {
myValue = myattr.get();
IDXCHANGETYPEDN = ((String) myValue).trim();
current_entry_attributes.remove("IDXCHANGETYPEDN");
} // End of Else.
// *******************************
// Obtain the Old DN if Available.
myattr = current_entry_attributes.get("IDXCHANGETYPEOLDDN");
if (myattr == null) {
IDXCHANGETYPEOLDDN = null;
} else {
myValue = myattr.get();
IDXCHANGETYPEOLDDN = ((String) myValue).trim();
current_entry_attributes.remove("IDXCHANGETYPEOLDDN");
} // End of Else.
IDXLOG.finer(CLASSNAME, METHODNAME, "Change Type Detected:[" + IDXCHANGETYPE + "], " +
"DN:[" + IDXCHANGETYPEDN + "], " +
"Old DN:[" + IDXCHANGETYPEOLDDN + "]");
// **********************************************
// Now Determine if the Entry should be processed
//
IDXCHANGEBYPASS = false;
if ((IDXCHANGETYPE == null) ||
(IDXCHANGETYPEDN == null)) {
IDXCHANGEBYPASS = true;
IDXLOG.warning(CLASSNAME, METHODNAME, "Bypassing Invalid Change Type Detected:[" + IDXCHANGETYPE + "], " +
"DN:[" + IDXCHANGETYPEDN + "], " +
"Old DN:[" + IDXCHANGETYPEOLDDN + "]");
continue;
} // End of If.
if ((IDXCHANGETYPE.equalsIgnoreCase("RENAME")) &&
((IDXCHANGETYPEOLDDN == null) || (IDXCHANGETYPEOLDDN.equals("")))) {
IDXCHANGEBYPASS = true;
IDXLOG.warning(CLASSNAME, METHODNAME, "Bypassing Invalid Rename Change:[" + IDXCHANGETYPE + "], " +
"DN:[" + IDXCHANGETYPEDN + "], " +
"Old DN:[" + IDXCHANGETYPEOLDDN + "]");
continue;
} // End of If.
// ***************************************
// If we have a RestoreOnlyDN Specified
// filter out the ones we do not need.
//
if (RESTOREONLY) {
// ************************************
// If we have a rename operation,
// make sure we use the old dn, as that is
// what will be effected from the change.
//
String ctDN = IDXCHANGETYPEDN;
if (IDXCHANGETYPE.equalsIgnoreCase("RENAME")) {
ctDN = IDXCHANGETYPEOLDDN;
}
try {
Incoming_Name = myParser.parse(ctDN);
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Exception Creating incoming Control Compound Name for DN:[" +
ctDN + "]" + e);
entries_exceptions++;
IDXCHANGEBYPASS = true;
continue;
} // End of exception
// ****************************************************
// If No Children, Compare Incoming and the RestoreOnly
if (!RESTOREONLY_WITH_CHILDREN) {
if (!Incoming_Name.equals(RESTOREONLY_Name)) {
entries_skipped++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Skipping DN-> " + ctDN);
// **************************************
// Clear out the Operation Data.
IDXCHANGEBYPASS = true;
IDXCHANGETYPE = null;
IDXCHANGETYPEDN = null;
IDXCHANGETYPEOLDDN = null;
continue;
}
} else {
// **********************************************************
// If Children, Compare Incoming has a suffix of RestoreOnly
if (!Incoming_Name.endsWith(RESTOREONLY_Name)) {
entries_skipped++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Skipping DN-> " + ctDN);
// **************************************
// Clear out the Operation Data.
IDXCHANGEBYPASS = true;
IDXCHANGETYPE = null;
IDXCHANGETYPEDN = null;
IDXCHANGETYPEOLDDN = null;
continue;
} // End of If.
} // End of Else.
} // End of If RestoreOnly
// ********************************************
// Only Exception, is that all Deletes happen
// now, since there may or may not be a
// Entry.
//
if ((!IDXCHANGEBYPASS) &&
(IDXCHANGETYPE.equalsIgnoreCase("DELETE"))) {
entries_processed++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Processing Delete of DN-> " + IDXCHANGETYPEDN);
try {
irrctx.unbind("\042" + IDXCHANGETYPEDN + "\042");
entries_deleted++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Deletion of DN, Successful.");
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Deletion Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
} // End of Delete Process.
continue; // Get Next LDIF Entry.
} // End of If for Control Information.
// ***************************************
// Now Perform Operation on the
// Change Log Entry, basically play the
// Operation.
//
// Skip the bypasses and the Deletes.
//
if ((IDXCHANGETYPE == null) ||
(IDXCHANGETYPEDN == null)) {
IDXLOG.warning(CLASSNAME, METHODNAME, "ChangeType and/or Entry DN is invalid, skipping.");
entries_exceptions++;
continue;
} // End of If.
if ((IDXCHANGETYPE.equalsIgnoreCase("DELETE"))) {
continue;
}
entries_processed++;
if (IDXCHANGEBYPASS) {
continue;
}
// ***************************************
// First make sure our control DN equals
// the control DN for consistency.
//
Incoming_Name = myParser.parse(current_dn);
Control_Name = myParser.parse(IDXCHANGETYPEDN);
if (!Incoming_Name.equals(Control_Name)) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Control DN and Entry DN do not Match," +
"\n Control DN:[" +
IDXCHANGETYPEDN + "]," +
"\n Entry DN:[" +
current_dn + "],");
entries_exceptions++;
continue;
} // End of If.
// ***************************************
// Now Determine what operation needs
// to be performed.
//
// ADD
if (IDXCHANGETYPE.equalsIgnoreCase("ADD")) {
IDXLOG.finer(CLASSNAME, METHODNAME, "Processing Add of DN-> " + IDXCHANGETYPEDN);
try {
irrctx.bind("\042" + current_dn + "\042",
null, current_entry_attributes);
entries_added++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Add of DN, Successful.");
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Add Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
} // End of Add Process.
// MODIFY
else if (IDXCHANGETYPE.equalsIgnoreCase("MODIFY")) {
IDXLOG.finer(CLASSNAME, METHODNAME, "Processing Modification of DN-> " + IDXCHANGETYPEDN);
try {
// ***********************************************
// Now remove ObjectClass from the Attributes.
current_entry_attributes.remove("objectclass");
// ***********************************************
// Now remove he Internal Replication Attribute.
current_entry_attributes.remove("cnxidaguid");
// ***********************************************
// Now remove the Naming Attribute as Well.
idxParseDN zXdn = new idxParseDN(IDXCHANGETYPEDN);
current_entry_attributes.remove(zXdn.getNamingAttribute());
if (current_entry_attributes.size() > 0) {
// ********************************************
// Attempt to remove any attributes on the
// existing source entry which do not exist in
// our current journal entry.
try {
RemoveNonExistentAttributes(irrctx, current_dn,
current_entry_attributes);
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Removal of NonExistentAttributes Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
// ********************************************
// Now Attempt to perform the modication.
irrctx.modifyAttributes("\042" + current_dn + "\042",
irrctx.REPLACE_ATTRIBUTE, current_entry_attributes);
entries_modified++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Modification of DN, Successful.");
} else {
entries_skipped++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Modification of DN, Skipped.");
} // End of Else.
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Modification Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
} // End of Modify Process.
// RENAME
else if (IDXCHANGETYPE.equalsIgnoreCase("RENAME")) {
IDXLOG.finer(CLASSNAME, METHODNAME, "Processing Rename of Old DN-> " + IDXCHANGETYPEOLDDN);
try {
irrctx.rename("\042" + IDXCHANGETYPEOLDDN + "\042",
"\042" + current_dn + "\042");
entries_renamed++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Rename of DN, Successful.");
// ************************************
// Now that the Entry has been renamed,
// simply perform a modification
// to ensure attributes are in a
// consistent state.
//
// ***********************************************
// Now remove ObjectClass from the Attributes.
current_entry_attributes.remove("objectclass");
// ***********************************************
// Now remove he Internal Replication Attribute.
current_entry_attributes.remove("cnxidaguid");
// ***********************************************
// Now remove the Naming Attribute as Well.
idxParseDN zXdn = new idxParseDN(current_dn);
current_entry_attributes.remove(zXdn.getNamingAttribute());
if (current_entry_attributes.size() > 0) {
// ********************************************
// Attempt to remove any attributes on the
// existing source entry which do not exist in
// our current journal entry.
try {
RemoveNonExistentAttributes(irrctx, current_dn,
current_entry_attributes);
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Removal of NonExistentAttributes Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
// ********************************************
// Now Attempt to perform the modication.
irrctx.modifyAttributes("\042" + current_dn + "\042",
irrctx.REPLACE_ATTRIBUTE, current_entry_attributes);
entries_modified++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Modification of DN, Successful.");
} else {
IDXLOG.finer(CLASSNAME, METHODNAME, "Modification of DN, Skipped.");
} // End of Else.
} catch (NameNotFoundException nnfe) {
// ********************************************************
// Name Not Found condition
// Indicates that the oldDN Name does not exist any longer,
// so attempt to add the entry with the new DN.
//
IDXLOG.warning(CLASSNAME, METHODNAME, "Attempting Add of DN->" +
IDXCHANGETYPEDN +
", since RENAME resulted in a Not Found for the Old DN.");
try {
irrctx.bind("\042" + current_dn + "\042",
null, current_entry_attributes);
entries_added++;
IDXLOG.finer(CLASSNAME, METHODNAME, "Add of DN, Successful.");
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Add Exception for DN:[" +
IDXCHANGETYPEDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
} catch (Exception e) {
IDXLOG.warning(CLASSNAME, METHODNAME, "Rename Exception for DN:[" +
IDXCHANGETYPEOLDDN + "],\n" + e);
entries_exceptions++;
} // End of Exception.
} // End of Rename Process.
// UNKNOWN
else {
IDXLOG.warning(CLASSNAME, METHODNAME, "Unknown Change Type Encountered:[" +
IDXCHANGETYPE + "] for DN:[" + IDXCHANGETYPEDN + "].");
entries_exceptions++;
} // End of Else.
} // End of While Loop.
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Exception during processing LDIF Input." + e);
throw new idxIRRException(MP + "Exception during processing LDIF Input. " + e,
EXIT_IRR_RESTORE_LDIF_INPUT_FAILURE);
} // End of exception
// ***************************************
// Close our Input File.
try {
LDIFIN.close();
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Exception closing LDIF Input." + e);
throw new idxIRRException("Exception closing LDIF Input. " + e,
EXIT_IRR_RESTORE_LDIF_INPUT_CLOSE_FAILURE);
} // End of exception
// ****************************************
// Any Entries Restored?
if (entries_processed == 0) {
IDXLOG.warning(CLASSNAME, METHODNAME, "No Entries were Processed.");
} // End of If.
// ****************************************
// Show the Statistics
dumpStats();
// ****************************************
// Note The End Time.
elt.setEnd();
// ****************************************
// Show Restore Timings.
IDXLOG.finer(CLASSNAME, METHODNAME, "Driven Restore Complete, Elapsed Time: " + elt.getElapsed());
} // End of Perform Method.
/**
* Removes any Attributes which do not exist in the current
* Entry about to be restored. This provides the capability to remove
* Attributes which have been removed during a modification.
*
* @param ctxSource current established Source JNDI Directory Context
* @param DNSource DN of source entry.
* @param NEW_ENTRYATTRS of current entry.
* @throws idxIRRException if any non-recoverable errors encountered.
*/
private void RemoveNonExistentAttributes(DirContext ctxSource, String DNSource,
Attributes NEW_ENTRYATTRS)
throws idxIRRException, NamingException {
String METHODNAME = "RemoveNonExistentAttributes";
// *************************************************
// Parse the DN to Obtain the DN's Naming Attribute.
idxParseDN xDN = new idxParseDN(DNSource);
// *************************************
// Now obtain the Existing Entry's
// Attributes.
//
Attributes CURRENT_ENTRYATTRS = null;
try {
CURRENT_ENTRYATTRS = ObtainExistingAttributes(ctxSource, DNSource);
} catch (Exception e) {
IDXLOG.severe(CLASSNAME, METHODNAME, "Exception Performing RemoveNonExistentAttributes for Entry:[" +
DNSource + "], " + e);
throw new idxIRRException("Exception Performing RemoveNonExistentAttributes for Entry:[" +
DNSource + "], " + e);
} // End of Exception.
if (CURRENT_ENTRYATTRS == null) {
IDXLOG.info(CLASSNAME, METHODNAME, "Existing Attributes not obtained for Entry:[" +
DNSource + "]");
return;
}
// ******************************************
// Now spin through the existing attributes
// and compare existenance against our
// current set we will be modifying.
//
for (NamingEnumeration eaids = CURRENT_ENTRYATTRS.getIDs(); eaids.hasMore(); ) {
String CURRENT_ATTRID = (String) eaids.next();
// ***********************************************
// Now check for certain attributes that will not
// and should not change.
if ((CURRENT_ATTRID.equalsIgnoreCase("objectclass")) ||
(CURRENT_ATTRID.equalsIgnoreCase("cnxidaguid")) ||
(CURRENT_ATTRID.equalsIgnoreCase(xDN.getNamingAttribute()))) {
continue;
}
// ****************************************
// If the Attribute does not exist in our
// new attribute set, then remove the
// attribute from the entry on the
// Directory Server.
Attribute NEW_ATTR = NEW_ENTRYATTRS.get(CURRENT_ATTRID);
if (NEW_ATTR == null) {
RemoveAttribute(ctxSource, DNSource, CURRENT_ATTRID);
}
} // End of For Loop.
// *************************************
// Return.
return;
} // End of RemoveNonExistentAttributes
/**
* Removes a Attribute from a Directory Entry.
*
* @param ctxSource current established Source JNDI Directory Context
* @param DNSource current DN of Entry which is to be removed.
* @param AttributeName current Attribute Name to be removed.
* @throws idxIRRException if any non-recoverable errors encountered.
*/
private void RemoveAttribute(DirContext ctxSource,
String DNSource,
String AttributeName)
throws idxIRRException {
try {
ModificationItem[] irrmods = new ModificationItem[1];
irrmods[0] = new ModificationItem(
ctxSource.REMOVE_ATTRIBUTE,
new BasicAttribute(AttributeName));
ctxSource.modifyAttributes(DNSource, irrmods);
} catch (NoSuchAttributeException nsae) {
return;
} catch (Exception e) {
throw new idxIRRException("Exception Performing IRR Removal of Attribute[" +
AttributeName + "], from Entry[" +
DNSource + "],\n" + e);
} // End of Exception.
} ///: End of RemoveAttribute.
/**
* Obtains Entry from Directory Context and returns Attributes to
* Calling class method.
*
* @param ctxSource current established Source JNDI Directory Context
* @param DNSource DN of source entry.
* @return Attributes Enumeration of all Attributes for this entry.
* @throws idxIRRException if any non-recoverable errors encountered.
*/
private Attributes ObtainExistingAttributes(DirContext ctxSource, String DNSource)
throws idxIRRException {
//******************************************
// Make sure we have a valid DN.
// If the Source Entry is Blank or caller
// trying to obtain ROOT, just ignore and
// return gracefully.
//
if (("".equals(DNSource)) ||
(DNSource == null)) {
return (null);
}
//******************************************
// Set up our Search Filter.
String SearchFilter = "(objectclass=*)";
//******************************************
// Set up our Search Controls.
String[] ALL_AttrIDs = {"*"};
SearchControls OS_ctls = new SearchControls();
OS_ctls.setReturningAttributes(ALL_AttrIDs);
OS_ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
// *****************************************
// Parse the Destination Entry DN to be sure
// we have any Quotes....
idxParseDN Naming_Source = new idxParseDN(DNSource);
DNSource = Naming_Source.getDNwithQuotes();
// *****************************************
// Obtain the Namespace.
String NameSpace = null;
try {
NameSpace = ctxSource.getNameInNamespace();
if (NameSpace.equals("")) {
NameSpace = DNSource;
}
} catch (Exception e) {
{
NameSpace = DNSource;
}
} // End of exception
// *****************************************
// Now obtain the Source Entry.
//
Attributes entryattrs = null;
try {
NamingEnumeration sl =
ctxSource.search(DNSource, SearchFilter, OS_ctls);
// ******************************
// If nothing return.
if (sl == null) {
return (null);
}
// ******************************
// Loop, only will have one entry
// but loop to close off
// Enumeration.
while (sl.hasMore()) {
SearchResult si = (SearchResult) sl.next();
// Obtain Attributes
entryattrs = si.getAttributes();
} // End of While Loop
} catch (NameNotFoundException e) {
return (null);
} // End of exception
catch (Exception e) {
throw new idxIRRException("Error Performing Method ObtainExistingAttributes() on Entry:[" +
DNSource + "],\n" + e);
} // End of exception
// *************************************
// Return the Entries Attributes.
return (entryattrs);
} // End of ObtainExistingAttributes
/**
* Main
*
* @param args Incoming Argument Array.
* @see jeffaschenk.commons.frameworks.cnxidx.admin.IRRChangeLogRestore
* @see IRRChangeLogger
*/
public static void main(String[] args) {
long starttime, endtime;
// ****************************************
// Local Objects
idxManageContext IRRDest = null;
String IRRHost = null;
String IRRPrincipal = null;
String IRRCredentials = null;
String INPUT_FILENAME = null;
String RESTOREONLY_SOURCEDN = null;
boolean INJAR = false;
boolean RESTOREONLY_WITH_CHILDREN = false;
boolean RESTOREONLY = false;
boolean VERBOSE = false;
// ****************************************
// Send the Greeting.
System.out.println(MP + 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("?")) {
Usage();
}
// ***************************************
// Was Verbosity Requested?
if (Zin.doesNameExist("verbose")) {
VERBOSE = true;
}
// ***************************************
// Show Arguments if Verbose Selected.
if (VERBOSE) {
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("infile",
true, true));
VAR.add(new idxArgVerificationRules("restoreonlydn",
false, true));
VAR.add(new idxArgVerificationRules("withchildren",
false, false));
VAR.add(new idxArgVerificationRules("jar",
false, false));
VAR.add(new idxArgVerificationRules("noschemacheck",
false, false));
VAR.add(new idxArgVerificationRules("schemacheck",
false, false));
VAR.add(new idxArgVerificationRules("verbose",
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(VERBOSE);
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 + "IRR ID:[" + IRRPrincipal + "]");
IRRCredentials = clPC.getCredentials();
//System.out.println(MP+"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("withchildren")) {
RESTOREONLY_WITH_CHILDREN = true;
}
if (Zin.doesNameExist("jar")) {
INJAR = true;
}
// **************************************************
// Load up the RunTime Arguments.
//
IRRHost = (String) Zin.getValue("hosturl");
System.out.println(MP + "IRR Host URL:[" + IRRHost + "]");
INPUT_FILENAME = ((String) Zin.getValue("infile")).trim();
if (!INJAR) {
System.out.println(MP + "Input File:[" + INPUT_FILENAME + "]");
} else {
System.out.println(MP + "Input JAR Class:[" + INPUT_FILENAME + "]");
} // End of Else.
if (Zin.doesNameExist("restoreonlydn")) {
RESTOREONLY_SOURCEDN = ((String) Zin.getValue("restoreonlydn")).trim();
}
// ************************************************
// Show Operational Parameters
if ((RESTOREONLY_SOURCEDN == null) ||
(RESTOREONLY_SOURCEDN.equals("")) ||
(RESTOREONLY_SOURCEDN.equals("*"))) {
System.out.println(MP + "All Input entries will be Restored.");
RESTOREONLY_SOURCEDN = "";
RESTOREONLY = false;
RESTOREONLY_WITH_CHILDREN = false;
} else {
System.out.println(MP + "Only DN: [" + RESTOREONLY_SOURCEDN + "] " +
"will be restored from the LDIF Input Source.");
RESTOREONLY = true;
if (RESTOREONLY_WITH_CHILDREN) {
System.out.println(MP + "Children will be restored for above DN.");
}
} // End of Else.
// ****************************************
// Note The Start Time.
idxElapsedTime elt = new idxElapsedTime();
// ***********************************************
// Now initiate a Connection to the Directory
// for a LDAP Source Context
System.out.println(MP + "Attempting Destination Directory Connection to Host URL:[" + IRRHost + "]");
IRRDest = new idxManageContext(IRRHost,
IRRPrincipal,
IRRCredentials,
"Restore Destination");
// ************************************************
// Exit on all Exceptions.
IRRDest.setExitOnException(true);
// ************************************************
// Now Try to Open and Obtain Context.
try {
IRRDest.open();
} catch (Exception e) {
System.err.println(MP + "Error Opening Directory Context: " + e);
System.exit(EXIT_IRR_UNABLE_TO_OBTAIN_CONTEXT);
} // End of exception
// *****************************************
// Disable the Factories.
try {
IRRDest.disableDSAEFactories();
} catch (Exception e) {
System.err.println(MP + "Error Disabling DSAE Factories: " + e);
System.exit(EXIT_GENERIC_FAILURE);
} // End of exception
// ****************************************
// Initailize Constructor.
IRRChangeLogRestore FUNCTION = new IRRChangeLogRestore();
// ****************************************
// Perform Function.
try {
FUNCTION.perform(IRRDest.irrctx,
INPUT_FILENAME,
RESTOREONLY_SOURCEDN,
INJAR,
RESTOREONLY_WITH_CHILDREN,
RESTOREONLY);
} catch (idxIRRException ire) {
System.err.println(MP + " " + ire.getMessage());
System.exit(ire.getRC());
} catch (Exception e) {
System.err.println(MP + "IRR Exception Performing IRRChangeLogRestore.\n" + e);
System.exit(EXIT_GENERIC_FAILURE);
} // End of Exception.
// ***************************************
// Close up Shop.
System.out.println(MP + "Closing Destination Directory Context.");
try {
IRRDest.close();
} catch (Exception e) {
System.err.println(e);
System.exit(EXIT_IRR_CLOSE_FAILURE);
} // End of exception
// ****************************************
// Show the Statistics
FUNCTION.dumpStats();
// ****************************************
// Note The End Time.
elt.setEnd();
// ****************************************
// Exit
System.out.println(MP + "Done, Elapsed Time: " + elt.getElapsed());
System.exit(EXIT_SUCCESSFUL);
} // End of Main
} // End of Class IRRChangeLogRestore