package com.tesora.dve.common; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import com.tesora.dve.exceptions.PECodingException; public final class PEStringUtils { public static final String FILE_SEP = "/"; private static final String[] EMPTY_ARRAY = new String[] {}; private static final Pattern HEX_MATCH_REGEX = Pattern.compile("0[xX][0-9a-fA-F]+"); private static final String SINGLE_QUOTE = "'"; private static final String DOUBLE_QUOTE = "\""; private static final String BACK_QUOTE = "`"; private static final String DEFAULT_INDENT = "\t"; private PEStringUtils() { } public static String buildPath(String dir, String sep, String name) { StringBuffer path = new StringBuffer(dir); if (!dir.endsWith(sep)) path.append(sep); return path.append(name).toString(); } public static StringBuffer toString(StringBuffer sb, String name, Collection<? extends Object> values) { sb.append(name).append('{'); toArrayString(sb, values); return sb.append('}'); } public static StringBuffer toArrayString(StringBuffer sb, Collection<? extends Object> values) { int i = 0; if (values != null) { for (Object o : values) { if (i++ > 0) sb.append(','); if (o == null) sb.append("null"); else sb.append(o.toString()); } } else sb.append("null"); return sb; } public static String toString(String name, Collection<? extends Object> values) { return toString(new StringBuffer(), name, values).toString(); } public static <T> String toString(Class<T> theClass, Collection<? extends Object> values) { return toString(new StringBuffer(), theClass.getSimpleName(), values).toString(); } public static <K, V> StringBuffer toString(StringBuffer sb, String name, Map<K, V> values) { sb.append(name).append('{'); int i = 0; if (values != null) { for (Entry<K, V> e : values.entrySet()) { if (i++ > 0) sb.append(','); sb.append(e.getKey().toString()).append('/').append(e.getValue().toString()); } } else sb.append("null"); return sb.append('}'); } public static <K, V> String toString(String name, Map<K, V> values) { return toString(new StringBuffer(), name, values).toString(); } public static String[] toArray(Collection<String> values) { return values.toArray(EMPTY_ARRAY); } /** * Convert decimal values that can be represented as integers integral * strings. * * @return trimToInt("3.1415") == "3.1415" * trimToInt("10.0") == "10" */ public static String trimToInt(final String numeric) { if (NumberUtils.isNumber(numeric)) { final double doubleValue = Double.parseDouble(numeric); if (MathUtils.isInteger(doubleValue)) { return String.format("%d", (int) doubleValue); } return numeric; } throw new PECodingException("The input must be a valid number but was: " + numeric); } /* * Returns a prefix needing to be pre-pended to a key for calling * Properties.getProperty. Handles null prefix; will add the trailing "." if * not already present. */ public static String normalizePrefix(String prefix) { String newPrefix = StringUtils.defaultString(prefix); if (newPrefix.length() > 0 && !StringUtils.endsWith(newPrefix, ".")) { newPrefix = newPrefix + "."; } return newPrefix; } /** * Get the stack trace as a string value * * @param e * @return */ public static String toString(Throwable e) { StringWriter stringWriter = new StringWriter(); e.printStackTrace(new PrintWriter(stringWriter)); return stringWriter.toString(); } /** * This method is used to convert a string pattern match (e.g. a SQL LIKE * expression) into a Java Pattern that can be used in a Matcher * * @param likeExpr - a string expression to be converted to a Pattern * @return - Pattern - a Pattern object representing the likeExpr */ public static Pattern buildSQLPattern(String likeExpr) { // let's build a regex out of a like string... char[] sqlPattern = likeExpr.trim().toLowerCase().toCharArray(); StringBuffer javaPattern = new StringBuffer(); boolean escape = false; for(int i = 0; i < sqlPattern.length; i++) { if (escape) { javaPattern.append(sqlPattern[i]); escape = false; } else if (sqlPattern[i] == '\\') escape = true; else if (".?+*|[]{}()^$-".indexOf(sqlPattern[i]) > -1) { javaPattern.append("\\"); javaPattern.append(sqlPattern[i]); } else if (sqlPattern[i] == '%') javaPattern.append(".*"); else if (sqlPattern[i] == '_') javaPattern.append("."); else javaPattern.append(sqlPattern[i]); } return Pattern.compile(javaPattern.toString()); } /** * Enclose the input string in single quotes if not already. */ public static String singleQuote(final String value) { if ((value != null) && !value.isEmpty() && !isQuoted(value, SINGLE_QUOTE)) { return SINGLE_QUOTE.concat(value).concat(SINGLE_QUOTE); } return value; } public static boolean isQuoted(final String value) { return (isQuoted(value, SINGLE_QUOTE) || isQuoted(value, DOUBLE_QUOTE) || isQuoted(value, BACK_QUOTE)); } private static boolean isQuoted(final String value, final String quote) { return value.startsWith(quote) && value.endsWith(quote); } public static String dequote(final String in) { if ((in != null) && !in.isEmpty() && isQuoted(in)) { // strip off the quotes return in.substring(1, in.length() - 1); } return in; } public static String escapeSingleQuoteIfNecessary(String t) { // if enclosed with double quotes and contains a single quote we need to escape the single quotes // because we ultimately enclose the entire literal with the ' character (ie. replace " with ') if (t.contains("'")) { // unfortunately cannot just replace ' if \' we have to leave it alone int searchStartIndex = 0; int quoteIndex = t.indexOf("'", searchStartIndex); int escapedQuoteIndex = t.indexOf("\\'", searchStartIndex); while (quoteIndex != -1) { if ((quoteIndex - escapedQuoteIndex) != 1) { t = t.substring(0, quoteIndex) + "\\" + t.substring(quoteIndex); quoteIndex += 1; } searchStartIndex = quoteIndex + 1; quoteIndex = t.indexOf("'", searchStartIndex); escapedQuoteIndex = t.indexOf("\\'", searchStartIndex); } } return t; } /** * Returns true if a value is given and has any normal semblance of being positive * * for example: "true", "on", "23", "yes" return true * "false", null, "0", "garbage" return false * * @param value * @return */ public static boolean toBoolean(String value) { try { if (value != null && value.length() > 0 && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase(PEConstants.YES) || value.equalsIgnoreCase("on") || Integer.parseInt(value) > 0)) return true; } catch (NumberFormatException nfe) { // ignore } return false; } public static boolean isHexNumber(final String value) { return HEX_MATCH_REGEX.matcher(value).matches(); } public static String getIndented(final String value) { return getIndented(value, 1); } public static String getIndented(final String value, final int numIndents) { return getIndented(value, DEFAULT_INDENT, numIndents); } public static String getIndented(final String value, final String indent, final int numIndents) { return buildIndent(indent, numIndents).concat(value); } public static String buildIndent(final int numIndents) { return StringUtils.repeat(DEFAULT_INDENT, numIndents); } public static String buildIndent(final String indent, final int numIndents) { return StringUtils.repeat(indent, numIndents); } }