📄 ldifutility.java
字号:
package com.ca.commons.naming;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.*;
import com.ca.commons.cbutil.*;
/**
* collection of static utility ftns. for
* writing and reading ldif files. Currently does not
* handle URLs properly, but will do base64 encoding
* quite happily given half a chance...
*/
//TODO: add 'version 2' handling to ldif file when using xml / ldif, and setup config parameter.
public class LdifUtility
{
private static boolean debug = false;
private static boolean handleXML = false;
private Hashtable params = null; // list of expandable strings for the ldif file, used during file parsing
// e.g. KEY: <base_dn>, KEY VALUE: "o=eTrust, cn=Users"
private String filedir = null;
private String cr = System.getProperty("line.separator", "\n");
private final static Logger log = Logger.getLogger(LdifUtility.class.getName());
public LdifUtility()
{
}
/**
* Sets whether to support the draft rfc for special handling of XML data in LDIF files.
* @param state
*/
public static void setSupportXML_LDIF_RFC(boolean state)
{
handleXML = state;
}
/**
* Constructor
*
* @param params - hashtable with the list of string that will have to be suvstituted in the ldif file
* @param filedir - ldif file directory, used to find the input files specified in the ldif stream
*/
public LdifUtility(Hashtable params, String filedir)
{
this.params = params;
this.filedir = filedir;
}
/**
* Set the ldif filepath - used to find input files
*
* @param filedir file path
*/
public void setFileDir(String filedir)
{
this.filedir = filedir + "\\";
}
/**
* Set the ldif file parameters
*
* @param params list of parameters
*/
public void setParams(Hashtable params)
{
this.params = params;
}
/**
* This is used to write a value that is *probably* normal
* string encoded, but *may* need to be base64 encoded.
* It also takes a boolean parameter that forces base64 encoding.
* Otherwise, it
* checks the string against the requirements of draft-good-ldap-ldif-04
* (initial character sane, subsequent characters not null, CR or LF),
* and returns the appropriate string, with appropriate ': ' or ':: '
* prefix.
*
* @param o the object to be ldif encoded
* @return the ldif encoding (possibly base64) with appropriate colons.
*/
public String ldifEncode(Object o, int offset, boolean forceBase64Encoding)
{
if (forceBase64Encoding == false)
return ldifEncode(o, offset);
String ret = ":: ";
if (o.getClass().isArray())
{
try
{
byte b[] = (byte[]) o;
ret += CBBase64.binaryToString(b, offset + 3);
return ret;
}
catch (ClassCastException e)
{
System.out.println("unable to cast array to byte array.");
}
}
// it's not a byte array; force it to a string, read as bytes,
// and code those. This will work in most cases, but will
// fail badly for isNonString data that has not been encoded properly
// already; e.g. a gif file should (probably) be translated to a
// byte array before being passed to this ftn.
ret += CBBase64.binaryToString(o.toString().getBytes(), offset + 3);
return ret;
}
/**
* This is used to write a value that is *probably* normal
* string encoded, but *may* need to be base64 encoded or xml encoded. It
* checks the string against the requirements of draft-good-ldap-ldif-04
* (initial character sane, subsequent characters not null, CR or LF),
* and returns the appropriate string, with appropriate ': ' or ':: '
* prefix. It also supports the draft 'Extended LDAP Data Interchange Foramt'
* handling of xml text that is identified by an initial '<?xml ' string.
*
* @param o the object to be ldif encoded
* @param offset The first line of the string may be offset by
* by this many characters for nice formatting (e.g. in
* an ldif file, the first line may include 'att value = ...'
* at the beginning of the base 64 encoded block).
* @return the ldif encoding (possibly base64) with appropriate colons.
*/
public String ldifEncode(Object o, int offset)
{
boolean base64Encode = false;
boolean xmlEncode = false;
if ((o instanceof String) == false)
{
if (debug == true) System.out.println("found a " + o.getClass().toString());
if (o.getClass().isArray())
{
try
{
byte b[] = (byte[]) o;
String ret = ":: " + CBBase64.binaryToString(b, offset + 3);
if (debug == true) System.out.println("phenomenal - identified and wrote '" + ret + "'");
return ret;
}
catch (ClassCastException e)
{
if (debug == true) System.out.println("unable to cast array to byte array.");
}
}
return o.toString();
}
else // we have a string
{
String s = o.toString();
int len = s.length();
if (len == 0) return ": "; // this shouldn't really happen; null attributes should be culled before we get here...
// run the rfc tests to see if this is a good and virtuous string
char startChar = s.charAt(0);
if ("\n\r :".indexOf(startChar) != -1) // check for safe start char
base64Encode = true;
else if (startChar == '<')
{
if (handleXML == true && s.startsWith("<?xml ")) // we have xml text, and will cope with wierd characters differently.
xmlEncode = true;
else
base64Encode = true;
}
else
{
char test[] = new char[len];
s.getChars(0, len, test, 0);
for (int i = 0; i < len; i++)
{
//System.out.println("checking: " + i + ": " + test[i] + " = " + CBUtility.charToHex(test[i]));
if (test[i] > 126 || test[i] < 32) // check for sane intermediate chars
{
base64Encode = true; // (may be unicode international string)
break;
}
}
}
if (s.charAt(s.length() - 1) == ' ') // end space considered harmful
base64Encode = true;
if (base64Encode)
{
return translateToLdifBase64(s, offset);
}
else if (xmlEncode)
return translateToLdifXML(s);
else
return ": " + s; // return unmodified string.
}
}
private String translateToLdifBase64(String s, int offset)
{
try
{
s = CBBase64.binaryToString(s.getBytes("UTF8"), offset + 3);
}
catch (UnsupportedEncodingException e) // why would we get this when utf8 is mandatory across all java platforms?
{
log.log(Level.WARNING, "error utf8 encoding strings...", e);
s = CBBase64.binaryToString(s.getBytes(), offset + 3);
}
return ":: " + s;
}
/**
* This replaces new lines (of various sorts) with a 'new line' + '>' character, as per 'xml in ldif' draft rfc.
* @param s
* @return
*/
private String translateToLdifXML(String s)
{
StringBuffer xml = new StringBuffer(";transfer-rxer>:").append(cr).append(s);
// carriage return madness :-(. Runs fastest on systems that use '\n' only. Seems about right.
if (s.indexOf("\r") != -1) // mac (I think)
{
CBParse.replaceAllBufferString(xml, "\r", "\r>");
}
if (s.indexOf("\n") != -1) // catches both '\r\n' and '\n'
{
CBParse.replaceAllBufferString(xml, "\n", "\n>");
}
return xml.toString();
}
/**
* Writes a single ldif entry...
*
*/
/**
* retrieves a single entry from the directory and writes it
* out to an ldif file. Note that ldif header 'version 1' must
* be written elsewhere...
*
* @param dn the ldap escaped dn of the entry being written
* @param saveFile the file to write the entry to
* @param originalPrefix an optional portion of the dn to update
* @param replacementPrefix an optional replacement for a portion of the dn
* @param atts the attributes of teh entry
*/
public void writeLdifEntry(String dn, FileWriter saveFile, String originalPrefix, String replacementPrefix, Attributes atts)
throws NamingException, IOException
{
if (atts == null)
{
log.info("no attributes available for " + dn);
return;
}
/**
* Prefix replacement magic. If we are moving the tree during
* the save, and a different prefix has been given (i.e. the
* originalPrefix and replacementPrefix variables aren't zero)
* we switch the relavent portion of the saved dn, substituting
* the portion of the dn that contains the original prefix with
* the replacement.
* e.g. cn=Fredo,o=FrogFarm,c=au, with original prefix o=FrogFarm,c=au
* and replacement o=FreeFrogs,c=au, becomes cn=Fredo,o=FreeFrogs,c=au
*/
if ((originalPrefix != null) && (dn.endsWith(originalPrefix))) // which it jolly well should...
{
if (debug == true) System.out.println("original DN = '" + dn + "'");
dn = dn.substring(0, dn.length() - originalPrefix.length()) + replacementPrefix;
if (debug == true) System.out.println("after replacement DN = '" + dn + "'");
}
Attribute oc; // we treat the object class attribute
oc = atts.get("oc"); // specially to ensure it is first after the dn.
if (oc != null) // XXX do a name conversion...
{
if (oc instanceof DXAttribute)
((DXAttribute) oc).setName("objectClass");
}
else // (mind you its bloody hard to track down...!)
oc = atts.get("objectclass"); // so keep looking...
if (oc == null)
oc = atts.get("objectClass"); // this really bites.
if (oc == null)
{
if (dn.endsWith("cn=schema")) // XXX el dirty hack to allow schema to be sorta written out...
oc = new BasicAttribute("oc", "schema");
}
if (oc == null)
{
log.info("unable to identify object class for " + dn + " - skipping entry");
return;
}
if (debug)
System.out.println("dn" + ldifEncode(dn, 2));
else
saveFile.write("dn" + ldifEncode(dn, 2) + "\n");
NamingEnumeration ocs = oc.getAll();
while (ocs.hasMore())
{
if (debug)
System.out.println(oc.getID() + ": " + ocs.next());
else
saveFile.write(oc.getID() + ldifEncode(ocs.next(), oc.getID().length()) + "\n");
}
NamingEnumeration allAtts = atts.getAll();
String attName;
Attribute currentAtt;
while (allAtts.hasMore())
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -