T[] nonNull(T[] array, Class> theClass) {
return array == null ? ((T[])Array.newInstance(theClass, 0)) : array;
}
/**
* get the prefix or suffix of a string based on a separator
*
* @param startString
* is the string to start with
* @param separator
* is the separator to split on
* @param isPrefix
* if thre prefix or suffix should be returned
*
* @return the prefix or suffix, if the separator isnt there, return the
* original string
*/
public static String prefixOrSuffix(String startString, String separator,
boolean isPrefix) {
String prefixOrSuffix = null;
//no nulls
if (startString == null) {
return startString;
}
//where is the separator
int separatorIndex = startString.indexOf(separator);
//if none exists, dont proceed
if (separatorIndex == -1) {
return startString;
}
//maybe the separator isnt on character
int separatorLength = separator.length();
if (isPrefix) {
prefixOrSuffix = startString.substring(0, separatorIndex);
} else {
prefixOrSuffix = startString.substring(separatorIndex + separatorLength,
startString.length());
}
return prefixOrSuffix;
}
/**
*
* this method will indent xml or json.
* this is for logging or documentations purposes only and should
* not be used for a production use (since it is not 100% tested
* or compliant with all constructs like xml CDATA
*
* For xml, assumes elements either have text or sub elements, not both.
* No cdata, nothing fancy.
*
* If the input is <a><b><c>hey</c><d><e>there</e></d></b></a>
* It would output:
* <a>
* <b>
* <c>hey</c>
* <d>
* <e>there</e>
* </d>
* </b>
* </a>
*
* For json, if the input is: {"a":{"b\"b":{"c\\":"d"},"e":"f","g":["h":"i"]}}
* It would output:
* {
* "a":{
* "b\"b":{
* "c\\":"d"
* },
* "e":"f",
* "g":[
* "h":"i"
* ]
* }
* }
*
*
*
* @param string
* @param failIfTypeNotFound
* @return the indented string, 2 spaces per line
*/
public static String indent(String string, boolean failIfTypeNotFound) {
if (string == null) {
return null;
}
string = trim(string);
if (string.startsWith("<")) {
//this is xml
return new XmlIndenter(string).result();
}
if (!failIfTypeNotFound) {
//just return if cant indent
return string;
}
throw new RuntimeException("Cant find type of string: " + string);
}
/**
* get the extension from name. if name is a:b:c, name is c
* @param name
* @return the name
*/
public static String extensionFromName(String name) {
if (isBlank(name)) {
return name;
}
int lastColonIndex = name.lastIndexOf(':');
if (lastColonIndex == -1) {
return name;
}
String extension = name.substring(lastColonIndex+1);
return extension;
}
/**
* Returns the class object.
* @param origClassName is fully qualified
* @return the class
*/
public static Class forName(String origClassName) {
try {
return Class.forName(origClassName);
} catch (Throwable t) {
throw new RuntimeException("Problem loading class: " + origClassName, t);
}
}
/**
* Construct a class
* @param template type
* @param theClass
* @return the instance
*/
public static T newInstance(Class theClass) {
try {
return theClass.newInstance();
} catch (Throwable e) {
if (theClass != null && Modifier.isAbstract(theClass.getModifiers())) {
throw new RuntimeException("Problem with class: " + theClass + ", maybe because it is abstract!", e);
}
throw new RuntimeException("Problem with class: " + theClass, e);
}
}
/**
* get the parent stem name from name. if already a root stem
* then just return null. e.g. if the name is a:b:c then
* the return value is a:b
* @param name
* @return the parent stem name or null if none
*/
public static String parentStemNameFromName(String name) {
int lastColonIndex = name.lastIndexOf(':');
if (lastColonIndex == -1) {
return null;
}
String parentStemName = name.substring(0,lastColonIndex);
return parentStemName;
}
/**
* return the string or the other if the first is blank
* @param string
* @param defaultStringIfBlank
* @return the string or the default one
*/
public static String defaultIfBlank(String string, String defaultStringIfBlank) {
return isBlank(string) ? defaultStringIfBlank : string;
}
/**
* genericized method to see if first is null, if so then return second, else first.
* @param
* @param theValue first input
* @param defaultIfTheValueIsNull second input
* @return the first if not null, second if no
*/
public static T defaultIfNull(T theValue, T defaultIfTheValueIsNull) {
return theValue != null ? theValue : defaultIfTheValueIsNull;
}
/**
* add each element of listToAdd if it is not already in list
* @param
* @param list to add to
* @param listToAdd each element will be added to list, or null if none
*/
public static void addIfNotThere(Collection list, Collection listToAdd) {
//maybe nothing to do
if (listToAdd == null) {
return;
}
for (T t : listToAdd) {
if (!list.contains(t)) {
list.add(t);
}
}
}
/**
* print out various types of objects
*
* @param object
* @param maxChars is where it should stop when figuring out object. note, result might be longer than max...
* need to abbreviate when back
* @param result is where to append to
*/
@SuppressWarnings("unchecked")
private static void toStringForLogHelper(Object object, int maxChars, StringBuilder result) {
try {
if (object == null) {
result.append("null");
} else if (object.getClass().isArray()) {
// handle arrays
int length = Array.getLength(object);
if (length == 0) {
result.append("Empty array");
} else {
result.append("Array size: ").append(length).append(": ");
for (int i = 0; i < length; i++) {
result.append("[").append(i).append("]: ").append(
Array.get(object, i)).append("\n");
if (maxChars != -1 && result.length() > maxChars) {
return;
}
}
}
} else if (object instanceof Collection) {
//give size and type if collection
Collection collection = (Collection) object;
int collectionSize = collection.size();
if (collectionSize == 0) {
result.append("Empty ").append(object.getClass().getSimpleName());
} else {
result.append(object.getClass().getSimpleName()).append(" size: ").append(collectionSize).append(": ");
int i=0;
for (Object collectionObject : collection) {
result.append("[").append(i).append("]: ").append(
collectionObject).append("\n");
if (maxChars != -1 && result.length() > maxChars) {
return;
}
i++;
}
}
} else {
result.append(object.toString());
}
} catch (Exception e) {
result.append("<> ").append(object.getClass()).append(":\n")
.append(getFullStackTrace(e)).append("\n");
}
}
/**
* convert a set to a string (comma separate)
* @param set
* @return the String
*/
public static String setToString(Set set) {
if (set == null) {
return "null";
}
if (set.size() == 0) {
return "empty";
}
StringBuilder result = new StringBuilder();
boolean first = true;
for (Object object : set) {
if (!first) {
result.append(", ");
}
first = false;
result.append(object);
}
return result.toString();
}
/**
* convert a set to a string (comma separate)
* @param map
* @return the String
* @deprecated use mapToString(map)
*/
@Deprecated
public static String MapToString(Map map) {
return mapToString(map);
}
/**
* convert a set to a string (comma separate)
* @param map
* @return the String
*/
public static String mapToString(Map map) {
if (map == null) {
return "null";
}
if (map.size() == 0) {
return "empty";
}
StringBuilder result = new StringBuilder();
boolean first = true;
for (Object object : map.keySet()) {
if (!first) {
result.append(", ");
}
first = false;
result.append(object).append(": ").append(map.get(object));
}
return result.toString();
}
/**
* print out various types of objects
*
* @param object
* @return the string value
*/
public static String toStringForLog(Object object) {
StringBuilder result = new StringBuilder();
toStringForLogHelper(object, -1, result);
return result.toString();
}
/**
* print out various types of objects
*
* @param object
* @param maxChars is the max chars that should be returned (abbreviate if longer), or -1 for any amount
* @return the string value
*/
public static String toStringForLog(Object object, int maxChars) {
StringBuilder result = new StringBuilder();
toStringForLogHelper(object, -1, result);
String resultString = result.toString();
if (maxChars != -1) {
return abbreviate(resultString, maxChars);
}
return resultString;
}
/**
* If batching this is the number of batches
* @param count is size of set
* @param batchSize
* @return the number of batches
*/
public static int batchNumberOfBatches(int count, int batchSize) {
int batches = 1 + ((count - 1) / batchSize);
return batches;
}
/**
* If batching this is the number of batches
* @param collection
* @param batchSize
* @return the number of batches
*/
public static int batchNumberOfBatches(Collection> collection, int batchSize) {
int arrraySize = length(collection);
return batchNumberOfBatches(arrraySize, batchSize);
}
/**
* retrieve a batch by 0 index. Will return an array of size batchSize or
* the remainder. the array will be full of elements. Note, this requires an
* ordered input (so use linkedhashset not hashset if doing sets)
* @param template type
* @param collection
* @param batchSize
* @param batchIndex
* @return the list
* This never returns null, only empty list
*/
@SuppressWarnings("unchecked")
public static List batchList(Collection collection, int batchSize,
int batchIndex) {
int numberOfBatches = batchNumberOfBatches(collection, batchSize);
int arraySize = length(collection);
// short circuit
if (arraySize == 0) {
return new ArrayList();
}
List theBatchObjects = new ArrayList();
// lets get the type of the first element if possible
// Object first = get(arrayOrCollection, 0);
//
// Class theType = first == null ? Object.class : first.getClass();
// if last batch
if (batchIndex == numberOfBatches - 1) {
// needs to work to 1-n
//int thisBatchSize = 1 + ((arraySize - 1) % batchSize);
int collectionIndex = 0;
for (T t : collection) {
if (collectionIndex++ < batchIndex * batchSize) {
continue;
}
//just copy the rest
//if (collectionIndex >= (batchIndex * batchSize) + arraySize) {
// break;
//}
//we are in the copy mode
theBatchObjects.add(t);
}
} else {
// if non-last batch
//int newIndex = 0;
int collectionIndex = 0;
for (T t : collection) {
if (collectionIndex < batchIndex * batchSize) {
collectionIndex++;
continue;
}
//done with batch
if (collectionIndex >= (batchIndex + 1) * batchSize) {
break;
}
theBatchObjects.add(t);
collectionIndex++;
}
}
return theBatchObjects;
}
/**
* trim the end of a string
* @param text
* @return the string
*/
public static String trimEnd(String text) {
if (text == null) {
return null;
}
//replace any whitespace at the end of the string
return text.replaceFirst("\\s+$", "");
}
/**
* split a string based on a separator into an array, and trim each entry (see
* the Commons Util trim() for more details)
*
* @param input
* is the delimited input to split and trim
* @param separator
* is what to split on
*
* @return the array of items after split and trimmed, or null if input is null. will be trimmed to empty
*/
public static String[] splitTrim(String input, String separator) {
return splitTrim(input, separator, true);
}
/**
* split a string based on a separator into an array, and trim each entry (see
* the Commons Util trim() for more details)
*
* @param input
* is the delimited input to split and trim
* @param separator
* is what to split on
*
* @return the list of items after split and trimmed, or null if input is null. will be trimmed to empty
*/
public static List splitTrimToList(String input, String separator) {
if (isBlank(input)) {
return null;
}
String[] array = splitTrim(input, separator);
return toList(array);
}
/**
* split a string based on a separator into an array, and trim each entry (see
* the Commons Util trim() for more details)
*
* @param input
* is the delimited input to split and trim
* @param separator
* is what to split on
* @param treatAdjacentSeparatorsAsOne
* @return the array of items after split and trimmed, or null if input is null. will be trimmed to empty
*/
public static String[] splitTrim(String input, String separator, boolean treatAdjacentSeparatorsAsOne) {
if (isBlank(input)) {
return null;
}
//first split
String[] items = treatAdjacentSeparatorsAsOne ? split(input, separator) :
splitPreserveAllTokens(input, separator);
//then trim
for (int i = 0; (items != null) && (i < items.length); i++) {
items[i] = trim(items[i]);
}
//return the array
return items;
}
/**
* escape url chars (e.g. a # is %23)
* @param string input
* @return the encoded string
*/
public static String escapeUrlEncode(String string) {
String result = null;
try {
result = URLEncoder.encode(string, "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("UTF-8 not supported", ex);
}
return result;
}
/**
* unescape url chars (e.g. a space is %20)
* @param string input
* @return the encoded string
*/
public static String escapeUrlDecode(String string) {
String result = null;
try {
result = URLDecoder.decode(string, "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("UTF-8 not supported", ex);
}
return result;
}
/**
* make sure a list is non null. If null, then return an empty list
* @param
* @param list
* @return the list or empty list if null
*/
public static List nonNull(List list) {
return list == null ? new ArrayList() : list;
}
/**
* make sure a list is non null. If null, then return an empty set
* @param
* @param set
* @return the set or empty set if null
*/
public static Set nonNull(Set set) {
return set == null ? new HashSet() : set;
}
/**
* make sure it is non null, if null, then give new map
*
* @param key of map
* @param value of map
* @param map is map
* @return set non null
*/
public static Map nonNull(Map map) {
return map == null ? new HashMap() : map;
}
/**
* return a list of objects from varargs. Though if there is one
* object, and it is a list, return it.
*
* @param
* template type of the objects
* @param objects
* @return the list or null if objects is null
*/
@SuppressWarnings("unchecked")
public static List toList(T... objects) {
if (objects == null) {
return null;
}
if (objects.length == 1 && objects[0] instanceof List) {
return (List)objects[0];
}
List result = new ArrayList();
for (T object : objects) {
result.add(object);
}
return result;
}
/**
* convert classes to a list
* @param classes
* @return list of classes
*/
public static List> toListClasses(Class>... classes) {
return toList(classes);
}
/**
* return a set of objects from varargs.
*
* @param template type of the objects
* @param objects
* @return the set
*/
public static Set toSet(T... objects) {
Set result = new LinkedHashSet();
for (T object : objects) {
result.add(object);
}
return result;
}
/**
* cache separator
*/
private static final String CACHE_SEPARATOR = "__";
/**
* string format of dates
*/
public static final String DATE_FORMAT = "yyyyMMdd";
/**
* format including minutes and seconds: yyyy/MM/dd HH:mm:ss
*/
public static final String DATE_MINUTES_SECONDS_FORMAT = "yyyy/MM/dd HH:mm:ss";
/**
* format including minutes and seconds: yyyyMMdd HH:mm:ss
*/
public static final String DATE_MINUTES_SECONDS_NO_SLASH_FORMAT = "yyyyMMdd HH:mm:ss";
/**
* format on screen of config for milestone: yyyy/MM/dd HH:mm:ss.SSS
*/
public static final String TIMESTAMP_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS";
/**
* format on screen of config for milestone: yyyyMMdd HH:mm:ss.SSS
*/
public static final String TIMESTAMP_NO_SLASH_FORMAT = "yyyyMMdd HH:mm:ss.SSS";
/**
* date format, make sure to synchronize
*/
final static SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
/**
* synchronize code that uses this standard formatter for dates with minutes and seconds
*/
public final static SimpleDateFormat dateMinutesSecondsFormat = new SimpleDateFormat(
DATE_MINUTES_SECONDS_FORMAT);
/**
* synchronize code that uses this standard formatter for dates with minutes and seconds
*/
final static SimpleDateFormat dateMinutesSecondsNoSlashFormat = new SimpleDateFormat(
DATE_MINUTES_SECONDS_NO_SLASH_FORMAT);
/**
* format: yyyy/MM/dd HH:mm:ss.SSS synchronize code that uses this standard formatter for timestamps
*/
final static SimpleDateFormat timestampFormat = new SimpleDateFormat(TIMESTAMP_FORMAT);
/**
* synchronize code that uses this standard formatter for timestamps
*/
final static SimpleDateFormat timestampNoSlashFormat = new SimpleDateFormat(
TIMESTAMP_NO_SLASH_FORMAT);
/**
* If false, throw an assertException, and give a reason
*
* @param isTrue
* @param reason
*/
public static void assertion(boolean isTrue, String reason) {
if (!isTrue) {
throw new RuntimeException(reason);
}
}
/**
* use the field cache, expire every day (just to be sure no leaks)
*/
private static ExpirableCache> fieldSetCache = null;
/**
* lazy load
* @return field set cache
*/
private static ExpirableCache> fieldSetCache() {
if (fieldSetCache == null) {
fieldSetCache = new ExpirableCache>(60*24);
}
return fieldSetCache;
}
/**
* make a cache with max size to cache declared methods
*/
private static ExpirableCache declaredMethodsCache = null;
/**
* lazy load
* @return declared method cache
*/
private static ExpirableCache declaredMethodsCache() {
if (declaredMethodsCache == null) {
declaredMethodsCache = new ExpirableCache(60*24);
}
return declaredMethodsCache;
}
/**
* use the field cache, expire every day (just to be sure no leaks)
*/
private static ExpirableCache> getterSetCache = null;
/**
* lazy load
* @return getter cache
*/
private static ExpirableCache> getterSetCache() {
if (getterSetCache == null) {
getterSetCache = new ExpirableCache>(60*24);
}
return getterSetCache;
}
/**
* use the field cache, expire every day (just to be sure no leaks)
*/
private static ExpirableCache> setterSetCache = null;
/**
* lazy load
* @return setter cache
*/
private static ExpirableCache> setterSetCache() {
if (setterSetCache == null) {
setterSetCache = new ExpirableCache>(60*24);
}
return setterSetCache;
}
/**
* Field lastId.
*/
private static char[] lastId = convertLongToStringSmall(new Date().getTime())
.toCharArray();
/**
* cache the properties read from resource
*/
private static Map resourcePropertiesCache = new HashMap();
/**
* assign data to a field
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param fieldName
* method name to call
* @param dataToAssign
* data
* @param callOnSupers
* if static and method not exists, try on supers
* @param overrideSecurity
* true to call on protected or private etc methods
* @param typeCast
* true if we should typecast
* @param annotationWithValueOverride
* annotation with value of override
*/
public static void assignField(Class theClass, Object invokeOn,
String fieldName, Object dataToAssign, boolean callOnSupers,
boolean overrideSecurity, boolean typeCast,
Class extends Annotation> annotationWithValueOverride) {
if (theClass == null && invokeOn != null) {
theClass = invokeOn.getClass();
}
Field field = field(theClass, fieldName, callOnSupers, true);
assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast,
annotationWithValueOverride);
}
/**
* assign data to a field. Will find the field in superclasses, will
* typecast, and will override security (private, protected, etc)
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param fieldName
* method name to call
* @param dataToAssign
* data
* @param annotationWithValueOverride
* annotation with value of override
*/
public static void assignField(Class theClass, Object invokeOn,
String fieldName, Object dataToAssign,
Class extends Annotation> annotationWithValueOverride) {
assignField(theClass, invokeOn, fieldName, dataToAssign, true, true,
true, annotationWithValueOverride);
}
/**
* assign data to a field
*
* @param field
* is the field to assign to
* @param invokeOn
* to call on or null for static
* @param dataToAssign
* data
* @param overrideSecurity
* true to call on protected or private etc methods
* @param typeCast
* true if we should typecast
*/
@SuppressWarnings("unchecked")
public static void assignField(Field field, Object invokeOn,
Object dataToAssign, boolean overrideSecurity, boolean typeCast) {
try {
Class fieldType = field.getType();
// typecast
if (typeCast) {
dataToAssign =
typeCast(dataToAssign, fieldType,
true, true);
}
if (overrideSecurity) {
field.setAccessible(true);
}
field.set(invokeOn, dataToAssign);
} catch (Exception e) {
throw new RuntimeException("Cant assign reflection field: "
+ (field == null ? null : field.getName()) + ", on: "
+ className(invokeOn) + ", with args: "
+ classNameCollection(dataToAssign), e);
}
}
/**
* null safe iterator getter if the type if collection
*
* @param collection
* @return the iterator
*/
public static Iterator iterator(Object collection) {
if (collection == null) {
return null;
}
// array list doesnt need an iterator
if (collection instanceof Collection
&& !(collection instanceof ArrayList)) {
return ((Collection) collection).iterator();
}
return null;
}
/**
* Null safe array length or map
*
* @param arrayOrCollection
* @return the length of the array (0 for null)
*/
public static int length(Object arrayOrCollection) {
if (arrayOrCollection == null) {
return 0;
}
if (arrayOrCollection.getClass().isArray()) {
return Array.getLength(arrayOrCollection);
}
if (arrayOrCollection instanceof Collection) {
return ((Collection) arrayOrCollection).size();
}
if (arrayOrCollection instanceof Map) {
return ((Map) arrayOrCollection).size();
}
// simple non array non collection object
return 1;
}
/**
* If array, get the element based on index, if Collection, get it based on
* iterator.
*
* @param arrayOrCollection
* @param iterator
* @param index
* @return the object
*/
public static Object next(Object arrayOrCollection, Iterator iterator,
int index) {
if (arrayOrCollection.getClass().isArray()) {
return Array.get(arrayOrCollection, index);
}
if (arrayOrCollection instanceof ArrayList) {
return ((ArrayList) arrayOrCollection).get(index);
}
if (arrayOrCollection instanceof Collection) {
return iterator.next();
}
// simple object
if (0 == index) {
return arrayOrCollection;
}
throw new RuntimeException("Invalid class type: "
+ arrayOrCollection.getClass().getName());
}
/**
* Remove the iterator or index
*
* @param arrayOrCollection
* @param index
* @return the object list or new array
*/
public static Object remove(Object arrayOrCollection,
int index) {
return remove(arrayOrCollection, null, index);
}
/**
* Remove the iterator or index
*
* @param arrayOrCollection
* @param iterator
* @param index
* @return the object list or new array
*/
public static Object remove(Object arrayOrCollection, Iterator iterator,
int index) {
//if theres an iterator, just use that
if (iterator != null) {
iterator.remove();
return arrayOrCollection;
}
if (arrayOrCollection.getClass().isArray()) {
int newLength = Array.getLength(arrayOrCollection) - 1;
Object newArray = Array.newInstance(arrayOrCollection.getClass().getComponentType(), newLength);
if (newLength == 0) {
return newArray;
}
if (index > 0) {
System.arraycopy(arrayOrCollection, 0, newArray, 0, index);
}
if (index < newLength) {
System.arraycopy(arrayOrCollection, index+1, newArray, index, newLength - index);
}
return newArray;
}
if (arrayOrCollection instanceof List) {
((List)arrayOrCollection).remove(index);
return arrayOrCollection;
} else if (arrayOrCollection instanceof Collection) {
//this should work unless there are duplicates or something weird
((Collection)arrayOrCollection).remove(get(arrayOrCollection, index));
return arrayOrCollection;
}
throw new RuntimeException("Invalid class type: "
+ arrayOrCollection.getClass().getName());
}
/**
* print the simple names of a list of classes
* @param object
* @return the simple names
*/
public static String classesString(Object object) {
StringBuilder result = new StringBuilder();
if (object.getClass().isArray()) {
int length = Array.getLength(object);
for (int i=0;i annotationWithValueOverride) {
if (annotationWithValueOverride != null) {
// see if in annotation
Annotation annotation = field
.getAnnotation(annotationWithValueOverride);
if (annotation != null) {
// type of the value, or String if not specific Class
// typeOfAnnotationValue = typeCast ? field.getType() :
// String.class; dataToAssign =
// AnnotationUtils.retrieveAnnotationValue(
// typeOfAnnotationValue, annotation, "value");
throw new RuntimeException("Not supported");
}
}
assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast);
}
/**
* assign data to a field. Will find the field in superclasses, will
* typecast, and will override security (private, protected, etc)
*
* @param invokeOn
* to call on or null for static
* @param fieldName
* method name to call
* @param dataToAssign
* data
*/
public static void assignField(Object invokeOn, String fieldName,
Object dataToAssign) {
assignField(null, invokeOn, fieldName, dataToAssign, true, true, true,
null);
}
/**
* get a field object for a class, potentially in superclasses
*
* @param theClass
* @param fieldName
* @param callOnSupers
* true if superclasses should be looked in for the field
* @param throwExceptionIfNotFound
* will throw runtime exception if not found
* @return the field object or null if not found (or exception if param is
* set)
*/
public static Field field(Class theClass, String fieldName,
boolean callOnSupers, boolean throwExceptionIfNotFound) {
try {
Field field = theClass.getDeclaredField(fieldName);
// found it
return field;
} catch (NoSuchFieldException e) {
// if method not found
// if traversing up, and not Object, and not instance method
if (callOnSupers && !theClass.equals(Object.class)) {
return field(theClass.getSuperclass(), fieldName, callOnSupers,
throwExceptionIfNotFound);
}
}
// maybe throw an exception
if (throwExceptionIfNotFound) {
throw new RuntimeException("Cant find field: " + fieldName
+ ", in: " + theClass + ", callOnSupers: " + callOnSupers);
}
return null;
}
/**
* return a set of Strings for a class and type. This is not for any
* supertypes, only for the type at hand. includes final fields
*
* @param theClass
* @param fieldType
* or null for all
* @param includeStaticFields
* @return the set of strings, or the empty Set if none
*/
@SuppressWarnings("unchecked")
public static Set fieldNames(Class theClass, Class fieldType,
boolean includeStaticFields) {
return fieldNamesHelper(theClass, theClass, fieldType, true, true,
includeStaticFields, null, true);
}
/**
* get all field names from a class, including superclasses (if specified)
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* if final fields should be included
* @return the set of field names or empty set if none
*/
public static Set fieldNames(Class theClass,
Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt, boolean includeStaticFields,
boolean includeFinalFields) {
return fieldNamesHelper(theClass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, null, true);
}
/**
* get all field names from a class, including superclasses (if specified).
* ignore a certain marker annotation
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* if final fields should be included
* @param markerAnnotationToIngore
* if this is not null, then if the field has this annotation,
* then do not include in list
* @return the set of field names
*/
public static Set fieldNames(Class theClass,
Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt, boolean includeStaticFields,
boolean includeFinalFields,
Class extends Annotation> markerAnnotationToIngore) {
return fieldNamesHelper(theClass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, markerAnnotationToIngore, false);
}
/**
* get all field names from a class, including superclasses (if specified)
* (up to and including the specified superclass). ignore a certain marker
* annotation. Dont get static or final field, and get fields of all types
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param markerAnnotationToIngore
* if this is not null, then if the field has this annotation,
* then do not include in list
* @return the set of field names or empty set if none
*/
public static Set fieldNames(Class theClass,
Class superclassToStopAt,
Class extends Annotation> markerAnnotationToIngore) {
return fieldNamesHelper(theClass, superclassToStopAt, null, true,
false, false, markerAnnotationToIngore, false);
}
/**
* get all field names from a class, including superclasses (if specified)
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* true to include finals
* @param markerAnnotation
* if this is not null, then if the field has this annotation,
* then do not include in list (if includeAnnotation is false)
* @param includeAnnotation
* true if the attribute should be included if annotation is
* present, false if exclude
* @return the set of field names or empty set if none
*/
@SuppressWarnings("unchecked")
static Set fieldNamesHelper(Class theClass,
Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt, boolean includeStaticFields,
boolean includeFinalFields,
Class extends Annotation> markerAnnotation,
boolean includeAnnotation) {
Set fieldSet = fieldsHelper(theClass, superclassToStopAt,
fieldType, includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, markerAnnotation, includeAnnotation);
Set fieldNameSet = new LinkedHashSet();
for (Field field : fieldSet) {
fieldNameSet.add(field.getName());
}
return fieldNameSet;
}
/**
* get all fields from a class, including superclasses (if specified)
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* if final fields should be included
* @param markerAnnotation
* if this is not null, then if the field has this annotation,
* then do not include in list (if includeAnnotation is false)
* @param includeAnnotation
* true if the attribute should be included if annotation is
* present, false if exclude
* @return the set of fields (wont return null)
*/
@SuppressWarnings("unchecked")
public static Set fields(Class theClass, Class superclassToStopAt,
Class fieldType, boolean includeSuperclassToStopAt,
boolean includeStaticFields, boolean includeFinalFields,
Class extends Annotation> markerAnnotation,
boolean includeAnnotation) {
return fieldsHelper(theClass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, markerAnnotation, includeAnnotation);
}
/**
* get all fields from a class, including superclasses (if specified) (up to
* and including the specified superclass). ignore a certain marker
* annotation, or only include it. Dont get static or final field, and get
* fields of all types
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param markerAnnotation
* if this is not null, then if the field has this annotation,
* then do not include in list (if includeAnnotation is false)
* @param includeAnnotation
* true if the attribute should be included if annotation is
* present, false if exclude
* @return the set of field names or empty set if none
*/
@SuppressWarnings("unchecked")
public static Set fields(Class theClass, Class superclassToStopAt,
Class extends Annotation> markerAnnotation,
boolean includeAnnotation) {
return fieldsHelper(theClass, superclassToStopAt, null, true, false,
false, markerAnnotation, includeAnnotation);
}
/**
* get all fields from a class, including superclasses (if specified)
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* if final fields should be included
* @param markerAnnotation
* if this is not null, then if the field has this annotation,
* then do not include in list (if includeAnnotation is false)
* @param includeAnnotation
* true if the attribute should be included if annotation is
* present, false if exclude
* @return the set of fields (wont return null)
*/
@SuppressWarnings("unchecked")
static Set fieldsHelper(Class theClass, Class superclassToStopAt,
Class> fieldType, boolean includeSuperclassToStopAt,
boolean includeStaticFields, boolean includeFinalFields,
Class extends Annotation> markerAnnotation,
boolean includeAnnotation) {
// MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED!
Set fieldNameSet = null;
String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt
+ CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR
+ includeSuperclassToStopAt + CACHE_SEPARATOR
+ includeStaticFields + CACHE_SEPARATOR + includeFinalFields
+ CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR
+ includeAnnotation;
fieldNameSet = fieldSetCache().get(cacheKey);
if (fieldNameSet != null) {
return fieldNameSet;
}
fieldNameSet = new LinkedHashSet();
fieldsHelper(theClass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, markerAnnotation, fieldNameSet,
includeAnnotation);
// add to cache
fieldSetCache().put(cacheKey, fieldNameSet);
return fieldNameSet;
}
/**
* compare two objects, compare primitives, Strings, maps of string attributes.
* if both objects equal each others references, then return empty set.
* then, if not, then if either is null, return all fields
* @param first
* @param second
* @param fieldsToCompare
* @param mapPrefix is the prefix for maps which are compared (e.g. attribute__)
* @return the set of fields which are different. never returns null
*/
@SuppressWarnings("unchecked")
public static Set compareObjectFields(Object first, Object second,
Set fieldsToCompare, String mapPrefix) {
Set differentFields = new LinkedHashSet();
if (first == second) {
return differentFields;
}
//if either null, then all fields are different
if (first == null || second == null) {
differentFields.addAll(fieldsToCompare);
}
for (String fieldName : fieldsToCompare) {
try {
Object firstValue = fieldValue(first, fieldName);
Object secondValue = fieldValue(second, fieldName);
if (firstValue == secondValue) {
continue;
}
if (firstValue instanceof Map || secondValue instanceof Map) {
mapDifferences((Map)firstValue, (Map)secondValue, differentFields, mapPrefix);
continue;
}
//compare things...
//for strings, null is equal to empty
if (firstValue instanceof String || secondValue instanceof String) {
if (!equals(defaultString((String)firstValue),
defaultString((String)secondValue))) {
differentFields.add(fieldName);
}
continue;
}
//if one is null, that is not good
if (firstValue == null || secondValue == null) {
differentFields.add(fieldName);
continue;
}
//everything (numbers, dates, etc) should work with equals method...
if (!firstValue.equals(secondValue)) {
differentFields.add(fieldName);
continue;
}
} catch (RuntimeException re) {
throw new RuntimeException("Problem comparing field " + fieldName
+ " on objects: " + className(first) + ", " + className(second));
}
}
return differentFields;
}
/**
* clone an object, assign primitives, Strings, maps of string attributes. Clone GrouperCloneable fields.
* @param template
* @param object
* @param fieldsToClone
* @return the cloned object or null if input is null
*/
@SuppressWarnings("unchecked")
public static T clone(T object, Set fieldsToClone) {
//make a return object
T result = (T)newInstance(object.getClass());
cloneFields(object, result, fieldsToClone);
return result;
}
/**
* clone an object, assign primitives, Strings, maps of string attributes. Clone GrouperCloneable fields.
* @param template
* @param object
* @param result
* @param fieldsToClone
*/
public static void cloneFields(T object, T result,
Set fieldsToClone) {
if (object == result) {
return;
}
//if either null, then all fields are different
if (object == null || result == null) {
throw new RuntimeException("Cant copy from or to null: " + className(object) + ", " + className(result));
}
Class> fieldValueClass = null;
for (String fieldName : nonNull(fieldsToClone)) {
try {
Object fieldValue = fieldValue(object, fieldName);
fieldValueClass = fieldValue == null ? null : fieldValue.getClass();
Object fieldValueToAssign = cloneValue(fieldValue);
//assign the field to the clone
assignField(result, fieldName, fieldValueToAssign);
} catch (RuntimeException re) {
throw new RuntimeException("Problem cloning field: " + object.getClass()
+ ", " + fieldName + ", " + fieldValueClass, re);
}
}
}
/**
* helper method to clone the value of a field. just returns the same
* reference for primitives and immutables. Will subclone GrouperCloneables,
* and will throw exception if not expecting the type. Will clone sets, lists, maps.
* @param template
*
* @param value
* @return the cloned value
*/
@SuppressWarnings("unchecked")
public static T cloneValue(T value) {
Object clonedValue = value;
if (value == null || value instanceof String
|| value.getClass().isPrimitive() || value instanceof Number
|| value instanceof Boolean
|| value instanceof Date) {
//clone things
//for strings, and immutable classes, just assign
//nothing to do, just assign the value
} else if (value instanceof Map) {
clonedValue = new LinkedHashMap();
Map mapValue = (Map)value;
Map clonedMapValue = (Map)clonedValue;
for (Object key : mapValue.keySet()) {
clonedMapValue.put(cloneValue(key), cloneValue(mapValue.get(key)));
}
} else if (value instanceof Set) {
clonedValue = new LinkedHashSet();
Set setValue = (Set)value;
Set clonedSetValue = (Set)clonedValue;
for (Object each : setValue) {
clonedSetValue.add(cloneValue(each));
}
} else if (value instanceof List) {
clonedValue = new ArrayList();
List listValue = (List)value;
List clonedListValue = (List)clonedValue;
for (Object each : listValue) {
clonedListValue.add(cloneValue(each));
}
} else if (value.getClass().isArray()) {
clonedValue = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value));
for (int i=0;i methodNames(Class> theClass, Class> superclassToStopAt,
boolean includeSuperclassToStopAt, boolean includeStaticMethods) {
Set methods = new LinkedHashSet();
methodsHelper(theClass, superclassToStopAt, includeSuperclassToStopAt, includeStaticMethods,
null, false, methods);
Set methodNames = new HashSet();
for (Method method : methods) {
methodNames.add(method.getName());
}
return methodNames;
}
/**
* get the set of methods
* @param theClass
* @param superclassToStopAt
* @param includeSuperclassToStopAt
* @param includeStaticMethods
* @param markerAnnotation
* @param includeAnnotation
* @param methodSet
*/
public static void methodsHelper(Class> theClass, Class> superclassToStopAt,
boolean includeSuperclassToStopAt,
boolean includeStaticMethods, Class extends Annotation> markerAnnotation,
boolean includeAnnotation, Set methodSet) {
Method[] methods = theClass.getDeclaredMethods();
if (length(methods) != 0) {
for (Method method : methods) {
// if not static, then continue
if (!includeStaticMethods
&& Modifier.isStatic(method.getModifiers())) {
continue;
}
// if checking for annotation
if (markerAnnotation != null
&& (includeAnnotation != method
.isAnnotationPresent(markerAnnotation))) {
continue;
}
// go for it
methodSet.add(method);
}
}
// see if done recursing (if superclassToStopAt is null, then stop at
// Object
if (theClass.equals(superclassToStopAt)
|| theClass.equals(Object.class)) {
return;
}
Class superclass = theClass.getSuperclass();
if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) {
return;
}
// recurse
methodsHelper(superclass, superclassToStopAt,
includeSuperclassToStopAt, includeStaticMethods,
markerAnnotation, includeAnnotation, methodSet);
}
/**
* get the set of methods
* @param theClass
* @param methodName
* @param paramTypesOrArrayOrList
* types of the params
* @param superclassToStopAt
* @param includeSuperclassToStopAt
* @param isStaticOrInstance true if static
* @param markerAnnotation
* @param includeAnnotation
* @return the method or null if not found
*
*/
public static Method method(Class> theClass,
String methodName, Object paramTypesOrArrayOrList,
Class> superclassToStopAt,
boolean includeSuperclassToStopAt,
boolean isStaticOrInstance, Class extends Annotation> markerAnnotation,
boolean includeAnnotation) {
Class[] paramTypesArray = (Class[]) toArray(paramTypesOrArrayOrList);
Method method = null;
try {
method = theClass.getDeclaredMethod(methodName, paramTypesArray);
} catch (NoSuchMethodException nsme) {
//this is ok
} catch (Exception e) {
throw new RuntimeException("Problem retrieving method: " + theClass.getSimpleName() + ", " + methodName, e);
}
if (method != null) {
//we found a method, make sure it is valid
// if not static, then return null (dont worry about superclass)
if (!isStaticOrInstance
&& Modifier.isStatic(method.getModifiers())) {
return null;
}
// if checking for annotation, if not there, then recurse
if (markerAnnotation == null
|| (includeAnnotation == method
.isAnnotationPresent(markerAnnotation))) {
return method;
}
}
// see if done recursing (if superclassToStopAt is null, then stop at
// Object
if (theClass.equals(superclassToStopAt)
|| theClass.equals(Object.class)) {
return null;
}
Class superclass = theClass.getSuperclass();
if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) {
return null;
}
// recurse
return method(superclass, methodName, paramTypesArray, superclassToStopAt,
includeSuperclassToStopAt, isStaticOrInstance, markerAnnotation, includeAnnotation);
}
/**
* get all field names from a class, including superclasses (if specified)
*
* @param theClass
* to look for fields in
* @param superclassToStopAt
* to go up to or null to go up to Object
* @param fieldType
* is the type of the field to get
* @param includeSuperclassToStopAt
* if we should include the superclass
* @param includeStaticFields
* if include static fields
* @param includeFinalFields
* if final fields should be included
* @param markerAnnotation
* if this is not null, then if the field has this annotation,
* then do not include in list
* @param fieldSet
* set to add fields to
* @param includeAnnotation
* if include or exclude
*/
@SuppressWarnings("unchecked")
private static void fieldsHelper(Class theClass, Class superclassToStopAt,
Class> fieldType, boolean includeSuperclassToStopAt,
boolean includeStaticFields, boolean includeFinalFields,
Class extends Annotation> markerAnnotation, Set fieldSet,
boolean includeAnnotation) {
Field[] fields = theClass.getDeclaredFields();
if (length(fields) != 0) {
for (Field field : fields) {
// if checking for type, and not right type, continue
if (fieldType != null
&& !fieldType.isAssignableFrom(field.getType())) {
continue;
}
// if not static, then continue
if (!includeStaticFields
&& Modifier.isStatic(field.getModifiers())) {
continue;
}
// if not final constinue
if (!includeFinalFields
&& Modifier.isFinal(field.getModifiers())) {
continue;
}
// if checking for annotation
if (markerAnnotation != null
&& (includeAnnotation != field
.isAnnotationPresent(markerAnnotation))) {
continue;
}
// go for it
fieldSet.add(field);
}
}
// see if done recursing (if superclassToStopAt is null, then stop at
// Object
if (theClass.equals(superclassToStopAt)
|| theClass.equals(Object.class)) {
return;
}
Class superclass = theClass.getSuperclass();
if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) {
return;
}
// recurse
fieldsHelper(superclass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, includeStaticFields,
includeFinalFields, markerAnnotation, fieldSet,
includeAnnotation);
}
/**
* find out a field value
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param fieldName
* method name to call
* @param callOnSupers
* if static and method not exists, try on supers
* @param overrideSecurity
* true to call on protected or private etc methods
* @return the current value
*/
public static Object fieldValue(Class theClass, Object invokeOn,
String fieldName, boolean callOnSupers, boolean overrideSecurity) {
Field field = null;
// only if the method exists, try to execute
try {
// ok if null
if (theClass == null) {
theClass = invokeOn.getClass();
}
field = field(theClass, fieldName, callOnSupers, true);
return fieldValue(field, invokeOn, overrideSecurity);
} catch (Exception e) {
throw new RuntimeException("Cant execute reflection field: "
+ fieldName + ", on: " + className(invokeOn), e);
}
}
/**
* get the value of a field, override security if needbe
*
* @param field
* @param invokeOn
* @return the value of the field
*/
public static Object fieldValue(Field field, Object invokeOn) {
return fieldValue(field, invokeOn, true);
}
/**
* get the value of a field
*
* @param field
* @param invokeOn
* @param overrideSecurity
* @return the value of the field
*/
public static Object fieldValue(Field field, Object invokeOn,
boolean overrideSecurity) {
if (overrideSecurity) {
field.setAccessible(true);
}
try {
return field.get(invokeOn);
} catch (Exception e) {
throw new RuntimeException("Cant execute reflection field: "
+ field.getName() + ", on: " + className(invokeOn), e);
}
}
/**
* find out a field value (invoke on supers, override security)
*
* @param invokeOn
* to call on or null for static
* @param fieldName
* method name to call
* @return the current value
*/
public static Object fieldValue(Object invokeOn, String fieldName) {
return fieldValue(null, invokeOn, fieldName, true, true);
}
/**
* get the decalred methods for a class, perhaps from cache
*
* @param theClass
* @return the declared methods
*/
@SuppressWarnings("unused")
private static Method[] retrieveDeclaredMethods(Class theClass) {
Method[] methods = declaredMethodsCache().get(theClass);
// get from cache if we can
if (methods == null) {
methods = theClass.getDeclaredMethods();
declaredMethodsCache().put(theClass, methods);
}
return methods;
}
/**
* helper method for calling a method with no params (could be in
* superclass)
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param methodName
* method name to call
* @return the data
*/
public static Object callMethod(Class theClass, Object invokeOn,
String methodName) {
return callMethod(theClass, invokeOn, methodName, null, null);
}
/**
* helper method for calling a method (could be in superclass)
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param methodName
* method name to call
* @param paramTypesOrArrayOrList
* types of the params
* @param paramsOrListOrArray
* data
* @return the data
*/
public static Object callMethod(Class theClass, Object invokeOn,
String methodName, Object paramTypesOrArrayOrList,
Object paramsOrListOrArray) {
return callMethod(theClass, invokeOn, methodName,
paramTypesOrArrayOrList, paramsOrListOrArray, true);
}
/**
* helper method for calling a method
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param methodName
* method name to call
* @param paramTypesOrArrayOrList
* types of the params
* @param paramsOrListOrArray
* data
* @param callOnSupers
* if static and method not exists, try on supers
* @return the data
*/
public static Object callMethod(Class theClass, Object invokeOn,
String methodName, Object paramTypesOrArrayOrList,
Object paramsOrListOrArray, boolean callOnSupers) {
return callMethod(theClass, invokeOn, methodName,
paramTypesOrArrayOrList, paramsOrListOrArray, callOnSupers,
false);
}
/**
* construct an instance by reflection
* @param
* @param theClass
* @param args
* @param types
* @return the instance
*/
public static T construct(Class theClass, Class[] types, Object[] args) {
try {
Constructor constructor = theClass.getConstructor(types);
return constructor.newInstance(args);
} catch (Exception e) {
throw new RuntimeException("Having trouble with constructor for class: " + theClass.getSimpleName()
+ " and args: " + classesString(types), e);
}
}
/**
* helper method for calling a method
*
* @param theClass
* the class which has the method
* @param invokeOn
* to call on or null for static
* @param methodName
* method name to call
* @param paramTypesOrArrayOrList
* types of the params
* @param paramsOrListOrArray
* data
* @param callOnSupers
* if static and method not exists, try on supers
* @param overrideSecurity
* true to call on protected or private etc methods
* @return the data
*/
public static Object callMethod(Class theClass, Object invokeOn,
String methodName, Object paramTypesOrArrayOrList,
Object paramsOrListOrArray, boolean callOnSupers,
boolean overrideSecurity) {
Method method = null;
Class[] paramTypesArray = (Class[]) toArray(paramTypesOrArrayOrList);
try {
method = theClass.getDeclaredMethod(methodName, paramTypesArray);
if (overrideSecurity) {
method.setAccessible(true);
}
} catch (Exception e) {
// if method not found
if (e instanceof NoSuchMethodException) {
// if traversing up, and not Object, and not instance method
// CH 070425 not sure why invokeOn needs to be null, removing
// this
if (callOnSupers /* && invokeOn == null */
&& !theClass.equals(Object.class)) {
return callMethod(theClass.getSuperclass(), invokeOn,
methodName, paramTypesOrArrayOrList,
paramsOrListOrArray, callOnSupers, overrideSecurity);
}
}
throw new RuntimeException("Problem calling method " + methodName
+ " on " + theClass.getName(), e);
}
return invokeMethod(method, invokeOn, paramsOrListOrArray);
}
/** pass this in the invokeOn to signify no params */
private static final Object NO_PARAMS = new Object();
/**
* Safely invoke a reflection method that takes no args
*
* @param method
* to invoke
* @param invokeOn
* if NO_PARAMS then will not pass in params.
* @return the result
*/
public static Object invokeMethod(Method method, Object invokeOn) {
return invokeMethod(method, invokeOn, NO_PARAMS);
}
/**
* Safely invoke a reflection method
*
* @param method
* to invoke
* @param invokeOn
* @param paramsOrListOrArray must be an arg. If null, will pass null.
* if NO_PARAMS then will not pass in params.
* @return the result
*/
public static Object invokeMethod(Method method, Object invokeOn,
Object paramsOrListOrArray) {
Object[] args = paramsOrListOrArray == NO_PARAMS ? null : (Object[]) toArray(paramsOrListOrArray);
//we want to make sure things are accessible
method.setAccessible(true);
//only if the method exists, try to execute
Object result = null;
Exception e = null;
try {
result = method.invoke(invokeOn, args);
} catch (IllegalAccessException iae) {
e = iae;
} catch (IllegalArgumentException iae) {
e = iae;
} catch (InvocationTargetException ite) {
//this means the underlying call caused exception... its ok if runtime
if (ite.getCause() instanceof RuntimeException) {
throw (RuntimeException)ite.getCause();
}
//else throw as invocation target...
e = ite;
}
if (e != null) {
throw new RuntimeException("Cant execute reflection method: "
+ method.getName() + ", on: " + className(invokeOn)
+ ", with args: " + classNameCollection(args), e);
}
return result;
}
/**
* Convert a list to an array with the type of the first element e.g. if it
* is a list of Person objects, then the array is Person[]
*
* @param objectOrArrayOrCollection
* is a list
* @return the array of objects with type of the first element in the list
*/
public static Object toArray(Object objectOrArrayOrCollection) {
// do this before length since if array with null in it, we want ti get
// it back
if (objectOrArrayOrCollection != null
&& objectOrArrayOrCollection.getClass().isArray()) {
return objectOrArrayOrCollection;
}
int length = length(objectOrArrayOrCollection);
if (length == 0) {
return null;
}
if (objectOrArrayOrCollection instanceof Collection) {
Collection collection = (Collection) objectOrArrayOrCollection;
Object first = collection.iterator().next();
return toArray(collection, first == null ? Object.class : first
.getClass());
}
// make an array of the type of object passed in, size one
Object array = Array.newInstance(objectOrArrayOrCollection.getClass(),
1);
Array.set(array, 0, objectOrArrayOrCollection);
return array;
}
/**
* convert a list into an array of type of theClass
* @param is the type of the array
* @param collection list to convert
* @param theClass type of array to return
* @return array of type theClass[] filled with the objects from list
*/
@SuppressWarnings("unchecked")
public static T[] toArray(Collection collection, Class theClass) {
if (collection == null || collection.size() == 0) {
return null;
}
return (T[])collection.toArray((Object[]) Array.newInstance(theClass,
collection.size()));
}
/**
* helper method for calling a static method up the stack. method takes no
* args (could be in superclass)
*
* @param theClass
* the class which has the method
* @param methodName
* method name to call
* @return the data
*/
public static Object callMethod(Class theClass, String methodName) {
return callMethod(theClass, null, methodName, null, null);
}
/**
* helper method for calling a static method with no params
*
* @param theClass
* the class which has the method
* @param methodName
* method name to call
* @param callOnSupers
* if we should try the super classes if not exists in this class
* @return the data
*/
public static Object callMethod(Class theClass, String methodName,
boolean callOnSupers) {
return callMethod(theClass, null, methodName, null, null, callOnSupers);
}
/**
* helper method for calling a static method up the stack
*
* @param theClass
* the class which has the method
* @param methodName
* method name to call
* @param paramTypesOrArrayOrList
* types of the params
* @param paramsOrListOrArray
* data
* @return the data
*/
public static Object callMethod(Class theClass, String methodName,
Object paramTypesOrArrayOrList, Object paramsOrListOrArray) {
return callMethod(theClass, null, methodName, paramTypesOrArrayOrList,
paramsOrListOrArray);
}
/**
* helper method for calling a method with no params (could be in
* superclass), will override security
*
* @param invokeOn
* instance to invoke on
* @param methodName
* method name to call not exists in this class
* @return the data
*/
public static Object callMethod(Object invokeOn, String methodName) {
if (invokeOn == null) {
throw new NullPointerException("invokeOn is null: " + methodName);
}
return callMethod(invokeOn.getClass(), invokeOn, methodName, null,
null, true, true);
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer. This does not recurse
*
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
* @return the string
*/
public static String replace(String text, Object searchFor,
Object replaceWith) {
return replace(null, null, text, searchFor, replaceWith, false, 0,
false);
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer
*
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
* @param recurse
* if true then do multiple replaces (on the replacements)
* @return the string
*/
public static String replace(String text, Object searchFor,
Object replaceWith, boolean recurse) {
return replace(null, null, text, searchFor, replaceWith, recurse,
recurse ? length(searchFor) : 0, false);
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer
*
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
* @param recurse
* if true then do multiple replaces (on the replacements)
* @param removeIfFound
* true if removing from searchFor and replaceWith if found
* @return the string
*/
public static String replace(String text, Object searchFor,
Object replaceWith, boolean recurse, boolean removeIfFound) {
return replace(null, null, text, searchFor, replaceWith, recurse,
recurse ? length(searchFor) : 0, removeIfFound);
}
/**
*
* Replaces all occurrences of a String within another String.
*
*
*
* A null
reference passed to this method is a no-op.
*
*
*
* replace(null, *, *) = null
* replace("", *, *) = ""
* replace("any", null, *) = "any"
* replace("any", *, null) = "any"
* replace("any", "", *) = "any"
* replace("aba", "a", null) = "aba"
* replace("aba", "a", "") = "b"
* replace("aba", "a", "z") = "zbz"
*
*
* @see #replace(String text, String repl, String with, int max)
* @param text
* text to search and replace in, may be null
* @param repl
* the String to search for, may be null
* @param with
* the String to replace with, may be null
* @return the text with any replacements processed, null
if
* null String input
*/
public static String replace(String text, String repl, String with) {
return replace(text, repl, with, -1);
}
/**
*
* Replaces a String with another String inside a larger String, for the
* first max
values of the search String.
*
*
*
* A null
reference passed to this method is a no-op.
*
*
*
* replace(null, *, *, *) = null
* replace("", *, *, *) = ""
* replace("any", null, *, *) = "any"
* replace("any", *, null, *) = "any"
* replace("any", "", *, *) = "any"
* replace("any", *, *, 0) = "any"
* replace("abaa", "a", null, -1) = "abaa"
* replace("abaa", "a", "", -1) = "b"
* replace("abaa", "a", "z", 0) = "abaa"
* replace("abaa", "a", "z", 1) = "zbaa"
* replace("abaa", "a", "z", 2) = "zbza"
* replace("abaa", "a", "z", -1) = "zbzz"
*
*
* @param text
* text to search and replace in, may be null
* @param repl
* the String to search for, may be null
* @param with
* the String to replace with, may be null
* @param max
* maximum number of values to replace, or -1
if
* no maximum
* @return the text with any replacements processed, null
if
* null String input
*/
public static String replace(String text, String repl, String with, int max) {
if (text == null || isEmpty(repl) || with == null || max == 0) {
return text;
}
StringBuffer buf = new StringBuffer(text.length());
int start = 0, end = 0;
while ((end = text.indexOf(repl, start)) != -1) {
buf.append(text.substring(start, end)).append(with);
start = end + repl.length();
if (--max == 0) {
break;
}
}
buf.append(text.substring(start));
return buf.toString();
}
/**
*
* Checks if a String is empty ("") or null.
*
*
*
* isEmpty(null) = true
* isEmpty("") = true
* isEmpty(" ") = false
* isEmpty("bob") = false
* isEmpty(" bob ") = false
*
*
*
* NOTE: This method changed in Lang version 2.0. It no longer trims the
* String. That functionality is available in isBlank().
*
*
* @param str
* the String to check, may be null
* @return true
if the String is empty or null
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer. This does not recurse
*
* @param outBuffer
* stringbuffer to write to
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
*/
public static void replace(StringBuffer outBuffer, String text,
Object searchFor, Object replaceWith) {
replace(outBuffer, null, text, searchFor, replaceWith, false, 0, false);
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer
*
* @param outBuffer
* stringbuffer to write to
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
* @param recurse
* if true then do multiple replaces (on the replacements)
*/
public static void replace(StringBuffer outBuffer, String text,
Object searchFor, Object replaceWith, boolean recurse) {
replace(outBuffer, null, text, searchFor, replaceWith, recurse,
recurse ? length(searchFor) : 0, false);
}
/**
* replace a string with other strings, and either write to outWriter, or
* StringBuffer, and if StringBuffer potentially return a string. If
* outBuffer and outWriter are null, then return the String
*
* @param outBuffer
* stringbuffer to write to, or null to not
* @param outWriter
* Writer to write to, or null to not.
* @param text
* string to look in
* @param searchFor
* string array to search for, or string, or list
* @param replaceWith
* string array to replace with, or string, or list
* @param recurse
* if true then do multiple replaces (on the replacements)
* @param timeToLive
* if recursing, prevent endless loops
* @param removeIfFound
* true if removing from searchFor and replaceWith if found
* @return the String if outBuffer and outWriter are null
* @throws IndexOutOfBoundsException
* if the lengths of the arrays are not the same (null is ok,
* and/or size 0)
* @throws IllegalArgumentException
* if the search is recursive and there is an endless loop due
* to outputs of one being inputs to another
*/
private static String replace(StringBuffer outBuffer, Writer outWriter,
String text, Object searchFor, Object replaceWith, boolean recurse,
int timeToLive, boolean removeIfFound) {
// if recursing, we need to get the string, then print to buffer (since
// we need multiple passes)
if (!recurse) {
return replaceHelper(outBuffer, outWriter, text, searchFor,
replaceWith, recurse, timeToLive, removeIfFound);
}
// get the string
String result = replaceHelper(null, null, text, searchFor, replaceWith,
recurse, timeToLive, removeIfFound);
if (outBuffer != null) {
outBuffer.append(result);
return null;
}
if (outWriter != null) {
try {
outWriter.write(result);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
return null;
}
return result;
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer. This does not recurse
*
* @param outWriter
* writer to write to
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
*/
public static void replace(Writer outWriter, String text, Object searchFor,
Object replaceWith) {
replace(null, outWriter, text, searchFor, replaceWith, false, 0, false);
}
/**
* replace a string or strings from a string, and put the output in a string
* buffer
*
* @param outWriter
* writer to write to
* @param text
* string to look in
* @param searchFor
* string array to search for
* @param replaceWith
* string array to replace with
* @param recurse
* if true then do multiple replaces (on the replacements)
*/
public static void replace(Writer outWriter, String text, Object searchFor,
Object replaceWith, boolean recurse) {
replace(null, outWriter, text, searchFor, replaceWith, recurse,
recurse ? length(searchFor) : 0, false);
}
/**
* replace a string with other strings, and either write to outWriter, or
* StringBuffer, and if StringBuffer potentially return a string. If
* outBuffer and outWriter are null, then return the String
*
* @param outBuffer
* stringbuffer to write to, or null to not
* @param outWriter
* Writer to write to, or null to not.
* @param text
* string to look in
* @param searchFor
* string array to search for, or string, or list
* @param replaceWith
* string array to replace with, or string, or list
* @param recurse
* if true then do multiple replaces (on the replacements)
* @param timeToLive
* if recursing, prevent endless loops
* @param removeIfFound
* true if removing from searchFor and replaceWith if found
* @return the String if outBuffer and outWriter are null
* @throws IllegalArgumentException
* if the search is recursive and there is an endless loop due
* to outputs of one being inputs to another
* @throws IndexOutOfBoundsException
* if the lengths of the arrays are not the same (null is ok,
* and/or size 0)
*/
private static String replaceHelper(StringBuffer outBuffer,
Writer outWriter, String text, Object searchFor,
Object replaceWith, boolean recurse, int timeToLive,
boolean removeIfFound) {
try {
// if recursing, this shouldnt be less than 0
if (timeToLive < 0) {
throw new IllegalArgumentException("TimeToLive under 0: "
+ timeToLive + ", " + text);
}
int searchForLength = length(searchFor);
boolean done = false;
// no need to do anything
if (isEmpty(text)) {
return text;
}
// need to write the input to output, later
if (searchForLength == 0) {
done = true;
}
boolean[] noMoreMatchesForReplIndex = null;
int inputIndex = -1;
int replaceIndex = -1;
long resultPacked = -1;
if (!done) {
// make sure lengths are ok, these need to be equal
if (searchForLength != length(replaceWith)) {
throw new IndexOutOfBoundsException("Lengths dont match: "
+ searchForLength + ", " + length(replaceWith));
}
// keep track of which still have matches
noMoreMatchesForReplIndex = new boolean[searchForLength];
// index of replace array that will replace the search string
// found
resultPacked = findNextIndexHelper(searchForLength, searchFor,
replaceWith,
noMoreMatchesForReplIndex, text, 0);
inputIndex = unpackInt(resultPacked, true);
replaceIndex = unpackInt(resultPacked, false);
}
// get a good guess on the size of the result buffer so it doesnt
// have to double if it
// goes over a bit
boolean writeToWriter = outWriter != null;
// no search strings found, we are done
if (done || inputIndex == -1) {
if (writeToWriter) {
outWriter.write(text, 0, text.length());
return null;
}
if (outBuffer != null) {
appendSubstring(outBuffer, text, 0, text.length());
return null;
}
return text;
}
// no buffer if writing to writer
StringBuffer bufferToWriteTo = outBuffer != null ? outBuffer
: (writeToWriter ? null : new StringBuffer(text.length()
+ replaceStringsBufferIncrease(text, searchFor,
replaceWith)));
String searchString = null;
String replaceString = null;
int start = 0;
while (inputIndex != -1) {
searchString = (String) get(searchFor, replaceIndex);
replaceString = (String) get(replaceWith, replaceIndex);
if (writeToWriter) {
outWriter.write(text, start, inputIndex - start);
outWriter.write(replaceString);
} else {
appendSubstring(bufferToWriteTo, text, start, inputIndex)
.append(replaceString);
}
if (removeIfFound) {
// better be an iterator based find replace
searchFor = remove(searchFor, replaceIndex);
replaceWith = remove(replaceWith, replaceIndex);
noMoreMatchesForReplIndex = (boolean[])remove(noMoreMatchesForReplIndex, replaceIndex);
// we now have a lesser size if we removed one
searchForLength--;
}
start = inputIndex + searchString.length();
resultPacked = findNextIndexHelper(searchForLength, searchFor,
replaceWith,
noMoreMatchesForReplIndex, text, start);
inputIndex = unpackInt(resultPacked, true);
replaceIndex = unpackInt(resultPacked, false);
}
if (writeToWriter) {
outWriter.write(text, start, text.length() - start);
} else {
appendSubstring(bufferToWriteTo, text, start, text.length());
}
// no need to convert to string if incoming buffer or writer
if (writeToWriter || outBuffer != null) {
if (recurse) {
throw new IllegalArgumentException(
"Cannot recurse and write to existing buffer or writer!");
}
return null;
}
String resultString = bufferToWriteTo.toString();
if (recurse) {
return replaceHelper(outBuffer, outWriter, resultString,
searchFor, replaceWith, recurse, timeToLive - 1, false);
}
// this might be null for writer
return resultString;
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* give a best guess on buffer increase for String[] replace get a good
* guess on the size of the result buffer so it doesnt have to double if it
* goes over a bit
*
* @param text
* @param repl
* @param with
* @return the increase, with 20% cap
*/
static int replaceStringsBufferIncrease(String text, Object repl,
Object with) {
// count the greaters
int increase = 0;
Iterator iteratorReplace = iterator(repl);
Iterator iteratorWith = iterator(with);
int replLength = length(repl);
String currentRepl = null;
String currentWith = null;
for (int i = 0; i < replLength; i++) {
currentRepl = (String) next(repl, iteratorReplace, i);
currentWith = (String) next(with, iteratorWith, i);
if (currentRepl == null || currentWith == null) {
throw new NullPointerException("Replace string is null: "
+ text + ", " + currentRepl + ", " + currentWith);
}
int greater = currentWith.length() - currentRepl.length();
increase += greater > 0 ? 3 * greater : 0; // assume 3 matches
}
// have upper-bound at 20% increase, then let Java take over
increase = Math.min(increase, text.length() / 5);
return increase;
}
/**
* Helper method to find the next match in an array of strings replace
*
* @param searchForLength
* @param searchFor
* @param replaceWith
* @param noMoreMatchesForReplIndex
* @param input
* @param start
* is where to start looking
* @return result packed into a long, inputIndex first, then replaceIndex
*/
private static long findNextIndexHelper(int searchForLength,
Object searchFor, Object replaceWith, boolean[] noMoreMatchesForReplIndex,
String input, int start) {
int inputIndex = -1;
int replaceIndex = -1;
Iterator iteratorSearchFor = iterator(searchFor);
Iterator iteratorReplaceWith = iterator(replaceWith);
String currentSearchFor = null;
String currentReplaceWith = null;
int tempIndex = -1;
for (int i = 0; i < searchForLength; i++) {
currentSearchFor = (String) next(searchFor, iteratorSearchFor, i);
currentReplaceWith = (String) next(replaceWith,
iteratorReplaceWith, i);
if (noMoreMatchesForReplIndex[i] || isEmpty(currentSearchFor)
|| currentReplaceWith == null) {
continue;
}
tempIndex = input.indexOf(currentSearchFor, start);
// see if we need to keep searching for this
noMoreMatchesForReplIndex[i] = tempIndex == -1;
if (tempIndex != -1 && (inputIndex == -1 || tempIndex < inputIndex)) {
inputIndex = tempIndex;
replaceIndex = i;
}
}
// dont create an array, no more objects
long resultPacked = packInts(inputIndex, replaceIndex);
return resultPacked;
}
/**
* pack two ints into a long. Note: the first is held in the left bits, the
* second is held in the right bits
*
* @param first
* is first int
* @param second
* is second int
* @return the long which has two ints in there
*/
public static long packInts(int first, int second) {
long result = first;
result <<= 32;
result |= second;
return result;
}
/**
* take a long
*
* @param theLong
* to unpack
* @param isFirst
* true for first, false for second
* @return one of the packed ints, first or second
*/
public static int unpackInt(long theLong, boolean isFirst) {
int result = 0;
// put this in the position of the second one
if (isFirst) {
theLong >>= 32;
}
// only look at right part
result = (int) (theLong & 0xffffffff);
return result;
}
/**
* append a substring to a stringbuffer. removes dependency on substring
* which creates objects
*
* @param buf
* stringbuffer
* @param string
* source string
* @param start
* start index of source string
* @param end
* end index of source string
* @return the string buffer for chaining
*/
private static StringBuffer appendSubstring(StringBuffer buf,
String string, int start, int end) {
for (int i = start; i < end; i++) {
buf.append(string.charAt(i));
}
return buf;
}
/**
* Get a specific index of an array or collection (note for collections and
* iterating, it is more efficient to get an iterator and iterate
*
* @param arrayOrCollection
* @param index
* @return the object at that index
*/
public static Object get(Object arrayOrCollection, int index) {
if (arrayOrCollection == null) {
if (index == 0) {
return null;
}
throw new RuntimeException("Trying to access index " + index
+ " of null");
}
// no need to iterator on list (e.g. FastProxyList has no iterator
if (arrayOrCollection instanceof List) {
return ((List) arrayOrCollection).get(index);
}
if (arrayOrCollection instanceof Collection) {
Iterator iterator = iterator(arrayOrCollection);
for (int i = 0; i < index; i++) {
next(arrayOrCollection, iterator, i);
}
return next(arrayOrCollection, iterator, index);
}
if (arrayOrCollection.getClass().isArray()) {
return Array.get(arrayOrCollection, index);
}
if (index == 0) {
return arrayOrCollection;
}
throw new RuntimeException("Trying to access index " + index
+ " of and object: " + arrayOrCollection);
}
/**
* fail safe toString for Exception blocks, and include the stack
* if there is a problem with toString()
* @param object
* @return the toStringSafe string
*/
@SuppressWarnings("unchecked")
public static String toStringSafe(Object object) {
if (object == null) {
return null;
}
try {
//give size and type if collection
if (object instanceof Collection) {
Collection collection = (Collection) object;
int collectionSize = collection.size();
if (collectionSize == 0) {
return "Empty " + object.getClass().getSimpleName();
}
Object first = collection.iterator().next();
return object.getClass().getSimpleName() + " of size "
+ collectionSize + " with first type: " +
(first == null ? null : first.getClass());
}
return object.toString();
} catch (Exception e) {
return "<> " + object.getClass() + ":\n" + getFullStackTrace(e) + "\n";
}
}
/**
* get the boolean value for an object, cant be null or blank
*
* @param object
* @return the boolean
*/
public static boolean booleanValue(Object object) {
// first handle blanks
if (nullOrBlank(object)) {
throw new RuntimeException(
"Expecting something which can be converted to boolean, but is null or blank: '"
+ object + "'");
}
// its not blank, just convert
if (object instanceof Boolean) {
return (Boolean) object;
}
if (object instanceof String) {
String string = (String) object;
if (equalsIgnoreCase(string, "true")
|| equalsIgnoreCase(string, "t")
|| equalsIgnoreCase(string, "yes")
|| equalsIgnoreCase(string, "y")) {
return true;
}
if (equalsIgnoreCase(string, "false")
|| equalsIgnoreCase(string, "f")
|| equalsIgnoreCase(string, "no")
|| equalsIgnoreCase(string, "n")) {
return false;
}
throw new RuntimeException(
"Invalid string to boolean conversion: '" + string
+ "' expecting true|false or t|f or yes|no or y|n case insensitive");
}
throw new RuntimeException("Cant convert object to boolean: "
+ object.getClass());
}
/**
* get the boolean value for an object
*
* @param object
* @param defaultBoolean
* if object is null or empty
* @return the boolean
*/
public static boolean booleanValue(Object object, boolean defaultBoolean) {
if (nullOrBlank(object)) {
return defaultBoolean;
}
return booleanValue(object);
}
/**
* get the Boolean value for an object
*
* @param object
* @return the Boolean or null if null or empty
*/
public static Boolean booleanObjectValue(Object object) {
if (nullOrBlank(object)) {
return null;
}
return booleanValue(object);
}
/**
* is an object null or blank
*
* @param object
* @return true if null or blank
*/
public static boolean nullOrBlank(Object object) {
// first handle blanks and nulls
if (object == null) {
return true;
}
if (object instanceof String && isBlank(((String) object))) {
return true;
}
return false;
}
/**
* get a getter method object for a class, potentially in superclasses
* @param theClass
* @param fieldName
* @param callOnSupers true if superclasses should be looked in for the getter
* @param throwExceptionIfNotFound will throw runtime exception if not found
* @return the getter object or null if not found (or exception if param is set)
*/
public static Method getter(Class theClass, String fieldName, boolean callOnSupers,
boolean throwExceptionIfNotFound) {
String getterName = getterNameFromPropertyName(fieldName);
return getterHelper(theClass, fieldName, getterName, callOnSupers, throwExceptionIfNotFound);
}
/**
* get a setter method object for a class, potentially in superclasses
* @param theClass
* @param fieldName
* @param getterName name of setter
* @param callOnSupers true if superclasses should be looked in for the setter
* @param throwExceptionIfNotFound will throw runtime exception if not found
* @return the setter object or null if not found (or exception if param is set)
*/
public static Method getterHelper(Class theClass, String fieldName, String getterName,
boolean callOnSupers, boolean throwExceptionIfNotFound) {
Method[] methods = retrieveDeclaredMethods(theClass);
if (methods != null) {
for (Method method : methods) {
if (equals(getterName, method.getName()) && isGetter(method)) {
return method;
}
}
}
//if method not found
//if traversing up, and not Object, and not instance method
if (callOnSupers && !theClass.equals(Object.class)) {
return getterHelper(theClass.getSuperclass(), fieldName, getterName,
callOnSupers, throwExceptionIfNotFound);
}
//maybe throw an exception
if (throwExceptionIfNotFound) {
throw new RuntimeException("Cant find getter: "
+ getterName + ", in: " + theClass
+ ", callOnSupers: " + callOnSupers);
}
return null;
}
/**
* generate getBb from bb
* @param propertyName
* @return the getter
*/
public static String getterNameFromPropertyName(String propertyName) {
return "get" + capitalize(propertyName);
}
/**
* get all getters from a class, including superclasses (if specified) (up to and including the specified superclass).
* ignore a certain marker annotation, or only include it.
* Dont get static or final getters, and get getters of all types
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list (if includeAnnotation is false)
* @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude
* @return the set of field names or empty set if none
*/
@SuppressWarnings("unchecked")
public static Set getters(Class theClass, Class superclassToStopAt,
Class extends Annotation> markerAnnotation, Boolean includeAnnotation) {
return gettersHelper(theClass, superclassToStopAt, null, true,
markerAnnotation, includeAnnotation);
}
/**
* get all getters from a class, including superclasses (if specified)
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param fieldType is the type of the field to get
* @param includeSuperclassToStopAt if we should include the superclass
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list (if includeAnnotation is false)
* @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude
* @return the set of fields (wont return null)
*/
@SuppressWarnings("unchecked")
static Set gettersHelper(Class theClass, Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt,
Class extends Annotation> markerAnnotation, Boolean includeAnnotation) {
//MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED!
Set getterSet = null;
String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt + CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR
+ includeSuperclassToStopAt + CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR + includeAnnotation;
getterSet = getterSetCache().get(cacheKey);
if (getterSet != null) {
return getterSet;
}
getterSet = new LinkedHashSet();
gettersHelper(theClass, superclassToStopAt, fieldType, includeSuperclassToStopAt,
markerAnnotation, getterSet, includeAnnotation);
//add to cache
getterSetCache().put(cacheKey, getterSet);
return getterSet;
}
/**
* get all getters from a class, including superclasses (if specified)
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param propertyType is the type of the field to get
* @param includeSuperclassToStopAt if we should include the superclass
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list
* @param getterSet set to add fields to
* @param includeAnnotation if include or exclude
*/
@SuppressWarnings("unchecked")
private static void gettersHelper(Class theClass, Class superclassToStopAt, Class> propertyType,
boolean includeSuperclassToStopAt,
Class extends Annotation> markerAnnotation, Set getterSet, Boolean includeAnnotation) {
Method[] methods = retrieveDeclaredMethods(theClass);
if (length(methods) != 0) {
for (Method method: methods) {
//must be a getter
if (!isGetter(method)) {
continue;
}
//if checking for annotation
if (markerAnnotation != null
&& (includeAnnotation != method.isAnnotationPresent(markerAnnotation))) {
continue;
}
//if checking for type, and not right type, continue
if (propertyType != null && !propertyType.isAssignableFrom(method.getReturnType())) {
continue;
}
//go for it
getterSet.add(method);
}
}
//see if done recursing (if superclassToStopAt is null, then stop at Object
if (theClass.equals(superclassToStopAt) || theClass.equals(Object.class)) {
return;
}
Class superclass = theClass.getSuperclass();
if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) {
return;
}
//recurse
gettersHelper(superclass, superclassToStopAt, propertyType,
includeSuperclassToStopAt, markerAnnotation, getterSet,
includeAnnotation);
}
/**
* if the method name starts with get, and takes no args, and returns something,
* then getter
* @param method
* @return true if getter
*/
public static boolean isGetter(Method method) {
//must start with get
String methodName = method.getName();
if (!methodName.startsWith("get") && !methodName.startsWith("is")) {
return false;
}
//must not be void
if (method.getReturnType() == Void.TYPE) {
return false;
}
//must not take args
if (length(method.getParameterTypes()) != 0) {
return false;
}
//must not be static
if (Modifier.isStatic(method.getModifiers())) {
return false;
}
return true;
}
/**
* assign data to a setter. Will find the field in superclasses, will typecast,
* and will override security (private, protected, etc)
* @param invokeOn to call on or null for static
* @param fieldName method name to call
* @param dataToAssign data
* @param typeCast will typecast if true
* @throws RuntimeException if not there
*/
public static void assignSetter(Object invokeOn,
String fieldName, Object dataToAssign, boolean typeCast) {
Class invokeOnClass = invokeOn.getClass();
try {
Method setter = setter(invokeOnClass, fieldName, true, true);
setter.setAccessible(true);
if (typeCast) {
dataToAssign = typeCast(dataToAssign, setter.getParameterTypes()[0]);
}
setter.invoke(invokeOn, new Object[]{dataToAssign});
} catch (Exception e) {
throw new RuntimeException("Problem assigning setter: " + fieldName
+ " on class: " + invokeOnClass + ", type of data is: " + className(dataToAssign), e);
}
}
/**
* if the method name starts with get, and takes no args, and returns something,
* then getter
* @param method
* @return true if getter
*/
public static boolean isSetter(Method method) {
//must start with get
if (!method.getName().startsWith("set")) {
return false;
}
//must be void
if (method.getReturnType() != Void.TYPE) {
return false;
}
//must take one arg
if (length(method.getParameterTypes()) != 1) {
return false;
}
//must not be static
if (Modifier.isStatic(method.getModifiers())) {
return false;
}
return true;
}
/**
* get a setter method object for a class, potentially in superclasses
* @param theClass
* @param fieldName
* @param callOnSupers true if superclasses should be looked in for the setter
* @param throwExceptionIfNotFound will throw runtime exception if not found
* @return the setter object or null if not found (or exception if param is set)
*/
public static Method setter(Class theClass, String fieldName, boolean callOnSupers,
boolean throwExceptionIfNotFound) {
String setterName = setterNameFromPropertyName(fieldName);
return setterHelper(theClass, fieldName, setterName, callOnSupers, throwExceptionIfNotFound);
}
/**
* get a setter method object for a class, potentially in superclasses
* @param theClass
* @param fieldName
* @param setterName name of setter
* @param callOnSupers true if superclasses should be looked in for the setter
* @param throwExceptionIfNotFound will throw runtime exception if not found
* @return the setter object or null if not found (or exception if param is set)
*/
public static Method setterHelper(Class theClass, String fieldName, String setterName,
boolean callOnSupers, boolean throwExceptionIfNotFound) {
Method[] methods = retrieveDeclaredMethods(theClass);
if (methods != null) {
for (Method method : methods) {
if (equals(setterName, method.getName()) && isSetter(method)) {
return method;
}
}
}
//if method not found
//if traversing up, and not Object, and not instance method
if (callOnSupers && !theClass.equals(Object.class)) {
return setterHelper(theClass.getSuperclass(), fieldName, setterName,
callOnSupers, throwExceptionIfNotFound);
}
//maybe throw an exception
if (throwExceptionIfNotFound) {
throw new RuntimeException("Cant find setter: "
+ setterName + ", in: " + theClass
+ ", callOnSupers: " + callOnSupers);
}
return null;
}
/**
* generate setBb from bb
* @param propertyName
* @return the setter
*/
public static String setterNameFromPropertyName(String propertyName) {
return "set" + capitalize(propertyName);
}
/**
* get all setters from a class, including superclasses (if specified)
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param fieldType is the type of the field to get
* @param includeSuperclassToStopAt if we should include the superclass
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list (if includeAnnotation is false)
* @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude
* @return the set of fields (wont return null)
*/
@SuppressWarnings("unchecked")
public static Set setters(Class theClass, Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt,
Class extends Annotation> markerAnnotation, boolean includeAnnotation) {
return settersHelper(theClass, superclassToStopAt, fieldType,
includeSuperclassToStopAt, markerAnnotation, includeAnnotation);
}
/**
* get all setters from a class, including superclasses (if specified)
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param fieldType is the type of the field to get
* @param includeSuperclassToStopAt if we should include the superclass
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list (if includeAnnotation is false)
* @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude
* @return the set of fields (wont return null)
*/
@SuppressWarnings("unchecked")
static Set settersHelper(Class theClass, Class superclassToStopAt, Class> fieldType,
boolean includeSuperclassToStopAt,
Class extends Annotation> markerAnnotation, boolean includeAnnotation) {
//MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED!
Set setterSet = null;
String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt + CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR
+ includeSuperclassToStopAt + CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR + includeAnnotation;
setterSet = setterSetCache().get(cacheKey);
if (setterSet != null) {
return setterSet;
}
setterSet = new LinkedHashSet();
settersHelper(theClass, superclassToStopAt, fieldType, includeSuperclassToStopAt,
markerAnnotation, setterSet, includeAnnotation);
//add to cache
setterSetCache().put(cacheKey, setterSet);
return setterSet;
}
/**
* get all setters from a class, including superclasses (if specified)
* @param theClass to look for fields in
* @param superclassToStopAt to go up to or null to go up to Object
* @param propertyType is the type of the field to get
* @param includeSuperclassToStopAt if we should include the superclass
* @param markerAnnotation if this is not null, then if the field has this annotation, then do not
* include in list
* @param setterSet set to add fields to
* @param includeAnnotation if include or exclude (or null if not looking for annotations)
*/
@SuppressWarnings("unchecked")
private static void settersHelper(Class theClass, Class superclassToStopAt, Class> propertyType,
boolean includeSuperclassToStopAt,
Class extends Annotation> markerAnnotation, Set setterSet, Boolean includeAnnotation) {
Method[] methods = retrieveDeclaredMethods(theClass);
if (length(methods) != 0) {
for (Method method: methods) {
//must be a getter
if (!isSetter(method)) {
continue;
}
//if checking for annotation
if (markerAnnotation != null
&& (includeAnnotation != method.isAnnotationPresent(markerAnnotation))) {
continue;
}
//if checking for type, and not right type, continue
if (propertyType != null && !propertyType.isAssignableFrom(method.getParameterTypes()[0])) {
continue;
}
//go for it
setterSet.add(method);
}
}
//see if done recursing (if superclassToStopAt is null, then stop at Object
if (theClass.equals(superclassToStopAt) || theClass.equals(Object.class)) {
return;
}
Class superclass = theClass.getSuperclass();
if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) {
return;
}
//recurse
settersHelper(superclass, superclassToStopAt, propertyType,
includeSuperclassToStopAt, markerAnnotation, setterSet,
includeAnnotation);
}
/**
* If this is a getter or setter, then get the property name
* @param method
* @return the property name
*/
public static String propertyName(Method method) {
String methodName = method.getName();
boolean isGetter = methodName.startsWith("get");
boolean isSetter = methodName.startsWith("set");
boolean isIsser = methodName.startsWith("is");
int expectedLength = isIsser ? 2 : 3;
int length = methodName.length();
if ((!(isGetter || isSetter || isIsser)) || (length <= expectedLength)) {
throw new RuntimeException("Not a getter or setter: " + methodName);
}
char fourthCharLower = Character.toLowerCase(methodName.charAt(expectedLength));
//if size 4, then return the string
if (length == expectedLength +1) {
return Character.toString(fourthCharLower);
}
//return the lower appended with the rest
return fourthCharLower + methodName.substring(expectedLength+1, length);
}
/**
* use reflection to get a property type based on getter or setter or field
* @param theClass
* @param propertyName
* @return the property type
*/
public static Class propertyType(Class theClass, String propertyName) {
Method method = getter(theClass, propertyName, true, false);
if (method != null) {
return method.getReturnType();
}
//use setter
method = setter(theClass, propertyName, true, false);
if (method != null) {
return method.getParameterTypes()[0];
}
//no setter or getter, use field
Field field = field(theClass, propertyName, true, true);
return field.getType();
}
/**
* If necessary, convert an object to another type. if type is Object.class, just return the input.
* Do not convert null to an empty primitive
* @param is template type
* @param value
* @param theClass
* @return the object of that instance converted into something else
*/
public static T typeCast(Object value, Class theClass) {
//default behavior is not to convert null to empty primitive
return typeCast(value, theClass, false, false);
}
/**
*
* make a new file in the name prefix dir. If parent dir name is c:\temp
* and namePrefix is grouperDdl and nameSuffix is sql, then the file will be:
*
* c:\temp\grouperDdl_20080721_13_45_43_123.sql
*
* If the file exists, it will make a new filename, and create the empty file, and return it
*
*
* @param parentDirName can be blank for current dir
* @param namePrefix the part before the date part
* @param nameSuffix the last part of file name (can contain dot or will be the extension
* @param createFile true to create the file
* @return the created file
*/
public static File newFileUniqueName(String parentDirName, String namePrefix, String nameSuffix, boolean createFile) {
DateFormat fileNameFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss_SSS");
if (!isBlank(parentDirName)) {
if (!parentDirName.endsWith("/") && !parentDirName.endsWith("\\")) {
parentDirName += File.separator;
}
//make sure it exists and is a dir
File parentDir = new File(parentDirName);
if (!parentDir.exists()) {
if (!parentDir.mkdirs()) {
throw new RuntimeException("Cant make dir: " + parentDir.getAbsolutePath());
}
} else {
if (!parentDir.isDirectory()) {
throw new RuntimeException("Parent dir is not a directory: " + parentDir.getAbsolutePath());
}
}
} else {
//make it empty string so it will concatenate well
parentDirName = "";
}
//make sure suffix has a dot in it
if (!nameSuffix.contains(".")) {
nameSuffix = "." + nameSuffix;
}
String fileName = parentDirName + namePrefix + "_" + fileNameFormat.format(new Date()) + nameSuffix;
int dotLocation = fileName.lastIndexOf('.');
String fileNamePre = fileName.substring(0,dotLocation);
String fileNamePost = fileName.substring(dotLocation);
File theFile = new File(fileName);
int i;
for (i=0;i<1000;i++) {
if (!theFile.exists()) {
break;
}
fileName = fileNamePre + "_" + i + fileNamePost;
theFile = new File(fileName);
}
if (i>=1000) {
throw new RuntimeException("Cant find filename to create: " + fileName);
}
if (createFile) {
try {
if (!theFile.createNewFile()) {
throw new RuntimeException("Cant create file, it returned false");
}
} catch (Exception e) {
throw new RuntimeException("Cant create file: " + fileName + ", make sure " +
"permissions and such are ok, or change file location in grouper.properties if applicable", e);
}
}
return theFile;
}
/**
*
* Convert an object to a java.util.Date. allows, dates, null, blank,
* yyyymmdd or yyyymmdd hh24:mm:ss
* or yyyy/MM/dd HH:mm:ss.SSS
*
* @param inputObject
* is the String or Date to convert
*
* @return the Date
*/
public static Date dateValue(Object inputObject) {
if (inputObject == null) {
return null;
}
if (inputObject instanceof java.util.Date) {
return (Date)inputObject;
}
if (inputObject instanceof String) {
String input = (String)inputObject;
//trim and handle null and empty
if (isBlank(input)) {
return null;
}
try {
if (input.length() == 8) {
return dateFormat().parse(input);
}
if (!contains(input, '.')) {
if (contains(input, '/')) {
return dateMinutesSecondsFormat.parse(input);
}
//else no slash
return dateMinutesSecondsNoSlashFormat.parse(input);
}
if (contains(input, '/')) {
//see if the period is 6 back
int lastDotIndex = input.lastIndexOf('.');
if (lastDotIndex == input.length() - 7) {
String nonNanoInput = input.substring(0,input.length()-3);
Date date = timestampFormat.parse(nonNanoInput);
//get the last 3
String lastThree = input.substring(input.length()-3,input.length());
int lastThreeInt = Integer.parseInt(lastThree);
Timestamp timestamp = new Timestamp(date.getTime());
timestamp.setNanos(timestamp.getNanos() + (lastThreeInt * 1000));
return timestamp;
}
return timestampFormat.parse(input);
}
//else no slash
return timestampNoSlashFormat.parse(input);
} catch (ParseException pe) {
throw new RuntimeException(errorStart + toStringForLog(input));
}
}
throw new RuntimeException("Cannot convert Object to date : " + toStringForLog(inputObject));
}
/**
* See if the input is null or if string, if it is empty or blank (whitespace)
* @param input
* @return true if blank
*/
public static boolean isBlank(Object input) {
if (null == input) {
return true;
}
return (input instanceof String && isBlank((String)input));
}
/**
* If necessary, convert an object to another type. if type is Object.class, just return the input
* @param is the type to return
* @param value
* @param theClass
* @param convertNullToDefaultPrimitive if the value is null, and theClass is primitive, should we
* convert the null to a primitive default value
* @param useNewInstanceHooks if theClass is not recognized, then honor the string "null", "newInstance",
* or get a constructor with one param, and call it
* @return the object of that instance converted into something else
*/
@SuppressWarnings({ "unchecked", "cast" })
public static T typeCast(Object value, Class theClass,
boolean convertNullToDefaultPrimitive, boolean useNewInstanceHooks) {
if (Object.class.equals(theClass)) {
return (T)value;
}
if (value==null) {
if (convertNullToDefaultPrimitive && theClass.isPrimitive()) {
if ( theClass == boolean.class ) {
return (T)Boolean.FALSE;
}
if ( theClass == char.class ) {
return (T)(Object)0;
}
//convert 0 to the type
return typeCast(0, theClass, false, false);
}
return null;
}
if (theClass.isInstance(value)) {
return (T)value;
}
//if array, get the base class
if (theClass.isArray() && theClass.getComponentType() != null) {
theClass = (Class)theClass.getComponentType();
}
Object resultValue = null;
//loop through and see the primitive types etc
if (theClass.equals(Date.class)) {
resultValue = dateValue(value);
} else if (theClass.equals(String.class)) {
resultValue = stringValue(value);
} else if (theClass.equals(Timestamp.class)) {
resultValue = toTimestamp(value);
} else if (theClass.equals(Boolean.class) || theClass.equals(boolean.class)) {
resultValue = booleanObjectValue(value);
} else if (theClass.equals(Integer.class) || theClass.equals(int.class)) {
resultValue = intObjectValue(value, true);
} else if (theClass.equals(Double.class) || theClass.equals(double.class)) {
resultValue = doubleObjectValue(value, true);
} else if (theClass.equals(Float.class) || theClass.equals(float.class)) {
resultValue = floatObjectValue(value, true);
} else if (theClass.equals(Long.class) || theClass.equals(long.class)) {
resultValue = longObjectValue(value, true);
} else if (theClass.equals(Byte.class) || theClass.equals(byte.class)) {
resultValue = byteObjectValue(value);
} else if (theClass.equals(Character.class) || theClass.equals(char.class)) {
resultValue = charObjectValue(value);
} else if (theClass.equals(Short.class) || theClass.equals(short.class)) {
resultValue = shortObjectValue(value);
} else if ( theClass.isEnum() && (value instanceof String) ) {
resultValue = Enum.valueOf((Class)theClass, (String) value);
} else if ( theClass.equals(Class.class) && (value instanceof String) ) {
resultValue = forName((String)value);
} else if (useNewInstanceHooks && value instanceof String) {
String stringValue = (String)value;
if ( equals("null", stringValue)) {
resultValue = null;
} else if (equals("newInstance", stringValue)) {
resultValue = newInstance(theClass);
} else { // instantiate using string
//note, we could typecast this to fit whatever is there... right now this is used for annotation
try {
Constructor constructor = theClass.getConstructor(new Class[] {String.class} );
resultValue = constructor.newInstance(new Object[] {stringValue} );
} catch (Exception e) {
throw new RuntimeException("Cant find constructor with string for class: " + theClass);
}
}
} else {
throw new RuntimeException("Cannot convert from type: " + value.getClass() + " to type: " + theClass);
}
return (T)resultValue;
}
/**
* see if a class is a scalar (not bean, not array or list, etc)
* @param type
* @return true if scalar
*/
public static boolean isScalar(Class> type) {
if (type.isArray()) {
return false;
}
//definitely all primitives
if (type.isPrimitive()) {
return true;
}
//Integer, Float, etc
if (Number.class.isAssignableFrom(type)) {
return true;
}
//Date, Timestamp
if (Date.class.isAssignableFrom(type)) {
return true;
}
if (Character.class.equals(type)) {
return true;
}
//handles strings and string builders
if (CharSequence.class.equals(type) || CharSequence.class.isAssignableFrom(type)) {
return true;
}
if (Class.class == type || Boolean.class == type || type.isEnum()) {
return true;
}
//appears not to be a scalar
return false;
}
/**
*
* Convert a string or object to a timestamp (could be string, date, timestamp, etc)
* yyyymmdd
* or
* yyyy/MM/dd HH:mm:ss
* or
* yyyy/MM/dd HH:mm:ss.SSS
* or
* yyyy/MM/dd HH:mm:ss.SSSSSS
*
*
*
* @param input
* @return the timestamp
* @throws RuntimeException if invalid format
*/
public static Timestamp toTimestamp(Object input) {
if (null == input) {
return null;
} else if (input instanceof java.sql.Timestamp) {
return (Timestamp) input;
} else if (input instanceof String) {
return stringToTimestamp((String) input);
} else if (input instanceof Date) {
return new Timestamp(((Date)input).getTime());
} else if (input instanceof java.sql.Date) {
return new Timestamp(((java.sql.Date)input).getTime());
} else {
throw new RuntimeException("Cannot convert Object to timestamp : " + input);
}
}
/**
* convert an object to a string
*
* @param input
* is the object to convert
*
* @return the String conversion of the object
*/
public static String stringValue(Object input) {
//this isnt needed
if (input == null) {
return (String) input;
}
if (input instanceof Timestamp) {
//convert to yyyy/MM/dd HH:mm:ss.SSS
return timestampToString((Timestamp) input);
}
if (input instanceof Date) {
//convert to yyyymmdd
return stringValue((Date) input);
}
if (input instanceof Number) {
DecimalFormat decimalFormat = new DecimalFormat(
"###################.###############");
return decimalFormat.format(((Number) input).doubleValue());
}
return input.toString();
}
/**
* Convert a timestamp into a string: yyyy/MM/dd HH:mm:ss.SSS
* @param timestamp
* @return the string representation
*/
public synchronized static String timestampToString(Date timestamp) {
if (timestamp == null) {
return null;
}
return timestampFormat.format(timestamp);
}
/**
* get the timestamp format for this thread
* if you call this make sure to synchronize on FastDateUtils.class
* @return the timestamp format
*/
synchronized static SimpleDateFormat dateFormat() {
return dateFormat;
}
/**
* convert a date to the standard string yyyymmdd
* @param date
* @return the string value
*/
public static String stringValue(java.util.Date date) {
synchronized (GrouperInstallerUtils.class) {
if (date == null) {
return null;
}
String theString = dateFormat().format(date);
return theString;
}
}
/**
* convert a string to timestamp based on the following formats:
* yyyyMMdd
* yyyy/MM/dd HH:mm:ss
* yyyy/MM/dd HH:mm:ss.SSS
* yyyy/MM/dd HH:mm:ss.SSSSSS
*
* @param input
* @return the timestamp object
*/
public static Timestamp stringToTimestamp(String input) {
Date date = stringToTimestampHelper(input);
if (date == null) {
return null;
}
//maybe already a timestamp
if (date instanceof Timestamp) {
return (Timestamp)date;
}
return new Timestamp(date.getTime());
}
/**
* return a date based on input, null safe. Allow any of the three
* formats:
* yyyyMMdd
* yyyy/MM/dd HH:mm:ss
* yyyy/MM/dd HH:mm:ss.SSS
* yyyy/MM/dd HH:mm:ss.SSSSSS
*
* @param input
* @return the millis, -1 for null
*/
synchronized static Date stringToTimestampHelper(String input) {
//trim and handle null and empty
if (isBlank(input)) {
return null;
}
try {
//convert mainframe
if (equals("99999999", input)
|| equals("999999", input)) {
input = "20991231";
}
if (input.length() == 8) {
return dateFormat().parse(input);
}
if (!contains(input, '.')) {
if (contains(input, '/')) {
return dateMinutesSecondsFormat.parse(input);
}
//else no slash
return dateMinutesSecondsNoSlashFormat.parse(input);
}
if (contains(input, '/')) {
//see if the period is 6 back
int lastDotIndex = input.lastIndexOf('.');
if (lastDotIndex == input.length() - 7) {
String nonNanoInput = input.substring(0,input.length()-3);
Date date = timestampFormat.parse(nonNanoInput);
//get the last 3
String lastThree = input.substring(input.length()-3,input.length());
int lastThreeInt = Integer.parseInt(lastThree);
Timestamp timestamp = new Timestamp(date.getTime());
timestamp.setNanos(timestamp.getNanos() + (lastThreeInt * 1000));
return timestamp;
}
return timestampFormat.parse(input);
}
//else no slash
return timestampNoSlashFormat.parse(input);
} catch (ParseException pe) {
throw new RuntimeException(errorStart + input);
}
}
/**
* start of error parsing messages
*/
private static final String errorStart = "Invalid timestamp, please use any of the formats: "
+ DATE_FORMAT + ", " + TIMESTAMP_FORMAT
+ ", " + DATE_MINUTES_SECONDS_FORMAT + ": ";
/**
* Convert an object to a byte, allow nulls
* @param input
* @return the boolean object value
*/
public static BigDecimal bigDecimalObjectValue(Object input) {
if (input instanceof BigDecimal) {
return (BigDecimal)input;
}
if (isBlank(input)) {
return null;
}
return BigDecimal.valueOf(doubleValue(input));
}
/**
* Convert an object to a byte, allow nulls
* @param input
* @return the boolean object value
*/
public static Byte byteObjectValue(Object input) {
if (input instanceof Byte) {
return (Byte)input;
}
if (isBlank(input)) {
return null;
}
return Byte.valueOf(byteValue(input));
}
/**
* convert an object to a byte
* @param input
* @return the byte
*/
public static byte byteValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Byte.parseByte(string);
}
if (input instanceof Number) {
return ((Number)input).byteValue();
}
throw new RuntimeException("Cannot convert to byte: " + className(input));
}
/**
* get the Double value of an object
*
* @param input
* is a number or String
* @param allowNullBlank used to default to false, if true, return null if nul inputted
*
* @return the Double equivalent
*/
public static Double doubleObjectValue(Object input, boolean allowNullBlank) {
if (input instanceof Double) {
return (Double) input;
}
if (allowNullBlank && isBlank(input)) {
return null;
}
return Double.valueOf(doubleValue(input));
}
/**
* get the double value of an object
*
* @param input
* is a number or String
*
* @return the double equivalent
*/
public static double doubleValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Double.parseDouble(string);
}
if (input instanceof Number) {
return ((Number)input).doubleValue();
}
throw new RuntimeException("Cannot convert to double: " + className(input));
}
/**
* get the double value of an object, do not throw an
* exception if there is an
* error
*
* @param input
* is a number or String
*
* @return the double equivalent
*/
public static double doubleValueNoError(Object input) {
if (input == null || (input instanceof String
&& isBlank((String)input))) {
return NOT_FOUND;
}
try {
return doubleValue(input);
} catch (Exception e) {
//no need to log here
}
return NOT_FOUND;
}
/**
* get the Float value of an object
*
* @param input
* is a number or String
* @param allowNullBlank true if allow null or blank
*
* @return the Float equivalent
*/
public static Float floatObjectValue(Object input, boolean allowNullBlank) {
if (input instanceof Float) {
return (Float) input;
}
if (allowNullBlank && isBlank(input)) {
return null;
}
return Float.valueOf(floatValue(input));
}
/**
* get the float value of an object
*
* @param input
* is a number or String
*
* @return the float equivalent
*/
public static float floatValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Float.parseFloat(string);
}
if (input instanceof Number) {
return ((Number)input).floatValue();
}
throw new RuntimeException("Cannot convert to float: " + className(input));
}
/**
* get the float value of an object, do not throw an exception if there is an
* error
*
* @param input
* is a number or String
*
* @return the float equivalent
*/
public static float floatValueNoError(Object input) {
if (input == null || (input instanceof String
&& isBlank((String)input))) {
return NOT_FOUND;
}
try {
return floatValue(input);
} catch (Exception e) {
e.printStackTrace();
}
return NOT_FOUND;
}
/**
* get the Integer value of an object
*
* @param input
* is a number or String
* @param allowNullBlank true if convert null or blank to null
*
* @return the Integer equivalent
*/
public static Integer intObjectValue(Object input, boolean allowNullBlank) {
if (input instanceof Integer) {
return (Integer) input;
}
if (allowNullBlank && isBlank(input)) {
return null;
}
return Integer.valueOf(intValue(input));
}
/**
* convert an object to a int
* @param input
* @return the number
*/
public static int intValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Integer.parseInt(string);
}
if (input instanceof Number) {
return ((Number)input).intValue();
}
if (false) {
if (input == null) {
return 0;
}
if (input instanceof String || isBlank((String)input)) {
return 0;
}
}
throw new RuntimeException("Cannot convert to int: " + className(input));
}
/**
* convert an object to a int
* @param input
* @param valueIfNull is if the input is null or empty, return this value
* @return the number
*/
public static int intValue(Object input, int valueIfNull) {
if (input == null || "".equals(input)) {
return valueIfNull;
}
return intObjectValue(input, false);
}
/**
* get the int value of an object, do not throw an exception if there is an
* error
*
* @param input
* is a number or String
*
* @return the int equivalent
*/
public static int intValueNoError(Object input) {
if (input == null || (input instanceof String
&& isBlank((String)input))) {
return NOT_FOUND;
}
try {
return intValue(input);
} catch (Exception e) {
//no need to log here
}
return NOT_FOUND;
}
/** special number when a number is not found */
public static final int NOT_FOUND = -999999999;
/**
* The name says it all.
*/
public static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
/**
* get the Long value of an object
*
* @param input
* is a number or String
* @param allowNullBlank true if null or blank converts to null
*
* @return the Long equivalent
*/
public static Long longObjectValue(Object input, boolean allowNullBlank) {
if (input instanceof Long) {
return (Long) input;
}
if (allowNullBlank && isBlank(input)) {
return null;
}
return Long.valueOf(longValue(input));
}
/**
* convert an object to a long
* @param input
* @return the number
*/
public static long longValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Long.parseLong(string);
}
if (input instanceof Number) {
return ((Number)input).longValue();
}
throw new RuntimeException("Cannot convert to long: " + className(input));
}
/**
* convert an object to a long
* @param input
* @param valueIfNull is if the input is null or empty, return this value
* @return the number
*/
public static long longValue(Object input, long valueIfNull) {
if (input == null || "".equals(input)) {
return valueIfNull;
}
return longObjectValue(input, false);
}
/**
* get the long value of an object, do not throw an exception if there is an
* error
*
* @param input
* is a number or String
*
* @return the long equivalent
*/
public static long longValueNoError(Object input) {
if (input == null || (input instanceof String
&& isBlank((String)input))) {
return NOT_FOUND;
}
try {
return longValue(input);
} catch (Exception e) {
//no need to log here
}
return NOT_FOUND;
}
/**
* get the Short value of an object. converts null or blank to null
*
* @param input
* is a number or String
*
* @return the Long equivalent
*/
public static Short shortObjectValue(Object input) {
if (input instanceof Short) {
return (Short) input;
}
if (isBlank(input)) {
return null;
}
return Short.valueOf(shortValue(input));
}
/**
* convert an object to a short
* @param input
* @return the number
*/
public static short shortValue(Object input) {
if (input instanceof String) {
String string = (String)input;
return Short.parseShort(string);
}
if (input instanceof Number) {
return ((Number)input).shortValue();
}
throw new RuntimeException("Cannot convert to short: " + className(input));
}
/**
* get the Character wrapper value for the input
* @param input allow null, return null
* @return the Character object wrapper
*/
public static Character charObjectValue(Object input) {
if (input instanceof Character) {
return (Character) input;
}
if (isBlank(input)) {
return null;
}
return new Character(charValue(input));
}
/**
* convert an object to a char
* @param input
* @return the number
*/
public static char charValue(Object input) {
if (input instanceof Character) {
return ((Character) input).charValue();
}
//if string length 1, thats ok
if (input instanceof String) {
String inputString = (String) input;
if (inputString.length() == 1) {
return inputString.charAt(0);
}
}
throw new RuntimeException("Cannot convert to char: "
+ (input == null ? null : (input.getClass() + ", " + input)));
}
/**
* Create the parent directories for a file if they do not already exist
* @param file
*/
public static void createParentDirectories(File file) {
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
throw new RuntimeException("Could not create directory : " + file.getParentFile());
}
}
}
/**
* save a string into a file, file does not have to exist
*
* @param file
* is the file to save to
* @param contents
* is the contents of the file
*/
public static void saveStringIntoFile(File file, String contents) {
try {
writeStringToFile(file, contents, "UTF-8");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* save a string into a file, file does not have to exist
*
* @param file
* is the file to save to
* @param contents
* is the contents of the file
* @param onlyIfDifferentContents true if only saving due to different contents
* @param ignoreWhitespace true to ignore whitespace
* @return true if contents were saved (thus different if param set)
*/
public static boolean saveStringIntoFile(File file, String contents,
boolean onlyIfDifferentContents, boolean ignoreWhitespace) {
if (onlyIfDifferentContents && file.exists()) {
String fileContents = readFileIntoString(file);
String compressedContents = contents;
if (ignoreWhitespace) {
compressedContents = replaceWhitespaceWithSpace(compressedContents);
fileContents = replaceWhitespaceWithSpace(fileContents);
}
//they are the same, dont worry about it
if (equals(fileContents, compressedContents)) {
return false;
}
}
saveStringIntoFile(file, contents);
return true;
}
/**
*
* Writes data to a file. The file will be created if it does not exist.
*
*
* There is no readFileToString method without encoding parameter because
* the default encoding can differ between platforms and therefore results
* in inconsistent results.
*
*
* @param file the file to write.
* @param data The content to write to the file.
* @param encoding encoding to use
* @throws IOException in case of an I/O error
* @throws UnsupportedEncodingException if the encoding is not supported
* by the VM
*/
public static void writeStringToFile(File file, String data, String encoding)
throws IOException {
OutputStream out = new java.io.FileOutputStream(file);
try {
out.write(data.getBytes(encoding));
} finally {
closeQuietly(out);
}
}
/**
*
* Writes data to a file. The file will be created if it does not exist.
*
*
* There is no readFileToString method without encoding parameter because
* the default encoding can differ between platforms and therefore results
* in inconsistent results.
*
*
* @param file the file to write.
* @param data The content to write to the file.
*/
public static void writeStringToFile(File file, String data) {
try {
writeStringToFile(file, data, "UTF-8");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* @param file
* is the file to read into a string
*
* @return String
*/
public static String readFileIntoString(File file) {
if (file == null) {
return null;
}
try {
return readFileToString(file, "UTF-8");
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* @param resourceName is the string resource from classpath to read (e.g. grouper.properties)
* @param allowNull is true if its ok if the resource is null or if it is not found or blank or whatever.
*
* @return String or null if allowed or RuntimeException if not allowed
*/
public static String readResourceIntoString(String resourceName, boolean allowNull) {
if (isBlank(resourceName)) {
if (allowNull) {
return null;
}
throw new RuntimeException("Resource name is blank");
}
URL url = computeUrl(resourceName, allowNull);
//this is ok
if (url == null && allowNull) {
return null;
}
InputStream inputStream = null;
StringWriter stringWriter = new StringWriter();
try {
inputStream = url.openStream();
copy(inputStream, stringWriter, "UTF-8");
} catch (IOException ioe) {
throw new RuntimeException("Error reading resource: '" + resourceName + "'", ioe);
} finally {
closeQuietly(inputStream);
closeQuietly(stringWriter);
}
return stringWriter.toString();
}
/**
* read resource into string
* @param resourceName
* @param classInJar if not null, then look for the jar where this file is, and look in the same dir
* @return the properties or null if not exist
*/
public static String readResourceIntoString(String resourceName, Class> classInJar) {
try {
return readResourceIntoString(resourceName, false);
} catch (Exception e) {
//try from jar location
}
//lets look next to jar
File jarFile = classInJar == null ? null : jarFile(classInJar);
File parentDir = jarFile == null ? null : jarFile.getParentFile();
String fileName = parentDir == null ? null
: (stripLastSlashIfExists(fileCanonicalPath(parentDir)) + File.separator + resourceName);
File configFile = fileName == null ? null
: new File(fileName);
return readFileIntoString(configFile);
}
/**
*
* Reads the contents of a file into a String.
*
*
* There is no readFileToString method without encoding parameter because
* the default encoding can differ between platforms and therefore results
* in inconsistent results.
*
*
* @param file the file to read.
* @param encoding the encoding to use
* @return The file contents or null if read failed.
* @throws IOException in case of an I/O error
*/
public static String readFileToString(File file, String encoding) throws IOException {
InputStream in = new java.io.FileInputStream(file);
try {
return toString(in, encoding);
} finally {
closeQuietly(in);
}
}
/**
* replace all whitespace with space
* @param input
* @return the string
*/
public static String replaceWhitespaceWithSpace(String input) {
if (input == null) {
return input;
}
return input.replaceAll("\\s+", " ");
}
/**
* Unconditionally close an InputStream
.
* Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
* @param input A (possibly null) InputStream
*/
public static void closeQuietly(InputStream input) {
if (input == null) {
return;
}
try {
input.close();
} catch (IOException ioe) {
}
}
/**
* Unconditionally close a ZipFile
.
* Equivalent to {@link ZipFile#close()}, except any exceptions will be ignored.
* @param input A (possibly null) ZipFile
*/
public static void closeQuietly(ZipFile input) {
if (input == null) {
return;
}
try {
input.close();
} catch (IOException ioe) {
}
}
/**
* Unconditionally close an OutputStream
.
* Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
* @param output A (possibly null) OutputStream
*/
public static void closeQuietly(OutputStream output) {
if (output == null) {
return;
}
try {
output.close();
} catch (IOException ioe) {
}
}
/**
* Unconditionally close an Reader
.
* Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
*
* @param input A (possibly null) Reader
*/
public static void closeQuietly(Reader input) {
if (input == null) {
return;
}
try {
input.close();
} catch (IOException ioe) {
}
}
/**
* close a writer quietly
* @param writer
*/
public static void closeQuietly(Writer writer) {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
//swallow, its ok
}
}
}
/**
* Get the contents of an InputStream
as a String.
* @param input the InputStream
to read from
* @param encoding The name of a supported character encoding. See the
* IANA
* Charset Registry for a list of valid encoding types.
* @return the requested String
* @throws IOException In case of an I/O problem
*/
public static String toString(InputStream input, String encoding) throws IOException {
StringWriter sw = new StringWriter();
copy(input, sw, encoding);
return sw.toString();
}
/**
* Copy and convert bytes from an InputStream
to chars on a
* Writer
, using the specified encoding.
* @param input the InputStream
to read from
* @param output the Writer
to write to
* @param encoding The name of a supported character encoding. See the
* IANA
* Charset Registry for a list of valid encoding types.
* @throws IOException In case of an I/O problem
*/
public static void copy(InputStream input, Writer output, String encoding)
throws IOException {
InputStreamReader in = new InputStreamReader(input, encoding);
copy(in, output);
}
/**
* Copy chars from a Reader
to a Writer
.
* @param input the Reader
to read from
* @param output the Writer
to write to
* @return the number of characters copied
* @throws IOException In case of an I/O problem
*/
public static int copy(Reader input, Writer output) throws IOException {
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
/**
* this method takes a long (less than 62) and converts it to a 1 character
* string (a-z, A-Z, 0-9)
*
* @param theLong
* is the long (less than 62) to convert to a 1 character string
*
* @return a one character string
*/
public static String convertLongToChar(long theLong) {
if ((theLong < 0) || (theLong >= 62)) {
throw new RuntimeException("convertLongToChar() "
+ " invalid input (not >=0 && <62: " + theLong);
} else if (theLong < 26) {
return "" + (char) ('a' + theLong);
} else if (theLong < 52) {
return "" + (char) ('A' + (theLong - 26));
} else {
return "" + (char) ('0' + (theLong - 52));
}
}
/**
* this method takes a long (less than 36) and converts it to a 1 character
* string (A-Z, 0-9)
*
* @param theLong
* is the long (less than 36) to convert to a 1 character string
*
* @return a one character string
*/
public static String convertLongToCharSmall(long theLong) {
if ((theLong < 0) || (theLong >= 36)) {
throw new RuntimeException("convertLongToCharSmall() "
+ " invalid input (not >=0 && <36: " + theLong);
} else if (theLong < 26) {
return "" + (char) ('A' + theLong);
} else {
return "" + (char) ('0' + (theLong - 26));
}
}
/**
* convert a long to a string by converting it to base 62 (26 lower, 26 upper,
* 10 digits)
*
* @param theLong
* is the long to convert
*
* @return the String conversion of this
*/
public static String convertLongToString(long theLong) {
long quotient = theLong / 62;
long remainder = theLong % 62;
if (quotient == 0) {
return convertLongToChar(remainder);
}
StringBuffer result = new StringBuffer();
result.append(convertLongToString(quotient));
result.append(convertLongToChar(remainder));
return result.toString();
}
/**
* convert a long to a string by converting it to base 36 (26 upper, 10
* digits)
*
* @param theLong
* is the long to convert
*
* @return the String conversion of this
*/
public static String convertLongToStringSmall(long theLong) {
long quotient = theLong / 36;
long remainder = theLong % 36;
if (quotient == 0) {
return convertLongToCharSmall(remainder);
}
StringBuffer result = new StringBuffer();
result.append(convertLongToStringSmall(quotient));
result.append(convertLongToCharSmall(remainder));
return result.toString();
}
/**
* increment a character (A-Z then 0-9)
*
* @param theChar
*
* @return the value
*/
public static char incrementChar(char theChar) {
if (theChar == 'Z') {
return '0';
}
if (theChar == '9') {
return 'A';
}
return ++theChar;
}
/**
* see if we are running on windows
* @return true if windows
*/
public static boolean isWindows() {
String osname = defaultString(System.getProperty("os.name"));
if (contains(osname.toLowerCase(), "windows")) {
return true;
}
return false;
}
/**
* Increment a string with A-Z and 0-9 (no lower case so case insensitive apps
* like windows IE will still work)
*
* @param string
*
* @return the value
*/
public static char[] incrementStringInt(char[] string) {
if (string == null) {
return string;
}
//loop through the string backwards
int i = 0;
for (i = string.length - 1; i >= 0; i--) {
char inc = string[i];
inc = incrementChar(inc);
string[i] = inc;
if (inc != 'A') {
break;
}
}
//if we are at 0, then it means we hit AAAAAAA (or more)
if (i < 0) {
return ("A" + new String(string)).toCharArray();
}
return string;
}
/**
* read properties from a resource, dont modify the properties returned since they are cached
* @param resourceName
* @return the properties
*/
public synchronized static Properties propertiesFromResourceName(String resourceName) {
return propertiesFromResourceName(resourceName, true, true, null, null);
}
/**
* logger
*/
private static Log LOG = GrouperInstallerUtils.retrieveLog(GrouperInstallerUtils.class);
/**
* clear properties cache (e.g. for testing)
*/
public static void propertiesCacheClear() {
resourcePropertiesCache.clear();
}
/**
* properties from file
* @param propertiesFile
* @return properties
*/
public static Properties propertiesFromFile(File propertiesFile) {
Properties properties = new Properties();
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(propertiesFile);
properties.load(fileInputStream);
return properties;
} catch (IOException ioe) {
throw new RuntimeException("Probably reading properties from file: "
+ (propertiesFile == null ? null : propertiesFile.getAbsolutePath()), ioe);
} finally {
closeQuietly(fileInputStream);
}
}
/**
* read properties from a resource, dont modify the properties returned since they are cached
* @param resourceName
* @param useCache
* @param exceptionIfNotExist
* @param classInJar if not null, then look for the jar where this file is, and look in the same dir
* @param callingLog
* @return the properties or null if not exist
*/
public synchronized static Properties propertiesFromResourceName(String resourceName, boolean useCache,
boolean exceptionIfNotExist, Class> classInJar, StringBuilder callingLog) {
Properties properties = resourcePropertiesCache.get(resourceName);
if (!useCache || !resourcePropertiesCache.containsKey(resourceName)) {
properties = new Properties();
boolean success = false;
URL url = computeUrl(resourceName, true);
InputStream inputStream = null;
try {
inputStream = url.openStream();
properties.load(inputStream);
success = true;
String theLog = "Reading resource: " + resourceName + ", from: " + url.toURI();
if (LOG != null) {
LOG.debug(theLog);
}
if (callingLog != null) {
callingLog.append(theLog);
}
} catch (Exception e) {
//clear out just in case
properties.clear();
//lets look next to jar
File jarFile = classInJar == null ? null : jarFile(classInJar);
File parentDir = jarFile == null ? null : jarFile.getParentFile();
String fileName = parentDir == null ? null
: (stripLastSlashIfExists(fileCanonicalPath(parentDir)) + File.separator + resourceName);
File configFile = fileName == null ? null
: new File(fileName);
try {
//looks like we have a match
if (configFile != null && configFile.exists() && configFile.isFile()) {
inputStream = new FileInputStream(configFile);
properties.load(inputStream);
success = true;
String theLog = "Reading resource: " + resourceName + ", from: " + fileCanonicalPath(configFile);
if (LOG != null) {
LOG.debug(theLog);
}
if (callingLog != null) {
callingLog.append(theLog);
}
}
} catch (Exception e2) {
if (LOG != null) {
LOG.debug("Error reading from file for resource: " + resourceName + ", file: " + fileName, e2);
}
}
if (!success) {
properties = null;
if (exceptionIfNotExist) {
throw new RuntimeException("Problem with resource: '" + resourceName + "'", e);
}
}
} finally {
closeQuietly(inputStream);
if (useCache && properties != null && properties.size() > 0) {
resourcePropertiesCache.put(resourceName, properties);
}
}
}
return properties;
}
/**
* do a case-insensitive matching
* @param theEnumClass class of the enum
* @param generic type
*
* @param string
* @param exceptionOnNotFound true if exception should be thrown on not found
* @return the enum or null or exception if not found
* @throws RuntimeException if there is a problem
*/
public static > E enumValueOfIgnoreCase(Class theEnumClass, String string,
boolean exceptionOnNotFound) throws RuntimeException {
return enumValueOfIgnoreCase(theEnumClass, string, exceptionOnNotFound, true);
}
/**
* do a case-insensitive matching
* @param theEnumClass class of the enum
* @param generic type
*
* @param string
* @param exceptionOnNotFound true if exception should be thrown on not found
* @param exceptionIfInvalid if there is a string, but it is invalid, if should throw exception
* @return the enum or null or exception if not found
* @throws RuntimeException if there is a problem
*/
public static > E enumValueOfIgnoreCase(Class theEnumClass, String string,
boolean exceptionOnNotFound, boolean exceptionIfInvalid) throws RuntimeException {
if (!exceptionOnNotFound && isBlank(string)) {
return null;
}
for (E e : theEnumClass.getEnumConstants()) {
if (equalsIgnoreCase(string, e.name())) {
return e;
}
}
if (!exceptionIfInvalid) {
return null;
}
StringBuilder error = new StringBuilder(
"Cant find " + theEnumClass.getSimpleName() + " from string: '").append(string);
error.append("', expecting one of: ");
for (E e : theEnumClass.getEnumConstants()) {
error.append(e.name()).append(", ");
}
throw new RuntimeException(error.toString());
}
/**
* this assumes the property exists, and is a simple property
* @param object
* @param property
* @return the value
*/
public static Object propertyValue(Object object, String property) {
Method getter = getter(object.getClass(), property, true, true);
Object result = invokeMethod(getter, object);
return result;
}
/**
* get a value (trimmed to e) from a property file
* @param properties
* @param key
* @return the property value
*/
public static String propertiesValue(Properties properties, String key) {
return propertiesValue(properties, null, key);
}
/**
* get a value (trimmed to e) from a property file
* @param properties
* @param overrideMap for testing, to override some properties values
* @param key
* @return the property value
*/
public static String propertiesValue(Properties properties, Map overrideMap, String key) {
return propertiesValue(properties, overrideMap, null, key);
}
/**
* get a value (trimmed to e) from a property file
* @param properties
* @param overrideMap for testing or threadlocal, to override some properties values
* @param overrideMap2 for testing, to provide some properties values
* @param key
* @return the property value
*/
public static String propertiesValue(Properties properties, Map overrideMap, Map overrideMap2, String key) {
String value = overrideMap == null ? null : overrideMap.get(key);
if (isBlank(value)) {
value = overrideMap2 == null ? null : overrideMap2.get(key);
}
if (isBlank(value)) {
value = properties.getProperty(key);
}
value = trim(value);
value = substituteCommonVars(value);
return value;
}
/**
* substitute common vars like $space$ and $newline$
* @param string
* @return the string
*/
public static String substituteCommonVars(String string) {
if (string == null) {
return string;
}
//short circuit
if (string.indexOf('$') < 0) {
return string;
}
//might have $space$
string = GrouperInstallerUtils.replace(string, "$space$", " ");
//note, at some point we could be OS specific
string = GrouperInstallerUtils.replace(string, "$newline$", "\n");
return string;
}
/**
* get a boolean property, or the default if cant find
* @param properties
* @param propertyName
* @param defaultValue
* @return the boolean
*/
public static boolean propertiesValueBoolean(Properties properties,
String propertyName, boolean defaultValue) {
return propertiesValueBoolean(properties, null, propertyName, defaultValue);
}
/**
* get a boolean property, or the default if cant find. Validate also with a descriptive exception if problem
* @param resourceName
* @param properties
* @param overrideMap for testing to override properties
* @param propertyName
* @param defaultValue
* @param required
* @return the boolean
*/
public static boolean propertiesValueBoolean(String resourceName, Properties properties,
Map overrideMap, String propertyName, boolean defaultValue, boolean required) {
propertyValidateValueBoolean(resourceName, properties, overrideMap, propertyName, required, true);
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
return propertiesValueBoolean(properties, threadLocalMap, overrideMap, propertyName, defaultValue);
}
/**
* get an int property, or the default if cant find. Validate also with a descriptive exception if problem
* @param resourceName
* @param properties
* @param overrideMap for testing to override properties
* @param propertyName
* @param defaultValue
* @param required
* @return the int
*/
public static int propertiesValueInt(String resourceName, Properties properties,
Map overrideMap, String propertyName, int defaultValue, boolean required) {
propertyValidateValueInt(resourceName, properties, overrideMap, propertyName, required, true);
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
return propertiesValueInt(properties, threadLocalMap, overrideMap, propertyName, defaultValue);
}
/**
* get a boolean property, or the default if cant find. Validate also with a descriptive exception if problem
* @param resourceName
* @param properties
* @param overrideMap for threadlocal or testing to override properties
* @param propertyName
* @param required
* @return the string
*/
public static String propertiesValue(String resourceName, Properties properties,
Map overrideMap, String propertyName, boolean required) {
if (required) {
propertyValidateValueRequired(resourceName, properties, overrideMap, propertyName, true);
}
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
return propertiesValue(properties, threadLocalMap, overrideMap, propertyName);
}
/**
* get a int property, or the default if cant find
* @param properties
* @param overrideMap for testing to override properties
* @param propertyName
* @param defaultValue
* @return the int
*/
public static int propertiesValueInt(Properties properties,
Map overrideMap, String propertyName, int defaultValue) {
return propertiesValueInt(properties, overrideMap, null, propertyName, defaultValue);
}
/**
* get a int property, or the default if cant find
* @param properties
* @param overrideMap for testing to override properties
* @param overrideMap2
* @param propertyName
* @param defaultValue
* @return the int
*/
public static int propertiesValueInt(Properties properties,
Map overrideMap, Map overrideMap2, String propertyName, int defaultValue) {
String value = propertiesValue(properties, overrideMap, overrideMap2, propertyName);
if (isBlank(value)) {
return defaultValue;
}
try {
return intValue(value);
} catch (Exception e) {}
throw new RuntimeException("Invalid int value: '" + value + "' for property: " + propertyName + " in grouper.properties");
}
/**
* get a boolean property, or the default if cant find
* @param properties
* @param overrideMap for testing to override properties
* @param propertyName
* @param defaultValue
* @return the boolean
*/
public static boolean propertiesValueBoolean(Properties properties,
Map overrideMap, String propertyName, boolean defaultValue) {
return propertiesValueBoolean(properties, overrideMap, null, propertyName, defaultValue);
}
/**
* get a boolean property, or the default if cant find
* @param properties
* @param overrideMap for testing or threadlocal to override properties
* @param overrideMap2 for testing or threadlocal to override properties
* @param propertyName
* @param defaultValue
* @return the boolean
*/
public static boolean propertiesValueBoolean(Properties properties,
Map overrideMap, Map overrideMap2, String propertyName, boolean defaultValue) {
String value = propertiesValue(properties, overrideMap, overrideMap2, propertyName);
if (isBlank(value)) {
return defaultValue;
}
if ("true".equalsIgnoreCase(value)) {
return true;
}
if ("false".equalsIgnoreCase(value)) {
return false;
}
if ("t".equalsIgnoreCase(value)) {
return true;
}
if ("f".equalsIgnoreCase(value)) {
return false;
}
throw new RuntimeException("Invalid boolean value: '" + value + "' for property: " + propertyName + " in properties file");
}
/**
* close a connection null safe and dont throw exception
* @param connection
*/
public static void closeQuietly(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
//ignore
}
}
}
/**
* close a statement null safe and dont throw exception
* @param statement
*/
public static void closeQuietly(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
//ignore
}
}
}
/**
* close a resultSet null safe and dont throw exception
* @param resultSet
*/
public static void closeQuietly(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
//ignore
}
}
}
/** cache the hostname, it wont change */
private static String hostname = null;
/**
* get the hostname of this machine
* @return the hostname
*/
public static String hostname() {
if (isBlank(hostname)) {
//get the hostname
hostname = "unknown";
try {
InetAddress addr = InetAddress.getLocalHost();
// Get hostname
hostname = addr.getHostName();
} catch (Exception e) {
System.err.println("Cant find servers hostname: ");
e.printStackTrace();
}
}
return hostname;
}
/**
* is ascii char
* @param input
* @return true if ascii
*/
public static boolean isAscii(char input) {
return input < 128;
}
/**
* find the length of ascii chars (non ascii are counted as two)
* @param input
* @return the length of ascii chars
*/
public static int lengthAscii(String input) {
if (input == null) {
return 0;
}
//see what real length is
int utfLength = input.length();
//count how many non asciis
int extras = 0;
for (int i=0;i requiredLength) {
//do not include the current char
return input.substring(0,i);
}
}
//must have fit
return input;
}
/**
* if the input is a file, read string from file. if not, or if disabled from grouper.properties, return the input
* @param in
* @param disableExternalFileLookup
* @return the result
*/
public static String readFromFileIfFile(String in, boolean disableExternalFileLookup) {
String theIn = in;
//convert both slashes to file slashes
if (File.separatorChar == '/') {
theIn = replace(theIn, "\\", "/");
} else {
theIn = replace(theIn, "/", "\\");
}
//see if it is a file reference
if (theIn.indexOf(File.separatorChar) != -1 && !disableExternalFileLookup) {
//read the contents of the file into a string
theIn = readFileIntoString(new File(theIn));
return theIn;
}
return in;
}
/**
* Create directories, throw exception if not possible.
* This is will be ok if the directory already exists (will not delete it)
* @param dir
*/
public static void mkdirs(File dir) {
if (!dir.exists()) {
if (!dir.mkdirs()) {
throw new RuntimeException("Could not create directory : " + dir.getParentFile());
}
return;
}
if (!dir.isDirectory()) {
throw new RuntimeException("Should be a directory but is not: " + dir);
}
}
/**
* null safe string compare
* @param first
* @param second
* @return true if equal
*/
public static boolean equals(String first, String second) {
if (first == second) {
return true;
}
if (first == null || second == null) {
return false;
}
return first.equals(second);
}
/**
* Checks if a String is whitespace, empty ("") or null.
*
*
* isBlank(null) = true
* isBlank("") = true
* isBlank(" ") = true
* isBlank("bob") = false
* isBlank(" bob ") = false
*
*
* @param str the String to check, may be null
* @return true
if the String is null, empty or whitespace
* @since 2.0
*/
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
/**
*
* @param str
* @return true if not blank
*/
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
* trim whitespace from string
* @param str
* @return trimmed string
*/
public static String trim(String str) {
return str == null ? null : str.trim();
}
/**
* equalsignorecase
* @param str1
* @param str2
* @return true if the strings are equal ignore case
*/
public static boolean equalsIgnoreCase(String str1, String str2) {
return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
}
/**
* trim to empty, convert null to empty
* @param str
* @return trimmed
*/
public static String trimToEmpty(String str) {
return str == null ? "" : str.trim();
}
/**
* Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "Now is the time for..."
*
* Specifically:
*
* If str
is less than maxWidth
characters
* long, return it.
* Else abbreviate it to (substring(str, 0, max-3) + "...")
.
* If maxWidth
is less than 4
, throw an
* IllegalArgumentException
.
* In no case will it return a String of length greater than
* maxWidth
.
*
*
*
*
* StringUtils.abbreviate(null, *) = null
* StringUtils.abbreviate("", 4) = ""
* StringUtils.abbreviate("abcdefg", 6) = "abc..."
* StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
* StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
* StringUtils.abbreviate("abcdefg", 4) = "a..."
* StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param maxWidth maximum length of result String, must be at least 4
* @return abbreviated String, null
if null String input
* @throws IllegalArgumentException if the width is too small
* @since 2.0
*/
public static String abbreviate(String str, int maxWidth) {
return abbreviate(str, 0, maxWidth);
}
/**
* Abbreviates a String using ellipses. This will turn
* "Now is the time for all good men" into "...is the time for..."
*
* Works like abbreviate(String, int)
, but allows you to specify
* a "left edge" offset. Note that this left edge is not necessarily going to
* be the leftmost character in the result, or the first character following the
* ellipses, but it will appear somewhere in the result.
*
*
In no case will it return a String of length greater than
* maxWidth
.
*
*
* StringUtils.abbreviate(null, *, *) = null
* StringUtils.abbreviate("", 0, 4) = ""
* StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
* StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
* StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
* StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
* StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
* StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
*
*
* @param str the String to check, may be null
* @param offset left edge of source String
* @param maxWidth maximum length of result String, must be at least 4
* @return abbreviated String, null
if null String input
* @throws IllegalArgumentException if the width is too small
* @since 2.0
*/
public static String abbreviate(String str, int offset, int maxWidth) {
if (str == null) {
return null;
}
if (maxWidth < 4) {
throw new IllegalArgumentException("Minimum abbreviation width is 4");
}
if (str.length() <= maxWidth) {
return str;
}
if (offset > str.length()) {
offset = str.length();
}
if ((str.length() - offset) < (maxWidth - 3)) {
offset = str.length() - (maxWidth - 3);
}
if (offset <= 4) {
return str.substring(0, maxWidth - 3) + "...";
}
if (maxWidth < 7) {
throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
}
if ((offset + (maxWidth - 3)) < str.length()) {
return "..." + abbreviate(str.substring(offset), maxWidth - 3);
}
return "..." + str.substring(str.length() - (maxWidth - 3));
}
// Splitting
//-----------------------------------------------------------------------
/**
* Splits the provided text into an array, using whitespace as the
* separator.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
*
*
* StringUtils.split(null) = null
* StringUtils.split("") = []
* StringUtils.split("abc def") = ["abc", "def"]
* StringUtils.split("abc def") = ["abc", "def"]
* StringUtils.split(" abc ") = ["abc"]
*
*
* @param str the String to parse, may be null
* @return an array of parsed Strings, null
if null String input
*/
public static String[] split(String str) {
return split(str, null, -1);
}
/**
* Splits the provided text into an array, separator specified.
* This is an alternative to using StringTokenizer.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
*
*
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
* StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
* StringUtils.split("a:b:c", '.') = ["a:b:c"]
* StringUtils.split("a\tb\nc", null) = ["a", "b", "c"]
* StringUtils.split("a b c", ' ') = ["a", "b", "c"]
*
*
* @param str the String to parse, may be null
* @param separatorChar the character used as the delimiter,
* null
splits on whitespace
* @return an array of parsed Strings, null
if null String input
* @since 2.0
*/
public static String[] split(String str, char separatorChar) {
return splitWorker(str, separatorChar, false);
}
/**
* Splits the provided text into an array, separators specified.
* This is an alternative to using StringTokenizer.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
*
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("abc def", null) = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
*
*
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* null
splits on whitespace
* @return an array of parsed Strings, null
if null String input
*/
public static String[] split(String str, String separatorChars) {
return splitWorker(str, separatorChars, -1, false);
}
/**
* Splits the provided text into an array with a maximum length,
* separators specified.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
*
* A null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
* If more than max
delimited substrings are found, the last
* returned string includes all characters after the first max - 1
* returned strings (including separator characters).
*
*
* StringUtils.split(null, *, *) = null
* StringUtils.split("", *, *) = []
* StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
* StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
* StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
* StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
*
*
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* null
splits on whitespace
* @param max the maximum number of elements to include in the
* array. A zero or negative value implies no limit
* @return an array of parsed Strings, null
if null String input
*/
public static String[] split(String str, String separatorChars, int max) {
return splitWorker(str, separatorChars, max, false);
}
/**
* Splits the provided text into an array, separator string specified.
*
* The separator(s) will not be included in the returned String array.
* Adjacent separators are treated as one separator.
*
* A null
input String returns null
.
* A null
separator splits on whitespace.
*
*
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("ab de fg", null) = ["ab", "de", "fg"]
* StringUtils.split("ab de fg", null) = ["ab", "de", "fg"]
* StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
* StringUtils.split("abstemiouslyaeiouyabstemiously", "aeiouy") = ["bst", "m", "sl", "bst", "m", "sl"]
* StringUtils.split("abstemiouslyaeiouyabstemiously", "aeiouy") = ["abstemiously", "abstemiously"]
*
*
* @param str the String to parse, may be null
* @param separator String containing the String to be used as a delimiter,
* null
splits on whitespace
* @return an array of parsed Strings, null
if null String was input
*/
public static String[] splitByWholeSeparator(String str, String separator) {
return splitByWholeSeparator(str, separator, -1);
}
/**
* Splits the provided text into an array, separator string specified.
* Returns a maximum of max
substrings.
*
* The separator(s) will not be included in the returned String array.
* Adjacent separators are treated as one separator.
*
* A null
input String returns null
.
* A null
separator splits on whitespace.
*
*
* StringUtils.splitByWholeSeparator(null, *, *) = null
* StringUtils.splitByWholeSeparator("", *, *) = []
* StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
* StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
* StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd"]
* StringUtils.splitByWholeSeparator("abstemiouslyaeiouyabstemiously", "aeiouy", 2) = ["bst", "m"]
* StringUtils.splitByWholeSeparator("abstemiouslyaeiouyabstemiously", "aeiouy", 2) = ["abstemiously", "abstemiously"]
*
*
* @param str the String to parse, may be null
* @param separator String containing the String to be used as a delimiter,
* null
splits on whitespace
* @param max the maximum number of elements to include in the returned
* array. A zero or negative value implies no limit.
* @return an array of parsed Strings, null
if null String was input
*/
@SuppressWarnings("unchecked")
public static String[] splitByWholeSeparator(String str, String separator, int max) {
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
if ((separator == null) || ("".equals(separator))) {
// Split on whitespace.
return split(str, null, max);
}
int separatorLength = separator.length();
ArrayList substrings = new ArrayList();
int numberOfSubstrings = 0;
int beg = 0;
int end = 0;
while (end < len) {
end = str.indexOf(separator, beg);
if (end > -1) {
if (end > beg) {
numberOfSubstrings += 1;
if (numberOfSubstrings == max) {
end = len;
substrings.add(str.substring(beg));
} else {
// The following is OK, because String.substring( beg, end ) excludes
// the character at the position 'end'.
substrings.add(str.substring(beg, end));
// Set the starting point for the next search.
// The following is equivalent to beg = end + (separatorLength - 1) + 1,
// which is the right calculation:
beg = end + separatorLength;
}
} else {
// We found a consecutive occurrence of the separator, so skip it.
beg = end + separatorLength;
}
} else {
// String.substring( beg ) goes from 'beg' to the end of the String.
substrings.add(str.substring(beg));
end = len;
}
}
return (String[]) substrings.toArray(new String[substrings.size()]);
}
//-----------------------------------------------------------------------
/**
* Splits the provided text into an array, using whitespace as the
* separator, preserving all tokens, including empty tokens created by
* adjacent separators. This is an alternative to using StringTokenizer.
* Whitespace is defined by {@link Character#isWhitespace(char)}.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as separators for empty tokens.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
*
*
* StringUtils.splitPreserveAllTokens(null) = null
* StringUtils.splitPreserveAllTokens("") = []
* StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
* StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
* StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
*
*
* @param str the String to parse, may be null
* @return an array of parsed Strings, null
if null String input
* @since 2.1
*/
public static String[] splitPreserveAllTokens(String str) {
return splitWorker(str, null, -1, true);
}
/**
* Splits the provided text into an array, separator specified,
* preserving all tokens, including empty tokens created by adjacent
* separators. This is an alternative to using StringTokenizer.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as separators for empty tokens.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
*
*
* StringUtils.splitPreserveAllTokens(null, *) = null
* StringUtils.splitPreserveAllTokens("", *) = []
* StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
* StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "b", "c"]
* StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
* StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
* StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
* StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
* StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
* StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
* StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
* StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
*
*
* @param str the String to parse, may be null
* @param separatorChar the character used as the delimiter,
* null
splits on whitespace
* @return an array of parsed Strings, null
if null String input
* @since 2.1
*/
public static String[] splitPreserveAllTokens(String str, char separatorChar) {
return splitWorker(str, separatorChar, true);
}
/**
* Performs the logic for the split
and
* splitPreserveAllTokens
methods that do not return a
* maximum array length.
*
* @param str the String to parse, may be null
* @param separatorChar the separate character
* @param preserveAllTokens if true
, adjacent separators are
* treated as empty token separators; if false
, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, null
if null String input
*/
@SuppressWarnings("unchecked")
private static String[] splitWorker(String str, char separatorChar,
boolean preserveAllTokens) {
// Performance tuned for 2.0 (JDK1.4)
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
while (i < len) {
if (str.charAt(i) == separatorChar) {
if (match || preserveAllTokens) {
list.add(str.substring(start, i));
match = false;
lastMatch = true;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Splits the provided text into an array, separators specified,
* preserving all tokens, including empty tokens created by adjacent
* separators. This is an alternative to using StringTokenizer.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as separators for empty tokens.
* For more control over the split use the StrTokenizer class.
*
* A null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
*
* StringUtils.splitPreserveAllTokens(null, *) = null
* StringUtils.splitPreserveAllTokens("", *) = []
* StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
* StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
* StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
* StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
* StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
* StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
* StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
* StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
* StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
* StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
*
*
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* null
splits on whitespace
* @return an array of parsed Strings, null
if null String input
* @since 2.1
*/
public static String[] splitPreserveAllTokens(String str, String separatorChars) {
return splitWorker(str, separatorChars, -1, true);
}
/**
* Splits the provided text into an array with a maximum length,
* separators specified, preserving all tokens, including empty tokens
* created by adjacent separators.
*
* The separator is not included in the returned String array.
* Adjacent separators are treated as separators for empty tokens.
* Adjacent separators are treated as one separator.
*
* A null
input String returns null
.
* A null
separatorChars splits on whitespace.
*
* If more than max
delimited substrings are found, the last
* returned string includes all characters after the first max - 1
* returned strings (including separator characters).
*
*
* StringUtils.splitPreserveAllTokens(null, *, *) = null
* StringUtils.splitPreserveAllTokens("", *, *) = []
* StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
* StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
* StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
* StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
* StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
* StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
* StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
*
*
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* null
splits on whitespace
* @param max the maximum number of elements to include in the
* array. A zero or negative value implies no limit
* @return an array of parsed Strings, null
if null String input
* @since 2.1
*/
public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
return splitWorker(str, separatorChars, max, true);
}
/**
* Performs the logic for the split
and
* splitPreserveAllTokens
methods that return a maximum array
* length.
*
* @param str the String to parse, may be null
* @param separatorChars the separate character
* @param max the maximum number of elements to include in the
* array. A zero or negative value implies no limit.
* @param preserveAllTokens if true
, adjacent separators are
* treated as empty token separators; if false
, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, null
if null String input
*/
@SuppressWarnings("unchecked")
private static String[] splitWorker(String str, String separatorChars, int max,
boolean preserveAllTokens) {
// Performance tuned for 2.0 (JDK1.4)
// Direct code is quicker than StringTokenizer.
// Also, StringTokenizer uses isSpace() not isWhitespace()
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int sizePlus1 = 1;
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
// Null separator means use whitespace
while (i < len) {
if (Character.isWhitespace(str.charAt(i))) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// Optimise 1 character case
char sep = separatorChars.charAt(0);
while (i < len) {
if (str.charAt(i) == sep) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else {
// standard case
while (i < len) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
// Joining
//-----------------------------------------------------------------------
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No separator is added to the joined String.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null) = null
* StringUtils.join([]) = ""
* StringUtils.join([null]) = ""
* StringUtils.join(["a", "b", "c"]) = "abc"
* StringUtils.join([null, "", "a"]) = "a"
*
*
* @param array the array of values to join together, may be null
* @return the joined String, null
if null array input
* @since 2.0
*/
public static String join(Object[] array) {
return join(array, null);
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join([null, "", "a"], ';') = ";;a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, null
if null array input
* @since 2.0
*/
public static String join(Object[] array, char separator) {
if (array == null) {
return null;
}
int arraySize = array.length;
int bufSize = (arraySize == 0 ? 0 : ((array[0] == null ? 16 : array[0].toString()
.length()) + 1)
* arraySize);
StringBuffer buf = new StringBuffer(bufSize);
for (int i = 0; i < arraySize; i++) {
if (i > 0) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided array into a single String
* containing the provided list of elements.
*
* No delimiter is added before or after the list.
* A null
separator is the same as an empty String ("").
* Null objects or empty strings within the array are represented by
* empty strings.
*
*
* StringUtils.join(null, *) = null
* StringUtils.join([], *) = ""
* StringUtils.join([null], *) = ""
* StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
* StringUtils.join(["a", "b", "c"], null) = "abc"
* StringUtils.join(["a", "b", "c"], "") = "abc"
* StringUtils.join([null, "", "a"], ',') = ",,a"
*
*
* @param array the array of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, null
if null array input
*/
public static String join(Object[] array, String separator) {
if (array == null) {
return null;
}
if (separator == null) {
separator = "";
}
int arraySize = array.length;
// ArraySize == 0: Len = 0
// ArraySize > 0: Len = NofStrings *(len(firstString) + len(separator))
// (Assuming that all Strings are roughly equally long)
int bufSize = ((arraySize == 0) ? 0 : arraySize
* ((array[0] == null ? 16 : array[0].toString().length()) + separator.length()));
StringBuffer buf = new StringBuffer(bufSize);
for (int i = 0; i < arraySize; i++) {
if (i > 0) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided Iterator
into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list. Null objects or empty
* strings within the iteration are represented by empty strings.
*
* See the examples here: {@link #join(Object[],char)}.
*
* @param iterator the Iterator
of values to join together, may be null
* @param separator the separator character to use
* @return the joined String, null
if null iterator input
* @since 2.0
*/
public static String join(Iterator iterator, char separator) {
if (iterator == null) {
return null;
}
StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
if (iterator.hasNext()) {
buf.append(separator);
}
}
return buf.toString();
}
/**
* Joins the elements of the provided Iterator
into
* a single String containing the provided elements.
*
* No delimiter is added before or after the list.
* A null
separator is the same as an empty String ("").
*
* See the examples here: {@link #join(Object[],String)}.
*
* @param iterator the Iterator
of values to join together, may be null
* @param separator the separator character to use, null treated as ""
* @return the joined String, null
if null iterator input
*/
public static String join(Iterator iterator, String separator) {
if (iterator == null) {
return null;
}
StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
if ((separator != null) && iterator.hasNext()) {
buf.append(separator);
}
}
return buf.toString();
}
/**
* Returns either the passed in String,
* or if the String is null
, an empty String ("").
*
*
* StringUtils.defaultString(null) = ""
* StringUtils.defaultString("") = ""
* StringUtils.defaultString("bat") = "bat"
*
*
* @see String#valueOf(Object)
* @param str the String to check, may be null
* @return the passed in String, or the empty String if it
* was null
*/
public static String defaultString(String str) {
return str == null ? "" : str;
}
/**
* Returns either the passed in String, or if the String is
* null
, the value of defaultStr
.
*
*
* StringUtils.defaultString(null, "NULL") = "NULL"
* StringUtils.defaultString("", "NULL") = ""
* StringUtils.defaultString("bat", "NULL") = "bat"
*
*
* @see String#valueOf(Object)
* @param str the String to check, may be null
* @param defaultStr the default String to return
* if the input is null
, may be null
* @return the passed in String, or the default if it was null
*/
public static String defaultString(String str, String defaultStr) {
return str == null ? defaultStr : str;
}
/**
* Returns either the passed in String, or if the String is
* empty or null
, the value of defaultStr
.
*
*
* StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
* StringUtils.defaultIfEmpty("", "NULL") = "NULL"
* StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
*
*
* @param str the String to check, may be null
* @param defaultStr the default String to return
* if the input is empty ("") or null
, may be null
* @return the passed in String, or the default
*/
public static String defaultIfEmpty(String str, String defaultStr) {
return isEmpty(str) ? defaultStr : str;
}
/**
* Capitalizes a String changing the first letter to title case as
* per {@link Character#toTitleCase(char)}. No other letters are changed.
*
* A null
input String returns null
.
*
*
* StringUtils.capitalize(null) = null
* StringUtils.capitalize("") = ""
* StringUtils.capitalize("cat") = "Cat"
* StringUtils.capitalize("cAt") = "CAt"
*
*
* @param str the String to capitalize, may be null
* @return the capitalized String, null
if null String input
* @since 2.0
*/
public static String capitalize(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
return new StringBuffer(strLen).append(Character.toTitleCase(str.charAt(0))).append(
str.substring(1)).toString();
}
/**
* Checks if String contains a search character, handling null
.
* This method uses {@link String#indexOf(int)}.
*
* A null
or empty ("") String will return false
.
*
*
* StringUtils.contains(null, *) = false
* StringUtils.contains("", *) = false
* StringUtils.contains("abc", 'a') = true
* StringUtils.contains("abc", 'z') = false
*
*
* @param str the String to check, may be null
* @param searchChar the character to find
* @return true if the String contains the search character,
* false if not or null
string input
* @since 2.0
*/
public static boolean contains(String str, char searchChar) {
if (isEmpty(str)) {
return false;
}
return str.indexOf(searchChar) >= 0;
}
/**
* Checks if String contains a search String, handling null
.
* This method uses {@link String#indexOf(int)}.
*
* A null
String will return false
.
*
*
* StringUtils.contains(null, *) = false
* StringUtils.contains(*, null) = false
* StringUtils.contains("", "") = true
* StringUtils.contains("abc", "") = true
* StringUtils.contains("abc", "a") = true
* StringUtils.contains("abc", "z") = false
*
*
* @param str the String to check, may be null
* @param searchStr the String to find, may be null
* @return true if the String contains the search String,
* false if not or null
string input
* @since 2.0
*/
public static boolean contains(String str, String searchStr) {
if (str == null || searchStr == null) {
return false;
}
return str.indexOf(searchStr) >= 0;
}
/**
* An empty immutable String
array.
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* Compares two objects for equality, where either one or both
* objects may be null
.
*
*
* ObjectUtils.equals(null, null) = true
* ObjectUtils.equals(null, "") = false
* ObjectUtils.equals("", null) = false
* ObjectUtils.equals("", "") = true
* ObjectUtils.equals(Boolean.TRUE, null) = false
* ObjectUtils.equals(Boolean.TRUE, "true") = false
* ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
* ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
*
*
* @param object1 the first object, may be null
* @param object2 the second object, may be null
* @return true
if the values of both objects are the same
*/
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if ((object1 == null) || (object2 == null)) {
return false;
}
return object1.equals(object2);
}
/**
* A way to get the entire nested stack-trace of an throwable.
*
* @param throwable the Throwable
to be examined
* @return the nested stack trace, with the root cause first
* @since 2.0
*/
public static String getFullStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
Throwable[] ts = getThrowables(throwable);
for (int i = 0; i < ts.length; i++) {
ts[i].printStackTrace(pw);
if (isNestedThrowable(ts[i])) {
break;
}
}
return sw.getBuffer().toString();
}
/**
* Returns the list of Throwable
objects in the
* exception chain.
*
* A throwable without cause will return an array containing
* one element - the input throwable.
* A throwable with one cause will return an array containing
* two elements. - the input throwable and the cause throwable.
* A null
throwable will return an array size zero.
*
* @param throwable the throwable to inspect, may be null
* @return the array of throwables, never null
*/
@SuppressWarnings("unchecked")
public static Throwable[] getThrowables(Throwable throwable) {
List list = new ArrayList();
while (throwable != null) {
list.add(throwable);
throwable = getCause(throwable);
}
return (Throwable[]) list.toArray(new Throwable[list.size()]);
}
/**
* The names of methods commonly used to access a wrapped exception.
*/
private static String[] CAUSE_METHOD_NAMES = {
"getCause",
"getNextException",
"getTargetException",
"getException",
"getSourceException",
"getRootCause",
"getCausedByException",
"getNested",
"getLinkedException",
"getNestedException",
"getLinkedCause",
"getThrowable",
};
/**
* Checks whether this Throwable
class can store a cause.
*
* This method does not check whether it actually does store a cause.
*
* @param throwable the Throwable
to examine, may be null
* @return boolean true
if nested otherwise false
* @since 2.0
*/
public static boolean isNestedThrowable(Throwable throwable) {
if (throwable == null) {
return false;
}
if (throwable instanceof SQLException) {
return true;
} else if (throwable instanceof InvocationTargetException) {
return true;
} else if (isThrowableNested()) {
return true;
}
Class cls = throwable.getClass();
for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) {
try {
Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], (Class[])null);
if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
return true;
}
} catch (NoSuchMethodException ignored) {
} catch (SecurityException ignored) {
}
}
try {
Field field = cls.getField("detail");
if (field != null) {
return true;
}
} catch (NoSuchFieldException ignored) {
} catch (SecurityException ignored) {
}
return false;
}
/**
*
The Method object for JDK1.4 getCause.
*/
private static final Method THROWABLE_CAUSE_METHOD;
static {
Method getCauseMethod;
try {
getCauseMethod = Throwable.class.getMethod("getCause", (Class[])null);
} catch (Exception e) {
getCauseMethod = null;
}
THROWABLE_CAUSE_METHOD = getCauseMethod;
}
/**
* Checks if the Throwable class has a getCause
method.
*
* This is true for JDK 1.4 and above.
*
* @return true if Throwable is nestable
* @since 2.0
*/
public static boolean isThrowableNested() {
return THROWABLE_CAUSE_METHOD != null;
}
/**
* Introspects the Throwable
to obtain the cause.
*
* The method searches for methods with specific names that return a
* Throwable
object. This will pick up most wrapping exceptions,
* including those from JDK 1.4, and
*
* The default list searched for are:
*
* getCause()
* getNextException()
* getTargetException()
* getException()
* getSourceException()
* getRootCause()
* getCausedByException()
* getNested()
*
*
* In the absence of any such method, the object is inspected for a
* detail
field assignable to a Throwable
.
*
* If none of the above is found, returns null
.
*
* @param throwable the throwable to introspect for a cause, may be null
* @return the cause of the Throwable
,
* null
if none found or null throwable input
* @since 1.0
*/
public static Throwable getCause(Throwable throwable) {
return getCause(throwable, CAUSE_METHOD_NAMES);
}
/**
* Introspects the Throwable
to obtain the cause.
*
*
* Try known exception types.
* Try the supplied array of method names.
* Try the field 'detail'.
*
*
* A null
set of method names means use the default set.
* A null
in the set of method names will be ignored.
*
* @param throwable the throwable to introspect for a cause, may be null
* @param methodNames the method names, null treated as default set
* @return the cause of the Throwable
,
* null
if none found or null throwable input
* @since 1.0
*/
public static Throwable getCause(Throwable throwable, String[] methodNames) {
if (throwable == null) {
return null;
}
Throwable cause = getCauseUsingWellKnownTypes(throwable);
if (cause == null) {
if (methodNames == null) {
methodNames = CAUSE_METHOD_NAMES;
}
for (int i = 0; i < methodNames.length; i++) {
String methodName = methodNames[i];
if (methodName != null) {
cause = getCauseUsingMethodName(throwable, methodName);
if (cause != null) {
break;
}
}
}
if (cause == null) {
cause = getCauseUsingFieldName(throwable, "detail");
}
}
return cause;
}
/**
* Finds a Throwable
by method name.
*
* @param throwable the exception to examine
* @param methodName the name of the method to find and invoke
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
Method method = null;
try {
method = throwable.getClass().getMethod(methodName, (Class[])null);
} catch (NoSuchMethodException ignored) {
} catch (SecurityException ignored) {
}
if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
try {
return (Throwable) method.invoke(throwable, EMPTY_OBJECT_ARRAY);
} catch (IllegalAccessException ignored) {
} catch (IllegalArgumentException ignored) {
} catch (InvocationTargetException ignored) {
}
}
return null;
}
/**
* Finds a Throwable
by field name.
*
* @param throwable the exception to examine
* @param fieldName the name of the attribute to examine
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) {
Field field = null;
try {
field = throwable.getClass().getField(fieldName);
} catch (NoSuchFieldException ignored) {
} catch (SecurityException ignored) {
}
if (field != null && Throwable.class.isAssignableFrom(field.getType())) {
try {
return (Throwable) field.get(throwable);
} catch (IllegalAccessException ignored) {
} catch (IllegalArgumentException ignored) {
}
}
return null;
}
/**
* Finds a Throwable
for known types.
*
* Uses instanceof
checks to examine the exception,
* looking for well known types which could contain chained or
* wrapped exceptions.
*
* @param throwable the exception to examine
* @return the wrapped exception, or null
if not found
*/
private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) {
if (throwable instanceof SQLException) {
return ((SQLException) throwable).getNextException();
} else if (throwable instanceof InvocationTargetException) {
return ((InvocationTargetException) throwable).getTargetException();
} else {
return null;
}
}
/**
* An empty immutable Object
array.
*/
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* from a command line arg, get the key. e.g. if input is --whatever=something
* then key is whatever, value is something
* @param option
* @return the key */
public static String argKey(String option) {
int equalsIndex = option.indexOf("=");
if (equalsIndex == -1) {
throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue");
}
String key = option.substring(0,equalsIndex);
if (!key.startsWith("--")) {
throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue");
}
key = key.substring(2);
return key;
}
/**
* from a command line arg, get the key. e.g. if input is --whatever=something
* then key is whatever, value is something
* @param option
* @return the value
*/
public static String argValue(String option) {
int equalsIndex = option.indexOf("=");
if (equalsIndex == -1) {
throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue");
}
String value = option.substring(equalsIndex+1, option.length());
return value;
}
/** add an option: --whatever=val to a map of options where --whatever is key, and val is value
* @param args
* @return the map
*/
public static Map argMap(String[] args) {
Map result = new LinkedHashMap();
for (String arg : nonNull(args,String.class)) {
String key = argKey(arg);
String value = argValue(arg);
if (result.containsKey(key)) {
throw new RuntimeException("Passing key twice: " + key);
}
result.put(key, value);
}
return result;
}
/**
* create a file, throw exception if doesnt work (unless already exists)
* @param fileToCreate
* @return if created
*/
public static boolean fileCreate(File fileToCreate) {
if (fileToCreate.exists() && fileToCreate.isFile()) {
return false;
}
if (fileToCreate.exists() && !fileToCreate.isFile()) {
throw new RuntimeException("Trying to create file and it doesnt exist: " + fileToCreate.getAbsolutePath());
}
try {
if (!fileToCreate.createNewFile()) {
throw new RuntimeException("Cant create file: " + fileToCreate);
}
} catch (IOException ioe) {
throw new RuntimeException("Cant create file: " + fileToCreate.getAbsolutePath(), ioe);
}
return true;
}
/**
* get the value from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @return the value or null or exception
*/
public static String argMapString(Map argMap, Map argMapNotUsed,
String key, boolean required) {
if (argMap.containsKey(key)) {
//keep track that this is gone
argMapNotUsed.remove(key);
return argMap.get(key);
}
if (required) {
throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=value");
}
return null;
}
/**
* Copies a directory to within another directory preserving the file dates.
*
* This method copies the source directory and all its contents to a
* directory of the same name in the specified destination directory.
*
* The destination directory is created if it does not exist.
* If the destination directory did exist, then this method merges
* the source with the destination, with the source taking precedence.
*
* @param srcDir an existing directory to copy, must not be null
* @param destDir the directory to place the copy in, must not be null
*
* @throws NullPointerException if source or destination is null
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.2
*/
public static void copyDirectoryToDirectory(File srcDir, File destDir)
throws IOException {
if (srcDir == null) {
throw new NullPointerException("Source must not be null");
}
if (srcDir.exists() && srcDir.isDirectory() == false) {
throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
}
if (destDir == null) {
throw new NullPointerException("Destination must not be null");
}
if (destDir.exists() && destDir.isDirectory() == false) {
throw new IllegalArgumentException("Destination '" + destDir
+ "' is not a directory");
}
copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
}
/**
* Copies a whole directory to a new location preserving the file dates.
*
* This method copies the specified directory and all its child
* directories and files to the specified destination.
* The destination is the new location and name of the directory.
*
* The destination directory is created if it does not exist.
* If the destination directory did exist, then this method merges
* the source with the destination, with the source taking precedence.
*
* @param srcDir an existing directory to copy, must not be null
* @param destDir the new directory, must not be null
*
* @throws NullPointerException if source or destination is null
* @since Commons IO 1.1
*/
public static void copyDirectory(File srcDir, File destDir) {
try {
copyDirectory(srcDir, destDir, true);
} catch (IOException ioe) {
throw new RuntimeException("Problem with sourceDir: " + srcDir + ", destDir: " + destDir, ioe);
}
}
/**
* find a jar
* @param allJars
* @param fileName
* @return the list that matches
*/
public static List jarFindJar(List allJars, String fileName) {
Set result = new HashSet();
//find the passed in base file name
Set baseFileNames = jarFileBaseNames(fileName);
if (GrouperInstallerUtils.length(baseFileNames) == 0) {
throw new RuntimeException("Why is base file name null? " + fileName);
}
//loop through and find matchers
for (File file : allJars) {
if (!file.getName().endsWith(".jar")) {
continue;
}
Set fileBaseFileNames = jarFileBaseNames(file.getName());
for (String fileBaseFileName : GrouperInstallerUtils.nonNull(fileBaseFileNames)) {
if (baseFileNames.contains(fileBaseFileName)) {
result.add(file);
}
}
}
return new ArrayList(result);
}
/**
* find a jar
* @param dir
* @param fileName
* @return the list that matches
*/
public static List jarFindJar(File dir, String fileName) {
if (dir.getName().equals("grouper") || dir.getName().equals("custom") || dir.getName().equals("jdbcSamples")) {
return jarFindJar(dir.getParentFile(), fileName);
}
return jarFindJar(GrouperInstallerUtils.fileListRecursive(dir), fileName);
}
/**
* if jarfile is someThing-1.2.3.jar, return something
* @param fileName
* @return the base file name for jar or null
*/
public static Set jarFileBaseNames(String fileName) {
Set result = new HashSet();
Pattern pattern = Pattern.compile("^(.*?)-[0-9].*.jar$");
Matcher matcher = pattern.matcher(fileName);
String baseName = null;
if (matcher.matches()) {
baseName = matcher.group(1);
} else if (fileName.endsWith(".jar")) {
baseName = fileName.substring(0, fileName.length() - ".jar".length());
} else {
return result;
}
result.add(baseName.toLowerCase());
if (baseName.endsWith("-core")) {
baseName = baseName.substring(0, baseName.length() - "-core".length());
result.add(baseName.toLowerCase());
}
if (baseName.toLowerCase().equals("mysql-connector-java") || baseName.toLowerCase().equals("mysql-connector-java-bin")) {
result.add("mysql-connector-java");
result.add("mysql-connector-java-bin");
}
if (baseName.toLowerCase().equals("mail") || baseName.toLowerCase().equals("mailapi")) {
result.add("mail");
result.add("mailapi");
}
return result;
}
/**
* if a collection contains any element in another collection
* @param
* @param a
* @param b
* @return true if contains
*/
public static boolean containsAny(Collection a, Collection b) {
if (a == null || b == null) {
return false;
}
for (T t : a) {
if (b.contains(t)) {
return true;
}
}
return false;
}
/**
* if jarfile is something-1.2.3.jar, return something
* @param fileName
* @return the base file name for jar or null
*/
public static String jarFileBaseName(String fileName) {
Pattern pattern = Pattern.compile("^(.*?)-[0-9].*.jar$");
Matcher matcher = pattern.matcher(fileName);
String baseName = null;
if (matcher.matches()) {
baseName = matcher.group(1);
} else if (fileName.endsWith(".jar")) {
baseName = fileName.substring(0, fileName.length() - ".jar".length());
} else {
return null;
}
if (baseName.endsWith("-core")) {
baseName = baseName.substring(0, baseName.length() - "-core".length());
}
return baseName;
}
/**
* Copies a whole directory to a new location.
*
* This method copies the contents of the specified source directory
* to within the specified destination directory.
*
* The destination directory is created if it does not exist.
* If the destination directory did exist, then this method merges
* the source with the destination, with the source taking precedence.
*
* @param srcDir an existing directory to copy, must not be null
* @param destDir the new directory, must not be null
* @param preserveFileDate true if the file date of the copy
* should be the same as the original
*
* @throws NullPointerException if source or destination is null
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.1
*/
public static void copyDirectory(File srcDir, File destDir,
boolean preserveFileDate) throws IOException {
copyDirectory(srcDir, destDir, null, preserveFileDate);
}
/**
* Copies a filtered directory to a new location preserving the file dates.
*
* This method copies the contents of the specified source directory
* to within the specified destination directory.
*
* The destination directory is created if it does not exist.
* If the destination directory did exist, then this method merges
* the source with the destination, with the source taking precedence.
*
*
Example: Copy directories only
*
* // only copy the directory structure
* FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
*
*
* Example: Copy directories and txt files
*
* // Create a filter for ".txt" files
* IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
* IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
*
* // Create a filter for either directories or ".txt" files
* FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
*
* // Copy using the filter
* FileUtils.copyDirectory(srcDir, destDir, filter);
*
*
* @param srcDir an existing directory to copy, must not be null
* @param destDir the new directory, must not be null
* @param filter the filter to apply, null means copy all directories and files
* should be the same as the original
*
* @throws NullPointerException if source or destination is null
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.4
*/
public static void copyDirectory(File srcDir, File destDir,
FileFilter filter) throws IOException {
copyDirectory(srcDir, destDir, filter, true);
}
/**
* Copies a filtered directory to a new location.
*
* This method copies the contents of the specified source directory
* to within the specified destination directory.
*
* The destination directory is created if it does not exist.
* If the destination directory did exist, then this method merges
* the source with the destination, with the source taking precedence.
*
*
Example: Copy directories only
*
* // only copy the directory structure
* FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
*
*
* Example: Copy directories and txt files
*
* // Create a filter for ".txt" files
* IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
* IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
*
* // Create a filter for either directories or ".txt" files
* FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
*
* // Copy using the filter
* FileUtils.copyDirectory(srcDir, destDir, filter, false);
*
*
* @param srcDir an existing directory to copy, must not be null
* @param destDir the new directory, must not be null
* @param filter the filter to apply, null means copy all directories and files
* @param preserveFileDate true if the file date of the copy
* should be the same as the original
*
* @throws NullPointerException if source or destination is null
* @throws IOException if source or destination is invalid
* @throws IOException if an IO error occurs during copying
* @since Commons IO 1.4
*/
public static void copyDirectory(File srcDir, File destDir,
FileFilter filter, boolean preserveFileDate) throws IOException {
if (srcDir == null) {
throw new NullPointerException("Source must not be null");
}
if (destDir == null) {
throw new NullPointerException("Destination must not be null");
}
if (srcDir.exists() == false) {
throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
}
if (srcDir.isDirectory() == false) {
throw new IOException("Source '" + srcDir + "' exists but is not a directory");
}
if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
throw new IOException("Source '" + srcDir + "' and destination '" + destDir
+ "' are the same");
}
// Cater for destination being directory within the source directory (see IO-141)
List exclusionList = null;
if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
if (srcFiles != null && srcFiles.length > 0) {
exclusionList = new ArrayList(srcFiles.length);
for (int i = 0; i < srcFiles.length; i++) {
File copiedFile = new File(destDir, srcFiles[i].getName());
exclusionList.add(copiedFile.getCanonicalPath());
}
}
}
doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList);
}
/**
* Internal copy directory method.
*
* @param srcDir the validated source directory, must not be null
* @param destDir the validated destination directory, must not be null
* @param filter the filter to apply, null means copy all directories and files
* @param preserveFileDate whether to preserve the file date
* @param exclusionList List of files and directories to exclude from the copy, may be null
* @throws IOException if an error occurs
* @since Commons IO 1.1
*/
private static void doCopyDirectory(File srcDir, File destDir, FileFilter filter,
boolean preserveFileDate, List exclusionList) throws IOException {
if (destDir.exists()) {
if (destDir.isDirectory() == false) {
throw new IOException("Destination '" + destDir
+ "' exists but is not a directory");
}
} else {
if (destDir.mkdirs() == false) {
throw new IOException("Destination '" + destDir + "' directory cannot be created");
}
if (preserveFileDate) {
destDir.setLastModified(srcDir.lastModified());
}
}
if (destDir.canWrite() == false) {
throw new IOException("Destination '" + destDir + "' cannot be written to");
}
// recurse
File[] files = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
if (files == null) { // null if security restricted
throw new IOException("Failed to list contents of " + srcDir);
}
for (int i = 0; i < files.length; i++) {
File copiedFile = new File(destDir, files[i].getName());
if (exclusionList == null || !exclusionList.contains(files[i].getCanonicalPath())) {
if (files[i].isDirectory()) {
doCopyDirectory(files[i], copiedFile, filter, preserveFileDate, exclusionList);
} else {
doCopyFile(files[i], copiedFile, preserveFileDate);
}
}
}
}
/**
* get the value from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @param defaultValue
* @return the value or null or exception
*/
public static boolean argMapBoolean(Map argMap, Map argMapNotUsed,
String key, boolean required, boolean defaultValue) {
String argString = argMapString(argMap, argMapNotUsed, key, required);
if (isBlank(argString) && required) {
throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=true");
}
return booleanValue(argString, defaultValue);
}
/**
* get the value from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @return the value or null or exception
*/
public static Timestamp argMapTimestamp(Map argMap, Map argMapNotUsed,
String key) {
String argString = argMapString(argMap, argMapNotUsed, key, false);
if (isBlank(argString)) {
return null;
}
Date date = stringToDate2(argString);
return new Timestamp(date.getTime());
}
/**
* get the value from the argMap
* @param argMap
* @param argMapNotUsed
* @param key
* @return the value or null or exception
*/
public static Boolean argMapBoolean(Map argMap, Map argMapNotUsed,
String key) {
String argString = argMapString(argMap, argMapNotUsed, key, false);
return booleanObjectValue(argString);
}
/**
* get the set from comma separated from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @return the value or null or exception
*/
public static Set argMapSet(Map argMap, Map argMapNotUsed,
String key, boolean required) {
List list = argMapList(argMap, argMapNotUsed, key, required);
return list == null ? null : new LinkedHashSet(list);
}
/**
* get the list from comma separated from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @return the value or null or exception
*/
public static List argMapList(Map argMap, Map argMapNotUsed,
String key, boolean required) {
String argString = argMapString(argMap, argMapNotUsed, key, required);
if (isBlank(argString)) {
return null;
}
return splitTrimToList(argString, ",");
}
/**
* get the list from comma separated from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @return the value or null or exception
*/
public static List argMapFileList(Map argMap, Map argMapNotUsed,
String key, boolean required) {
String argString = argMapString(argMap, argMapNotUsed, key, required);
if (isBlank(argString)) {
return null;
}
//read from file
File file = new File(argString);
try {
//do this by regex, since we dont know what platform we are on
String listString = GrouperInstallerUtils.readFileIntoString(file);
String[] array = listString.split("\\s+");
List list = new ArrayList();
for (String string : array) {
//dont know if any here will be blank or whatnot
if (!GrouperInstallerUtils.isBlank(string)) {
//should already be trimmed, but just in case
list.add(trim(string));
}
}
return list;
} catch (Exception e) {
throw new RuntimeException("Error reading file: '"
+ GrouperInstallerUtils.fileCanonicalPath(file) + "' from command line arg: " + key, e );
}
}
/**
* for testing, get the response body as a string
* @param method
* @return the string of response body
*/
public static String responseBodyAsString(HttpMethodBase method) {
InputStream inputStream = null;
try {
StringWriter writer = new StringWriter();
inputStream = method.getResponseBodyAsStream();
copy(inputStream, writer);
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
closeQuietly(inputStream);
}
}
/**
* Copy bytes from an InputStream
to chars on a
* Writer
using the default character encoding of the platform.
*
* This method buffers the input internally, so there is no need to use a
* BufferedInputStream
.
*
* This method uses {@link InputStreamReader}.
*
* @param input the InputStream
to read from
* @param output the Writer
to write to
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.1
*/
public static void copy(InputStream input, Writer output)
throws IOException {
String charsetName = "UTF-8";
InputStreamReader in = new InputStreamReader(input, charsetName);
copy(in, output);
}
/**
* get a jar file from a sample class
* @param sampleClass
* @return the jar file
*/
public static File jarFile(Class sampleClass) {
try {
CodeSource codeSource = sampleClass.getProtectionDomain().getCodeSource();
if (codeSource != null && codeSource.getLocation() != null) {
String fileName = URLDecoder.decode(codeSource.getLocation().getFile(), "UTF-8");
return new File(fileName);
}
String resourcePath = sampleClass.getName();
resourcePath = resourcePath.replace('.', '/') + ".class";
URL url = computeUrl(resourcePath, true);
String urlPath = url.toString();
if (urlPath.startsWith("jar:")) {
urlPath = urlPath.substring(4);
}
if (urlPath.startsWith("file:")) {
urlPath = urlPath.substring(5);
}
urlPath = prefixOrSuffix(urlPath, "!", true);
urlPath = URLDecoder.decode(urlPath, "UTF-8");
File file = new File(urlPath);
if (urlPath.endsWith(".jar") && file.exists() && file.isFile()) {
return file;
}
} catch (Exception e) {
LOG.warn("Cant find jar for class: " + sampleClass + ", " + e.getMessage(), e);
}
return null;
}
/**
* strip the last slash (/ or \) from a string if it exists
*
* @param input
*
* @return input - the last / or \
*/
public static String stripLastSlashIfExists(String input) {
if ((input == null) || (input.length() == 0)) {
return null;
}
char lastChar = input.charAt(input.length() - 1);
if ((lastChar == '\\') || (lastChar == '/')) {
return input.substring(0, input.length() - 1);
}
return input;
}
/**
* retrieve a password from stdin
* @param dontMask
* @param prompt to print to user
* @return the password
*/
public static String retrievePasswordFromStdin(boolean dontMask, String prompt) {
String passwordString = null;
if (dontMask) {
System.out.print(prompt);
// open up standard input
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// read the username from the command-line; need to use try/catch with the
// readLine() method
try {
passwordString = br.readLine();
} catch (IOException ioe) {
System.out.println("IO error! " + getFullStackTrace(ioe));
System.exit(1);
}
} else {
char password[] = null;
try {
password = retrievePasswordFromStdin(System.in, prompt);
} catch (IOException ioe) {
ioe.printStackTrace();
}
passwordString = String.valueOf(password);
}
return passwordString;
}
/**
* @param in stream to be used (e.g. System.in)
* @param prompt The prompt to display to the user.
* @return The password as entered by the user.
* @throws IOException
*/
public static final char[] retrievePasswordFromStdin(InputStream in, String prompt) throws IOException {
MaskingThread maskingthread = new MaskingThread(prompt);
Thread thread = new Thread(maskingthread);
thread.start();
char[] lineBuffer;
char[] buf;
buf = lineBuffer = new char[128];
int room = buf.length;
int offset = 0;
int c;
loop: while (true) {
switch (c = in.read()) {
case -1:
case '\n':
break loop;
case '\r':
int c2 = in.read();
if ((c2 != '\n') && (c2 != -1)) {
if (!(in instanceof PushbackInputStream)) {
in = new PushbackInputStream(in);
}
((PushbackInputStream) in).unread(c2);
} else {
break loop;
}
default:
if (--room < 0) {
buf = new char[offset + 128];
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0, buf, 0, offset);
Arrays.fill(lineBuffer, ' ');
lineBuffer = buf;
}
buf[offset++] = (char) c;
break;
}
}
maskingthread.stopMasking();
if (offset == 0) {
return null;
}
char[] ret = new char[offset];
System.arraycopy(buf, 0, ret, 0, offset);
Arrays.fill(buf, ' ');
return ret;
}
/**
* thread to mask input
*/
static class MaskingThread extends Thread {
/** stop */
private volatile boolean stop;
/** echo char, this doesnt work correctly, so make a space so people dont notice...
* prints out too many */
private char echochar = ' ';
/**
*@param prompt The prompt displayed to the user
*/
public MaskingThread(String prompt) {
System.out.print(prompt);
}
/**
* Begin masking until asked to stop.
*/
@Override
public void run() {
int priority = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try {
this.stop = true;
while (this.stop) {
System.out.print("\010" + this.echochar);
try {
// attempt masking at this rate
Thread.sleep(1);
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
return;
}
}
} finally { // restore the original priority
Thread.currentThread().setPriority(priority);
}
}
/**
* Instruct the thread to stop masking.
*/
public void stopMasking() {
this.stop = false;
}
}
/**
* make sure a value exists in properties
* @param resourceName
* @param properties
* @param overrideMap
* @param key
* @param exceptionOnError
* @return true if ok, false if not
*/
public static boolean propertyValidateValueRequired(String resourceName, Properties properties,
Map overrideMap, String key, boolean exceptionOnError) {
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
String value = propertiesValue(properties, threadLocalMap, overrideMap, key);
if (!GrouperInstallerUtils.isBlank(value)) {
return true;
}
String error = "Cant find property " + key + " in resource: " + resourceName + ", it is required";
if (exceptionOnError) {
throw new RuntimeException(error);
}
System.err.println("Grouper error: " + error);
LOG.error(error);
return false;
}
/**
* make sure a value is boolean in properties
* @param resourceName
* @param properties
* @param overrideMap
* @param key
* @param required
* @param exceptionOnError
* @return true if ok, false if not
*/
public static boolean propertyValidateValueBoolean(String resourceName, Properties properties,
Map overrideMap, String key,
boolean required, boolean exceptionOnError) {
if (required && !propertyValidateValueRequired(resourceName, properties,
overrideMap, key, exceptionOnError)) {
return false;
}
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
String value = propertiesValue(properties, threadLocalMap, overrideMap, key);
//maybe ok not there
if (!required && GrouperInstallerUtils.isBlank(value)) {
return true;
}
try {
booleanValue(value);
return true;
} catch (Exception e) {
}
String error = "Expecting true or false property " + key + " in resource: " + resourceName + ", but is '" + value + "'";
if (exceptionOnError) {
throw new RuntimeException(error);
}
System.err.println("Grouper error: " + error);
LOG.error(error);
return false;
}
/**
* every 5 seconds print a status dot to system out, and newline at end. After 20, newline
* @param runnable runnable to run
* @param printProgress if print progress during thread
*/
public static void threadRunWithStatusDots(final Runnable runnable, boolean printProgress) {
threadRunWithStatusDots(runnable, printProgress, true);
}
/**
* every 5 seconds print a status dot to system out, and newline at end. After 20, newline
* @param runnable runnable to run
* @param printProgress if print progress during thread
* @param injectStackInException
*/
public static void threadRunWithStatusDots(final Runnable runnable, boolean printProgress, boolean injectStackInException) {
if (!printProgress) {
runnable.run();
return;
}
try {
final Exception[] theException = new Exception[1];
Runnable wrappedRunnable = new Runnable() {
public void run() {
try {
runnable.run();
} catch (Exception e) {
theException[0] = e;
}
}
};
Thread thread = new Thread(wrappedRunnable);
thread.start();
long start = System.currentTimeMillis();
boolean wroteProgress = false;
int dotCount = 0;
while (true) {
if (thread.isAlive()) {
if (System.currentTimeMillis() - start > 5000) {
wroteProgress = true;
System.out.print(".");
dotCount++;
start = System.currentTimeMillis();
if (dotCount % 40 == 0) {
System.out.println("");
}
} else {
GrouperInstallerUtils.sleep(500);
}
} else {
if (wroteProgress) {
//start with a newline
System.out.println("");
}
break;
}
}
//probably dont need this
thread.join();
if (theException[0] != null) {
if (injectStackInException) {
//append this stack
injectInException(theException[0], getFullStackTrace(new RuntimeException("caller stack")));
}
throw theException[0];
}
} catch (Exception exception) {
if (exception instanceof RuntimeException) {
throw (RuntimeException)exception;
}
throw new RuntimeException(exception);
}
}
/**
* make sure a value is int in properties
* @param resourceName
* @param properties
* @param overrideMap
* @param key
* @param required
* @param exceptionOnError
* @return true if ok, false if not
*/
public static boolean propertyValidateValueInt(String resourceName, Properties properties,
Map overrideMap, String key,
boolean required, boolean exceptionOnError) {
if (required && !propertyValidateValueRequired(resourceName, properties,
overrideMap, key, exceptionOnError)) {
return false;
}
Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName);
String value = propertiesValue(properties, threadLocalMap, overrideMap, key);
//maybe ok not there
if (!required && GrouperInstallerUtils.isBlank(value)) {
return true;
}
try {
intValue(value);
return true;
} catch (Exception e) {
}
String error = "Expecting integer property " + key + " in resource: " + resourceName + ", but is '" + value + "'";
if (exceptionOnError) {
throw new RuntimeException(error);
}
System.err.println("Grouper error: " + error);
LOG.error(error);
return false;
}
/**
* make sure a property is a class of a certain type
* @param resourceName
* @param properties
* @param overrideMap
* @param key
* @param classType
* @param required
* @param exceptionOnError
* @return true if ok
*/
public static boolean propertyValidateValueClass(String resourceName, Properties properties,
Map overrideMap, String key, Class> classType, boolean required, boolean exceptionOnError) {
if (required && !propertyValidateValueRequired(resourceName, properties,
overrideMap, key, exceptionOnError)) {
return false;
}
String value = propertiesValue(properties, overrideMap, key);
//maybe ok not there
if (!required && GrouperInstallerUtils.isBlank(value)) {
return true;
}
String extraError = "";
try {
Class> theClass = forName(value);
if (classType.isAssignableFrom(theClass)) {
return true;
}
extraError = " does not derive from class: " + classType.getSimpleName();
} catch (Exception e) {
extraError = ", " + getFullStackTrace(e);
}
String error = "Cant process property " + key + " in resource: " + resourceName + ", the current" +
" value is '" + value + "', which should be of type: "
+ classType.getName() + extraError;
if (exceptionOnError) {
throw new RuntimeException(error);
}
System.err.println("Grouper error: " + error);
LOG.error(error);
return false;
}
/**
* Strips any of a set of characters from the start of a String.
*
* A null
input String returns null
.
* An empty string ("") input returns the empty string.
*
* If the stripChars String is null
, whitespace is
* stripped as defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.stripStart(null, *) = null
* StringUtils.stripStart("", *) = ""
* StringUtils.stripStart("abc", "") = "abc"
* StringUtils.stripStart("abc", null) = "abc"
* StringUtils.stripStart(" abc", null) = "abc"
* StringUtils.stripStart("abc ", null) = "abc "
* StringUtils.stripStart(" abc ", null) = "abc "
* StringUtils.stripStart("yxabc ", "xyz") = "abc "
*
*
* @param str the String to remove characters from, may be null
* @param stripChars the characters to remove, null treated as whitespace
* @return the stripped String, null
if null String input
*/
public static String stripStart(String str, String stripChars) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
int start = 0;
if (stripChars == null) {
while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
start++;
}
} else if (stripChars.length() == 0) {
return str;
} else {
while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != -1)) {
start++;
}
}
return str.substring(start);
}
/**
* Strips any of a set of characters from the end of a String.
*
* A null
input String returns null
.
* An empty string ("") input returns the empty string.
*
* If the stripChars String is null
, whitespace is
* stripped as defined by {@link Character#isWhitespace(char)}.
*
*
* StringUtils.stripEnd(null, *) = null
* StringUtils.stripEnd("", *) = ""
* StringUtils.stripEnd("abc", "") = "abc"
* StringUtils.stripEnd("abc", null) = "abc"
* StringUtils.stripEnd(" abc", null) = " abc"
* StringUtils.stripEnd("abc ", null) = "abc"
* StringUtils.stripEnd(" abc ", null) = " abc"
* StringUtils.stripEnd(" abcyx", "xyz") = " abc"
*
*
* @param str the String to remove characters from, may be null
* @param stripChars the characters to remove, null treated as whitespace
* @return the stripped String, null
if null String input
*/
public static String stripEnd(String str, String stripChars) {
int end;
if (str == null || (end = str.length()) == 0) {
return str;
}
if (stripChars == null) {
while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
end--;
}
} else if (stripChars.length() == 0) {
return str;
} else {
while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != -1)) {
end--;
}
}
return str.substring(0, end);
}
/**
* The empty String ""
.
* @since 2.0
*/
public static final String EMPTY = "";
/**
* Represents a failed index search.
* @since 2.1
*/
public static final int INDEX_NOT_FOUND = -1;
/**
* The maximum size to which the padding constant(s) can expand.
*/
private static final int PAD_LIMIT = 8192;
/**
* An array of String
s used for padding.
*
* Used for efficient space padding. The length of each String expands as needed.
*/
private static final String[] PADDING = new String[Character.MAX_VALUE];
static {
// space padding is most common, start with 64 chars
PADDING[32] = " ";
}
/**
* Repeat a String repeat
times to form a
* new String.
*
*
* StringUtils.repeat(null, 2) = null
* StringUtils.repeat("", 0) = ""
* StringUtils.repeat("", 2) = ""
* StringUtils.repeat("a", 3) = "aaa"
* StringUtils.repeat("ab", 2) = "abab"
* StringUtils.repeat("a", -2) = ""
*
*
* @param str the String to repeat, may be null
* @param repeat number of times to repeat str, negative treated as zero
* @return a new String consisting of the original String repeated,
* null
if null String input
*/
public static String repeat(String str, int repeat) {
// Performance tuned for 2.0 (JDK1.4)
if (str == null) {
return null;
}
if (repeat <= 0) {
return EMPTY;
}
int inputLength = str.length();
if (repeat == 1 || inputLength == 0) {
return str;
}
if (inputLength == 1 && repeat <= PAD_LIMIT) {
return padding(repeat, str.charAt(0));
}
int outputLength = inputLength * repeat;
switch (inputLength) {
case 1:
char ch = str.charAt(0);
char[] output1 = new char[outputLength];
for (int i = repeat - 1; i >= 0; i--) {
output1[i] = ch;
}
return new String(output1);
case 2:
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char[] output2 = new char[outputLength];
for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
output2[i] = ch0;
output2[i + 1] = ch1;
}
return new String(output2);
default:
StringBuffer buf = new StringBuffer(outputLength);
for (int i = 0; i < repeat; i++) {
buf.append(str);
}
return buf.toString();
}
}
/**
* Returns padding using the specified delimiter repeated
* to a given length.
*
*
* StringUtils.padding(0, 'e') = ""
* StringUtils.padding(3, 'e') = "eee"
* StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
*
*
* @param repeat number of times to repeat delim
* @param padChar character to repeat
* @return String with repeated character
* @throws IndexOutOfBoundsException if repeat < 0
*/
private static String padding(int repeat, char padChar) {
// be careful of synchronization in this method
// we are assuming that get and set from an array index is atomic
String pad = PADDING[padChar];
if (pad == null) {
pad = String.valueOf(padChar);
}
while (pad.length() < repeat) {
pad = pad.concat(pad);
}
PADDING[padChar] = pad;
return pad.substring(0, repeat);
}
/**
* Right pad a String with spaces (' ').
*
* The String is padded to the size of size
.
*
*
* StringUtils.rightPad(null, *) = null
* StringUtils.rightPad("", 3) = " "
* StringUtils.rightPad("bat", 3) = "bat"
* StringUtils.rightPad("bat", 5) = "bat "
* StringUtils.rightPad("bat", 1) = "bat"
* StringUtils.rightPad("bat", -1) = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @return right padded String or original String if no padding is necessary,
* null
if null String input
*/
public static String rightPad(String str, int size) {
return rightPad(str, size, ' ');
}
/**
* Right pad a String with a specified character.
*
* The String is padded to the size of size
.
*
*
* StringUtils.rightPad(null, *, *) = null
* StringUtils.rightPad("", 3, 'z') = "zzz"
* StringUtils.rightPad("bat", 3, 'z') = "bat"
* StringUtils.rightPad("bat", 5, 'z') = "batzz"
* StringUtils.rightPad("bat", 1, 'z') = "bat"
* StringUtils.rightPad("bat", -1, 'z') = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padChar the character to pad with
* @return right padded String or original String if no padding is necessary,
* null
if null String input
* @since 2.0
*/
public static String rightPad(String str, int size, char padChar) {
if (str == null) {
return null;
}
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original String when possible
}
if (pads > PAD_LIMIT) {
return rightPad(str, size, String.valueOf(padChar));
}
return str.concat(padding(pads, padChar));
}
/**
* Right pad a String with a specified String.
*
* The String is padded to the size of size
.
*
*
* StringUtils.rightPad(null, *, *) = null
* StringUtils.rightPad("", 3, "z") = "zzz"
* StringUtils.rightPad("bat", 3, "yz") = "bat"
* StringUtils.rightPad("bat", 5, "yz") = "batyz"
* StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
* StringUtils.rightPad("bat", 1, "yz") = "bat"
* StringUtils.rightPad("bat", -1, "yz") = "bat"
* StringUtils.rightPad("bat", 5, null) = "bat "
* StringUtils.rightPad("bat", 5, "") = "bat "
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padStr the String to pad with, null or empty treated as single space
* @return right padded String or original String if no padding is necessary,
* null
if null String input
*/
public static String rightPad(String str, int size, String padStr) {
if (str == null) {
return null;
}
if (isEmpty(padStr)) {
padStr = " ";
}
int padLen = padStr.length();
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str; // returns original String when possible
}
if (padLen == 1 && pads <= PAD_LIMIT) {
return rightPad(str, size, padStr.charAt(0));
}
if (pads == padLen) {
return str.concat(padStr);
} else if (pads < padLen) {
return str.concat(padStr.substring(0, pads));
} else {
char[] padding = new char[pads];
char[] padChars = padStr.toCharArray();
for (int i = 0; i < pads; i++) {
padding[i] = padChars[i % padLen];
}
return str.concat(new String(padding));
}
}
/**
* Left pad a String with spaces (' ').
*
* The String is padded to the size of size.
*
*
* StringUtils.leftPad(null, *) = null
* StringUtils.leftPad("", 3) = " "
* StringUtils.leftPad("bat", 3) = "bat"
* StringUtils.leftPad("bat", 5) = " bat"
* StringUtils.leftPad("bat", 1) = "bat"
* StringUtils.leftPad("bat", -1) = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @return left padded String or original String if no padding is necessary,
* null
if null String input
*/
public static String leftPad(String str, int size) {
return leftPad(str, size, ' ');
}
/**
* Left pad a String with a specified character.
*
* Pad to a size of size
.
*
*
* StringUtils.leftPad(null, *, *) = null
* StringUtils.leftPad("", 3, 'z') = "zzz"
* StringUtils.leftPad("bat", 3, 'z') = "bat"
* StringUtils.leftPad("bat", 5, 'z') = "zzbat"
* StringUtils.leftPad("bat", 1, 'z') = "bat"
* StringUtils.leftPad("bat", -1, 'z') = "bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padChar the character to pad with
* @return left padded String or original String if no padding is necessary,
* null
if null String input
* @since 2.0
*/
public static String leftPad(String str, int size, char padChar) {
if (str == null) {
return null;
}
int pads = size - str.length();
if (pads <= 0) {
return str; // returns original String when possible
}
if (pads > PAD_LIMIT) {
return leftPad(str, size, String.valueOf(padChar));
}
return padding(pads, padChar).concat(str);
}
/**
* Left pad a String with a specified String.
*
* Pad to a size of size
.
*
*
* StringUtils.leftPad(null, *, *) = null
* StringUtils.leftPad("", 3, "z") = "zzz"
* StringUtils.leftPad("bat", 3, "yz") = "bat"
* StringUtils.leftPad("bat", 5, "yz") = "yzbat"
* StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
* StringUtils.leftPad("bat", 1, "yz") = "bat"
* StringUtils.leftPad("bat", -1, "yz") = "bat"
* StringUtils.leftPad("bat", 5, null) = " bat"
* StringUtils.leftPad("bat", 5, "") = " bat"
*
*
* @param str the String to pad out, may be null
* @param size the size to pad to
* @param padStr the String to pad with, null or empty treated as single space
* @return left padded String or original String if no padding is necessary,
* null
if null String input
*/
public static String leftPad(String str, int size, String padStr) {
if (str == null) {
return null;
}
if (isEmpty(padStr)) {
padStr = " ";
}
int padLen = padStr.length();
int strLen = str.length();
int pads = size - strLen;
if (pads <= 0) {
return str; // returns original String when possible
}
if (padLen == 1 && pads <= PAD_LIMIT) {
return leftPad(str, size, padStr.charAt(0));
}
if (pads == padLen) {
return padStr.concat(str);
} else if (pads < padLen) {
return padStr.substring(0, pads).concat(str);
} else {
char[] padding = new char[pads];
char[] padChars = padStr.toCharArray();
for (int i = 0; i < pads; i++) {
padding[i] = padChars[i % padLen];
}
return new String(padding).concat(str);
}
}
/**
* convert an exception to a runtime exception
* @param e
*/
public static void convertToRuntimeException(Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
throw new RuntimeException(e.getMessage(), e);
}
/**
* Gets the substring before the first occurrence of a separator.
* The separator is not returned.
*
* A null
string input will return null
.
* An empty ("") string input will return the empty string.
* A null
separator will return the input string.
*
*
* StringUtils.substringBefore(null, *) = null
* StringUtils.substringBefore("", *) = ""
* StringUtils.substringBefore("abc", "a") = ""
* StringUtils.substringBefore("abcba", "b") = "a"
* StringUtils.substringBefore("abc", "c") = "ab"
* StringUtils.substringBefore("abc", "d") = "abc"
* StringUtils.substringBefore("abc", "") = ""
* StringUtils.substringBefore("abc", null) = "abc"
*
*
* @param str the String to get a substring from, may be null
* @param separator the String to search for, may be null
* @return the substring before the first occurrence of the separator,
* null
if null String input
* @since 2.0
*/
public static String substringBefore(String str, String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
if (separator.length() == 0) {
return EMPTY;
}
int pos = str.indexOf(separator);
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
/**
* Gets the substring after the first occurrence of a separator.
* The separator is not returned.
*
* A null
string input will return null
.
* An empty ("") string input will return the empty string.
* A null
separator will return the empty string if the
* input string is not null
.
*
*
* StringUtils.substringAfter(null, *) = null
* StringUtils.substringAfter("", *) = ""
* StringUtils.substringAfter(*, null) = ""
* StringUtils.substringAfter("abc", "a") = "bc"
* StringUtils.substringAfter("abcba", "b") = "cba"
* StringUtils.substringAfter("abc", "c") = ""
* StringUtils.substringAfter("abc", "d") = ""
* StringUtils.substringAfter("abc", "") = "abc"
*
*
* @param str the String to get a substring from, may be null
* @param separator the String to search for, may be null
* @return the substring after the first occurrence of the separator,
* null
if null String input
* @since 2.0
*/
public static String substringAfter(String str, String separator) {
if (isEmpty(str)) {
return str;
}
if (separator == null) {
return EMPTY;
}
int pos = str.indexOf(separator);
if (pos == -1) {
return EMPTY;
}
return str.substring(pos + separator.length());
}
/**
* Gets the substring before the last occurrence of a separator.
* The separator is not returned.
*
* A null
string input will return null
.
* An empty ("") string input will return the empty string.
* An empty or null
separator will return the input string.
*
*
* StringUtils.substringBeforeLast(null, *) = null
* StringUtils.substringBeforeLast("", *) = ""
* StringUtils.substringBeforeLast("abcba", "b") = "abc"
* StringUtils.substringBeforeLast("abc", "c") = "ab"
* StringUtils.substringBeforeLast("a", "a") = ""
* StringUtils.substringBeforeLast("a", "z") = "a"
* StringUtils.substringBeforeLast("a", null) = "a"
* StringUtils.substringBeforeLast("a", "") = "a"
*
*
* @param str the String to get a substring from, may be null
* @param separator the String to search for, may be null
* @return the substring before the last occurrence of the separator,
* null
if null String input
* @since 2.0
*/
public static String substringBeforeLast(String str, String separator) {
if (isEmpty(str) || isEmpty(separator)) {
return str;
}
int pos = str.lastIndexOf(separator);
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
/**
* Gets the substring after the last occurrence of a separator.
* The separator is not returned.
*
* A null
string input will return null
.
* An empty ("") string input will return the empty string.
* An empty or null
separator will return the empty string if
* the input string is not null
.
*
*
* StringUtils.substringAfterLast(null, *) = null
* StringUtils.substringAfterLast("", *) = ""
* StringUtils.substringAfterLast(*, "") = ""
* StringUtils.substringAfterLast(*, null) = ""
* StringUtils.substringAfterLast("abc", "a") = "bc"
* StringUtils.substringAfterLast("abcba", "b") = "a"
* StringUtils.substringAfterLast("abc", "c") = ""
* StringUtils.substringAfterLast("a", "a") = ""
* StringUtils.substringAfterLast("a", "z") = ""
*
*
* @param str the String to get a substring from, may be null
* @param separator the String to search for, may be null
* @return the substring after the last occurrence of the separator,
* null
if null String input
* @since 2.0
*/
public static String substringAfterLast(String str, String separator) {
if (isEmpty(str)) {
return str;
}
if (isEmpty(separator)) {
return EMPTY;
}
int pos = str.lastIndexOf(separator);
if (pos == -1 || pos == (str.length() - separator.length())) {
return EMPTY;
}
return str.substring(pos + separator.length());
}
/**
* get the value from the argMap, throw exception if not there and required
* @param argMap
* @param argMapNotUsed
* @param key
* @param required
* @param defaultValue
* @return the value or null or exception
*/
public static Integer argMapInteger(Map argMap, Map argMapNotUsed,
String key, boolean required, Integer defaultValue) {
String argString = argMapString(argMap, argMapNotUsed, key, required);
if (isBlank(argString) && required) {
throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=5");
}
if (isBlank(argString)) {
if (defaultValue != null) {
return defaultValue;
}
return null;
}
return intValue(argString);
}
/**
* null safe convert from util date to sql date
* @param date
* @return the sql date
*/
public static java.sql.Date toSqlDate(Date date) {
if (date == null) {
return null;
}
return new java.sql.Date(date.getTime());
}
/**
* Find the index of the given object in the array.
*
* This method returns -1
if null
array input.
*
* @param array the array to search through for the object, may be null
* @param objectToFind the object to find, may be null
* @return the index of the object within the array,
* -1
if not found or null
array input
*/
public static int indexOf(Object[] array, Object objectToFind) {
return indexOf(array, objectToFind, 0);
}
/**
* Checks if the object is in the given array.
*
* The method returns false
if a null
array is passed in.
*
* @param array the array to search through
* @param objectToFind the object to find
* @return true
if the array contains the object
*/
public static boolean contains(Object[] array, Object objectToFind) {
return indexOf(array, objectToFind) != -1;
}
/**
* Find the index of the given object in the array starting at the given index.
*
* This method returns -1
if null
array input.
*
* A negative startIndex is treated as zero. A startIndex larger than the array
* length will return -1
.
*
* @param array the array to search through for the object, may be null
* @param objectToFind the object to find, may be null
* @param startIndex the index to start searching at
* @return the index of the object within the array starting at the index,
* -1
if not found or null
array input
*/
public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
if (array == null) {
return -1;
}
if (startIndex < 0) {
startIndex = 0;
}
if (objectToFind == null) {
for (int i = startIndex; i < array.length; i++) {
if (array[i] == null) {
return i;
}
}
} else {
for (int i = startIndex; i < array.length; i++) {
if (objectToFind.equals(array[i])) {
return i;
}
}
}
return -1;
}
/**
* Note, this is
* web service format string
*/
private static final String WS_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS";
/**
* Note, this is
* web service format string
*/
private static final String WS_DATE_FORMAT2 = "yyyy/MM/dd_HH:mm:ss.SSS";
/**
* convert a date to a string using the standard web service pattern
* yyyy/MM/dd HH:mm:ss.SSS Note that HH is 0-23
*
* @param date
* @return the string, or null if the date is null
*/
public static String dateToString(Date date) {
if (date == null) {
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WS_DATE_FORMAT);
return simpleDateFormat.format(date);
}
/**
* convert a string to a date using the standard web service pattern Note
* that HH is 0-23
*
* @param dateString
* @return the string, or null if the date was null
*/
public static Date stringToDate(String dateString) {
if (isBlank(dateString)) {
return null;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WS_DATE_FORMAT);
try {
return simpleDateFormat.parse(dateString);
} catch (ParseException e) {
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat(WS_DATE_FORMAT2);
try {
return simpleDateFormat2.parse(dateString);
} catch (ParseException e2) {
throw new RuntimeException("Cannot convert '" + dateString
+ "' to a date based on format: " + WS_DATE_FORMAT, e);
}
}
}
/**
* match regex pattern yyyy-mm-dd or yyyy/mm/dd
*/
private static Pattern datePattern_yyyy_mm_dd = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$");
/**
* match regex pattern dd-mon-yyyy or dd/mon/yyyy
*/
private static Pattern datePattern_dd_mon_yyyy = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})$");
/**
* match regex pattern yyyy-mm-dd hh:mm:ss or yyyy/mm/dd hh:mm:ss
*/
private static Pattern datePattern_yyyy_mm_dd_hhmmss = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$");
/**
* match regex pattern dd-mon-yyyy hh:mm:ss or dd/mon/yyyy hh:mm:ss
*/
private static Pattern datePattern_dd_mon_yyyy_hhmmss = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$");
/**
* match regex pattern yyyy-mm-dd hh:mm:ss.SSS or yyyy/mm/dd hh:mm:ss.SSS
*/
private static Pattern datePattern_yyyy_mm_dd_hhmmss_SSS = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,3})$");
/**
* match regex pattern dd-mon-yyyy hh:mm:ss.SSS or dd/mon/yyyy hh:mm:ss.SSS
*/
private static Pattern datePattern_dd_mon_yyyy_hhmmss_SSS = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,3})$");
/**
* take as input:
* yyyy/mm/dd
* yyyy-mm-dd
* dd-mon-yyyy
* yyyy/mm/dd hh:mm:ss
* dd-mon-yyyy hh:mm:ss
* yyyy/mm/dd hh:mm:ss.SSS
* dd-mon-yyyy hh:mm:ss.SSS
* @param input
* @return the date
*/
public static Date stringToDate2(String input) {
if (isBlank(input)) {
return null;
}
input = input.trim();
Matcher matcher = null;
int month = 0;
int day = 0;
int year = 0;
int hour = 0;
int minute = 0;
int second = 0;
int milli = 0;
boolean foundMatch = false;
//yyyy/mm/dd
if (!foundMatch) {
matcher = datePattern_yyyy_mm_dd.matcher(input);
if (matcher.matches()) {
year = intValue(matcher.group(1));
month = intValue(matcher.group(2));
day = intValue(matcher.group(3));
foundMatch = true;
}
}
//dd-mon-yyyy
if (!foundMatch) {
matcher = datePattern_dd_mon_yyyy.matcher(input);
if (matcher.matches()) {
day = intValue(matcher.group(1));
month = monthInt(matcher.group(2));
year = intValue(matcher.group(3));
foundMatch = true;
}
}
//yyyy/mm/dd hh:mm:ss
if (!foundMatch) {
matcher = datePattern_yyyy_mm_dd_hhmmss.matcher(input);
if (matcher.matches()) {
year = intValue(matcher.group(1));
month = intValue(matcher.group(2));
day = intValue(matcher.group(3));
hour = intValue(matcher.group(4));
minute = intValue(matcher.group(5));
second = intValue(matcher.group(6));
foundMatch = true;
}
}
//dd-mon-yyyy hh:mm:ss
if (!foundMatch) {
matcher = datePattern_dd_mon_yyyy_hhmmss.matcher(input);
if (matcher.matches()) {
day = intValue(matcher.group(1));
month = monthInt(matcher.group(2));
year = intValue(matcher.group(3));
hour = intValue(matcher.group(4));
minute = intValue(matcher.group(5));
second = intValue(matcher.group(6));
foundMatch = true;
}
}
//yyyy/mm/dd hh:mm:ss.SSS
if (!foundMatch) {
matcher = datePattern_yyyy_mm_dd_hhmmss_SSS.matcher(input);
if (matcher.matches()) {
year = intValue(matcher.group(1));
month = intValue(matcher.group(2));
day = intValue(matcher.group(3));
hour = intValue(matcher.group(4));
minute = intValue(matcher.group(5));
second = intValue(matcher.group(6));
milli = intValue(matcher.group(7));
foundMatch = true;
}
}
//dd-mon-yyyy hh:mm:ss.SSS
if (!foundMatch) {
matcher = datePattern_dd_mon_yyyy_hhmmss_SSS.matcher(input);
if (matcher.matches()) {
day = intValue(matcher.group(1));
month = monthInt(matcher.group(2));
year = intValue(matcher.group(3));
hour = intValue(matcher.group(4));
minute = intValue(matcher.group(5));
second = intValue(matcher.group(6));
milli = intValue(matcher.group(7));
foundMatch = true;
}
}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month-1);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
calendar.set(Calendar.MILLISECOND, milli);
return calendar.getTime();
}
/**
* convert a month string to an int (1 indexed).
* e.g. if input is feb or Feb or february or February return 2
* @param mon
* @return the month
*/
public static int monthInt(String mon) {
if (!isBlank(mon)) {
mon = mon.toLowerCase();
if (equals(mon, "jan") || equals(mon, "january")) {
return 1;
}
if (equals(mon, "feb") || equals(mon, "february")) {
return 2;
}
if (equals(mon, "mar") || equals(mon, "march")) {
return 3;
}
if (equals(mon, "apr") || equals(mon, "april")) {
return 4;
}
if (equals(mon, "may")) {
return 5;
}
if (equals(mon, "jun") || equals(mon, "june")) {
return 6;
}
if (equals(mon, "jul") || equals(mon, "july")) {
return 7;
}
if (equals(mon, "aug") || equals(mon, "august")) {
return 8;
}
if (equals(mon, "sep") || equals(mon, "september")) {
return 9;
}
if (equals(mon, "oct") || equals(mon, "october")) {
return 10;
}
if (equals(mon, "nov") || equals(mon, "november")) {
return 11;
}
if (equals(mon, "dec") || equals(mon, "december")) {
return 12;
}
}
throw new RuntimeException("Invalid month: " + mon);
}
/**
* override map for properties in thread local to be used in a web server or the like, based on property file name
* @param propertiesFileName
* @return the override map
*/
public static Map propertiesThreadLocalOverrideMap(String propertiesFileName) {
Map> overrideMap = propertiesThreadLocalOverrideMap.get();
if (overrideMap == null) {
overrideMap = new HashMap>();
propertiesThreadLocalOverrideMap.set(overrideMap);
}
Map propertiesOverrideMap = overrideMap.get(propertiesFileName);
if (propertiesOverrideMap == null) {
propertiesOverrideMap = new HashMap();
overrideMap.put(propertiesFileName, propertiesOverrideMap);
}
return propertiesOverrideMap;
}
/**
* configure jdk14 logs once
*/
private static boolean configuredLogs = false;
/** log level */
public static String theLogLevel = "WARNING";
/**
* replace separators which are wrong os, and add last slash if not exist
* @param filePath
* @return the file path
*/
public static String fileAddLastSlashIfNotExists(String filePath) {
filePath = filePath.replace(File.separatorChar == '/' ? '\\' : '/', File.separatorChar);
if (!filePath.endsWith(File.separator)) {
filePath = filePath + File.separatorChar;
}
return filePath;
}
/**
* @param theClass
* @return the log
*/
public static Log retrieveLog(Class> theClass) {
Log theLog = LogFactory.getLog(theClass);
if (!configuredLogs) {
String logLevel = theLogLevel;
String logFile = null;
boolean hasLogLevel = !isBlank(logLevel);
boolean hasLogFile = !isBlank(logFile);
if (hasLogLevel || hasLogFile) {
if (theLog instanceof Jdk14Logger) {
Jdk14Logger jdkLogger = (Jdk14Logger) theLog;
Logger logger = jdkLogger.getLogger();
long timeToLive = 60;
while (logger.getParent() != null && timeToLive-- > 0) {
//this should be root logger
logger = logger.getParent();
}
if (length(logger.getHandlers()) == 1) {
//remove console appender if only one
if (logger.getHandlers()[0].getClass() == ConsoleHandler.class) {
logger.removeHandler(logger.getHandlers()[0]);
}
}
if (length(logger.getHandlers()) == 0) {
Handler handler = null;
if (hasLogFile) {
try {
handler = new FileHandler(logFile, true);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
} else {
handler = new ConsoleHandler();
}
handler.setFormatter(new SimpleFormatter());
handler.setLevel(Level.ALL);
logger.addHandler(handler);
logger.setUseParentHandlers(false);
}
if (hasLogLevel) {
Level level = Level.parse(logLevel);
logger.setLevel(level);
}
}
}
configuredLogs = true;
}
return new GrouperInstallerLog(theLog);
}
/**
* turn a directory and contents into a tar file
* @param directory
* @param tarFile
*/
public static void tar(File directory, File tarFile) {
tar(directory, tarFile, true);
}
/**
* turn a directory and contents into a tar file
* @param directory
* @param includeDirectoryInTarPath true if should include the dirname in the tar file
* @param tarFile
*/
public static void tar(File directory, File tarFile, boolean includeDirectoryInTarPath) {
try {
tarFile.createNewFile();
TarArchiveOutputStream tarArchiveOutputStream = new TarArchiveOutputStream(new FileOutputStream(tarFile));
//we need long file support
tarArchiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
for (File file : fileListRecursive(directory)) {
if (file.isFile()) {
String relativePath = (includeDirectoryInTarPath ? (directory.getName() + File.separator) : "") + fileRelativePath(directory, file);
//lets do back slashes
relativePath = replace(relativePath, "\\", "/");
TarArchiveEntry entry = new TarArchiveEntry(file, relativePath);
tarArchiveOutputStream.putArchiveEntry(entry);
copy(new FileInputStream(file), tarArchiveOutputStream);
tarArchiveOutputStream.closeArchiveEntry();
}
}
tarArchiveOutputStream.close();
} catch (Exception e) {
throw new RuntimeException("Error creating tar: " + tarFile.getAbsolutePath() + ", from dir: " + directory.getAbsolutePath(), e);
}
}
/**
*
* @param inputFile
* @param outputFile
*/
public static void gzip(File inputFile, File outputFile) {
GZIPOutputStream gzipOutputStream = null;
try {
outputFile.createNewFile();
gzipOutputStream = new GZIPOutputStream(
new BufferedOutputStream(new FileOutputStream(outputFile)));
copy(new FileInputStream(inputFile), gzipOutputStream);
} catch (Exception e) {
throw new RuntimeException("Error creating gzip from " + inputFile.getAbsolutePath() + " to " + outputFile.getAbsolutePath());
} finally {
closeQuietly(gzipOutputStream);
}
}
/**
*
* @param file
* @return the hex sha1
*/
public static String fileSha1(File file) {
FileInputStream fis = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
fis = new FileInputStream(file);
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
//convert the byte to hex format
StringBuffer sb = new StringBuffer("");
for (int i = 0; i < mdbytes.length; i++) {
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("Problem getting checksum of file: " + file.getAbsolutePath(), e);
} finally {
closeQuietly(fis);
}
}
/** override map for properties */
private static Map grouperInstallerOverrideMap = new LinkedHashMap();
/**
* override map for properties for testing
* @return the override map
*/
public static Map grouperInstallerOverrideMap() {
return grouperInstallerOverrideMap;
}
/**
* grouper installer properties
* @return the properties
*/
public static Properties grouperInstallerProperties() {
Properties properties = null;
try {
properties = propertiesFromResourceName(
"grouper.installer.properties", true, true, GrouperInstallerUtils.class, null);
} catch (Exception e) {
throw new RuntimeException("Error accessing file: grouper.installer.properties " +
"This properties file needs to be in the same directory as grouperInstaller.jar, or on your Java classpath", e);
}
return properties;
}
/**
* if the properties contains a key
* @param key
* @return true or false
*/
public static boolean propertiesContainsKey(String key) {
return grouperInstallerProperties().containsKey(key);
}
/**
* get a property and validate required from grouper.installer.properties
* @param key
* @param required
* @return the value
*/
public static String propertiesValue(String key, boolean required) {
return GrouperInstallerUtils.propertiesValue("grouper.installer.properties",
grouperInstallerProperties(),
GrouperInstallerUtils.grouperInstallerOverrideMap(), key, required);
}
/**
* get a boolean and validate from grouper.installer.properties
* @param key
* @param defaultValue
* @param required
* @return the string
*/
public static boolean propertiesValueBoolean(String key, boolean defaultValue, boolean required ) {
return GrouperInstallerUtils.propertiesValueBoolean(
"grouper.installer.properties", grouperInstallerProperties(),
GrouperInstallerUtils.grouperInstallerOverrideMap(),
key, defaultValue, required);
}
/**
* get a boolean and validate from grouper.installer.properties
* @param key
* @param defaultValue
* @param required
* @return the string
*/
public static int propertiesValueInt(String key, int defaultValue, boolean required ) {
return GrouperInstallerUtils.propertiesValueInt(
"grouper.installer.properties", grouperInstallerProperties(),
GrouperInstallerUtils.grouperInstallerOverrideMap(),
key, defaultValue, required);
}
/**
* Copy bytes from an InputStream
to an
* OutputStream
.
*
* This method buffers the input internally, so there is no need to use a
* BufferedInputStream
.
*
* Large streams (over 2GB) will return a bytes copied value of
* -1
after the copy has completed since the correct
* number of bytes cannot be returned as an int. For large streams
* use the copyLarge(InputStream, OutputStream)
method.
*
* @param input the InputStream
to read from
* @param output the OutputStream
to write to
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @throws ArithmeticException if the byte count is too large
* @since Commons IO 1.1
*/
public static int copy(InputStream input, OutputStream output) throws IOException {
long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
/**
* Copy bytes from a large (over 2GB) InputStream
to an
* OutputStream
.
*
* This method buffers the input internally, so there is no need to use a
* BufferedInputStream
.
*
* @param input the InputStream
to read from
* @param output the OutputStream
to write to
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.3
*/
public static long copyLarge(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
/**
* clear out all files recursively in a directory, including the directory
* itself
* @param dirName
*
* @throws RuntimeException
* when something goes wrong
*/
public static void deleteRecursiveDirectory(String dirName) {
//delete all files in the directory
File dir = new File(dirName);
//if it doesnt exist then we are done
if (!dir.exists()) {
return;
}
//see if its a directory
if (!dir.isDirectory()) {
throw new RuntimeException("The directory: " + dirName + " is not a directory");
}
//get the files into a vector
File[] allFiles = dir.listFiles();
//loop through the array
for (int i = 0; i < allFiles.length; i++) {
if (-1 < allFiles[i].getName().indexOf("..")) {
continue; //dont go to the parent directory
}
if (allFiles[i].isFile()) {
//delete the file
if (!allFiles[i].delete()) {
throw new RuntimeException("Could not delete file: " + allFiles[i].getPath());
}
} else {
//its a directory
deleteRecursiveDirectory(allFiles[i].getPath());
}
}
//delete the directory itself
if (!dir.delete()) {
throw new RuntimeException("Could not delete directory: " + dir.getPath());
}
}
/**
* This will execute a command, and split spaces for args (might not be what
* you want if you are using quotes)
*
* @param command
* @param printProgress if dots for progress should be used
* @return the result of the command
*/
public static CommandResult execCommand(String command, boolean printProgress) {
String[] args = splitTrim(command, " ");
return execCommand(args, printProgress);
}
/**
* Gobble up a stream from a runtime
* @author mchyzer
*/
private static class StreamGobbler implements Runnable {
/** stream to read */
private InputStream inputStream;
/** where to put the result */
private String resultString;
/** type of the output for logging purposes */
private String type;
/** command to log */
private String command;
/** if print to stdout */
private File printToFile;
/** if this is out or error */
private boolean outOrErr;
/**
* if should print stdout and stderr as received
*/
private boolean printOutputErrorAsReceived;
/**
* construct
* @param is
* @param theType
* @param theCommand
* @param thePrintToFile
* @param thePrintOutputErrorAsReceived
* @param theOutOrErr
*/
private StreamGobbler(InputStream is, String theType, String theCommand, File thePrintToFile,
boolean thePrintOutputErrorAsReceived, boolean theOutOrErr) {
this.inputStream = is;
this.type = theType;
this.command = theCommand;
this.printToFile = thePrintToFile;
this.printOutputErrorAsReceived = thePrintOutputErrorAsReceived;
this.outOrErr = theOutOrErr;
}
/**
* get the string result
* @return the result
*/
public String getResultString() {
return this.resultString;
}
/**
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = this.printToFile == null ? null : new FileOutputStream(this.printToFile);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
try {
if (this.printOutputErrorAsReceived) {
if (this.outOrErr) {
copy(this.inputStream, System.out);
} else {
copy(this.inputStream, System.err);
}
} else if (this.printToFile != null) {
copy(this.inputStream, fileOutputStream);
} else {
StringWriter stringWriter = new StringWriter();
copy(this.inputStream, stringWriter);
this.resultString = stringWriter.toString();
}
} catch (Exception e) {
LOG.warn("Error saving output of executable: " + (this.resultString)
+ ", " + this.type + ", " + this.command, e);
throw new RuntimeException(e);
} finally {
closeQuietly(fileOutputStream);
}
}
}
/**
*
This will execute a command (with args). In this method,
* if the exit code of the command is not zero, an exception will be thrown.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param printProgress if dots for progress should be used
* @return the output text of the command.
*/
public static CommandResult execCommand(String[] arguments, boolean printProgress) {
return execCommand(arguments, true, printProgress);
}
/**
* This will execute a command (with args). In this method,
* if the exit code of the command is not zero, an exception will be thrown.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param command to execute
* @param arguments are the commands
* @param printProgress if dots for progress should be used
* @return the output text of the command.
*/
public static CommandResult execCommand(String command, String[] arguments, boolean printProgress) {
List args = new ArrayList();
args.add(command);
for (String argument : nonNull(arguments, String.class)) {
args.add(argument);
}
return execCommand(toArray(args, String.class), true, printProgress);
}
/**
* threadpool
*/
private static ExecutorService executorService = Executors.newCachedThreadPool();
/**
*
* @return executor service
*/
public static ExecutorService retrieveExecutorService() {
return executorService;
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param printProgress if dots for progress should be used
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
public static CommandResult execCommand(String[] arguments, boolean exceptionOnExitValueNeZero, boolean printProgress) {
return execCommand(arguments, exceptionOnExitValueNeZero, true, printProgress);
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param waitFor if we should wait for this process to end
* @param printProgress if dots for progress should be used
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
public static CommandResult execCommand(String[] arguments, boolean exceptionOnExitValueNeZero, boolean waitFor, boolean printProgress) {
return execCommand(arguments, exceptionOnExitValueNeZero, waitFor, null, null, null, printProgress);
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param waitFor if we should wait for this process to end
* @param workingDirectory
* @param envVariables are env vars with name=val
* @param outputFilePrefix will be the file prefix and Out.log and Err.log will be added to them
* @param printProgress if dots for progress should be used
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
public static CommandResult execCommand(String[] arguments, boolean exceptionOnExitValueNeZero, boolean waitFor,
String[] envVariables, File workingDirectory, String outputFilePrefix, boolean printProgress) {
return execCommand(arguments, exceptionOnExitValueNeZero, waitFor, envVariables, workingDirectory, outputFilePrefix, false, printProgress);
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param waitFor if we should wait for this process to end
* @param workingDirectory
* @param envVariables are env vars with name=val
* @param outputFilePrefix will be the file prefix and Out.log and Err.log will be added to them
* @param printOutputErrorAsReceived if should print output error as received
* @param printProgress if dots for progress should be used
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
public static CommandResult execCommand(final String[] arguments, final boolean exceptionOnExitValueNeZero, final boolean waitFor,
final String[] envVariables, final File workingDirectory, final String outputFilePrefix,
final boolean printOutputErrorAsReceived, boolean printProgress) {
return execCommand(arguments, exceptionOnExitValueNeZero, waitFor, envVariables,
workingDirectory, outputFilePrefix, printOutputErrorAsReceived, printProgress, true);
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param waitFor if we should wait for this process to end
* @param workingDirectory
* @param envVariables are env vars with name=val
* @param outputFilePrefix will be the file prefix and Out.log and Err.log will be added to them
* @param printOutputErrorAsReceived if should print output error as received
* @param printProgress if dots for progress should be used
* @param logError true if errors should be logged. otherwise they will only be thrown
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
public static CommandResult execCommand(final String[] arguments, final boolean exceptionOnExitValueNeZero, final boolean waitFor,
final String[] envVariables, final File workingDirectory, final String outputFilePrefix,
final boolean printOutputErrorAsReceived, boolean printProgress, final boolean logError) {
final CommandResult[] result = new CommandResult[1];
Runnable runnable = new Runnable() {
public void run() {
result[0] = execCommandHelper(arguments, exceptionOnExitValueNeZero, waitFor,
envVariables, workingDirectory, outputFilePrefix, printOutputErrorAsReceived, logError);
}
};
GrouperInstallerUtils.threadRunWithStatusDots(runnable, printProgress, logError);
return result[0];
}
/**
* This will execute a command (with args). Under normal operation,
* if the exit code of the command is not zero, an exception will be thrown.
* If the parameter exceptionOnExitValueNeZero is set to true, the
* results of the call will be returned regardless of the exit status.
* Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
*
* @param arguments are the commands
* @param exceptionOnExitValueNeZero if this is set to false, the
* results of the call will be returned regardless of the exit status
* @param waitFor if we should wait for this process to end
* @param workingDirectory
* @param envVariables are env vars with name=val
* @param outputFilePrefix will be the file prefix and Out.log and Err.log will be added to them
* @param printOutputErrorAsReceived if should print output error as received
* @param logError if error should be logged, otherwise it will only be thrown
* @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false.
*/
private static CommandResult execCommandHelper(String[] arguments, boolean exceptionOnExitValueNeZero, boolean waitFor,
String[] envVariables, File workingDirectory, String outputFilePrefix, boolean printOutputErrorAsReceived, boolean logError) {
if (printOutputErrorAsReceived && !isBlank(outputFilePrefix)) {
throw new RuntimeException("Cant print as received and have output file prefix");
}
Process process = null;
StringBuilder commandBuilder = new StringBuilder();
for (int i = 0; i < arguments.length; i++) {
commandBuilder.append(arguments[i]).append(" ");
}
String command = commandBuilder.toString();
if (LOG.isDebugEnabled()) {
LOG.debug("Running command: " + command);
}
StreamGobbler outputGobbler = null;
StreamGobbler errorGobbler = null;
try {
process = Runtime.getRuntime().exec(arguments, envVariables, workingDirectory);
if (!waitFor) {
return new CommandResult(null, null, -1);
}
outputGobbler = new StreamGobbler(process.getInputStream(), ".out", command, outputFilePrefix == null ? null : new File(outputFilePrefix + "Out.log"), printOutputErrorAsReceived, true);
errorGobbler = new StreamGobbler(process.getErrorStream(), ".err", command, outputFilePrefix == null ? null : new File(outputFilePrefix + "Err.log"), printOutputErrorAsReceived, false);
Thread outputThread = new Thread(outputGobbler);
outputThread.setDaemon(true);
outputThread.start();
Thread errorThread = new Thread(errorGobbler);
errorThread.setDaemon(true);
errorThread.start();
try {
process.waitFor();
} finally {
//finish running these threads
try {
outputThread.join();
} catch (Exception e) {
}
try {
errorThread.join();
} catch (Exception e) {
}
}
} catch (Exception e) {
if (logError) {
LOG.error("Error running command: " + command, e);
}
throw new RuntimeException("Error running command: " + command + ", " + e.getMessage(), e);
} finally {
try {
process.destroy();
} catch (Exception e) {
}
}
//was not successful???
if (process.exitValue() != 0 && exceptionOnExitValueNeZero) {
String message = "Process exit status=" + process.exitValue() + ": out: " +
(outputGobbler == null ? null : outputGobbler.getResultString())
+ ", err: " + (errorGobbler == null ? null : errorGobbler.getResultString());
if (logError) {
LOG.error(message + ", on command: " + command + (workingDirectory == null ? "" : (", workingDir: " + workingDirectory.getAbsolutePath())));
}
throw new RuntimeException(message);
}
int exitValue = process.exitValue();
return new CommandResult(errorGobbler.getResultString(), outputGobbler.getResultString(), exitValue);
}
/**
* The results of executing a command.
*/
public static class CommandResult{
/**
* If any error text was generated by the call, it will be set here.
*/
private String errorText;
/**
* If any output text was generated by the call, it will be set here.
*/
private String outputText;
/**
* If any exit code was generated by the call, it will be set here.
*/
private int exitCode;
/**
* Create a container to hold the results of an execution.
* @param _errorText
* @param _outputText
* @param _exitCode
*/
public CommandResult(String _errorText, String _outputText, int _exitCode){
this.errorText = _errorText;
this.outputText = _outputText;
this.exitCode = _exitCode;
}
/**
* If any error text was generated by the call, it will be set here.
* @return the errorText
*/
public String getErrorText() {
return this.errorText;
}
/**
* If any output text was generated by the call, it will be set here.
* @return the outputText
*/
public String getOutputText() {
return this.outputText;
}
/**
* If any exit code was generated by the call, it will be set here.
* @return the exitCode
*/
public int getExitCode() {
return this.exitCode;
}
}
/**
*
* @return java command
*/
public static String javaCommand() {
return javaHome() + File.separator + "bin" + File.separator + "java";
}
/** */
private static String JAVA_HOME = null;
/**
*
* @return the java home location without slash afterward
*/
public static String javaHome() {
if (isBlank(JAVA_HOME)) {
//try to get a jdk
JAVA_HOME = System.getProperty("java.home");
if (JAVA_HOME.endsWith("jre")) {
String newJavaHome = JAVA_HOME.substring(0,JAVA_HOME.length()-4);
File javac = new File(newJavaHome + File.separator + "bin" + File.separator + "javac");
if (javac.exists()) {
JAVA_HOME = newJavaHome;
}
javac = new File(newJavaHome + File.separator + "bin" + File.separator + "javac.exe");
if (javac.exists()) {
JAVA_HOME = newJavaHome;
}
}
}
return JAVA_HOME;
}
/**
* Checks to see if a specific port is available.
*
* @param port the port to check for availability
* @return true if available
*/
public static boolean portAvailable(int port) {
return portAvailable(port, null);
}
/**
* Checks to see if a specific port is available.
*
* @param port the port to check for availability
* @param ipAddress
* @return true if available
*/
public static boolean portAvailable(int port, String ipAddress) {
ServerSocket ss = null;
try {
if (isBlank(ipAddress) || "0.0.0.0".equals(ipAddress)) {
ss = new ServerSocket(port);
} else {
Pattern pattern = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)");
Matcher matcher = pattern.matcher(ipAddress);
if (!matcher.matches()) {
throw new RuntimeException("IP address not valid! '" + ipAddress + "'");
}
byte[] b = new byte[4];
for (int i=0;i<4;i++) {
int theInt = intValue(matcher.group(i+1));
if (theInt > 255 || theInt < 0) {
System.out.println("IP address part must be between 0 and 255: '" + theInt + "'");
}
b[i] = (byte)theInt;
}
//Returns an InetAddress object given the raw IP address .
InetAddress inetAddress = InetAddress.getByAddress(b);
ss = new ServerSocket(port, 50, inetAddress);
}
ss.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
/**
* add a jar to classpath
* @param file
*/
public static void classpathAddFile(File file) {
try {
classpathAddUrl(file.toURI().toURL());
} catch (IOException ioe) {
throw new RuntimeException("Problem adding file to classpath: " + (file == null ? null : file.getAbsolutePath()));
}
}
/**
* keep track of urls added so we dont add twice
*/
private static Set urlsAddedToClasspath = new HashSet();
/**
* use reflection to add a jar to the classpath
* @param url
*/
public static void classpathAddUrl(URL url) {
String urlString = url.toString();
if (urlsAddedToClasspath.contains(urlString)) {
return;
}
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
method.invoke(sysloader, new Object[] { url });
} catch (Throwable t) {
throw new RuntimeException("Error, could not add URL to system classloader: " + urlString, t);
}
urlsAddedToClasspath.add(urlString);
}
/**
* Return the zero element of the list, if it exists, null if the list is empty.
* If there is more than one element in the list, an exception is thrown.
* @param
* @param list is the container of objects to get the first of.
* @return the first object, null, or exception.
*/
public static T listPopOne(List list) {
int size = length(list);
if (size == 1) {
return list.get(0);
} else if (size == 0) {
return null;
}
throw new RuntimeException("More than one object of type " + className(list.get(0))
+ " was returned when only one was expected. (size:" + size +")" );
}
/**
* Copy a file to another file. this perserves the file date
*
* @param sourceFile
* @param destinationFile
*/
public static void copyFile(File sourceFile, File destinationFile) {
copyFile(sourceFile, destinationFile, true);
}
/**
* Copy a file to another file. this perserves the file date
*
* @param sourceFile
* @param destinationFile
* @param onlyIfDifferentContents true if only saving due to different contents. Note, this is only for non-binary files!
* @param ignoreWhitespace true to ignore whitespace in comparisons
* @return true if contents were saved (thus different if param set)
*/
public static boolean copyFile(File sourceFile, File destinationFile, boolean onlyIfDifferentContents,
boolean ignoreWhitespace) {
if (onlyIfDifferentContents) {
String sourceContents = readFileIntoString(sourceFile);
return saveStringIntoFile(destinationFile, sourceContents,
onlyIfDifferentContents, ignoreWhitespace);
}
copyFile(sourceFile, destinationFile);
return true;
}
/**
* Copies a file to a new location.
*
* This method copies the contents of the specified source file
* to the specified destination file.
* The directory holding the destination file is created if it does not exist.
* If the destination file exists, then this method will overwrite it.
*
* @param srcFile an existing file to copy, must not be null
* @param destFile the new file, must not be null
* @param preserveFileDate true if the file date of the copy
* should be the same as the original
*
* @throws NullPointerException if source or destination is null
*/
public static void copyFile(File srcFile, File destFile,
boolean preserveFileDate) {
try {
if (srcFile == null) {
throw new NullPointerException("Source must not be null");
}
if (destFile == null) {
throw new NullPointerException("Destination must not be null");
}
if (srcFile.exists() == false) {
throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
}
if (srcFile.isDirectory()) {
throw new IOException("Source '" + srcFile + "' exists but is a directory");
}
if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
throw new IOException("Source '" + srcFile + "' and destination '" + destFile
+ "' are the same");
}
if (destFile.getParentFile() != null && destFile.getParentFile().exists() == false) {
if (destFile.getParentFile().mkdirs() == false) {
throw new IOException("Destination '" + destFile
+ "' directory cannot be created");
}
}
if (destFile.exists() && destFile.canWrite() == false) {
throw new IOException("Destination '" + destFile + "' exists but is read-only");
}
doCopyFile(srcFile, destFile, preserveFileDate);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* Internal copy file method.
*
* @param srcFile the validated source file, must not be null
* @param destFile the validated destination file, must not be null
* @param preserveFileDate whether to preserve the file date
* @throws IOException if an error occurs
*/
private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate)
throws IOException {
if (destFile.exists() && destFile.isDirectory()) {
throw new IOException("Destination '" + destFile + "' exists but is a directory");
}
FileInputStream input = new FileInputStream(srcFile);
try {
FileOutputStream output = new FileOutputStream(destFile);
try {
copy(input, output);
} finally {
closeQuietly(output);
}
} finally {
closeQuietly(input);
}
if (srcFile.length() != destFile.length()) {
throw new IOException("Failed to copy full contents from '" +
srcFile + "' to '" + destFile + "'");
}
if (preserveFileDate) {
destFile.setLastModified(srcFile.lastModified());
}
}
/**
*
* @param xmlFile
* @param xpathExpression
* @return the nodelist
*/
public static NodeList xpathEvaluate(File xmlFile, String xpathExpression) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(xmlFile);
return xpathEvaluate(inputStream, xpathExpression);
} catch (Exception e) {
String errorMessage = "Problem with file: " + xmlFile == null ? null : xmlFile.getAbsolutePath();
if (e instanceof RuntimeException) {
GrouperInstallerUtils.injectInException(e, errorMessage);
throw (RuntimeException)e;
}
throw new RuntimeException(errorMessage, e);
} finally {
GrouperInstallerUtils.closeQuietly(inputStream);
}
}
/**
* @param url
* @param xpathExpression
* @return the nodelist
*/
public static NodeList xpathEvaluate(URL url, String xpathExpression) {
InputStream inputStream = null;
try {
inputStream = url.openStream();
return xpathEvaluate(inputStream, xpathExpression);
} catch (Exception e) {
String errorMessage = "Problem with url: " + url == null ? null : url.toExternalForm();
if (e instanceof RuntimeException) {
GrouperInstallerUtils.injectInException(e, errorMessage);
throw (RuntimeException)e;
}
throw new RuntimeException(errorMessage, e);
} finally {
GrouperInstallerUtils.closeQuietly(inputStream);
}
}
/**
* @param inputStream
* @param xpathExpression
* @return the nodelist
*/
public static NodeList xpathEvaluate(InputStream inputStream, String xpathExpression) {
try {
DocumentBuilderFactory domFactory = xmlDocumentBuilderFactory();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
XPath xpath = XPathFactory.newInstance().newXPath();
// XPath Query for showing all nodes value
XPathExpression expr = xpath.compile(xpathExpression);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
return nodes;
} catch (Exception e) {
throw new RuntimeException("Problem evaluating xpath: " + ", expression: '" + xpathExpression + "'", e);
}
}
/**
* xml builder factory that doesnt go to internet to get dtd
* @return the factory
*/
public static DocumentBuilderFactory xmlDocumentBuilderFactory() {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
domFactory.setValidating(false);
try {
domFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
} catch (ParserConfigurationException pce) {
throw new RuntimeException(pce);
}
return domFactory;
}
/** array for converting HTML to string */
private static final String[] XML_SEARCH_NO_SINGLE = new String[]{"&","<",">","\""};
/** array for converting HTML to string */
private static final String[] XML_REPLACE_NO_SINGLE = new String[]{"&","<",">","""};
/**
* Convert an XML string to HTML to display on the screen
*
* @param input
* is the XML to convert
*
* @return the HTML converted string
*/
public static String xmlEscape(String input) {
return xmlEscape(input, true);
}
/**
* Convert an XML string to HTML to display on the screen
*
* @param input
* is the XML to convert
* @param isEscape true to escape chars, false to unescape
*
* @return the HTML converted string
*/
public static String xmlEscape(String input, boolean isEscape) {
if (isEscape) {
return replace(input, XML_SEARCH_NO_SINGLE, XML_REPLACE_NO_SINGLE);
}
return replace(input, XML_REPLACE_NO_SINGLE, XML_SEARCH_NO_SINGLE);
}
/**
*
* @param xmlFile
* @param xpathExpression
* @param attributeName
* @return the nodelist
*/
public static String xpathEvaluateAttribute(File xmlFile, String xpathExpression, String attributeName) {
NodeList nodes = GrouperInstallerUtils.xpathEvaluate(xmlFile, xpathExpression);
if (nodes == null || nodes.getLength() == 0) {
return null;
}
if (nodes.getLength() != 1) {
throw new RuntimeException("There is more than 1 xpath expression: '" + xpathExpression + "' element in server.xml: " + xmlFile.getAbsolutePath());
}
NamedNodeMap attributes = nodes.item(0).getAttributes();
if (attributes == null || attributes.getLength() == 0 ) {
return null;
}
Node attribute = attributes.getNamedItem(attributeName);
if (attribute == null) {
return null;
}
String nodeValue = attribute.getNodeValue();
return nodeValue;
}
/**
* turn a map of attributes into an xml string
* @param elementName
* @param extraAttributes
* @param attributes
* @return the xml
*/
public static String xmlElementToXml(String elementName,
String extraAttributes, Map attributes) {
StringBuilder result = new StringBuilder();
result.append("<").append(elementName).append(" ");
if (!isBlank(extraAttributes)) {
result.append(extraAttributes);
}
for (String attributeName : attributes.keySet()) {
result.append(" ").append(attributeName).append("=\"");
String attributeValue = GrouperInstallerUtils.trimToEmpty(attributes.get(attributeName));
result.append(GrouperInstallerUtils.xmlEscape(attributeValue)).append("\"");
}
result.append(" />");
return result.toString();
}
/**
* convert XML to string
* @param document
* @return the string of the XML
*/
public static String xmlToString(Node document) {
try {
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
/**
*
* @param xmlFile
* @param xpathExpression
* @param attributeName
* @param defaultValue
* @return the nodelist
*/
public static Integer xpathEvaluateAttributeInt(File xmlFile, String xpathExpression, String attributeName, Integer defaultValue) {
String nodeValue = xpathEvaluateAttribute(xmlFile, xpathExpression, attributeName);
Integer intValue = GrouperInstallerUtils.intValue(nodeValue, defaultValue);
return intValue;
}
/**
*
* @param jarFile
* @return the version
*/
public static String jarVersion(File jarFile) {
return jarVersion(jarFile, false);
}
/**
* see which jar is newer or null if dont know
* @param jar1
* @param jar2
* @return the jar which is newer or null if cant find
*/
public static File jarNewerVersion(File jar1, File jar2) {
String version1 = jarVersion(jar1, false);
String version2 = jarVersion(jar2, false);
if (version1 == null && version2 == null) {
return null;
}
if (version1 == null) {
return jar2;
}
if (version2 == null) {
return jar1;
}
GiGrouperVersion giGrouperVersion1 = GiGrouperVersion.valueOfIgnoreCase(version1, false);
GiGrouperVersion giGrouperVersion2 = GiGrouperVersion.valueOfIgnoreCase(version2, false);
if (giGrouperVersion1 == null && giGrouperVersion2 == null) {
return null;
}
if (giGrouperVersion1 == null) {
return jar2;
}
if (giGrouperVersion2 == null) {
return jar1;
}
if (giGrouperVersion1.lessThanArg(giGrouperVersion2)) {
return jar2;
}
return jar1;
}
/**
*
* @param jarFile
* @param exceptionIfProblem true if should throw exception if problem, otherwise blank
* @return the version
*/
public static String jarVersion(File jarFile, boolean exceptionIfProblem) {
try {
String version = jarVersion0(jarFile);
if (isBlank(version)) {
version = jarVersion1(jarFile);
}
if (isBlank(version)) {
//hopefully this is set
if (tempFilePathForJars != null) {
String jarFilePath = jarFile.getAbsolutePath();
jarFilePath = replace(jarFilePath, ":", "_");
if (jarFilePath.startsWith("/") || jarFilePath.startsWith("\\")) {
jarFilePath = jarFilePath.substring(1);
}
jarFilePath = tempFilePathForJars + jarFilePath;
File bakJarFile = new File(jarFilePath);
mkdirs(bakJarFile.getParentFile());
copyFile(jarFile, bakJarFile);
version = jarVersion2(bakJarFile);
} else {
throw new RuntimeException("You need to set tempFileForJars");
}
}
return version;
} catch (RuntimeException e) {
injectInException(e, "Problem with jar: " + jarFile.getAbsolutePath());
if (exceptionIfProblem) {
throw e;
}
System.out.println("Non-fatal issue with " + jarFile.getAbsolutePath() + ", " + e.getMessage() + ", assuming cant find version");
}
return null;
}
private static Pattern versionPattern = Pattern.compile("^.*(\\d+)\\.(\\d+)\\.(\\d+)\\.jar*$");
/**
* get the property value from version in the manifest of a jar
* @param jarFile
* @return the version or null if cant find
*/
public static String jarVersion0(File jarFile) {
String fileName = jarFile.getName();
Matcher matcher = versionPattern.matcher(fileName);
if (matcher.matches()) {
return matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3);
}
return null;
}
/** set this to copy jars if the jarinputstream doesnt work, must end in File.separator, set this at the beginning of the
* program.
*/
public static String tempFilePathForJars = null;
/**
*
* @param jarFile
* @return the version
*/
public static String jarVersion2(File jarFile) {
InputStream manifestStream = null;
try {
URL manifestUrl = new URL("jar:file:" + jarFile.getCanonicalPath() + "!/META-INF/MANIFEST.MF");
manifestStream = manifestUrl.openStream();
Manifest manifest = new Manifest(manifestStream);
return manifest == null ? null : manifestVersion(jarFile, manifest);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
throw new RuntimeException(jarFile.getAbsolutePath() + ", " + e.getMessage(), e);
} finally {
closeQuietly(manifestStream);
}
}
/**
* split a string (e.g. file contents) into lines
* @param string
* @return the lines
*/
public static String[] splitLines(String string) {
String newline = newlineFromFile(string);
String[] lines = null;
if ("\n".equals(newline)) {
lines = string.split("[\\n]");
} else if ("\r".equals(newline)) {
lines = string.split("[\\r]");
} else if ("\r\n".equals(newline)) {
lines = string.split("[\\r\\n]");
} else {
lines = string.split("[\\r\\n]+");
}
return lines;
}
/**
* replace newlines with space
* @param input
* @return the string
*/
public static String replaceNewlinesWithSpace(String input) {
if (input == null) {
return null;
}
input = GrouperInstallerUtils.replace(input, "\r\n", " ");
input = GrouperInstallerUtils.replace(input, "\r", " ");
input = GrouperInstallerUtils.replace(input, "\n", " ");
return input;
}
/**
* if printed cant find version, put the jar name here
*/
private static Set printedCantFindVersionJarName = new HashSet();
static {
//we know about this one, signed, cant change
//sqljdbc4.jar, Manifest-Version: 1.0
//sqljdbc4.jar, Created-By: 1.6.0_33 (Sun Microsystems Inc.)
printedCantFindVersionJarName.add("sqljdbc4.jar");
}
/**
* @param jarFile
* @param manifest
* @return manifest version
*/
public static String manifestVersion(File jarFile, Manifest manifest) {
boolean printJarVersionProblemsV1 = propertiesValueBoolean("grouperInstaller.printJarVersionIssuesV1", false, false);
String[] propertyNames = new String[]{
"Implementation-Version","Version"};
Map attributeMap = manifest.getEntries();
String value = null;
for (String propertyName : propertyNames) {
value = manifest.getMainAttributes().getValue(propertyName);
if (!isBlank(value)) {
break;
}
}
if (value == null) {
OUTER:
for (Attributes attributes: attributeMap.values()) {
for (String propertyName : propertyNames) {
value = attributes.getValue(propertyName);
if (!isBlank(value)) {
break OUTER;
}
}
}
}
if (value == null) {
if (!printedCantFindVersionJarName.contains(jarFile.getName())) {
printedCantFindVersionJarName.add(jarFile.getName());
if (printJarVersionProblemsV1) {
System.out.println("Error: cant find version for jar: " + jarFile.getName());
}
if (printJarVersionProblemsV1) {
for (Attributes attributes: attributeMap.values()) {
for (Object key : attributes.keySet()) {
System.out.println(jarFile.getName() + ", " + key + ": " + attributes.getValue((Name)key));
}
}
Attributes attributes = manifest.getMainAttributes();
for (Object key : attributes.keySet()) {
System.out.println(jarFile.getName() + ", main " + key + ": " + attributes.getValue((Name)key));
}
}
}
}
return value;
}
/**
* based on file contents see what the newline type is
* @param fileContents
* @return the newline
*/
public static String newlineFromFile(String fileContents) {
String newline = "\n";
if (fileContents.contains("\r\n")) {
newline = "\r\n";
}
if (fileContents.contains("\n\r")) {
newline = "\n\r";
}
if (fileContents.contains("\r")) {
newline = "\r";
}
return newline;
}
/**
* list files recursively from parent, dont include
* @param parent
* @param fileName
* @return set of files wont return null
*/
public static List fileListRecursive(File parent, String fileName) {
List allFiles = GrouperInstallerUtils.fileListRecursive(parent);
List result = new ArrayList();
for (File file : allFiles) {
if (equals(file.getName(), fileName)) {
result.add(file);
}
}
return result;
}
/**
* list files recursively from parent, dont include
* @param parent
* @return set of files wont return null
*/
public static List fileListRecursive(File parent) {
List results = new ArrayList();
fileListRecursiveHelper(parent, results);
return results;
}
/**
* helper to add child files to a parent (
* @param parent
* @param fileList
*/
private static void fileListRecursiveHelper(File parent, List fileList) {
if (parent == null || !parent.exists() || !parent.isDirectory()) {
return;
}
List subFiles = nonNull(toList(parent.listFiles()));
for (File subFile : subFiles) {
if (subFile.isFile()) {
fileList.add(subFile);
}
if (subFile.isDirectory()) {
fileListRecursiveHelper(subFile, fileList);
}
}
}
/**
* @param path
* @return the new path
*/
public static String fileMassagePathsNoLeadingOrTrailing(String path) {
path = path.replace(File.separatorChar == '/' ? '\\' : '/', File.separatorChar);
if (path.startsWith(File.separator)) {
path = path.substring(1);
}
if (path.endsWith(File.separator)) {
path = path.substring(0, path.length()-1);
}
return path;
}
/**
* Compares the contents of two files to determine if they are equal or not.
*
* This method checks to see if the two files are different lengths
* or if they point to the same file, before resorting to byte-by-byte
* comparison of the contents.
*
* Code origin: Avalon
*
* @param file1 the first file
* @param file2 the second file
* @return true if the content of the files are equal or they both don't
* exist, false otherwise
*/
public static boolean contentEquals(File file1, File file2) {
try {
boolean file1Exists = file1 != null && file1.exists();
boolean file2Exists = file2 != null && file2.exists();
if (file1Exists != file2Exists) {
return false;
}
if (!file1Exists) {
// two not existing files are equal
return true;
}
if (file1.isDirectory() || file2.isDirectory()) {
// don't want to compare directory contents
throw new IOException("Can't compare directories, only files: " + file1.getAbsolutePath() + ", " + file2.getAbsolutePath());
}
if (file1.length() != file2.length()) {
// lengths differ, cannot be equal
return false;
}
if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
// same file
return true;
}
InputStream input1 = null;
InputStream input2 = null;
try {
input1 = new FileInputStream(file1);
input2 = new FileInputStream(file2);
return contentEquals(input1, input2);
} finally {
closeQuietly(input1);
closeQuietly(input2);
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/**
* Compare the contents of two Streams to determine if they are equal or
* not.
*
* This method buffers the input internally using
* BufferedInputStream
if they are not already buffered.
*
* @param input1 the first stream
* @param input2 the second stream
* @return true if the content of the streams are equal or they both don't
* exist, false otherwise
* @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
*/
public static boolean contentEquals(InputStream input1, InputStream input2)
throws IOException {
if (!(input1 instanceof BufferedInputStream)) {
input1 = new BufferedInputStream(input1);
}
if (!(input2 instanceof BufferedInputStream)) {
input2 = new BufferedInputStream(input2);
}
int ch = input1.read();
while (-1 != ch) {
int ch2 = input2.read();
if (ch != ch2) {
return false;
}
ch = input1.read();
}
int ch2 = input2.read();
return (ch2 == -1);
}
/**
* Compare the contents of two Readers to determine if they are equal or
* not.
*
* This method buffers the input internally using
* BufferedReader
if they are not already buffered.
*
* @param input1 the first reader
* @param input2 the second reader
* @return true if the content of the readers are equal or they both don't
* exist, false otherwise
* @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.1
*/
public static boolean contentEquals(Reader input1, Reader input2)
throws IOException {
if (!(input1 instanceof BufferedReader)) {
input1 = new BufferedReader(input1);
}
if (!(input2 instanceof BufferedReader)) {
input2 = new BufferedReader(input2);
}
int ch = input1.read();
while (-1 != ch) {
int ch2 = input2.read();
if (ch != ch2) {
return false;
}
ch = input1.read();
}
int ch2 = input2.read();
return (ch2 == -1);
}
/**
* get the relative paths of descendant files
* @param parentDir
* @return the relative paths of files underneath, dont start with slash
*/
public static Set fileDescendantRelativePaths(File parentDir) {
Set result = new LinkedHashSet();
List descendants = fileListRecursive(parentDir);
for (File file : GrouperInstallerUtils.nonNull(descendants)) {
String descendantPath = file.getAbsolutePath();
String parentPath = parentDir.getAbsolutePath();
if (!descendantPath.startsWith(parentPath)) {
throw new RuntimeException("Why doesnt descendantPath '" + descendantPath + "' start with parent path '" + parentPath + "'?");
}
descendantPath = descendantPath.substring(parentPath.length());
if (descendantPath.startsWith("/") || descendantPath.startsWith("\\")) {
descendantPath = descendantPath.substring(1);
}
result.add(descendantPath);
}
return result;
}
/**
* get the relative path of descendant file
* @param parentDir
* @param file
* @return the relative path of file underneath, dont start with slash
*/
public static String fileRelativePath(File parentDir, File file) {
String descendantPath = file.getAbsolutePath();
String parentPath = parentDir.getAbsolutePath();
if (!descendantPath.startsWith(parentPath)) {
throw new RuntimeException("Why doesnt descendantPath '" + descendantPath + "' start with parent path '" + parentPath + "'?");
}
descendantPath = descendantPath.substring(parentPath.length());
if (descendantPath.startsWith("/") || descendantPath.startsWith("\\")) {
descendantPath = descendantPath.substring(1);
}
return descendantPath;
}
/**
*
* @param bigPath
* @param prefixPath
* @return true if starts with
*/
public static boolean filePathStartsWith(String bigPath, String prefixPath) {
bigPath = replace(bigPath, "\\\\", "\\");
bigPath = replace(bigPath, "\\", "/");
prefixPath = replace(prefixPath, "\\\\", "\\");
prefixPath = replace(prefixPath, "\\", "/");
return bigPath.startsWith(prefixPath);
}
/**
* get the property value from version in the manifest of a jar
* @param jarFile
* @return the version
*/
public static String jarVersion1(File jarFile) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(jarFile);
JarInputStream jarInputStream = new JarInputStream(fileInputStream);
Manifest manifest = jarInputStream.getManifest();
return manifest == null ? null : manifestVersion(jarFile, manifest);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
throw new RuntimeException(e.getMessage(), e);
} finally {
closeQuietly(fileInputStream);
}
}
}