| /* |
| * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 1998, 2018 IBM Corporation. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // 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(); |
| |
| private static java.time.format.DateTimeFormatter dateTimeFormatter; |
| |
| // 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; |
| } |
| |
| public static java.time.format.DateTimeFormatter getDefaultDateTimeFormatter() { |
| if (dateTimeFormatter == null) { |
| dateTimeFormatter = new java.time.format.DateTimeFormatterBuilder() |
| .append(new java.time.format.DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .parseLenient() |
| .optionalStart() |
| .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE) |
| .optionalEnd() |
| .optionalStart() |
| .appendLiteral('T') |
| .optionalEnd() |
| .optionalStart() |
| .append(java.time.format.DateTimeFormatter.ISO_LOCAL_TIME) |
| .optionalEnd() |
| .toFormatter()) |
| .optionalStart() |
| .appendOffsetId() |
| .optionalStart() |
| .appendLiteral('[') |
| .parseCaseSensitive() |
| .appendZoneRegionId() |
| .appendLiteral(']') |
| .toFormatter(); |
| } |
| return dateTimeFormatter; |
| } |
| |
| /** |
| * 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<>(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 originalVector - 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 timestamp - 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, 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 date - 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 millis - 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 millis - 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 |
| * YYYY/MM/DD HH:MM:SS.NNNNNNN |
| * YYYY/MM/DD HH:MM:SS.NNNNNNN+Z |
| * |
| * @param timestampString - string representation of timestamp |
| * @return - timestamp representation of string |
| */ |
| 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 = 0, month = 0, day = 0; |
| int hour = 0, minute = 0, second = 0, nanos = 0; |
| 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. |
| } |
| } catch (NumberFormatException exception) { |
| throw ConversionException.incorrectTimestampFormat(timestampString); |
| } |
| |
| boolean containsNanos = timestampString.indexOf('.') > -1; |
| if (containsNanos) { |
| try { |
| String nanoToken = timestampStringTokenizer.nextToken(); |
| nanos = Integer.parseInt(nanoToken); |
| for (int times = 0; times < (9 - nanoToken.length()); times++) { |
| nanos = nanos * 10; |
| } |
| } catch (NumberFormatException exception) { |
| throw ConversionException.incorrectTimestampFormat(timestampString); |
| } |
| } |
| |
| // Java returns the month in terms of 0 - 11 instead of 1 - 12. |
| return timestampFromYearMonthDateHourMinuteSecondNanos( |
| year, month - 1, day, hour, minute, second, nanos |
| ); |
| } |
| |
| /** |
| * 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; |
| } |
| } |