/******************************************************************************* * Copyright (c) 1998, 2016 Oracle and/or its affiliates, IBM Corporation. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink * dminsky - added countOccurrencesOf(Object, List) API * 08/23/2010-2.2 Michael O'Brien * - 323043: application.xml module ordering may cause weaving not to occur causing an NPE. * warn if expected "_persistence_*_vh" method not found * instead of throwing NPE during deploy validation. * 08/29/2016 Jody Grassel * - 500441: Eclipselink core has System.getProperty() calls that are not potentially executed under doPriv() ******************************************************************************/ package org.eclipse.persistence.internal.helper; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.Vector; import java.util.concurrent.ConcurrentLinkedQueue; import org.eclipse.persistence.config.SystemProperties; import org.eclipse.persistence.exceptions.ConversionException; import org.eclipse.persistence.exceptions.EclipseLinkException; import org.eclipse.persistence.exceptions.ValidationException; import org.eclipse.persistence.internal.core.helper.CoreHelper; import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor; import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; import org.eclipse.persistence.internal.security.PrivilegedClassForName; import org.eclipse.persistence.internal.security.PrivilegedGetField; import org.eclipse.persistence.internal.security.PrivilegedGetMethod; import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass; import org.eclipse.persistence.logging.AbstractSessionLog; import org.eclipse.persistence.logging.SessionLog; /** * INTERNAL: * <p> * <b>Purpose</b>: Define any useful methods that are missing from the base Java. */ public class Helper extends CoreHelper implements Serializable { /** Used to configure JDBC level date optimization. */ public static boolean shouldOptimizeDates = false; /** Used to store null values in hashtables, is helper because need to be serializable. */ public static final Object NULL_VALUE = new Helper(); /** Used to convert {@code null} value to {@link String}. */ private static final String NULL_STRING = "null"; /** PERF: Used to cache a set of calendars for conversion/printing purposes. */ protected static final Queue<Calendar> calendarCache = initCalendarCache(); /** PERF: Cache default timezone for calendar conversion. */ protected static final TimeZone defaultTimeZone = TimeZone.getDefault(); // Changed static initialization to lazy initialization for bug 2756643 /** Store CR string, for some reason \n is not platform independent. */ protected static String CR; /** formatting strings for indenting */ public static final String SPACE = " "; public static final String INDENT = " "; /** Store newline string */ public static final String NL = "\n"; /** Prime the platform-dependent path separator */ protected static String PATH_SEPARATOR = null; /** Prime the platform-dependent file separator */ protected static String FILE_SEPARATOR = null; /** Prime the platform-dependent current working directory */ protected static String CURRENT_WORKING_DIRECTORY = null; /** Prime the platform-dependent temporary directory */ protected static String TEMP_DIRECTORY = null; /** Backdoor to allow 0 to be used in primary keys. * @deprecated * Instead of setting the flag to true use: * session.getProject().setDefaultIdValidation(IdValidation.NULL) **/ @Deprecated public static boolean isZeroValidPrimaryKey = false; // settings to allow ascertaining attribute names from method names public static final String IS_PROPERTY_METHOD_PREFIX = "is"; public static final String GET_PROPERTY_METHOD_PREFIX = "get"; public static final String SET_PROPERTY_METHOD_PREFIX = "set"; public static final String SET_IS_PROPERTY_METHOD_PREFIX = "setIs"; public static final int POSITION_AFTER_IS_PREFIX = IS_PROPERTY_METHOD_PREFIX.length(); public static final int POSITION_AFTER_GET_PREFIX = GET_PROPERTY_METHOD_PREFIX.length(); public static final String DEFAULT_DATABASE_DELIMITER = "\""; public static final String PERSISTENCE_SET = "_persistence_set_"; public static final String PERSISTENCE_GET = "_persistence_get_"; // 323403: These constants are used to search for missing weaved functions - this is a copy is of the jpa project under ClassWeaver public static final String PERSISTENCE_FIELDNAME_PREFIX = "_persistence_"; public static final String PERSISTENCE_FIELDNAME_POSTFIX = "_vh"; private static String defaultStartDatabaseDelimiter = null; private static String defaultEndDatabaseDelimiter = null; /** * Return if JDBC date access should be optimized. */ public static boolean shouldOptimizeDates() { return shouldOptimizeDates; } /** * Return if JDBC date access should be optimized. */ public static void setShouldOptimizeDates(boolean value) { shouldOptimizeDates = value; } /** * PERF: * Return the calendar cache use to avoid calendar creation for processing java.sql/util.Date/Time/Timestamp objects. */ public static Queue<Calendar> getCalendarCache() { return calendarCache; } /** * PERF: * Init the calendar cache use to avoid calendar creation for processing java.sql/util.Date/Time/Timestamp objects. */ public static Queue initCalendarCache() { Queue calendarCache = new ConcurrentLinkedQueue(); for (int index = 0; index < 10; index++) { calendarCache.add(Calendar.getInstance()); } return calendarCache; } /** * PERF: This is used to optimize Calendar conversion/printing. * This should only be used when a calendar is temporarily required, * when finished it must be released back. */ public static Calendar allocateCalendar() { Calendar calendar = getCalendarCache().poll(); if (calendar == null) { calendar = Calendar.getInstance(); } return calendar; } /** * PERF: Return the cached default platform. * Used for ensuring Calendar are in the local timezone. * The JDK method clones the timezone, so cache it locally. */ public static TimeZone getDefaultTimeZone() { return defaultTimeZone; } /** * PERF: This is used to optimize Calendar conversion/printing. * This should only be used when a calendar is temporarily required, * when finished it must be released back. */ public static void releaseCalendar(Calendar calendar) { getCalendarCache().offer(calendar); } public static void addAllToVector(Vector theVector, Vector elementsToAdd) { for (Enumeration stream = elementsToAdd.elements(); stream.hasMoreElements();) { theVector.addElement(stream.nextElement()); } } public static Vector addAllUniqueToVector(Vector objects, List objectsToAdd) { if (objectsToAdd == null) { return objects; } int size = objectsToAdd.size(); for (int index = 0; index < size; index++) { Object element = objectsToAdd.get(index); if (!objects.contains(element)) { objects.add(element); } } return objects; } public static List addAllUniqueToList(List objects, List objectsToAdd) { if (objectsToAdd == null) { return objects; } int size = objectsToAdd.size(); for (int index = 0; index < size; index++) { Object element = objectsToAdd.get(index); if (!objects.contains(element)) { objects.add(element); } } return objects; } /** * Convert the specified vector into an array. */ public static Object[] arrayFromVector(Vector vector) { Object[] result = new Object[vector.size()]; for (int i = 0; i < vector.size(); i++) { result[i] = vector.elementAt(i); } return result; } /** * Convert {@link Integer} to hexadecimal {@link String}. * @param i An {@link Integer} to be converted to a hexadecimal string. * @return The {@link String} representation of the unsigned integer value represented by the argument * in hexadecimal or {@code "null"} if provided {@link Integer} argument is {@code null}. */ public static String integerToHexString(final Integer i) { return i != null ? Integer.toHexString(i) : NULL_STRING; } /** * Convert the HEX string to a byte array. * HEX allows for binary data to be printed. */ public static byte[] buildBytesFromHexString(String hex) { String tmpString = hex; if ((tmpString.length() % 2) != 0) { throw ConversionException.couldNotConvertToByteArray(hex); } byte[] bytes = new byte[tmpString.length() / 2]; int byteIndex; int strIndex; byte digit1; byte digit2; for (byteIndex = bytes.length - 1, strIndex = tmpString.length() - 2; byteIndex >= 0; byteIndex--, strIndex -= 2) { digit1 = (byte)Character.digit(tmpString.charAt(strIndex), 16); digit2 = (byte)Character.digit(tmpString.charAt(strIndex + 1), 16); if ((digit1 == -1) || (digit2 == -1)) { throw ConversionException.couldNotBeConverted(hex, ClassConstants.APBYTE); } bytes[byteIndex] = (byte)((digit1 * 16) + digit2); } return bytes; } /** * Convert the byte array to a HEX string. * HEX allows for binary data to be printed. */ public static String buildHexStringFromBytes(byte[] bytes) { char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; StringBuilder stringBuilder = new StringBuilder(); int tempByte; for (int byteIndex = 0; byteIndex < (bytes).length; byteIndex++) { tempByte = (bytes)[byteIndex]; if (tempByte < 0) { tempByte = tempByte + 256;//compensate for the fact that byte is signed in Java } tempByte = (byte)(tempByte / 16);//get the first digit if (tempByte > 16) { throw ConversionException.couldNotBeConverted(bytes, ClassConstants.STRING); } stringBuilder.append(hexArray[tempByte]); tempByte = (bytes)[byteIndex]; if (tempByte < 0) { tempByte = tempByte + 256; } tempByte = (byte)(tempByte % 16);//get the second digit if (tempByte > 16) { throw ConversionException.couldNotBeConverted(bytes, ClassConstants.STRING); } stringBuilder.append(hexArray[tempByte]); } return stringBuilder.toString(); } /** * Create a new Vector containing all of the map elements. */ public static Vector buildVectorFromMapElements(Map map) { Vector vector = new Vector(map.size()); Iterator iterator = map.values().iterator(); while (iterator.hasNext()) { vector.addElement(iterator.next()); } return vector; } /** * Answer a Calendar from a date. */ public static Calendar calendarFromUtilDate(java.util.Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); //In jdk1.3, millisecond is missing if (date instanceof Timestamp) { calendar.set(Calendar.MILLISECOND, ((Timestamp)date).getNanos() / 1000000); } return calendar; } /** * INTERNAL: * Return whether a Class implements a specific interface, either directly or indirectly * (through interface or implementation inheritance). * @return boolean */ public static boolean classImplementsInterface(Class aClass, Class anInterface) { // quick check if (aClass == anInterface) { return true; } Class[] interfaces = aClass.getInterfaces(); // loop through the "directly declared" interfaces for (int i = 0; i < interfaces.length; i++) { if (interfaces[i] == anInterface) { return true; } } // recurse through the interfaces for (int i = 0; i < interfaces.length; i++) { if (classImplementsInterface(interfaces[i], anInterface)) { return true; } } // finally, recurse up through the superclasses to Object Class superClass = aClass.getSuperclass(); if (superClass == null) { return false; } return classImplementsInterface(superClass, anInterface); } /** * INTERNAL: * Return whether a Class is a subclass of, or the same as, another Class. * @return boolean */ public static boolean classIsSubclass(Class subClass, Class superClass) { Class temp = subClass; if (superClass == null) { return false; } while (temp != null) { if (temp == superClass) { return true; } temp = temp.getSuperclass(); } return false; } /** * INTERNAL: * Compares two version in num.num.num.num.num*** format. * -1, 0, 1 means the version1 is less than, equal, greater than version2. * Example: compareVersions("11.1.0.6.0-Production", "11.1.0.7") == -1 * Example: compareVersions("WebLogic Server 10.3.4", "10.3.3.0") == 1 */ public static int compareVersions(String version1, String version2) { return compareVersions(version(version1), version(version2)); } /** * INTERNAL: * Expects version in ***num.num.num.num.num*** format, converts it to a List of Integers. * Example: "11.1.0.6.0_Production" -> {11, 1, 0, 6, 0} * Example: "WebLogic Server 10.3.3.0" -> {10, 3, 3, 0} */ static protected List<Integer> version(String version) { ArrayList<Integer> list = new ArrayList<Integer>(5); // first char - a digit - in the string corresponding to the current list index int iBegin = -1; // used to remove a non-digital prefix boolean isPrefix = true; for(int i=0; i<version.length(); i++) { char ch = version.charAt(i); if('0' <= ch && ch <= '9') { isPrefix = false; // it's a digit if(iBegin == -1) { iBegin = i; } } else { // it's not a digit - try to create a number ending on the previous char - unless it's still part of the non-digital prefix. if(iBegin == -1) { if(!isPrefix) { break; } } else { isPrefix = false; String strNum = version.substring(iBegin, i); int num = Integer.parseInt(strNum, 10); list.add(num); iBegin = -1; if(ch != '.') { break; } } } } if(iBegin >= 0) { String strNum = version.substring(iBegin, version.length()); int num = Integer.parseInt(strNum, 10); list.add(num); } return list; } /** * INTERNAL: * Compares two lists of Integers * -1, 0, 1 means the first list is less than, equal, greater than the second list. * Example: {11, 1, 0, 6, 0} < {11, 1, 0, 7} */ static protected int compareVersions(List<Integer> list1, List<Integer>list2) { int n = Math.max(list1.size(), list2.size()); int res = 0; for(int i=0; i<n; i++) { int l1 = 0; if(i < list1.size()) { l1 = list1.get(i); } int l2 = 0; if(i < list2.size()) { l2 = list2.get(i); } if(l1 < l2) { res =-1; break; } else if(l1 > l2) { res = 1; break; } } return res; } public static Class getClassFromClasseName(String className, ClassLoader classLoader){ Class convertedClass = null; if(className==null){ return null; } try{ if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { convertedClass = AccessController.doPrivileged(new PrivilegedClassForName(className, true, classLoader)); } catch (PrivilegedActionException exception) { throw ValidationException.classNotFoundWhileConvertingClassNames(className, exception.getException()); } } else { convertedClass = org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName(className, true, classLoader); } return convertedClass; } catch (ClassNotFoundException exc){ throw ValidationException.classNotFoundWhileConvertingClassNames(className, exc); } } public static String getComponentTypeNameFromArrayString(String aString) { if (aString == null || aString.length() == 0) { return null; } // complex array component type case if (aString.length() > 3 && (aString.startsWith("[L") && aString.endsWith(";"))) { return aString.substring(2, aString.length() - 1); } else if (aString.startsWith("[")){ Class primitiveClass = null; try { primitiveClass = Class.forName(aString); } catch (ClassNotFoundException cnf) { // invalid name specified - do not rethrow exception primitiveClass = null; } if (primitiveClass != null) { return primitiveClass.getComponentType().getName(); } } return null; } public static boolean compareArrays(Object[] array1, Object[] array2) { if (array1.length != array2.length) { return false; } for (int index = 0; index < array1.length; index++) { //Related to Bug#3128838 fix. ! is added to correct the logic. if(array1[index] != null) { if (!array1[index].equals(array2[index])) { return false; } } else { if(array2[index] != null) { return false; } } } return true; } /** * Compare two BigDecimals. * This is required because the .equals method of java.math.BigDecimal ensures that * the scale of the two numbers are equal. Therefore 0.0 != 0.00. * @see java.math.BigDecimal#equals(Object) */ public static boolean compareBigDecimals(java.math.BigDecimal one, java.math.BigDecimal two) { if (one.scale() != two.scale()) { double doubleOne = (one).doubleValue(); double doubleTwo = (two).doubleValue(); if ((doubleOne != Double.POSITIVE_INFINITY) && (doubleOne != Double.NEGATIVE_INFINITY) && (doubleTwo != Double.POSITIVE_INFINITY) && (doubleTwo != Double.NEGATIVE_INFINITY)) { return doubleOne == doubleTwo; } } return one.equals(two); } public static boolean compareByteArrays(byte[] array1, byte[] array2) { if (array1.length != array2.length) { return false; } for (int index = 0; index < array1.length; index++) { if (array1[index] != array2[index]) { return false; } } return true; } public static boolean compareCharArrays(char[] array1, char[] array2) { if (array1.length != array2.length) { return false; } for (int index = 0; index < array1.length; index++) { if (array1[index] != array2[index]) { return false; } } return true; } /** * PUBLIC: * * Compare two vectors of types. Return true if the size of the vectors is the * same and each of the types in the first Vector are assignable from the types * in the corresponding objects in the second Vector. */ public static boolean areTypesAssignable(List types1, List types2) { if ((types1 == null) || (types2 == null)) { return false; } if (types1.size() == types2.size()) { for (int i = 0; i < types1.size(); i++) { Class type1 = (Class)types1.get(i); Class type2 = (Class)types2.get(i); // if either are null then we assume assignability. if ((type1 != null) && (type2 != null)) { if (!type1.isAssignableFrom(type2)) { return false; } } } return true; } return false; } /** * PUBLIC: * Compare the elements in 2 hashtables to see if they are equal * * Added Nov 9, 2000 JED Patch 2.5.1.8 */ public static boolean compareHashtables(Hashtable hashtable1, Hashtable hashtable2) { Enumeration enumtr; Object element; Hashtable clonedHashtable; if (hashtable1.size() != hashtable2.size()) { return false; } clonedHashtable = (Hashtable)hashtable2.clone(); enumtr = hashtable1.elements(); while (enumtr.hasMoreElements()) { element = enumtr.nextElement(); if (clonedHashtable.remove(element) == null) { return false; } } return clonedHashtable.isEmpty(); } /** * Compare two potential arrays and return true if they are the same. Will * check for BigDecimals as well. */ public static boolean comparePotentialArrays(Object firstValue, Object secondValue) { Class firstClass = firstValue.getClass(); Class secondClass = secondValue.getClass(); // Arrays must be checked for equality because default does identity if ((firstClass == ClassConstants.APBYTE) && (secondClass == ClassConstants.APBYTE)) { return compareByteArrays((byte[])firstValue, (byte[])secondValue); } else if ((firstClass == ClassConstants.APCHAR) && (secondClass == ClassConstants.APCHAR)) { return compareCharArrays((char[])firstValue, (char[])secondValue); } else if ((firstClass.isArray()) && (secondClass.isArray())) { return compareArrays((Object[])firstValue, (Object[])secondValue); } else if (firstValue instanceof java.math.BigDecimal && secondValue instanceof java.math.BigDecimal) { // BigDecimals equals does not consider the precision correctly return compareBigDecimals((java.math.BigDecimal)firstValue, (java.math.BigDecimal)secondValue); } return false; } /** * Merge the two Maps into a new HashMap. */ public static Map concatenateMaps(Map first, Map second) { Map concatenation = new HashMap(first.size() + second.size() + 4); concatenation.putAll(first); concatenation.putAll(second); return concatenation; } /** * Return a new vector with no duplicated values. */ public static Vector concatenateUniqueVectors(Vector first, Vector second) { Vector concatenation; Object element; concatenation = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); for (Enumeration stream = first.elements(); stream.hasMoreElements();) { concatenation.addElement(stream.nextElement()); } for (Enumeration stream = second.elements(); stream.hasMoreElements();) { element = stream.nextElement(); if (!concatenation.contains(element)) { concatenation.addElement(element); } } return concatenation; } /** * Return a new List with no duplicated values. */ public static List concatenateUniqueLists(List first, List second) { List concatenation = new ArrayList(first.size() + second.size()); concatenation.addAll(first); for (Object element : second) { if (!concatenation.contains(element)) { concatenation.add(element); } } return concatenation; } public static Vector concatenateVectors(Vector first, Vector second) { Vector concatenation; concatenation = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); for (Enumeration stream = first.elements(); stream.hasMoreElements();) { concatenation.addElement(stream.nextElement()); } for (Enumeration stream = second.elements(); stream.hasMoreElements();) { concatenation.addElement(stream.nextElement()); } return concatenation; } /** Return a copy of the vector containing a subset starting at startIndex * and ending at stopIndex. * @param vector - original vector * @param startIndex - starting position in vector * @param stopIndex - ending position in vector * @exception EclipseLinkException */ public static Vector copyVector(List originalVector, int startIndex, int stopIndex) throws ValidationException { Vector newVector; if (stopIndex < startIndex) { return NonSynchronizedVector.newInstance(); } newVector = NonSynchronizedVector.newInstance(stopIndex - startIndex); for (int index = startIndex; index < stopIndex; index++) { newVector.add(originalVector.get(index)); } return newVector; } /** * Copy an array of strings to a new array * @param original * @return */ public static String[] copyStringArray(String[] original){ if (original == null){ return null; } int length = original.length; String[] copy = new String[length]; System.arraycopy(original, 0, copy, 0, length); return copy; } /** * Copy an array of int to a new array * @param original * @return */ public static int[] copyIntArray(int[] original){ if (original == null){ return null; } int length = original.length; int[] copy = new int[length]; System.arraycopy(original, 0, copy, 0, length); return copy; } /** * Return a string containing the platform-appropriate * characters for carriage return. */ public static String cr() { if (CR == null) { CR = PrivilegedAccessHelper.getSystemProperty("line.separator"); } return CR; } /** * Return the name of the "current working directory". */ public static String currentWorkingDirectory() { // bug 2756643 if (CURRENT_WORKING_DIRECTORY == null) { CURRENT_WORKING_DIRECTORY = PrivilegedAccessHelper.getSystemProperty("user.dir"); } return CURRENT_WORKING_DIRECTORY; } /** * Return the name of the "temporary directory". */ public static String tempDirectory() { // Bug 2756643 if (TEMP_DIRECTORY == null) { TEMP_DIRECTORY = PrivilegedAccessHelper.getSystemProperty("java.io.tmpdir"); } return TEMP_DIRECTORY; } /** * Answer a Date from a long * * This implementation is based on the java.sql.Date class, not java.util.Date. * @param longObject - milliseconds from the epoch (00:00:00 GMT * Jan 1, 1970). Negative values represent dates prior to the epoch. */ public static java.sql.Date dateFromLong(Long longObject) { return new java.sql.Date(longObject.longValue()); } /** * Answer a Date with the year, month, date. * This builds a date avoiding the deprecated, inefficient and concurrency bottleneck date constructors. * This implementation is based on the java.sql.Date class, not java.util.Date. * The year, month, day are the values calendar uses, * i.e. year is from 0, month is 0-11, date is 1-31. */ public static java.sql.Date dateFromYearMonthDate(int year, int month, int day) { // Use a calendar to compute the correct millis for the date. Calendar localCalendar = allocateCalendar(); localCalendar.clear(); localCalendar.set(year, month, day, 0, 0, 0); long millis = localCalendar.getTimeInMillis(); java.sql.Date date = new java.sql.Date(millis); releaseCalendar(localCalendar); return date; } /** * Answer a Date from a string representation. * The string MUST be a valid date and in one of the following * formats: YYYY/MM/DD, YYYY-MM-DD, YY/MM/DD, YY-MM-DD. * * This implementation is based on the java.sql.Date class, not java.util.Date. * * The Date class contains some minor gotchas that you have to watch out for. * @param dateString - string representation of date * @return - date representation of string */ public static java.sql.Date dateFromString(String dateString) throws ConversionException { int year; int month; int day; StringTokenizer dateStringTokenizer; if (dateString.indexOf('/') != -1) { dateStringTokenizer = new StringTokenizer(dateString, "/"); } else if (dateString.indexOf('-') != -1) { dateStringTokenizer = new StringTokenizer(dateString, "- "); } else { throw ConversionException.incorrectDateFormat(dateString); } try { year = Integer.parseInt(dateStringTokenizer.nextToken()); month = Integer.parseInt(dateStringTokenizer.nextToken()); day = Integer.parseInt(dateStringTokenizer.nextToken()); } catch (NumberFormatException exception) { throw ConversionException.incorrectDateFormat(dateString); } // Java returns the month in terms of 0 - 11 instead of 1 - 12. month = month - 1; return dateFromYearMonthDate(year, month, day); } /** * Answer a Date from a timestamp * * This implementation is based on the java.sql.Date class, not java.util.Date. * @param timestampObject - timestamp representation of date * @return - date representation of timestampObject */ public static java.sql.Date dateFromTimestamp(java.sql.Timestamp timestamp) { return sqlDateFromUtilDate(timestamp); } /** * Returns true if the file of this name does indeed exist */ public static boolean doesFileExist(String fileName) { FileReader reader = null; try { reader = new FileReader(fileName); } catch (FileNotFoundException fnfException) { return false; } finally { Helper.close(reader); } return true; } /** * Double up \ to allow printing of directories for source code generation. */ public static String doubleSlashes(String path) { StringBuilder buffer = new StringBuilder(path.length() + 5); for (int index = 0; index < path.length(); index++) { char charater = path.charAt(index); buffer.append(charater); if (charater == '\\') { buffer.append('\\'); } } return buffer.toString(); } /** * Extracts the actual path to the jar file. */ public static String extractJarNameFromURL(java.net.URL url) { String tempName = url.getFile(); int start = tempName.indexOf("file:") + 5; int end = tempName.indexOf("!/"); return tempName.substring(start, end); } /** * Return a string containing the platform-appropriate * characters for separating directory and file names. */ public static String fileSeparator() { //Bug 2756643 if (FILE_SEPARATOR == null) { FILE_SEPARATOR = PrivilegedAccessHelper.getSystemProperty("file.separator"); } return FILE_SEPARATOR; } /** * INTERNAL: * Returns a Field for the specified Class and field name. * Uses Class.getDeclaredField(String) to find the field. * If the field is not found on the specified class * the superclass is checked, and so on, recursively. * Set accessible to true, so we can access private/package/protected fields. */ public static Field getField(Class javaClass, String fieldName) throws NoSuchFieldException { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { return AccessController.doPrivileged(new PrivilegedGetField(javaClass, fieldName, true)); } catch (PrivilegedActionException exception) { throw (NoSuchFieldException)exception.getException(); } } else { return PrivilegedAccessHelper.getField(javaClass, fieldName, true); } } /** * INTERNAL: * Returns a Method for the specified Class, method name, and that has no * parameters. Uses Class.getDeclaredMethod(String Class[]) to find the * method. If the method is not found on the specified class the superclass * is checked, and so on, recursively. Set accessible to true, so we can * access private/package/protected methods. */ public static Method getDeclaredMethod(Class javaClass, String methodName) throws NoSuchMethodException { return getDeclaredMethod(javaClass, methodName, (Class[]) null); } /** * INTERNAL: * Returns a Method for the specified Class, method name, and formal * parameter types. Uses Class.getDeclaredMethod(String Class[]) to find * the method. If the method is not found on the specified class the * superclass is checked, and so on, recursively. Set accessible to true, * so we can access private/package/protected methods. */ public static Method getDeclaredMethod(Class javaClass, String methodName, Class[] methodParameterTypes) throws NoSuchMethodException { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { return AccessController.doPrivileged( new PrivilegedGetMethod(javaClass, methodName, methodParameterTypes, true)); } catch (PrivilegedActionException pae){ if (pae.getCause() instanceof NoSuchMethodException){ throw (NoSuchMethodException)pae.getCause(); } else { // really shouldn't happen throw (RuntimeException)pae.getCause(); } } } else { return PrivilegedAccessHelper.getMethod(javaClass, methodName, methodParameterTypes, true); } } /** * Return the class instance from the class */ public static Object getInstanceFromClass(Class classFullName) { if (classFullName == null) { return null; } try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(classFullName)); } catch (PrivilegedActionException exception) { Exception throwableException = exception.getException(); if (throwableException instanceof InstantiationException) { ValidationException exc = new ValidationException(); exc.setInternalException(throwableException); throw exc; } else { ValidationException exc = new ValidationException(); exc.setInternalException(throwableException); throw exc; } } } else { return PrivilegedAccessHelper.newInstanceFromClass(classFullName); } } catch (InstantiationException notInstantiatedException) { ValidationException exception = new ValidationException(); exception.setInternalException(notInstantiatedException); throw exception; } catch (IllegalAccessException notAccessedException) { ValidationException exception = new ValidationException(); exception.setInternalException(notAccessedException); throw exception; } } /** * Returns the object class. If a class is primitive return its non primitive class */ public static Class getObjectClass(Class javaClass) { return ConversionManager.getObjectClass(javaClass); } /** * Answers the unqualified class name for the provided class. */ public static String getShortClassName(Class javaClass) { return getShortClassName(javaClass.getName()); } /** * Answers the unqualified class name from the specified String. */ public static String getShortClassName(String javaClassName) { return javaClassName.substring(javaClassName.lastIndexOf('.') + 1); } /** * Answers the unqualified class name for the specified object. */ public static String getShortClassName(Object object) { return getShortClassName(object.getClass()); } /** * return a package name for the specified class. */ public static String getPackageName(Class javaClass) { String className = Helper.getShortClassName(javaClass); return javaClass.getName().substring(0, (javaClass.getName().length() - (className.length() + 1))); } /** * Return a string containing the specified number of tabs. */ public static String getTabs(int noOfTabs) { StringWriter writer = new StringWriter(); for (int index = 0; index < noOfTabs; index++) { writer.write("\t"); } return writer.toString(); } /** * Returns the index of the the first <code>null</code> element found in the specified * <code>Vector</code> starting the search at the starting index specified. * Return an int >= 0 and less than size if a <code>null</code> element was found. * Return -1 if a <code>null</code> element was not found. * This is needed in jdk1.1, where <code>Vector.contains(Object)</code> * for a <code>null</code> element will result in a <code>NullPointerException</code>.... */ public static int indexOfNullElement(Vector v, int index) { int size = v.size(); for (int i = index; i < size; i++) { if (v.elementAt(i) == null) { return i; } } return -1; } /** * ADVANCED * returns true if the class in question is a primitive wrapper */ public static boolean isPrimitiveWrapper(Class classInQuestion) { return classInQuestion.equals(Character.class) || classInQuestion.equals(Boolean.class) || classInQuestion.equals(Byte.class) || classInQuestion.equals(Short.class) || classInQuestion.equals(Integer.class) || classInQuestion.equals(Long.class) || classInQuestion.equals(Float.class) || classInQuestion.equals(Double.class); } /** * Returns true if the string given is an all upper case string */ public static boolean isUpperCaseString(String s) { char[] c = s.toCharArray(); for (int i = 0; i < s.length(); i++) { if (Character.isLowerCase(c[i])) { return false; } } return true; } /** * Returns true if the character given is a vowel. I.e. one of a,e,i,o,u,A,E,I,O,U. */ public static boolean isVowel(char c) { return (c == 'A') || (c == 'a') || (c == 'e') || (c == 'E') || (c == 'i') || (c == 'I') || (c == 'o') || (c == 'O') || (c == 'u') || (c == 'U'); } /** * Return an array of the files in the specified directory. * This allows us to simplify jdk1.1 code a bit. */ public static File[] listFilesIn(File directory) { if (directory.isDirectory()) { return directory.listFiles(); } else { return new File[0]; } } /** * Make a Vector from the passed object. * If it's a Collection, iterate over the collection and add each item to the Vector. * If it's not a collection create a Vector and add the object to it. */ public static Vector makeVectorFromObject(Object theObject) { if (theObject instanceof Vector) { return ((Vector)theObject); } if (theObject instanceof Collection) { Vector returnVector = new Vector(((Collection)theObject).size()); Iterator iterator = ((Collection)theObject).iterator(); while (iterator.hasNext()) { returnVector.add(iterator.next()); } return returnVector; } Vector returnVector = new Vector(); returnVector.addElement(theObject); return returnVector; } /** * Used by our byte code weaving to enable users who are debugging to output * the generated class to a file * * @param className * @param classBytes * @param outputPath */ public static void outputClassFile(String className, byte[] classBytes, String outputPath) { StringBuilder directoryName = new StringBuilder(); StringTokenizer tokenizer = new StringTokenizer(className, "\n\\/"); String token = null; while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); if (tokenizer.hasMoreTokens()) { directoryName.append(token + File.separator); } } FileOutputStream fos = null; try { String usedOutputPath = outputPath; if (!outputPath.endsWith(File.separator)) { usedOutputPath = outputPath + File.separator; } File file = new File(usedOutputPath + directoryName); if (!file.exists()) { if (!file.mkdirs()) { AbstractSessionLog.getLog().log(SessionLog.FINE, SessionLog.WEAVER, "weaver_not_overwriting", file); } } file = new File(file, token + ".class"); if (!file.exists()) { if (!file.createNewFile()) { AbstractSessionLog.getLog().log(SessionLog.FINE, SessionLog.WEAVER, "weaver_not_overwriting", file); } } else { if (!PrivilegedAccessHelper.getSystemProperty(SystemProperties.WEAVING_SHOULD_OVERWRITE, "false").equalsIgnoreCase("true")) { AbstractSessionLog.getLog().log(SessionLog.WARNING, SessionLog.WEAVER, "weaver_not_overwriting", className); return; } } fos = new FileOutputStream(file); fos.write(classBytes); } catch (Exception e) { AbstractSessionLog.getLog().log(SessionLog.WARNING, SessionLog.WEAVER, "weaver_could_not_write", className, e); AbstractSessionLog.getLog().logThrowable(SessionLog.FINEST, SessionLog.WEAVER, e); } finally { Helper.close(fos); } } /** * Return a string containing the platform-appropriate * characters for separating entries in a path (e.g. the classpath) */ public static String pathSeparator() { // Bug 2756643 if (PATH_SEPARATOR == null) { PATH_SEPARATOR = PrivilegedAccessHelper.getSystemProperty("path.separator"); } return PATH_SEPARATOR; } /** * Return a String containing the printed stacktrace of an exception. */ public static String printStackTraceToString(Throwable aThrowable) { StringWriter swriter = new StringWriter(); PrintWriter writer = new PrintWriter(swriter, true); aThrowable.printStackTrace(writer); writer.close(); return swriter.toString(); } /* Return a string representation of a number of milliseconds in terms of seconds, minutes, or * milliseconds, whichever is most appropriate. */ public static String printTimeFromMilliseconds(long milliseconds) { if ((milliseconds > 1000) && (milliseconds < 60000)) { return (milliseconds / 1000) + "s"; } if (milliseconds > 60000) { return (milliseconds / 60000) + "min " + printTimeFromMilliseconds(milliseconds % 60000); } return milliseconds + "ms"; } /** * Given a Vector, print it, even if there is a null in it */ public static String printVector(Vector vector) { StringWriter stringWriter = new StringWriter(); stringWriter.write("["); Enumeration enumtr = vector.elements(); stringWriter.write(String.valueOf(enumtr.nextElement())); while (enumtr.hasMoreElements()) { stringWriter.write(" "); stringWriter.write(String.valueOf(enumtr.nextElement())); } stringWriter.write("]"); return stringWriter.toString(); } public static Hashtable rehashHashtable(Hashtable table) { Hashtable rehashedTable = new Hashtable(table.size() + 2); Enumeration values = table.elements(); for (Enumeration keys = table.keys(); keys.hasMoreElements();) { Object key = keys.nextElement(); Object value = values.nextElement(); rehashedTable.put(key, value); } return rehashedTable; } public static Map rehashMap(Map table) { HashMap rehashedTable = new HashMap(table.size() + 2); Iterator values = table.values().iterator(); for (Iterator keys = table.keySet().iterator(); keys.hasNext();) { Object key = keys.next(); Object value = values.next(); rehashedTable.put(key, value); } return rehashedTable; } /** * Returns a String which has had enough non-alphanumeric characters removed to be equal to * the maximumStringLength. */ public static String removeAllButAlphaNumericToFit(String s1, int maximumStringLength) { int s1Size = s1.length(); if (s1Size <= maximumStringLength) { return s1; } // Remove the necessary number of characters StringBuilder buf = new StringBuilder(); int numberOfCharsToBeRemoved = s1.length() - maximumStringLength; int s1Index = 0; while ((numberOfCharsToBeRemoved > 0) && (s1Index < s1Size)) { char currentChar = s1.charAt(s1Index); if (Character.isLetterOrDigit(currentChar)) { buf.append(currentChar); } else { numberOfCharsToBeRemoved--; } s1Index++; } // Append the rest of the character that were not parsed through. // Is it quicker to build a substring and append that? while (s1Index < s1Size) { buf.append(s1.charAt(s1Index)); s1Index++; } // return buf.toString(); } /** * Returns a String which has had enough of the specified character removed to be equal to * the maximumStringLength. */ public static String removeCharacterToFit(String s1, char aChar, int maximumStringLength) { int s1Size = s1.length(); if (s1Size <= maximumStringLength) { return s1; } // Remove the necessary number of characters StringBuilder buf = new StringBuilder(); int numberOfCharsToBeRemoved = s1.length() - maximumStringLength; int s1Index = 0; while ((numberOfCharsToBeRemoved > 0) && (s1Index < s1Size)) { char currentChar = s1.charAt(s1Index); if (currentChar == aChar) { numberOfCharsToBeRemoved--; } else { buf.append(currentChar); } s1Index++; } // Append the rest of the character that were not parsed through. // Is it quicker to build a substring and append that? while (s1Index < s1Size) { buf.append(s1.charAt(s1Index)); s1Index++; } // return buf.toString(); } /** * Returns a String which has had enough of the specified character removed to be equal to * the maximumStringLength. */ public static String removeVowels(String s1) { // Remove the vowels StringBuilder buf = new StringBuilder(); int s1Size = s1.length(); int s1Index = 0; while (s1Index < s1Size) { char currentChar = s1.charAt(s1Index); if (!isVowel(currentChar)) { buf.append(currentChar); } s1Index++; } // return buf.toString(); } /** * Replaces the first subString of the source with the replacement. */ public static String replaceFirstSubString(String source, String subString, String replacement) { int index = source.indexOf(subString); if (index >= 0) { return source.substring(0, index) + replacement + source.substring(index + subString.length()); } return null; } public static Vector reverseVector(Vector theVector) { Vector tempVector = new Vector(theVector.size()); Object currentElement; for (int i = theVector.size() - 1; i > -1; i--) { currentElement = theVector.elementAt(i); tempVector.addElement(currentElement); } return tempVector; } /** * Returns a new string with all space characters removed from the right * * @param originalString - timestamp representation of date * @return - String */ public static String rightTrimString(String originalString) { int len = originalString.length(); while ((len > 0) && (originalString.charAt(len - 1) <= ' ')) { len--; } return originalString.substring(0, len); } /** * Returns a String which is a concatenation of two string which have had enough * vowels removed from them so that the sum of the sized of the two strings is less than * or equal to the specified size. */ public static String shortenStringsByRemovingVowelsToFit(String s1, String s2, int maximumStringLength) { int size = s1.length() + s2.length(); if (size <= maximumStringLength) { return s1 + s2; } // Remove the necessary number of characters int s1Size = s1.length(); int s2Size = s2.length(); StringBuilder buf1 = new StringBuilder(); StringBuilder buf2 = new StringBuilder(); int numberOfCharsToBeRemoved = size - maximumStringLength; int s1Index = 0; int s2Index = 0; int modulo2 = 0; // While we still want to remove characters, and not both string are done. while ((numberOfCharsToBeRemoved > 0) && !((s1Index >= s1Size) && (s2Index >= s2Size))) { if ((modulo2 % 2) == 0) { // Remove from s1 if (s1Index < s1Size) { if (isVowel(s1.charAt(s1Index))) { numberOfCharsToBeRemoved--; } else { buf1.append(s1.charAt(s1Index)); } s1Index++; } } else { // Remove from s2 if (s2Index < s2Size) { if (isVowel(s2.charAt(s2Index))) { numberOfCharsToBeRemoved--; } else { buf2.append(s2.charAt(s2Index)); } s2Index++; } } modulo2++; } // Append the rest of the character that were not parsed through. // Is it quicker to build a substring and append that? while (s1Index < s1Size) { buf1.append(s1.charAt(s1Index)); s1Index++; } while (s2Index < s2Size) { buf2.append(s2.charAt(s2Index)); s2Index++; } // return buf1.toString() + buf2.toString(); } /** * Answer a sql.Date from a timestamp. */ public static java.sql.Date sqlDateFromUtilDate(java.util.Date utilDate) { // PERF: Avoid deprecated get methods, that are now very inefficient. Calendar calendar = allocateCalendar(); calendar.setTime(utilDate); java.sql.Date date = dateFromCalendar(calendar); releaseCalendar(calendar); return date; } /** * Print the sql.Date. */ public static String printDate(java.sql.Date date) { // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString. Calendar calendar = allocateCalendar(); calendar.setTime(date); String string = printDate(calendar); releaseCalendar(calendar); return string; } /** * Print the date part of the calendar. */ public static String printDate(Calendar calendar) { return printDate(calendar, true); } /** * Print the date part of the calendar. * Normally the calendar must be printed in the local time, but if the timezone is printed, * it must be printing in its timezone. */ public static String printDate(Calendar calendar, boolean useLocalTime) { int year; int month; int day; if (useLocalTime && (!defaultTimeZone.equals(calendar.getTimeZone()))) { // Must convert the calendar to the local timezone if different, as dates have no timezone (always local). Calendar localCalendar = allocateCalendar(); localCalendar.setTimeInMillis(calendar.getTimeInMillis()); year = localCalendar.get(Calendar.YEAR); month = localCalendar.get(Calendar.MONTH) + 1; day = localCalendar.get(Calendar.DATE); releaseCalendar(localCalendar); } else { year = calendar.get(Calendar.YEAR); month = calendar.get(Calendar.MONTH) + 1; day = calendar.get(Calendar.DATE); } char[] buf = "2000-00-00".toCharArray(); buf[0] = Character.forDigit(year / 1000, 10); buf[1] = Character.forDigit((year / 100) % 10, 10); buf[2] = Character.forDigit((year / 10) % 10, 10); buf[3] = Character.forDigit(year % 10, 10); buf[5] = Character.forDigit(month / 10, 10); buf[6] = Character.forDigit(month % 10, 10); buf[8] = Character.forDigit(day / 10, 10); buf[9] = Character.forDigit(day % 10, 10); return new String(buf); } /** * Print the sql.Time. */ public static String printTime(java.sql.Time time) { // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString. Calendar calendar = allocateCalendar(); calendar.setTime(time); String string = printTime(calendar); releaseCalendar(calendar); return string; } /** * Print the time part of the calendar. */ public static String printTime(Calendar calendar) { return printTime(calendar, true); } /** * Print the time part of the calendar. * Normally the calendar must be printed in the local time, but if the timezone is printed, * it must be printing in its timezone. */ public static String printTime(Calendar calendar, boolean useLocalTime) { int hour; int minute; int second; if (useLocalTime && (!defaultTimeZone.equals(calendar.getTimeZone()))) { // Must convert the calendar to the local timezone if different, as dates have no timezone (always local). Calendar localCalendar = allocateCalendar(); localCalendar.setTimeInMillis(calendar.getTimeInMillis()); hour = localCalendar.get(Calendar.HOUR_OF_DAY); minute = localCalendar.get(Calendar.MINUTE); second = localCalendar.get(Calendar.SECOND); releaseCalendar(localCalendar); } else { hour = calendar.get(Calendar.HOUR_OF_DAY); minute = calendar.get(Calendar.MINUTE); second = calendar.get(Calendar.SECOND); } String hourString; String minuteString; String secondString; if (hour < 10) { hourString = "0" + hour; } else { hourString = Integer.toString(hour); } if (minute < 10) { minuteString = "0" + minute; } else { minuteString = Integer.toString(minute); } if (second < 10) { secondString = "0" + second; } else { secondString = Integer.toString(second); } return (hourString + ":" + minuteString + ":" + secondString); } /** * Print the Calendar. */ public static String printCalendar(Calendar calendar) { return printCalendar(calendar, true); } /** * Print the Calendar. * Normally the calendar must be printed in the local time, but if the timezone is printed, * it must be printing in its timezone. */ public static String printCalendar(Calendar calendar, boolean useLocalTime) { String millisString; // String zeros = "000000000"; if (calendar.get(Calendar.MILLISECOND) == 0) { millisString = "0"; } else { millisString = buildZeroPrefixAndTruncTrailZeros(calendar.get(Calendar.MILLISECOND), 3); } StringBuilder timestampBuf = new StringBuilder(); timestampBuf.append(printDate(calendar, useLocalTime)); timestampBuf.append(" "); timestampBuf.append(printTime(calendar, useLocalTime)); timestampBuf.append("."); timestampBuf.append(millisString); return timestampBuf.toString(); } /** * Print the sql.Timestamp. */ public static String printTimestamp(java.sql.Timestamp timestamp) { // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString. Calendar calendar = allocateCalendar(); calendar.setTime(timestamp); String nanosString; if (timestamp.getNanos() == 0) { nanosString = "0"; } else { nanosString = buildZeroPrefixAndTruncTrailZeros(timestamp.getNanos(), 9); } StringBuilder timestampBuf = new StringBuilder(); timestampBuf.append(printDate(calendar)); timestampBuf.append(" "); timestampBuf.append(printTime(calendar)); timestampBuf.append("."); timestampBuf.append(nanosString); releaseCalendar(calendar); return (timestampBuf.toString()); } /** * Build a numerical string with leading 0s. number is an existing number that * the new string will be built on. totalDigits is the number of the required * digits of the string. */ public static String buildZeroPrefix(int number, int totalDigits) { String numbString = buildZeroPrefixWithoutSign(number, totalDigits); if (number < 0) { numbString = "-" + numbString; } else { numbString = "+" + numbString; } return numbString; } /** * Build a numerical string with leading 0s. number is an existing number that * the new string will be built on. totalDigits is the number of the required * digits of the string. */ public static String buildZeroPrefixWithoutSign(int number, int totalDigits) { String zeros = "000000000"; int absValue = (number < 0) ? (-number) : number; String numbString = Integer.toString(absValue); // Add leading zeros numbString = zeros.substring(0, (totalDigits - numbString.length())) + numbString; return numbString; } /** * Build a numerical string with leading 0s and truncate trailing zeros. number is * an existing number that the new string will be built on. totalDigits is the number * of the required digits of the string. */ public static String buildZeroPrefixAndTruncTrailZeros(int number, int totalDigits) { String zeros = "000000000"; String numbString = Integer.toString(number); // Add leading zeros numbString = zeros.substring(0, (totalDigits - numbString.length())) + numbString; // Truncate trailing zeros char[] numbChar = new char[numbString.length()]; numbString.getChars(0, numbString.length(), numbChar, 0); int truncIndex = totalDigits - 1; while (numbChar[truncIndex] == '0') { truncIndex--; } return new String(numbChar, 0, truncIndex + 1); } /** * Print the sql.Timestamp without the nanos portion. */ public static String printTimestampWithoutNanos(java.sql.Timestamp timestamp) { // PERF: Avoid deprecated get methods, that are now very inefficient and used from toString. Calendar calendar = allocateCalendar(); calendar.setTime(timestamp); String string = printCalendarWithoutNanos(calendar); releaseCalendar(calendar); return string; } /** * Print the Calendar without the nanos portion. */ public static String printCalendarWithoutNanos(Calendar calendar) { StringBuilder timestampBuf = new StringBuilder(); timestampBuf.append(printDate(calendar)); timestampBuf.append(" "); timestampBuf.append(printTime(calendar)); return timestampBuf.toString(); } /** * Answer a sql.Date from a Calendar. */ public static java.sql.Date dateFromCalendar(Calendar calendar) { if (!defaultTimeZone.equals(calendar.getTimeZone())) { // Must convert the calendar to the local timezone if different, as dates have no timezone (always local). Calendar localCalendar = allocateCalendar(); localCalendar.setTimeInMillis(calendar.getTimeInMillis()); java.sql.Date date = dateFromYearMonthDate(localCalendar.get(Calendar.YEAR), localCalendar.get(Calendar.MONTH), localCalendar.get(Calendar.DATE)); releaseCalendar(localCalendar); return date; } else if ((calendar.get(Calendar.HOUR_OF_DAY) == 0) && (calendar.get(Calendar.MINUTE) == 0) && (calendar.get(Calendar.SECOND) == 0) && (calendar.get(Calendar.MILLISECOND) == 0)) { // PERF: If just a date set in the Calendar, then just use its millis. return new java.sql.Date(calendar.getTimeInMillis()); } return dateFromYearMonthDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE)); } /** * Return a sql.Date with time component zeroed out. * Starting with version 12.1 Oracle jdbc Statement.setDate method no longer zeroes out the time component. */ public static java.sql.Date truncateDate(java.sql.Date date) { // PERF: Avoid deprecated get methods, that are now very inefficient. Calendar calendar = allocateCalendar(); calendar.setTime(date); if ((calendar.get(Calendar.HOUR_OF_DAY) != 0) || (calendar.get(Calendar.MINUTE) != 0) || (calendar.get(Calendar.SECOND) != 0) || (calendar.get(Calendar.MILLISECOND) != 0)) { int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); int day = calendar.get(Calendar.DATE); calendar.clear(); calendar.set(year, month, day, 0, 0, 0); long millis = calendar.getTimeInMillis(); date = new java.sql.Date(millis); } releaseCalendar(calendar); return date; } /** * Return a sql.Date with time component zeroed out (with possible exception of milliseconds). * Starting with version 12.1 Oracle jdbc Statement.setDate method no longer zeroes out the whole time component, * yet it still zeroes out milliseconds. */ public static java.sql.Date truncateDateIgnoreMilliseconds(java.sql.Date date) { // PERF: Avoid deprecated get methods, that are now very inefficient. Calendar calendar = allocateCalendar(); calendar.setTime(date); if ((calendar.get(Calendar.HOUR_OF_DAY) != 0) || (calendar.get(Calendar.MINUTE) != 0) || (calendar.get(Calendar.SECOND) != 0)) { int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); int day = calendar.get(Calendar.DATE); calendar.clear(); calendar.set(year, month, day, 0, 0, 0); long millis = calendar.getTimeInMillis(); date = new java.sql.Date(millis); } releaseCalendar(calendar); return date; } /** * Can be used to mark code if a workaround is added for a JDBC driver or other bug. */ public static void systemBug(String description) { // Use sender to find what is needy. } /** * Answer a Time from a Date * * This implementation is based on the java.sql.Date class, not java.util.Date. * @param timestampObject - time representation of date * @return - time representation of dateObject */ public static java.sql.Time timeFromDate(java.util.Date date) { // PERF: Avoid deprecated get methods, that are now very inefficient. Calendar calendar = allocateCalendar(); calendar.setTime(date); java.sql.Time time = timeFromCalendar(calendar); releaseCalendar(calendar); return time; } /** * Answer a Time from a long * * @param longObject - milliseconds from the epoch (00:00:00 GMT * Jan 1, 1970). Negative values represent dates prior to the epoch. */ public static java.sql.Time timeFromLong(Long longObject) { return new java.sql.Time(longObject.longValue()); } /** * Answer a Time with the hour, minute, second. * This builds a time avoiding the deprecated, inefficient and concurrency bottleneck date constructors. * The hour, minute, second are the values calendar uses, * i.e. year is from 0, month is 0-11, date is 1-31. */ public static java.sql.Time timeFromHourMinuteSecond(int hour, int minute, int second) { // Use a calendar to compute the correct millis for the date. Calendar localCalendar = allocateCalendar(); localCalendar.clear(); localCalendar.set(1970, 0, 1, hour, minute, second); long millis = localCalendar.getTimeInMillis(); java.sql.Time time = new java.sql.Time(millis); releaseCalendar(localCalendar); return time; } /** * Answer a Time from a string representation. * This method will accept times in the following * formats: HH-MM-SS, HH:MM:SS * * @param timeString - string representation of time * @return - time representation of string */ public static java.sql.Time timeFromString(String timeString) throws ConversionException { int hour; int minute; int second; String timePortion = timeString; if (timeString.length() > 12) { // Longer strings are Timestamp format (ie. Sybase & Oracle) timePortion = timeString.substring(11, 19); } if ((timePortion.indexOf('-') == -1) && (timePortion.indexOf('/') == -1) && (timePortion.indexOf('.') == -1) && (timePortion.indexOf(':') == -1)) { throw ConversionException.incorrectTimeFormat(timePortion); } StringTokenizer timeStringTokenizer = new StringTokenizer(timePortion, " /:.-"); try { hour = Integer.parseInt(timeStringTokenizer.nextToken()); minute = Integer.parseInt(timeStringTokenizer.nextToken()); second = Integer.parseInt(timeStringTokenizer.nextToken()); } catch (NumberFormatException exception) { throw ConversionException.incorrectTimeFormat(timeString); } return timeFromHourMinuteSecond(hour, minute, second); } /** * Answer a Time from a Timestamp * Usus the Hours, Minutes, Seconds instead of getTime() ms value. */ public static java.sql.Time timeFromTimestamp(java.sql.Timestamp timestamp) { return timeFromDate(timestamp); } /** * Answer a sql.Time from a Calendar. */ public static java.sql.Time timeFromCalendar(Calendar calendar) { if (!defaultTimeZone.equals(calendar.getTimeZone())) { // Must convert the calendar to the local timezone if different, as dates have no timezone (always local). Calendar localCalendar = allocateCalendar(); localCalendar.setTimeInMillis(calendar.getTimeInMillis()); java.sql.Time date = timeFromHourMinuteSecond(localCalendar.get(Calendar.HOUR_OF_DAY), localCalendar.get(Calendar.MINUTE), localCalendar.get(Calendar.SECOND)); releaseCalendar(localCalendar); return date; } return timeFromHourMinuteSecond(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND)); } /** * Answer a Timestamp from a Calendar. */ public static java.sql.Timestamp timestampFromCalendar(Calendar calendar) { return timestampFromLong(calendar.getTimeInMillis()); } /** * Answer a Timestamp from a java.util.Date. */ public static java.sql.Timestamp timestampFromDate(java.util.Date date) { return timestampFromLong(date.getTime()); } /** * Answer a Time from a long * * @param longObject - milliseconds from the epoch (00:00:00 GMT * Jan 1, 1970). Negative values represent dates prior to the epoch. */ public static java.sql.Timestamp timestampFromLong(Long millis) { return timestampFromLong(millis.longValue()); } /** * Answer a Time from a long * * @param longObject - milliseconds from the epoch (00:00:00 GMT * Jan 1, 1970). Negative values represent dates prior to the epoch. */ public static java.sql.Timestamp timestampFromLong(long millis) { java.sql.Timestamp timestamp = new java.sql.Timestamp(millis); // P2.0.1.3: Didn't account for negative millis < 1970 // Must account for the jdk millis bug where it does not set the nanos. if ((millis % 1000) > 0) { timestamp.setNanos((int)(millis % 1000) * 1000000); } else if ((millis % 1000) < 0) { timestamp.setNanos((int)(1000000000 - (Math.abs((millis % 1000) * 1000000)))); } return timestamp; } /** * Answer a Timestamp from a string representation. * This method will accept strings in the following * formats: YYYY/MM/DD HH:MM:SS, YY/MM/DD HH:MM:SS, YYYY-MM-DD HH:MM:SS, YY-MM-DD HH:MM:SS * * @param timestampString - string representation of timestamp * @return - timestamp representation of string */ @SuppressWarnings("deprecation") public static java.sql.Timestamp timestampFromString(String timestampString) throws ConversionException { if ((timestampString.indexOf('-') == -1) && (timestampString.indexOf('/') == -1) && (timestampString.indexOf('.') == -1) && (timestampString.indexOf(':') == -1)) { throw ConversionException.incorrectTimestampFormat(timestampString); } StringTokenizer timestampStringTokenizer = new StringTokenizer(timestampString, " /:.-"); int year; int month; int day; int hour; int minute; int second; int nanos; try { year = Integer.parseInt(timestampStringTokenizer.nextToken()); month = Integer.parseInt(timestampStringTokenizer.nextToken()); day = Integer.parseInt(timestampStringTokenizer.nextToken()); try { hour = Integer.parseInt(timestampStringTokenizer.nextToken()); minute = Integer.parseInt(timestampStringTokenizer.nextToken()); second = Integer.parseInt(timestampStringTokenizer.nextToken()); } catch (java.util.NoSuchElementException endOfStringException) { // May be only a date string desired to be used as a timestamp. hour = 0; minute = 0; second = 0; } } catch (NumberFormatException exception) { throw ConversionException.incorrectTimestampFormat(timestampString); } try { String nanoToken = timestampStringTokenizer.nextToken(); nanos = Integer.parseInt(nanoToken); for (int times = 0; times < (9 - nanoToken.length()); times++) { nanos = nanos * 10; } } catch (java.util.NoSuchElementException endOfStringException) { nanos = 0; } catch (NumberFormatException exception) { throw ConversionException.incorrectTimestampFormat(timestampString); } // Java dates are based on year after 1900 so I need to delete it. year = year - 1900; // Java returns the month in terms of 0 - 11 instead of 1 - 12. month = month - 1; java.sql.Timestamp timestamp; // TODO: This was not converted to use Calendar for the conversion because calendars do not take nanos. // but it should be, and then just call setNanos. timestamp = new java.sql.Timestamp(year, month, day, hour, minute, second, nanos); return timestamp; } /** * Answer a Timestamp with the year, month, day, hour, minute, second. * The hour, minute, second are the values calendar uses, * i.e. year is from 0, month is 0-11, date is 1-31, time is 0-23/59. */ @SuppressWarnings("deprecation") public static java.sql.Timestamp timestampFromYearMonthDateHourMinuteSecondNanos(int year, int month, int date, int hour, int minute, int second, int nanos) { // This was not converted to use Calendar for the conversion because calendars do not take nanos. // but it should be, and then just call setNanos. return new java.sql.Timestamp(year - 1900, month, date, hour, minute, second, nanos); } /** * Can be used to mark code as need if something strange is seen. */ public static void toDo(String description) { // Use sender to find what is needy. } /** * Convert dotted format class name to slashed format class name. * @param dottedClassName * @return String */ public static String toSlashedClassName(String dottedClassName){ if(dottedClassName==null){ return null; }else if(dottedClassName.indexOf('.')>=0){ return dottedClassName.replace('.', '/'); }else{ return dottedClassName; } } /** * If the size of the original string is larger than the passed in size, * this method will remove the vowels from the original string. * * The removal starts backward from the end of original string, and stops if the * resulting string size is equal to the passed in size. * * If the resulting string is still larger than the passed in size after * removing all vowels, the end of the resulting string will be truncated. */ public static String truncate(String originalString, int size) { if (originalString.length() <= size) { //no removal and truncation needed return originalString; } String vowels = "AaEeIiOoUu"; StringBuilder newStringBufferTmp = new StringBuilder(originalString.length()); //need to remove the extra characters int counter = originalString.length() - size; for (int index = (originalString.length() - 1); index >= 0; index--) { //search from the back to the front, if vowel found, do not append it to the resulting (temp) string! //i.e. if vowel not found, append the chararcter to the new string buffer. if (vowels.indexOf(originalString.charAt(index)) == -1) { newStringBufferTmp.append(originalString.charAt(index)); } else { //vowel found! do NOT append it to the temp buffer, and decrease the counter counter--; if (counter == 0) { //if the exceeded characters (counter) of vowel haven been removed, the total //string size should be equal to the limits, so append the reversed remaining string //to the new string, break the loop and return the shrunk string. StringBuilder newStringBuffer = new StringBuilder(size); newStringBuffer.append(originalString.substring(0, index)); //need to reverse the string //bug fix: 3016423. append(BunfferString) is jdk1.4 version api. Use append(String) instead //in order to support jdk1.3. newStringBuffer.append(newStringBufferTmp.reverse().toString()); return newStringBuffer.toString(); } } } //the shrunk string still too long, revrese the order back and truncate it! return newStringBufferTmp.reverse().toString().substring(0, size); } /** * Answer a Date from a long * * This implementation is based on the java.sql.Date class, not java.util.Date. * @param longObject - milliseconds from the epoch (00:00:00 GMT * Jan 1, 1970). Negative values represent dates prior to the epoch. */ public static java.util.Date utilDateFromLong(Long longObject) { return new java.util.Date(longObject.longValue()); } /** * Answer a java.util.Date from a sql.date * * @param sqlDate - sql.date representation of date * @return - java.util.Date representation of the sql.date */ public static java.util.Date utilDateFromSQLDate(java.sql.Date sqlDate) { return new java.util.Date(sqlDate.getTime()); } /** * Answer a java.util.Date from a sql.Time * * @param time - time representation of util date * @return - java.util.Date representation of the time */ public static java.util.Date utilDateFromTime(java.sql.Time time) { return new java.util.Date(time.getTime()); } /** * Answer a java.util.Date from a timestamp * * @param timestampObject - timestamp representation of date * @return - java.util.Date representation of timestampObject */ public static java.util.Date utilDateFromTimestamp(java.sql.Timestamp timestampObject) { // Bug 2719624 - Conditionally remove workaround for java bug which truncated // nanoseconds from timestamp.getTime(). We will now only recalculate the nanoseconds // When timestamp.getTime() results in nanoseconds == 0; long time = timestampObject.getTime(); boolean appendNanos = ((time % 1000) == 0); if (appendNanos) { return new java.util.Date(time + (timestampObject.getNanos() / 1000000)); } else { return new java.util.Date(time); } } /** * Convert the specified array into a vector. */ public static Vector vectorFromArray(Object[] array) { Vector result = new Vector(array.length); for (int i = 0; i < array.length; i++) { result.addElement(array[i]); } return result; } /** * Convert the byte array to a HEX string. * HEX allows for binary data to be printed. */ public static void writeHexString(byte[] bytes, Writer writer) throws IOException { writer.write(buildHexStringFromBytes(bytes)); } /** * Check if the value is 0 (int/long) for primitive ids. */ public static boolean isEquivalentToNull(Object value) { return (!isZeroValidPrimaryKey && (((value.getClass() == ClassConstants.LONG) && (((Long)value).longValue() == 0L)) || ((value.getClass() == ClassConstants.INTEGER) && (((Integer)value).intValue() == 0)))); } /** * Returns true if the passed value is Number that is negative or equals to zero. */ public static boolean isNumberNegativeOrZero(Object value) { return ((value.getClass() == ClassConstants.BIGDECIMAL) && (((BigDecimal)value).signum() <= 0)) || ((value.getClass() == ClassConstants.BIGINTEGER) && (((BigInteger)value).signum() <= 0)) || ((value instanceof Number) && (((Number)value).longValue() <= 0)); } /** * Return an integer representing the number of occurrences (using equals()) of the * specified object in the specified list. * If the list is null or empty (or both the object and the list is null), 0 is returned. */ public static int countOccurrencesOf(Object comparisonObject, List list) { int instances = 0; boolean comparisonObjectIsNull = comparisonObject == null; if (list != null) { for (int i = 0; i < list.size(); i++) { Object listObject = list.get(i); if ((comparisonObjectIsNull && listObject == null) || (!comparisonObjectIsNull && comparisonObject.equals(listObject))) { instances++; } } } return instances; } /** * Convert the URL into a URI allowing for special chars. */ public static URI toURI(java.net.URL url) throws URISyntaxException { try { // Attempt to use url.toURI since it will deal with all urls // without special characters and URISyntaxException allows us // to catch issues with special characters. This will handle // URLs that already have special characters replaced such as // URLS derived from searches for persistence.xml on the Java // System class loader return url.toURI(); } catch (URISyntaxException exception) { // Use multi-argument constructor for URI since single-argument // constructor and URL.toURI() do not deal with special // characters in path return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), null); } } /** * Return the get method name weaved for a value-holder attribute. */ public static String getWeavedValueHolderGetMethodName(String attributeName) { return PERSISTENCE_GET + attributeName + "_vh"; } /** * Return the set method name weaved for a value-holder attribute. */ public static String getWeavedValueHolderSetMethodName(String attributeName) { return PERSISTENCE_SET + attributeName + "_vh"; } /** * Return the set method name weaved for getting attribute value. * This method is always weaved in field access case. * In property access case the method weaved only if attribute name is the same as property name: * for instance, the method weaved for "manager" attribute that uses "getManager" / "setManager" access methods, * but not for "m_address" attribute that uses "getAddress" / "setAddress" access methods. */ public static String getWeavedGetMethodName(String attributeName) { return PERSISTENCE_GET + attributeName; } /** * Return the set method name weaved for setting attribute value. * This method is always weaved in field access case. * In property access case the method weaved only if attribute name is the same as property name: * for instance, the method weaved for "manager" attribute that uses "getManager" / "setManager" access methods, * but not for "m_address" attribute that uses "getAddress" / "setAddress" access methods. */ public static String getWeavedSetMethodName(String attributeName) { return PERSISTENCE_SET + attributeName; } /** * Close a closeable object, eating the exception */ public static void close(Closeable c) { try { if (c != null) { c.close(); } } catch (IOException exception) { } } /** * INTERNAL: * Method to convert a getXyz or isXyz method name to an xyz attribute name. * NOTE: The method name passed it may not actually be a method name, so * by default return the name passed in. */ public static String getAttributeNameFromMethodName(String methodName) { String restOfName = methodName; // We're looking at method named 'get' or 'set', therefore, // there is no attribute name, set it to "" string for now. if (methodName.equals(GET_PROPERTY_METHOD_PREFIX) || methodName.equals(IS_PROPERTY_METHOD_PREFIX)) { return ""; } else if (methodName.startsWith(GET_PROPERTY_METHOD_PREFIX)) { restOfName = methodName.substring(POSITION_AFTER_GET_PREFIX); } else if (methodName.startsWith(IS_PROPERTY_METHOD_PREFIX)){ restOfName = methodName.substring(POSITION_AFTER_IS_PREFIX); } //added for bug 234222 - property name generation differs from Introspector.decapitalize return java.beans.Introspector.decapitalize(restOfName); } public static String getDefaultStartDatabaseDelimiter(){ if (defaultStartDatabaseDelimiter == null){ defaultStartDatabaseDelimiter = DEFAULT_DATABASE_DELIMITER; } return defaultStartDatabaseDelimiter; } public static String getDefaultEndDatabaseDelimiter(){ if (defaultEndDatabaseDelimiter == null){ defaultEndDatabaseDelimiter = DEFAULT_DATABASE_DELIMITER; } return defaultEndDatabaseDelimiter; } public static void setDefaultStartDatabaseDelimiter(String delimiter){ defaultStartDatabaseDelimiter = delimiter; } public static void setDefaultEndDatabaseDelimiter(String delimiter){ defaultEndDatabaseDelimiter = delimiter; } /** * Convert the SQL like pattern to a regex pattern. */ public static String convertLikeToRegex(String like) { // Bug 3936427 - Replace regular expression reserved characters with escaped version of those characters // For instance replace ? with \? String pattern = like.replaceAll("\\?", "\\\\?"); pattern = pattern.replaceAll("\\*", "\\\\*"); pattern = pattern.replaceAll("\\.", "\\\\."); pattern = pattern.replaceAll("\\[", "\\\\["); pattern = pattern.replaceAll("\\)", "\\\\)"); pattern = pattern.replaceAll("\\(", "\\\\("); pattern = pattern.replaceAll("\\{", "\\\\{"); pattern = pattern.replaceAll("\\+", "\\\\+"); pattern = pattern.replaceAll("\\^", "\\\\^"); pattern = pattern.replaceAll("\\|", "\\\\|"); // regular expressions to substitute SQL wildcards with regex wildcards // Use look behind operators to replace "%" which is not preceded by "\" with ".*" pattern = pattern.replaceAll("(?<!\\\\)%", ".*"); // Use look behind operators to replace "_" which is not preceded by "\" with "." pattern = pattern.replaceAll("(?<!\\\\)_", "."); // replace "\%" with "%" pattern = pattern.replaceAll("\\\\%", "%"); // replace "\_" with "_" pattern = pattern.replaceAll("\\\\_", "_"); // regex requires ^ and $ if pattern must start at start and end at end of string as like requires. pattern = "^" + pattern + "$"; return pattern; } public static boolean isLob(DatabaseField field) { int sqlType = field.sqlType; if (sqlType == DatabaseField.NULL_SQL_TYPE) { Class type = field.getType(); if (type != null) { return ClassConstants.BLOB.equals(type) || ClassConstants.CLOB.equals(type); } else { return false; } } else { return DatabaseAccessor.isBlob(sqlType) || DatabaseAccessor.isClob(sqlType); } } public static boolean hasLob(Collection<DatabaseField> fields) { for (DatabaseField field : fields) { if (isLob(field)) { return true; } } return false; } public static long timeWithRoundMiliseconds() { return new Date().getTime() / 1000 * 1000; } }