package utils.notes;
/**
* This is a light-weight class that can convert various forms of a Lotus Notes user name
* string into other various corresponding forms of a user name string. Lotus/IBM supply
* the lotus.domino.Name class for these types of operations (and more) but it must be
* instantiated from lotus.domino.Session, which is not always practical or convenient.
* This class has no such requirement.
* <p>The supported forms of a Notes user name here are as follows:<ol>
* <li>CN=Joe Blow/OU=IS/O=Acme Anvils (canonical name),</li>
* <li>CN=Joe Blow/OU=IS/O=Acme Anvils@Acme (canonical name with a domain),</li>
* <li>Joe Blow/IS/Acme Anvils (abbreviated name), and</li>
* <li>Joe Blow/IS/Acme Anvils@Acme (abbreviated name with domain).</li></ol>
* The country may also be specified in combination with any of the above name forms.</p>
* </p>An example of a full hierarchical name that takes advantage of every parameter:<ul>
* G=Joe/I=JB/S=Blow/Q=Jr/CN=Joe Blow/OU=IS/OU=Engineering/O=Acme Anvils/P=PrivAdmin/A=PubAdmin/C=US
* </ul>where<ul>
* <li>"G" is the given name component (first name)</li>
* <li>"I" is the initials</li>
* <li>"S" is the sir name component (last name)</li>
* <li>"Q" is the generational qualifier component (such as "Jr")</li>
* <li>"CN" is the common name component</li>
* <li>"OU" is the organizational unit component</li>
* <li>"O" is the organization component</li>
* <li>"P" is the PRMD component (private management domain name)</li>
* <li>"A" is the ADMD component (administration management domain name)</li>
* <li>"C" is the country</li>
* </ul></p>
*
* @since 06/17/2005
* @author Dallas Gimpel
*/
public abstract class NotesNameParser {
/** String - The common name prefix for a Notes name in canonical form.*/
public static final String COMMON_NAME_PREFIX = "CN=";
/** String - The organizational unit prefix for a Notes name in canonical form.*/
public static final String ORGANIZATIONAL_UNIT_PREFIX = "/OU=";
/** String - The organizational prefix for a Notes name in canonical form.*/
public static final String ORGANIZATION_PREFIX = "/O=";
/** String - The country prefix for a Notes name in canonical form.*/
public static final String COUNTRY_PREFIX = "/C=";
/** String - The character used to delimit the elements of a Notes name in abbreviated form.*/
public static final String ABBREVIATED_NAME_DELIMITER = "/";
/** String - The character used to indicate the domain of a given Notes name.*/
public static final String DOMAIN_INDICATOR = "@";
/** String - The value to be returned when no value exists, is valid, etc.*/
public static final String NO_VALUE = "";
/**
* Method attempts to parse the "common" name (e.g., "Joe Blow") from the abbreviated
* or canonical Notes name String it is passed.
* @param pstrNameVal - String, abbreviated or canonical Notes name String from which to
* parse a "common" name (e.g., "CN=Joe Blow/OU=IS/O=Acme Anvils" or "Joe Blow/IS/Acme
* Anvils").
* @return String, "common" name parsed (if any) from the String passed
*/
public static String parseCommonName(String pstrNameVal) {
if (!NotesNameParser.isValidString(pstrNameVal)) {
return NotesNameParser.NO_VALUE;
}
String astrName = pstrNameVal;
if (NotesNameParser.isNameCanonical(pstrNameVal)) {
astrName = NotesNameParser.cleanName(pstrNameVal);
}
String[] astrNameElements = astrName.split(NotesNameParser.ABBREVIATED_NAME_DELIMITER);
if (astrNameElements.length == 1) {
return NotesNameParser.removeDomainName(astrName);
}
// remove the "CN=" prefix (if it exists)
return astrNameElements[0].replaceFirst("([Cc][Nn][=])+", "");
}
/**
* Method attempts to parse the "abbreviated" name (e.g., "Joe Blow/IS/Acme Anvils")
* from the canonical Notes name String it is passed.
* @param pstrNameVal - String, a canonical Notes name String from which to parse an
* "abbreviated" Notes name String
* @return String, "abbreviated" name String parsed (if any) from the String passed
*/
public static String parseAbbreviatedName(String pstrNameVal) {
if (!NotesNameParser.isValidString(pstrNameVal)) {
return NotesNameParser.NO_VALUE;
}
if (!NotesNameParser.isNameCanonical(pstrNameVal)) {
return NotesNameParser.removeDomainName(pstrNameVal);
}
String astrName = NotesNameParser.cleanName(NotesNameParser.removeDomainName(pstrNameVal));
StringBuffer asbuff = new StringBuffer(astrName.length());
String[] astrNameElements = astrName.split("=");
for (int i = 1; i < astrNameElements.length; i++) {
asbuff.append(astrNameElements[i].split(NotesNameParser.ABBREVIATED_NAME_DELIMITER)[0]);
asbuff.append(NotesNameParser.ABBREVIATED_NAME_DELIMITER);
}
asbuff.setLength(asbuff.length() - 1); // remove the last character in the buffer (should be ABBREVIATED_NAME_DELIMITER)
return asbuff.toString();
}
/**
* Method attempts to parse the "canonical" name (e.g., "CN=Joe Blow/OU=IS/O=Acme Anvils")
* from the abbreviated Notes name String it is passed.
* @param pstrNameVal - String, abbreviated Notes name String from which to parse a
* "canonical" Notes name String
* @param pbEnableCountry - boolean, enables/disables support for country component of name
* @return String, "canonical" name String parsed (if any) from the String passed
*/
public static String parseCanonicalName(String pstrNameVal, boolean pbEnableCountry) {
if (!NotesNameParser.isValidString(pstrNameVal)) {
return NotesNameParser.NO_VALUE;
}
String astrCanonicalName = NotesNameParser.removeDomainName(pstrNameVal);
if (NotesNameParser.isNameCanonical(astrCanonicalName)) { // ensure upper case prefixes
astrCanonicalName = NotesNameParser.cleanName(astrCanonicalName);
astrCanonicalName = astrCanonicalName.replaceFirst("([Cc][Nn][=])+", NotesNameParser.COMMON_NAME_PREFIX);
astrCanonicalName = astrCanonicalName.replaceAll("([/][Oo][Uu][=])+", NotesNameParser.ORGANIZATIONAL_UNIT_PREFIX);
astrCanonicalName = astrCanonicalName.replaceFirst("([/][o][=])+", NotesNameParser.ORGANIZATION_PREFIX);
astrCanonicalName = astrCanonicalName.replaceFirst("([/][c][=])+", NotesNameParser.COUNTRY_PREFIX);
return astrCanonicalName;
}
// Split the abbreviated name into an array of its individual elements.
String[] astrNameElements = astrCanonicalName.split(NotesNameParser.ABBREVIATED_NAME_DELIMITER);
int aiLen = astrNameElements.length;
if (aiLen < 2) { // insufficient information to accurately determine the canonical name
return astrCanonicalName;
}
StringBuffer asbuff = new StringBuffer(pstrNameVal.length() + 32);
if (pbEnableCountry) { // use the country as last item
for (int i = 0; i < aiLen; i++) {
if (i == 0) { // add common name tag before the first name element
asbuff.append(NotesNameParser.COMMON_NAME_PREFIX).append(astrNameElements[i]);
} else if (i == (aiLen - 2)) { // add organizational prefix before the second to last name element
asbuff.append(NotesNameParser.ORGANIZATION_PREFIX).append(astrNameElements[i]);
} else if (i == (aiLen - 1)) { // add country prefix before the last name element
asbuff.append(NotesNameParser.COUNTRY_PREFIX).append(astrNameElements[i]);
} else { // add organizational unit prefix before all other name elements
asbuff.append(NotesNameParser.ORGANIZATIONAL_UNIT_PREFIX).append(astrNameElements[i]);
}
}
} else { // use organization as last item
for (int i = 0; i < aiLen; i++) {
if (i == 0) { // insert common name tag before the first name element
asbuff.append(NotesNameParser.COMMON_NAME_PREFIX).append(astrNameElements[i]);
} else if (i == (aiLen - 1)) { // insert organizational prefix before the last name element
asbuff.append(NotesNameParser.ORGANIZATION_PREFIX).append(astrNameElements[i]);
} else { // insert organizational unit prefix before all other name elements
asbuff.append(NotesNameParser.ORGANIZATIONAL_UNIT_PREFIX).append(astrNameElements[i]);
}
}
}
return asbuff.toString();
}
/**
* Determines whether or not the String passed represents a Notes name in its canonical
* form by checking to see if the String contains {@value NotesNameParser#COMMON_NAME_PRFX}.
* If it does, the name is assumed to be a canonical Notes name and the method returns
* true. Otherwise, the method returns false.
* @param pstrNameVal - String, name to be checked
* @return boolean, true if the String passed begins with {@value NotesNameParser#COMMON_NAME_PRFX}
*/
public static boolean isNameCanonical(String pstrNameVal) {
return pstrNameVal.matches("(.)*([Cc][Nn][=])+(.)*");
}
/**
* Method validates the String passed by ensuring that it is not null and that its
* length is greater than zero
* @param pstrNameVal - String, value to be validated
* @return boolean, true unless the String passed is null or its length is zero
*/
private static boolean isValidString(String pstrNameVal) {
return (pstrNameVal != null && pstrNameVal.length() > 0);
}
/**
* Method removes unsupported name components from the name value passed and returns
* the cleaned name as a String.
* @param pstrNameVal - String, name value to be cleaned of unsupported name components
* @return String, the "clean" version of the name
*/
private static String cleanName(String pstrNameVal) {
String astrName = pstrNameVal;
// remove the "given" component
astrName = astrName.replaceFirst("([Gg][=])+((.)+?([/])+)?", "");
// remove "initials" component
astrName = astrName.replaceFirst("([Ii][=])+((.)+?([/])+)?", "");
// remove "sirname" component
astrName = astrName.replaceFirst("([Ss][=])+((.)+?([/])+)?", "");
// remove "qualified generational" component
astrName = astrName.replaceFirst("([Qq][=])+((.)+?([/])+)?", "");
// remove "PRMD component" component
astrName = astrName.replaceFirst("([Pp][=])+((.)+?([/])+)?", "");
// remove "ADMD component" component
astrName = astrName.replaceFirst("([Aa][=])+((.)+?([/])+)?", "");
return astrName;
}
/**
* Method searches the String passed for the {@value NotesNameParser#DOMAIN_INDICATOR}. If found,
* {@value NotesNameParser#DOMAIN_INDICATOR} and all characters to the right of it are removed. So
* for example, if "Joe Blow/IS/Acme Anvils@Acme" is passed, the method would return
* "Joe Blow/IS/Acme Anvils".
* @param pstrNameVal - String, value from which the domain is to be removed (if found)
* @return String, the value passed without a domain
*/
private static String removeDomainName(String pstrNameVal) {
int aiDomainPos = pstrNameVal.indexOf(NotesNameParser.DOMAIN_INDICATOR);
if (aiDomainPos > -1) {
return pstrNameVal.substring(0, aiDomainPos);
}
return pstrNameVal;
}
}