org.eclipse.persistence.internal.helper.Helper Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2022 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:
*
* Purpose: 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 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 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 version(String version) {
ArrayList 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= 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 list1, Listlist2) {
int n = Math.max(list1.size(), list2.size());
int res = 0;
for(int i=0; i 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;
}
/**
* Copy an array of boolean to a new array
* @param original
* @return
*/
public static boolean[] copyBooleanArray(boolean[] original){
if (original == null){
return null;
}
int length = original.length;
boolean[] copy = new boolean[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, (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 null
element found in the specified
* Vector
starting the search at the starting index specified.
* Return an int >= 0 and less than size if a null
element was found.
* Return -1 if a null
element was not found.
* This is needed in jdk1.1, where Vector.contains(Object)
* for a null
element will result in a NullPointerException
....
*/
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
*/
@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 = 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("(? fields) {
for (DatabaseField field : fields) {
if (isLob(field)) {
return true;
}
}
return false;
}
public static long timeWithRoundMiliseconds() {
return new Date().getTime() / 1000 * 1000;
}
}