package com.gmail.dpierron.tools; /** * Useful utility functions called from multiple areas of program */ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.rmi.dgc.VMID; import java.text.Collator; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.Locale; public class Helper { private final static Logger logger = LogManager.getLogger(Helper.class); private static final String DEFAULT_PREFIX = "com.gmail.dpierron."; static final int DEFAULT_STACK_DEPTH = 5; /** * checked s1.equals(s2) */ public static final boolean stringEquals(String s1, String s2) { return objectEquals(s1, s2); } /** * checked s1.equals(s2) */ public static final boolean objectEquals(Object o1, Object o2) { if (o1 == null || o2 == null) return (o1 == null && o2 == null); return o1.equals(o2); } public static String newId() { String result = new VMID().toString(); result = result.replace('0', 'G'); result = result.replace('1', 'H'); result = result.replace('2', 'I'); result = result.replace('3', 'J'); result = result.replace('4', 'K'); result = result.replace('5', 'L'); result = result.replace('6', 'M'); result = result.replace('7', 'N'); result = result.replace('8', 'O'); result = result.replace('9', 'P'); result = result.replaceAll("-", ""); result = result.replaceAll(":", ""); return result; } public static void logStack(Logger logger) { logStack(logger, 2, DEFAULT_STACK_DEPTH, DEFAULT_PREFIX); } public static void logStack(Logger logger, int maxDepth) { logStack(logger, 2, maxDepth, DEFAULT_PREFIX); } public static void logStack(Logger logger, int skip, int maxDepth) { logStack(logger, skip + 2, maxDepth, DEFAULT_PREFIX); } public static void logStack(Logger logger, int skip, int maxDepth, String removePrefix) { Exception e = new RuntimeException(); e.fillInStackTrace(); StackTraceElement[] calls = e.getStackTrace(); for (int i = skip; i < maxDepth + skip; i++) { if (i >= calls.length) break; StackTraceElement call = e.getStackTrace()[i]; String msg = call.toString(); if (removePrefix != null) { int pos = msg.indexOf(removePrefix); if (pos > -1) msg = msg.substring(pos + removePrefix.length()); } if (logger.isDebugEnabled()) logger.debug("Stack trace [" + (i - skip) + "] -> " + msg); } } public static String concatenateList(Collection toConcatenate) { return concatenateList(null, toConcatenate, (String[]) null); } public static String concatenateList(String separator, Collection toConcatenate) { return concatenateList(separator, toConcatenate, (String[]) null); } public static String concatenateList(Collection toConcatenate, String... methodName) { return concatenateList(null, toConcatenate, methodName); } public static String concatenateList(String separator, Collection toConcatenate, String... methodName) { try { if (toConcatenate == null || toConcatenate.size() == 0) return ""; StringBuffer lines = new StringBuffer(); String theSeparator = (separator == null ? ", " : separator); for (Object o : toConcatenate) { Object result = o; if (methodName == null) { result = o.toString(); } else { for (String theMethodName : methodName) { Method method = null; try { method = result.getClass().getMethod(theMethodName); } catch (SecurityException e) { logger.warn(e.getMessage(), e); } catch (NoSuchMethodException e) { logger.warn(e.getMessage(), e); } if (method != null) try { result = method.invoke(result); } catch (IllegalArgumentException e) { logger.warn(e.getMessage(), e); } catch (IllegalAccessException e) { logger.warn(e.getMessage(), e); } catch (InvocationTargetException e) { logger.warn(e.getMessage(), e); } } } lines.append(result); lines.append(theSeparator); } String sLines = lines.length() >= theSeparator.length() ? lines.substring(0, lines.length() - theSeparator.length()) : ""; return sLines; } catch (Exception e) { return ""; } } public static Collection transformList(Collection toTransform, String... methodName) { List transformed = new LinkedList(); try { if (toTransform == null || toTransform.size() == 0) return toTransform; for (Object o : toTransform) { Object result = o; if (methodName == null) { result = o.toString(); } else { for (String theMethodName : methodName) { Method method; method = result.getClass().getMethod(theMethodName); result = method.invoke(result); } } transformed.add(result); } return transformed; } catch (Exception e) { return transformed; } } public static List<String> tokenize(String text, String delim) { return tokenize(text, delim, false); } public static List<String> tokenize(String text, String delim, boolean trim) { List<String> result = new LinkedList<String>(); if (isNotNullOrEmpty(text)) { // Note: Do not use replaceall as this uses regular expressions for the 'delim' // parameter which can ahve unexpected side effects if special characters used. // String s = text.replaceAll(delim, "�"); String s = text.replace(delim, "�"); String[] tokens = s.split("�"); for (String token : tokens) { if (trim) token = token.trim(); result.add(token); } } return result; } public static String deTokenize(Collection<String> list, String delim) { if (list.size() > 0) { StringBuffer sb = new StringBuffer(); for (String text : list) { if (sb.length() > 0) sb.append(delim); sb.append(text); } return sb.toString(); } else return ""; } public static String leftPad(String s, char paddingCharacter, int length) { if (s.length() >= length) return s; StringBuffer sb = new StringBuffer(); for (int i = s.length(); i < length; i++) { sb.append(paddingCharacter); } sb.append(s); return sb.toString(); } public static String pad(String s, char paddingCharacter, int length) { if (s.length() >= length) return s; StringBuffer sb = new StringBuffer(s); for (int i = s.length(); i < length; i++) { sb.append(paddingCharacter); } return sb.toString(); } /** * @return the last numeric component of string s (that is, the part of the * string to the right of the last non-numeric character) */ public static String getLastNumericComponent(String s) { int i = s.length() - 1; while ((i >= 0) && (Character.isDigit(s.charAt(i)))) i--; if (i < 0) return s; if (i == s.length() - 1 && !Character.isDigit(s.charAt(i))) return null; return (s.substring(i + 1)); } /** * @return the right part of string s, after the first occurence of string * toSubstract, or the whole string s if it does not contain * toSubstract */ public static String substractString(String s, String toSubstract) { if (isNullOrEmpty(s)) return s; if (isNullOrEmpty(toSubstract)) return s; if (!s.startsWith(toSubstract)) return s; return s.substring(toSubstract.length()); } public static boolean trueBooleanEquals(Object o1, Object o2) { return trueBoolean(o1) == trueBoolean(o2); } public static boolean trueBoolean(Object o) { if (o == null) return false; if (o instanceof Boolean) return ((Boolean) o).booleanValue(); else return new Boolean(o.toString()).booleanValue(); } public static Integer parseInteger(String s) { if (isNullOrEmpty(s)) return null; try { int i = Integer.parseInt(s); return new Integer(i); } catch (NumberFormatException e) { return null; } } public static boolean trueStringEquals(Object o1, Object o2) { return trueString(o1).equals(trueString(o2)); } public static int trueStringCompare(Object o1, Object o2) { return trueString(o1).compareTo(trueString(o2)); } public static String trueString(Object o) { if (o == null) return ""; else return o.toString(); } public static Object[] arrayThis(Object[] theArray, Object... objects) { ArrayList result = listThis(objects); return result.toArray(theArray); } public static ArrayList listThis(Object... objects) { return listThis(false, objects); } public static ArrayList listThis(boolean duplicates, Object... objects) { ArrayList result = new ArrayList(); if (objects != null) for (Object object : objects) { if (object == null) continue; if (object instanceof List) { List list = (List) object; if (duplicates) { result.addAll(list); } else { if (list != null) for (Object item : list) { if (item == null) continue; if (!result.contains(item)) result.add(item); } } } else { result.add(object); } } return result; } /** * This method takes a string and wraps it to a line length of no more than * wrap_length. If prepend is not null, each resulting line will be prefixed * with the prepend string. In that case, resultant line length will be no * more than wrap_length + prepend.length() */ public static String wrap(String inString, int wrap_length, String prepend) { char[] charAry; int p, p2, offset = 0, marker; StringBuffer result = new StringBuffer(); /* -- */ if (inString == null) { return null; } if (wrap_length < 0) { throw new IllegalArgumentException("bad params"); } if (prepend != null) { result.append(prepend); } charAry = inString.toCharArray(); p = marker = 0; // each time through the loop, p starts out pointing to the same char as // marker while (marker < charAry.length) { while (p < charAry.length && (charAry[p] != '\n') && ((p - marker) < wrap_length)) { p++; } if (p == charAry.length) { result.append(inString.substring(marker, p)); return result.toString(); } if (charAry[p] == '\n') { /* * We've got a newline. This newline is bound to have terminated the * while loop above. Step p back one character so that the isspace(*p) * check below will detect that it hit the \n, and will do the right * thing. */ result.append(inString.substring(marker, p + 1)); if (prepend != null) { result.append(prepend); } p = marker = p + 1; continue; } p2 = p - 1; /* * We've either hit the end of the string, or we've gotten past the * wrap_length. Back p2 up to the last space before the wrap_length, if * there is such a space. Note that if the next character in the string * (the character immediately after the break point) is a space, we don't * need to back up at all. We'll just print up to our current location, do * the newline, and skip to the next line. */ if (p < charAry.length) { if (isspace(charAry[p])) { offset = 1; /* * the next character is white space. We'll want to skip * that. */ } else { /* back p2 up to the last white space before the break point */ while ((p2 > marker) && !isspace(charAry[p2])) { p2--; } offset = 0; } } /* * If the line was completely filled (no place to break), we'll just copy * the whole line out and force a break. */ if (p2 == marker) { p2 = p - 1; } if (!isspace(charAry[p2])) { /* * If weren't were able to back up to a space, copy out the whole line, * including the break character (in this case, we'll be making the * string one character longer by inserting a newline). */ result.append(inString.substring(marker, p2 + 1)); } else { /* * The break character is whitespace. We'll copy out the characters up * to but not including the break character, which we will effectively * replace with a newline. */ result.append(inString.substring(marker, p2)); } /* If we have not reached the end of the string, newline */ if (p < charAry.length) { result.append("\n"); if (prepend != null) { result.append(prepend); } } p = marker = p2 + 1 + offset; } return result.toString(); } public static String wrap(String inString, int wrap_length) { return wrap(inString, wrap_length, null); } public static String wrap(String inString) { return wrap(inString, 150, null); } public static boolean isspace(char c) { return (c == '\n' || c == ' ' || c == '\t'); } /** * checks whether the object o is contained in the collection c * * @param comparator if not null, used to determine if two items are the same */ public static boolean contains(Collection c, Object o, Comparator comparator) { if (comparator == null) { // simply check if 'c' contains the pointer 'o' return c.contains(o); } else { // look into 'c' for occurence of 'o' for (Object o2 : c) { if (comparator.compare(o, o2) == 0) { // the objects match return true; } } } return false; } /** * Computes the intersection between two collections * * @param c1 the first collection * @param c2 the second (obviously) collection */ public static Collection intersect(Collection c1, Collection c2) { return intersect(c1, c2, null); } /** * Computes the intersection between two collections * * @param c1 the first collection * @param c2 the second (obviously) collection * @param comparator is used to determine if two items are the same */ public static Collection intersect(Collection c1, Collection c2, Comparator comparator) { Collection result = new LinkedList(); if (c1 == null || c2 == null || c1.size() == 0 || c2.size() == 0) return result; /* * This algorithm is shamelessly stolen from Collections.disjoint() ... * * We're going to iterate through c1 and test for inclusion in c2. If c1 is * a Set and c2 isn't, swap the collections. Otherwise, place the shorter * collection in c1. Hopefully this heuristic will minimize the cost of the * operation. */ Collection left = c1; Collection right = c2; if ((left instanceof Set) && !(right instanceof Set) || (left.size() > right.size())) { left = c2; right = c1; } for (Object l : left) { if (contains(right, l, comparator)) result.add(l); } return result; } /** * Returns true if the object specified is nor null nor empty (e.g., an empty * string, or an empty collection) * * @param object the object to check * @return true if the text specified is nor null nor empty, false otherwise */ public final static boolean isNotNullOrEmpty(Object object) { return !(isNullOrEmpty(object)); } /** * Returns true if the object specified is nor null nor empty (e.g., an empty * string, or an empty collection, or in this case a zero-valued number) * * @param object the object to check * @return true if the text specified is null or empty, false otherwise */ public final static boolean isNotNullOrEmptyOrZero(Object object) { return !(isNullOrEmpty(object, true)); } /** * Returns true if the object specified is null or empty (e.g., an empty * string, or an empty collection) * * @param object the object to check * @return true if the text specified is null or empty, false otherwise */ public final static boolean isNullOrEmpty(Object object) { return (isNullOrEmpty(object, false)); } /** * Returns true if the object specified is null or empty (e.g., an empty * string, or an empty collection, or in this case a zero-valued number) * * @param object the object to check * @return true if the text specified is null or empty, false otherwise */ public final static boolean isNullOrEmptyOrZero(Object object) { return (isNullOrEmpty(object, true)); } private final static boolean isNullOrEmpty(Object object, boolean zeroEqualsEmpty) { if (object == null) return true; if (object instanceof Collection) return ((Collection) object).size() == 0; else if (object instanceof Map) return ((Map) object).size() == 0; else if (object.getClass().isArray()) return ((Object[]) object).length == 0; else if (object instanceof Number && zeroEqualsEmpty) return ((Number) object).longValue() == 0; else return object.toString().length() == 0; } /** * Returns the list of files corresponding to the extension, in the currentDir * and below */ public static List<File> recursivelyGetFiles(final String extension, File currentDir) { List<File> result = new LinkedList<File>(); recursivelyGetFiles(extension, currentDir, result); return result; } private static void recursivelyGetFiles(final String extension, File currentDir, List<File> filesList) { String[] files = currentDir.list(new FilenameFilter() { public boolean accept(File dir, String name) { File f = new File(dir, name); return f.isDirectory() || name.endsWith(extension); } }); for (String filename : files) { File f = new File(currentDir, filename); if (f.isDirectory()) recursivelyGetFiles(extension, f, filesList); else filesList.add(f); } } /** * forces a string into a specific encoding */ public static String forceCharset(String text, String charset) { String result = text; try { result = new String(text.getBytes(charset)); } catch (UnsupportedEncodingException e) { logger.error(e.getMessage(), e); } return result; } public static Object getDelegateOrNull(Object source) { return getDelegateOrNull(source, false); } public static Object getDelegateOrNull(Object source, boolean digDeep) { if (source == null) return null; Object result = source; try { Method method = source.getClass().getMethod("getDelegate", (Class[]) null); if (method != null) result = method.invoke(source, (Object[]) null); } catch (SecurityException e) { // let's return the source object } catch (NoSuchMethodException e) { // let's return the source object } catch (IllegalArgumentException e) { // let's return the source object } catch (IllegalAccessException e) { // let's return the source object } catch (InvocationTargetException e) { // let's return the source object } if (digDeep && (result != source)) return getDelegateOrNull(result, digDeep); else return result; } public static List filter(List source, List unwantedKeys, String method) { if (isNullOrEmpty(unwantedKeys)) return source; if (isNullOrEmpty(source)) return source; List result = new LinkedList(); for (Object object : source) { if (object == null) continue; Object key = null; try { Method keyGetter = object.getClass().getMethod(method, (Class[]) null); if (keyGetter != null) key = keyGetter.invoke(object, (Object[]) null); } catch (SecurityException e) { // key stays null } catch (NoSuchMethodException e) { // key stays null } catch (IllegalArgumentException e) { // key stays null } catch (IllegalAccessException e) { // key stays null } catch (InvocationTargetException e) { // key stays null } if (key == null) key = object.toString(); if (key != null && !unwantedKeys.contains(key)) result.add(object); } return result; } public static List filter(List source, List<Class> unwantedClasses) { if (isNullOrEmpty(unwantedClasses)) return source; if (isNullOrEmpty(source)) return source; List result = new LinkedList(); for (Object object : source) { if (object == null) continue; if (!unwantedClasses.contains(object.getClass())) result.add(object); } return result; } /** * Fetch the entire contents of a text stream, and return it in a String. * This style of implementation does not throw Exceptions to the caller. */ public static String readTextFile(InputStream is) { //...checks on aFile are elided StringBuilder contents = new StringBuilder(); try { //use buffering, reading one line at a time //FileReader always assumes default encoding is OK! BufferedReader input = new BufferedReader(new InputStreamReader(is)); try { String line = null; //not declared within while loop /* * readLine is a bit quirky : * it returns the content of a line MINUS the newline. * it returns null only for the END of the stream. * it returns an empty String if two newlines appear in a row. */ while ((line = input.readLine()) != null) { contents.append(line); contents.append(System.getProperty("line.separator")); } } finally { input.close(); } } catch (IOException ex) { ex.printStackTrace(); } return contents.toString(); } public static String readTextFile(String fullPathFilename) throws IOException { return readTextFile(new FileInputStream(fullPathFilename)); } public static File putBytesIntoFile(byte[] bytes, File file) throws IOException { FileOutputStream out = new FileOutputStream(file); try { out.write(bytes); } finally { out.close(); } return file; } public static File getFileFromBytes(byte[] bytes) throws IOException { String prefix = new VMID().toString(); return getFileFromBytes(bytes, prefix); } public static File getFileFromBytes(byte[] bytes, String prefix) throws IOException { File f = File.createTempFile(prefix, null); return putBytesIntoFile(bytes, f); } public static byte[] getBytesFromFile(File file) throws IOException { InputStream is = new FileInputStream(file); // Get the size of the file long length = file.length(); // You cannot create an array using a long type. // It needs to be an int type. // Before converting to an int type, check // to ensure that file is not larger than Integer.MAX_VALUE. if (length > Integer.MAX_VALUE) { // File is too large } // Create the byte array to hold the data byte[] bytes = new byte[(int) length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; } // Ensure all the bytes have been read in if (offset < bytes.length) { throw new IOException("Could not completely read file " + file.getName()); } // Close the input stream and return bytes is.close(); return bytes; } public static String nowAs14CharString() { final DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); return format.format(new Date()); } public static String removeLeadingZeroes(String value) { return removeLeadingChars(value, '0'); } public static String removeLeadingChars(String value, char charToRemove) { if (Helper.isNotNullOrEmpty(value)) { String regex = "^" + charToRemove + "*"; return value.replaceAll(regex, ""); } return value; } public static String makeString(String baseString, int number) { if (Helper.isNotNullOrEmpty(baseString) && (number > 0)) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < number; i++) sb.append(baseString); return sb.toString(); } return ""; } /** * Convert the stack trace into a string suitable for logging * @param t * @return */ public static String getStackTrace(Throwable t) { StringBuilder sb = new StringBuilder(""); if (t != null) { for (StackTraceElement element : t.getStackTrace()) { sb.append(element.toString() + '\n'); } } return sb.toString(); } public static Stack<Throwable> unwrap(Throwable t) { Stack<Throwable> result = new Stack<Throwable>(); while (t != null) { result.add(t); t = t.getCause(); } return result; } public static class ListCopier<T> { public List<T> copyList(List<T> original, int pMaxSize) { if (original == null) return null; int maxSize = pMaxSize; if (maxSize < 0) maxSize = original.size(); if (original.size() <= maxSize) return new LinkedList<T>(original); List<T> result = new LinkedList<T>(); for (int i = 0; i < maxSize; i++) { result.add(original.get(i)); } return result; } } public static String shorten(String s, int maxSize) { if (isNullOrEmpty(s) || maxSize < 2) return s; if (s.length() > maxSize) return s.substring(0, maxSize) + "..."; else return s; } // ITIMPI: It appears this routine is no longer used! // the logic has been subsumed into Catalog.merge() /* public static void copy(File src, File dst, boolean checkDates) throws IOException { if (src == null || dst == null) return; if (!src.exists()) return; if (src.isDirectory()) { if (!dst.exists()) dst.mkdirs(); else if (!dst.isDirectory()) return; } else { boolean copy = false; if (!dst.exists()) { // ITIMPI: Is there a reason this is not logged via logger()? System.out.println("creating dirs " + dst.getPath()); dst.mkdirs(); copy = true; } copy = copy || (!checkDates || (src.lastModified() > dst.lastModified())); if (copy) { InputStream in = new FileInputStream(src); copy(in, dst); } } } */ public static void copy(File src, File dst) throws IOException { InputStream in = null; try { in = new FileInputStream(src); Helper.copy(in, dst); } finally { if (in != null) in.close(); } } public static void copy(InputStream in, File dst) throws IOException { if (!dst.exists()) { if (dst.getName().endsWith("_Page")) assert true; dst.getParentFile().mkdirs(); } OutputStream out = null; try { out = new FileOutputStream(dst); copy(in, out); } finally { if (out != null) out.close(); } } public static void copy(InputStream in, OutputStream out) throws IOException { try { // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } finally { if (out != null) out.close(); } } private final static String[] FilesToKeep = new String[] { ".htaccess", "index.html" }; /** * Delete the given folder/files. * * You can specifiy whether the file should not be deleted if it is on * the list of those to keep, or should be deleted unconditionally * * @param path File to delete * @param check Specify whether to be kept if on reserved list */ static public void delete (File path, boolean check) { if (path.exists()) { // Allow for list of Delete file xceptions (#c2o-112) if (check) { for (String f : FilesToKeep) { if (path.getName().toLowerCase().endsWith(f)) { if (logger.isTraceEnabled()) logger.trace("File not deleted (on exception list): " + path); return; } } } if (path.isDirectory()) { File[] files = path.listFiles(); if (files != null) for (int i = 0; i < files.length; i++) { delete(files[i], check); } } path.delete(); } } /** * Given a path, get a count of the contained folders and files * @param path * @return */ static public long count(File path) { int result = 0; if (path.exists()) { if (path.isDirectory()) { File[] files = path.listFiles(); if (files != null) for (int i = 0; i < files.length; i++) { result += count(files[i]); } } result++; } return result; } /** * Routine to carry out comparisons using the object type's * compareTo methods. Allows for either option to be passed * in a null. * NOTE: This uses the object's compareTo for method, so for * string objects this is a strict comparison that does * not take into account locale differences. If you want * locale to be considerd then use the collator methods. * @param o1 * @param o2 * @return */ public static int checkedCompare(Comparable o1, Comparable o2) { if (o1 == null) { if (o2 == null) return 0; else return 1; } else if (o2 == null) { if (o1 == null) return 0; else return -1; } return o1.compareTo(o2); } /** * A checked string comparison that allows for null parameters * but ignores case differences. * @param s1 * @param s2 * @return */ public static int checkedCompareIgnorCase (String s1, String s2) { if (s1 == null) { if (s2 == null) return 0; else return 1; } else if (s2 == null) { if (s1 == null) return 0; else return -1; } return s1.toUpperCase().compareTo(s2.toUpperCase()); } /** * A checked string compare that uses the collator methods * that take into account local. This method uses the * default locale. * @param s1 * @param s2 * @return */ public static int checkedCollatorCompare (String s1, String s2, Collator collator) { if (s1 == null) { if (s2 == null) return 0; else return 1; } else if (s2 == null) { if (s1 == null) return 0; else return -1; } return collator.compare(s1, s2); } public static int checkedCollatorCompareIgnoreCase (String s1, String s2, Collator collator) { return checkedCollatorCompare(s1.toUpperCase(), s2.toUpperCase(), collator); } /** * A checked string compare that uses the collator methods * that take into account local. This method uses the * default locale. * @param s1 * @param s2 * @return */ public static int checkedCollatorCompare (String s1, String s2) { final Collator collator = Collator.getInstance(); return checkedCollatorCompare(s1, s2, collator); } /** * A checked string compare that uses the collator methods * that take into account local. This method uses the * default locale. * @param s1 First string to compare * @param s2 Second string to compare * @return */ public static int checkedCollatorCompareIgnoreCase (String s1, String s2) { return checkedCollatorCompare(s1.toUpperCase(), s2.toUpperCase()); } public static int checkedCollatorCompare (String s1, String s2, Locale locale) { return checkedCollatorCompare(s1, s2, Collator.getInstance(locale)); } public static int checkedCollatorCompareIgnoreCase (String s1, String s2, Locale locale) { return checkedCollatorCompare(s1.toUpperCase(), s2.toUpperCase(), locale); } public static ArrayList<File> listFilesIn(File dir) { ArrayList<File> result = new ArrayList<File>(); if (dir != null && dir.isDirectory()) { String[] children = dir.list(); if (children != null) { for (String childName : children) { File child = new File(dir, childName); if (child.isDirectory()) { result.addAll(listFilesIn(child)); } result.add(child); } } } return result; } public static String toTitleCase(String s) { if (Helper.isNullOrEmpty(s)) return s; StringBuffer sb = new StringBuffer(s.length()); sb.append(Character.toUpperCase(s.charAt(0))); sb.append(s.substring(1)); return sb.toString(); } /** * Code to remove HTML tags from an HTML string * * TODO: Consider whether this can be better implemented * TODO: using FOM and the InnterText metthod? * * TODO: Might want to consider replacing </p> tags with CR/LF? * @param s * @return */ public static String removeHtmlElements(String s) { // process possible HTML tags StringBuffer sb = new StringBuffer(); if (s != null) { boolean skipping = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (!skipping) { if (c == '<') skipping = true; else sb.append(c); } else { if (c == '>') skipping = false; } } } else { return ""; } return sb.toString(); } public static String stringToHex(String base) { StringBuffer buffer = new StringBuffer(); int intValue; for (int x = 0; x < base.length(); x++) { int cursor = 0; intValue = base.charAt(x); String binaryChar = new String(Integer.toBinaryString(base.charAt(x))); for (int i = 0; i < binaryChar.length(); i++) { if (binaryChar.charAt(i) == '1') { cursor += 1; } } if ((cursor % 2) > 0) { intValue += 128; } buffer.append(Integer.toHexString(intValue) + " "); } return buffer.toString(); } public static String convertToHex(String s) { if (isNullOrEmpty(s)) return ""; StringBuffer sb = new StringBuffer(); for (int pos=0;pos<s.length();pos++) { int codepoint = s.codePointAt(pos); sb.append(Integer.toHexString(codepoint)); } return sb.toString(); } /** * This function is the 'worker' one for handling derived names * for split-by-letter or split by page number. * * Any characters that are not alpha-numeric or the split character are hex encoded * to make the results safe to use in a URN or filename. * * As an optimisation to try and keep values start, it assumed that if the end of the * string passed in as the base corresponds to the start of the new encoded splitText * then it is only necessay to extend the name to make it unique by the difference. * * @param baseString The base string fromt he previous level * @param splitText The text for this split level * @param splitSeparator The seperator to be used between levels * @return The link to this level for parent */ public static String getSplitString (String baseString, String splitText, String splitSeparator) { StringBuffer encodedSplitText = new StringBuffer(); encodedSplitText.append(splitSeparator); // Get the encoded form of the splitText // TODO ITIMPI: Need to check why this encoding is needed! for (int x= 0; x < splitText.length(); x++) { char c = splitText.charAt(x); if (Character.isLetterOrDigit(c)) { // Alphanumerics are passed through unchanged encodedSplitText.append(c); } else { // Other characters are hex encoded encodedSplitText.append(Integer.toHexString(c)); } } // Now see if we only we need to extend the basename or add a new section int pos = baseString.lastIndexOf(splitSeparator); if (pos > 0) { // Get the amount we want to check String checkPart = baseString.substring(pos); if (encodedSplitText.toString().length() != checkPart.length() && encodedSplitText.toString().startsWith(checkPart)) { baseString = baseString.substring(0,pos); } } return baseString + encodedSplitText.toString(); } /* * Convert a parameter option 'glob' that contains ? and * wildcards to a regex * * Adapted from routine found via google search */ public static String convertGlobToRegEx(String line) { line = line.trim(); int strLen = line.length(); StringBuilder sb = new StringBuilder(strLen); // Remove beginning and ending * globs because they're useless // TODO: ITMPI This does not seem to be true - not sure why code was originally here! /* if (line.startsWith("*")) { line = line.substring(1); strLen--; } if (line.endsWith("*")) { line = line.substring(0, strLen-1); strLen--; } */ boolean escaping = false; int inCurlies = 0; for (char currentChar : line.toCharArray()) { switch (currentChar) { // Wild car characters case '*': if (escaping) sb.append("\\*"); else sb.append(".+"); escaping = false; break; case '?': if (escaping) sb.append("\\?"); else sb.append('.'); escaping = false; break; // Characters needing special treatment case '.': case '(': case ')': case '+': case '|': case '^': case '$': case '@': case '%': // TODO ITIMPI: Following added as special cases below seem not relevant case '[': case ']': case '\\': case '{': case '}': case ',': sb.append('\\'); sb.append(currentChar); escaping = false; break; /* case '\\': if (escaping) { sb.append("\\\\"); escaping = false; } else escaping = true; break; case '{': if (escaping) { sb.append("\\{"); } else { sb.append('('); inCurlies++; } escaping = false; break; case '}': if (inCurlies > 0 && !escaping) { sb.append(')'); inCurlies--; } else if (escaping) sb.append("\\}"); else sb.append("}"); escaping = false; break; case ',': if (inCurlies > 0 && !escaping) { sb.append('|'); } else if (escaping) sb.append("\\,"); else sb.append(","); break; */ // characters that can just be passed through unchanged default: escaping = false; sb.append(currentChar); } } return sb.toString(); } // All possible locales private final static Locale[] availableLocales = Locale.getAvailableLocales(); // Saved subset that we have actually used for faster searching // (can have duplicates under different length keys) private static HashMap<String,Locale> usedLocales = new HashMap<String, Locale>(); /** * Get the local that corresponds to the provided language string * The following assumptions are made about the supplied parameter: * - If it is 2 characters in length then it is assumed to be the ISO2 value * - If it is 3 characters in length then it is assumed to be the ISO3 value * - If it is 4+ characters then it is assumed to be the Display Language text * If no match can be found then the English Locale is always returned * TODO: Perhaps we should consider returning null if no match found? * * @param lang * @return Locale */ public static Locale getLocaleFromLanguageString(String lang) { if (usedLocales.containsKey(lang)) { return usedLocales.get(lang); } if (lang != null && lang.length() > 1) { for (Locale l : availableLocales) { switch (lang.length()) { // Note te case of a 2 character lang needs special treatment - see Locale code for getLangugage case 2: String s = l.toString(); String ll = l.getLanguage(); if (s.length() < 2 || s.length() > 2) break; // Ignore entries that are not 2 characters if (! s.equalsIgnoreCase(lang)) break; usedLocales.put(lang,l); return l; case 3: if (! l.getISO3Language().equalsIgnoreCase(lang)) break; usedLocales.put(lang,l); return l; default: if (! l.getDisplayLanguage().equalsIgnoreCase(lang)) break; usedLocales.put(lang,l); return l; } } } logger.warn("Program Error: Unable to find locale for '" + lang + "'"); return null; } /** * Convert a pseudo=html string to plain text * * We sometimes use a form of Pseudo-HTML is strings that are to be * displayed in the GUI. These can be identifed by the fact that they * start with <HTML> andd contain <BR> where end-of-line is wanted. */ public static String getTextFromPseudoHtmlText (String htmltext) { String text; if (! htmltext.toUpperCase().startsWith("<HTML>")) { text = htmltext; } else { text = htmltext.substring("<HTML>".length()).toUpperCase().replace("<br>", "\r\n"); } return text; } private static File installDirectory; /** * * @return */ public static File getInstallDirectory() { if (installDirectory == null) { URL mySource = Helper.class.getProtectionDomain().getCodeSource().getLocation(); File sourceFile = new File(mySource.getPath()); installDirectory = sourceFile.getParentFile(); } return installDirectory; } }