package com.icentris.util;
import java.text.ParseException;
import javax.swing.text.MaskFormatter;
import org.apache.commons.lang.StringUtils;
/**
* This class was designed as a light-weight wrapper for
* javax.swing.text.MaskFormatter's valueToString() method. It takes a String, a
* phone number from a database for example, and applies a mask to it. If, for
* instance, your mask was (###) ###-#### and your input was 8019931070 the
* mask() method would return (801) 550-9713. It can also account for foreign
* characters and even letters in the case of this type of mask. Using the same
* mask previously mentioned, the input 801.993-1070 would be returned as (801)
* 993-1070.
*
* The inspiration for this came from the need to present data the same to users
* on the front end no matter how it was given to us from the DB. Some systems
* provide numerous different types of formats, many being rather unattractive
* and difficult to read. This class hopes to give the user a consistent format
* for masked numbers.
*
* All the work of masking is taken care of by MaskFormatter. The purpose for
* this class is to prepare the String for MaskFormatter to be able to digest.
* MaskFormatter, sadly, cannot handle an all number mask with letters or other
* characters in it. My second example above would throw an exception. This
* class attempts to clean out those kinds of characters based on the mask
* given.
*
* This class is far from robust. It does a great job for simple masks like
* phone numbers and social security numbers. As for things that are more
* complex such as masks that require numbers and letters, you're on your own.
* Try it, and if it doesn't work the way you'd hoped, please take the time to
* improve this class and make it that much more robust.
*
* Also, at this time I would NOT recommend using this class to format dates.
* This needs to be thought out better.
*
* @author Spencer Mefford
*
*/
public class StringMasker {
private String mask = null;
private String value = null;
private String parsedValue = null;
/**
* Constructs a StringMasker.
*
* @param mask
* Something like "(###) ###-####".
* @param value
* Value to be formatted.
*/
public StringMasker(String mask, String value) {
this.setMask(mask);
this.setValue(value);
this.setParsedValue(this.parseValue());
}
/**
* Attempts to strip out characters that do not belong (ie. special
* characters).
*
* @return A clean String ready to be masked.
*/
private String parseValue() {
String pv = this.getValue();
String m = this.getMask();
if(pv != null && m != null) {
// Remove all white-space
pv = pv.replaceAll("\\s", "");
// Remove all non-word characters
pv = pv.replaceAll("\\W", "");
// Don't remove numbers if they're included in the mask
if(!m.contains("#") && !m.contains("A")) {
pv = pv.replaceAll("[0-9]+", "");
}
// Don't remove uppercase letters if they're included in the mask
if(!m.contains("U") && !m.contains("A") && !m.contains("?")) {
pv = pv.replaceAll("[A-Z]", "");
}
// Don't remove lowercase letters if they're included in the mask
if(!m.contains("L") && !m.contains("A") && !m.contains("?")) {
pv = pv.replaceAll("[a-z]", "");
}
}
return pv;
}
/**
* Performs the mask using Java's MaskFormatter.
*
* @return The masked String.
*/
public String mask() {
String maskedValue = "";
String pv = this.getParsedValue();
String m = this.getMask();
if( !StringUtils.isEmpty( pv ) && m != null) {
try {
MaskFormatter mf = new MaskFormatter(m);
mf.setValueContainsLiteralCharacters(false);
maskedValue = mf.valueToString(pv);
if(maskedValue != null) {
// MaskFormatter leaves extra white space if it's too short, not good
// for our purposes
maskedValue = maskedValue.trim();
}
} catch(ParseException e) {
// If I cannot mask the value, I will send it back as it came in
maskedValue = this.getValue();
}
} else {
maskedValue = "";
}
return maskedValue;
}
/**
* Returns a masked String to its most basic, unmasked form. Nice for use in
* save and update actions so that data sent to the database is cleaned of
* formatting.
*
* @return The unmasked String.
*/
public String unmask() {
String unmaskedValue = "";
String v = this.getValue();
String m = this.getMask();
if(v != null && m != null) {
try {
MaskFormatter mf = new MaskFormatter(m);
mf.setValueContainsLiteralCharacters(false);
unmaskedValue = (String) mf.stringToValue(v);
if(unmaskedValue != null) {
// MaskFormatter leaves extra white space if it's too short, not good
// for our purposes
unmaskedValue = unmaskedValue.trim();
}
} catch(ParseException e) {
// If I cannot unmask the value, I will send it back as it came in
unmaskedValue = this.getParsedValue();
}
} else {
unmaskedValue = null;
}
return unmaskedValue;
}
public String getMask() {
return this.mask;
}
public void setMask(String mask) {
this.mask = mask;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public String getParsedValue() {
return parsedValue;
}
public void setParsedValue(String parsedValue) {
this.parsedValue = parsedValue;
}
}