/*
* Copyright 2013
*
* @author Devin S. Olson (dolson@czarnowski.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
package org.openntf.arpa;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openntf.domino.utils.Strings;
/**
* Carrier and parsing object for various RFC822 name parts.
*
* @author Devin S. Olsonm (dolson@czarnowski.com)
*
* @see "RFC822: Standard for ARPA Internet Text Messages" http://www.w3.org/Protocols/rfc822/
*
*/
@SuppressWarnings("javadoc")
public class RFC822name extends HashMap<RFC822name.Key, String> implements Serializable {
@SuppressWarnings("unused")
private static final Logger log_ = Logger.getLogger(RFC822name.class.getName());
private static final long serialVersionUID = 1L;
public static enum Key {
Comment1, Comment2, Comment3, Local, Domain, Phrase;
@Override
public String toString() {
return Key.class.getName() + ": " + this.name();
}
public String getInfo() {
return this.getDeclaringClass() + "." + this.getClass() + ":" + this.name();
}
};
/**
* Zero Argument Constructor
*/
public RFC822name() {
super();
}
/**
* Default Constructor
*
* @param source
* String from which to construct the object
*/
public RFC822name(final String string) {
super();
this.parse(string);
}
/*
* ******************************************************************
* ******************************************************************
*
* RFC82x getters
*
* ******************************************************************
* ******************************************************************
*/
/**
* Gets the ARPA Internet Name Addr821 component of the object
*
* @return the Addr821 component
*/
public String getAddr821() {
final String local = this.getAddr822LocalPart();
if (local.length() > 0) {
final String domain = this.getAddr822Domain();
return (domain.length() > 0) ? local + "@" + domain : "";
}
return "";
}
/**
* Gets the ARPA Internet Name getAddr822Comment for the specified comment number (1 - 3)
*
* @param commentnumber
* Number of the comment (1 - 3) component to retrieve.
*
* @return the Addr822Comment component specified by the comment number
*/
public String getAddr822Comment(final int commentnumber) {
Key key = null;
switch (commentnumber) {
case 1:
key = Key.Comment1;
break;
case 2:
key = Key.Comment2;
break;
case 3:
key = Key.Comment3;
break;
default:
return "";
}
final String comment = this.get(key);
return (comment.length() < 1) ? "" : "(" + comment + ")";
}
/**
* Gets the ARPA Internet Name Addr822Comment1 component of the object
*
* @return the Addr822Comment1 component
*/
public String getAddr822Comment1() {
return this.getAddr822Comment(1);
}
/**
* Gets the ARPA Internet Name Addr822Comment2 component of the object
*
* @return the Addr822Comment2 component
*/
public String getAddr822Comment2() {
return this.getAddr822Comment(2);
}
/**
* Gets the ARPA Internet Name Addr822Comment3 component of the object
*
* @return the Addr822Comment3 component
*/
public String getAddr822Comment3() {
return this.getAddr822Comment(3);
}
/**
* Gets the ARPA Internet Name Addr822Domain component of the object
*
* @return the Addr822Domain component
*/
public String getAddr822Domain() {
return this.get(Key.Domain);
}
/**
* Gets the ARPA Internet Name Addr822LocalPart component of the object
*
* @return the Addr822LocalPart component
*/
public String getAddr822LocalPart() {
return this.get(Key.Local);
}
/**
* Gets the ARPA Internet Name Addr822Full component of the object
*
* @return the Addr822Full component
*/
public String getAddr822Full() {
final StringBuilder sb = new StringBuilder(this.getAddr822Simple());
if (sb.length() > 0) {
if (this.getAddr822Comment1().length() > 0) {
sb.append(" " + this.getAddr822Comment1());
}
if (this.getAddr822Comment2().length() > 0) {
sb.append(" " + this.getAddr822Comment2());
}
if (this.getAddr822Comment3().length() > 0) {
sb.append(" " + this.getAddr822Comment3());
}
}
return sb.toString();
}
/**
* Gets the ARPA Internet Name Addr822Full component of the object, formatted with the Phrase component in FIRST LAST order
*
* @return the Addr822Full component
*/
public String getAddr822FullFirstLast() {
final StringBuilder sb = new StringBuilder(this.getAddr822SimpleFirstLast());
if (sb.length() > 0) {
if (this.getAddr822Comment1().length() > 0) {
sb.append(" " + this.getAddr822Comment1());
}
if (this.getAddr822Comment2().length() > 0) {
sb.append(" " + this.getAddr822Comment2());
}
if (this.getAddr822Comment3().length() > 0) {
sb.append(" " + this.getAddr822Comment3());
}
}
return sb.toString();
}
/**
* Gets the ARPA Internet Name Addr822Simple component of the object
*
* @return the Addr822Simple component
*/
public String getAddr822Simple() {
final String addr821 = this.getAddr821();
if (addr821.length() > 0) {
final StringBuilder sb = new StringBuilder("");
final String phrase = this.getAddr822Phrase();
if (phrase.length() > 0) {
sb.append("\"");
sb.append(phrase);
sb.append("\" ");
}
sb.append("<");
sb.append(addr821);
sb.append(">");
return sb.toString();
}
return "";
}
/**
* Gets the ARPA Internet Name Addr822Simple component of the object, formatted with the Phrase component in FIRST LAST order
*
* @return the Addr822Simple component
*/
public String getAddr822SimpleFirstLast() {
final String addr821 = this.getAddr821();
if (addr821.length() > 0) {
final StringBuilder sb = new StringBuilder("");
final String phrase = this.getAddr822PhraseFirstLast();
if (phrase.length() > 0) {
sb.append("\"");
sb.append(phrase);
sb.append("\" ");
}
sb.append("<");
sb.append(addr821);
sb.append(">");
return sb.toString();
}
return "";
}
/**
* Gets the ARPA Internet Name Addr822Phrase component of the object
*
* @return the Addr822Phrase component
*/
public String getAddr822Phrase() {
return this.get(Key.Phrase);
}
/**
* Gets the ARPA Internet Name Addr822Phrase component of the object, formatted with the Phrase component in FIRST LAST order
*
* @return the Addr822Phrase component
*/
public String getAddr822PhraseFirstLast() {
final StringBuilder sb = new StringBuilder("");
final String phrase = this.getAddr822Phrase();
if (phrase.indexOf(',') > 0) {
// assume name format of Lastname, Firstname and reverse
// to format of Firstname Lastname
final String[] chunks = phrase.split(",");
for (int i = chunks.length - 1; i > -1; i--) {
sb.append(ISO.toProperCase(chunks[i].trim()));
sb.append(" ");
}
} else if (phrase.indexOf('.') > 0) {
// assume name format of Firstname.Lastname and strip
// out the period
final String[] chunks = phrase.split("\\.");
for (final String s : chunks) {
sb.append(ISO.toProperCase(s.trim()));
sb.append(" ");
}
} else {
sb.append(phrase);
}
return sb.toString();
}
/**
* Indicates whether the object has RFC82xContent
*
* @return Flag indicating if the object has RFC82xContent
*/
public boolean isHasRFC82xContent() {
if (this.size() > 0) {
for (final String s : this.values()) {
if ((null != s) && (s.trim().length() > 0)) {
return true;
}
}
}
return false;
}
/**
* Determines if any of the mapped values are equal to the passed in string.
*
* Performs a case-insensitive search.
*
* @param string
* String tom compare values against
*
* @return Flag indicating if any of the values are equal to the string.
*/
public boolean equalsIgnoreCase(final String string) {
if (!ISO.isBlankString(string)) {
for (final String s : this.values()) {
if (string.equalsIgnoreCase(s)) {
return true;
}
}
}
return false;
}
/**
* Determines if any of the mapped values begin with the prefix.
*
* @param prefix
* Value to compare to the mapped values.
*
* @param casesensitive
* Flag indicating if Case-Sensitive comparisons should be enforced.
*
* @return Flag indicating if any of the mapped values begin with the prefix
*/
public boolean startsWith(final String prefix, final boolean casesensitive) {
if (!ISO.isBlankString(prefix)) {
if (casesensitive) {
for (final String s : this.values()) {
if ((null != s) && s.startsWith(prefix)) {
return true;
}
}
} else {
for (final String s : this.values()) {
if (Strings.startsWithIgnoreCase(s, prefix)) {
return true;
}
}
}
}
return false;
}
/*
* ******************************************************************
* ******************************************************************
*
* other methods
*
* ******************************************************************
* ******************************************************************
*/
@Override
public String get(final Object key) {
return (key instanceof RFC822name.Key) ? this.get((RFC822name.Key) key) : "";
}
public String get(final RFC822name.Key key) {
final String result = (null == key) ? "" : super.get(key);
return (null == result) ? "" : result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("RFC822name");
if (this.size() < 1) {
return sb.toString();
}
sb.append(" [");
final Iterator<Map.Entry<RFC822name.Key, String>> it = this.entrySet().iterator();
while (it.hasNext()) {
final Map.Entry<RFC822name.Key, String> entry = it.next();
sb.append(entry.getKey() + "=" + entry.getValue());
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
/**
* Parses the source string and sets the appropriate RFC822 values.
*
* @param string
* RFC822 source string from which to set the appropriate RFC822 values.
*/
public void parseRFC82xContent(final String string) {
this.clear();
this.parse(string);
}
/*
* ******************************************************************
* ******************************************************************
*
* PUBLIC STATIC methods
*
* ******************************************************************
* ******************************************************************
*/
/**
* Generates an RFC822 Addr822Full Address String from the specified component parts.
*
* @param phrase
* Addr822Phrase part used to construct the result.
* @param addr821
* Addr821 part used to construct the result.
* @param comments
* Addr822Comment1, Addr822Comment2, and Addr822Comment2 parts used to construct the result.
* @return properly formatted RFC822 Addr822Full string generated from the component parts. Empty string on error or no value for
* addr821.
*/
public static String buildAddr822Full(final String phrase, final String addr821, final String... comments) {
if ((null != addr821) && (addr821.trim().length() > 0)) {
final StringBuilder sb = new StringBuilder((null == phrase) ? "" : phrase.trim());
sb.append("<");
sb.append(addr821);
sb.append(">");
if (null != comments) {
int idx = 0;
for (final String comment : comments) {
if (!ISO.isBlankString(comment)) {
sb.append("(");
sb.append(comment);
sb.append(")");
idx++;
if (idx > 2) {
break;
}
}
}
}
return sb.toString();
}
return "";
}
/*
* ******************************************************************
* ******************************************************************
*
* private methods
*
* ******************************************************************
* ******************************************************************
*/
public void setAddr822Comment(final int commentnumber, final String comment) {
Key key = null;
switch (commentnumber) {
case 1:
key = Key.Comment1;
break;
case 2:
key = Key.Comment2;
break;
case 3:
key = Key.Comment3;
break;
default:
return;
}
this.put(key, comment);
}
public static Pattern PARENS_MATCH = Pattern.compile("\\(.+?\\)");
public static Pattern INPARENS_MATCH = Pattern.compile("/\\(([^()]+)\\)");
/**
* Retrieves and sets the various content values by parsing an input source string.
*
* @param string
* String from which to parse the content values.
*/
private void parse(final String string) {
if (!ISO.isBlankString(string)) {
final Matcher matcher = ISO.PatternRFC822.matcher(string);
if (matcher.matches()) {
/*
* test matches anytext<anytext>anytext
*
* get the three primary chunks as
* phrase<internetaddress>comments from the source
*/
final int idxLT = string.indexOf('<');
final int idxGT = string.indexOf('>', idxLT);
// parse the phrase part
final String phrase = (idxLT > 0) ? string.substring(0, idxLT).trim() : "";
if (phrase.length() > 0) {
this.put(Key.Phrase, phrase.replaceAll("\"", "").trim());
}
// parse the internetaddress part
final String internetaddress = (idxGT > (idxLT + 1)) ? string.substring(idxLT + 1, idxGT).trim() : "";
if ((internetaddress.length() > 0) && (internetaddress.indexOf('@') >= 0)) {
final String[] chunks = internetaddress.split("@");
if (null != chunks) {
if (null != chunks[0]) {
this.put(Key.Local, chunks[0].trim());
if ((2 <= chunks.length) && (null != chunks[1])) {
this.put(Key.Domain, chunks[1].trim());
}
}
}
}
// parse the comments part
final String comments = (idxGT < string.length()) ? string.substring(idxGT).trim() : "";
if (comments.length() > 0) {
if (!comments.startsWith("(")) {
this.setAddr822Comment(1, comments.replaceAll("\\(", " ").replaceAll("\\)", " ").trim());
} else {
final String[] commentSet = RFC822name.INPARENS_MATCH.split(comments);
for (int i = 0; i < commentSet.length; i++) {
if (i < 3) {
this.setAddr822Comment(i + 1, commentSet[i]);
} else {
break;
}
}
}
}
}
}
}
}