package rocks.inspectit.agent.java.util;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provides methods for string manipulation purposes as cropping a string to a specified
* length.
*
* @author Patrick Eschenbach
*/
public class StringConstraint {
/**
* The logger of this class. Initialized manually.
*/
private static final Logger LOG = LoggerFactory.getLogger(StringConstraint.class);
/**
* Boolean indicating whether to use three trailing dots or not.
*/
private static final boolean USE_TRAILING_DOTS = true;
/**
* Global definition of the maximal string length.
*/
private static final int MAX_STRING_LENGTH = Integer.MAX_VALUE;
/**
* The effective string length which is defined as the smaller one of the sensor's configuration
* or MAX_STRING_LENGTH.
*/
private int effectiveStringLength;
/**
* The default constructor which needs one parameter for initialization.
*
* @param parameter
* Parameter map to extract the constrain information.
*/
public StringConstraint(Map<String, Object> parameter) {
effectiveStringLength = MAX_STRING_LENGTH;
String value = (String) parameter.get("stringLength");
if (value != null) {
try {
int configStringLength = Integer.parseInt(value);
// only use the given length if smaller than the max length and not smaller than 0
if ((configStringLength < MAX_STRING_LENGTH) && (configStringLength >= 0)) {
effectiveStringLength = configStringLength;
}
} catch (NumberFormatException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Property 'stringLength' is not defined correctly. Using unlimited string length.");
}
}
}
}
/**
* Crops the given string based on this instance's configuration. If the string is shorter than
* the specified string length the given string is not altered.
*
* @param string
* The string to crop.
* @return The cropped string.
*/
public String crop(String string) {
if ((null == string) || (string.length() <= effectiveStringLength)) {
return string;
}
if (effectiveStringLength == 0) {
return "";
}
String cropped = string.substring(0, effectiveStringLength);
if (USE_TRAILING_DOTS) {
cropped = appendTrailingDots(cropped);
}
return cropped;
}
/**
* Analyzes the given map and tries to re-use the values in String arrays and the string arrays
* themself to converse memory. A new String array for values is only created if one entry in
* the values needed cropping to ensure that the original map is not changed.
*
* @param original
* the Map<String, String[]> that potentially needs cropping
* @return a new Map<String, String[]> that contains cropped Strings that potentially re-use the
* String references of the initial Map if the Strings did not change.
*/
public Map<String, String[]> crop(final Map<String, String[]> original) {
Map<String, String[]> result = new HashMap<String, String[]>(original.size());
for (Map.Entry<String, String[]> entry : original.entrySet()) {
String key = entry.getKey();
if (null == key) {
continue;
}
String[] value = entry.getValue();
String[] convertedValue;
if (null == value) {
convertedValue = new String[1];
convertedValue[0] = "<notset>";
} else {
boolean croppingWasNeeded = false;
convertedValue = value;
for (int i = 0, l = value.length; i < l; i++) {
String curValue = value[i];
String croppingResult = crop(curValue);
// Identity comparison is on purpose
if ((curValue != croppingResult) & !croppingWasNeeded) { // NOPMD
// The string reference was changed and thus cropped
croppingWasNeeded = true;
// we need to change to an own array as we cannot reuse the
// existing array as we would change strings of the application
convertedValue = new String[value.length];
System.arraycopy(value, 0, convertedValue, 0, i);
// and add the one we are currently dealing with
convertedValue[i] = croppingResult;
}
if (croppingWasNeeded) {
// we already have a copied array so we can add to this.
convertedValue[i] = croppingResult;
}
// if we do not find anything that needed cropping we just re-use
// the old representation.
}
}
result.put(key, convertedValue);
}
return result;
}
/**
* Crops the given string and adds the given final character to the string's end. If the string
* is shorter than the specified string length the given string is not altered.
*
* @param string
* The string to crop.
* @param finalChar
* The character to append at the end.
* @return A cropped string ending with the given final character.
*/
public String cropKeepFinalCharacter(String string, char finalChar) {
String cropped = crop(string);
if ((null == string) || string.equals(cropped)) {
return string;
}
if (cropped.length() == 0) {
return cropped;
}
return cropped + finalChar;
}
/**
* Appends three dots to the given string to indicate that the string was cropped.
*
* @param string
* The string to append the dots to.
* @return A new string equal to the given one + three dots.
*/
private String appendTrailingDots(String string) {
return string + "...";
}
}