com.tangosol.util.Base Maven / Gradle / Ivy
Show all versions of coherence Show documentation
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.util;
import com.oracle.coherence.common.base.Blocking;
import com.oracle.coherence.common.base.Hasher;
import com.oracle.coherence.common.util.CommonMonitor;
import com.tangosol.coherence.config.Config;
import com.tangosol.io.ReadBuffer;
import com.tangosol.net.CacheFactory;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.rmi.RemoteException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TimeZone;
import java.util.concurrent.ThreadLocalRandom;
/**
* Base class for providing standard functionality.
*
* @author cp 2000.08.02
*/
public abstract class Base
{
// ----- debugging support: expression evaluation ----------------------
/**
* Display the value of a boolean expression.
*
* @param fVal the boolean value
*/
public static void trace(boolean fVal)
{
traceImpl(String.valueOf(fVal));
}
/**
* Display the value of a char expression.
*
* @param chVal the char value
*/
public static void trace(char chVal)
{
traceImpl(String.valueOf(chVal));
}
/**
* Display the value of an int expression.
*
* @param nVal the int value
*/
public static void trace(int nVal)
{
traceImpl(String.valueOf(nVal));
}
/**
* Display the value of a long expression.
*
* @param lVal the long value
*/
public static void trace(long lVal)
{
traceImpl(String.valueOf(lVal));
}
/**
* Display the value of a float expression.
*
* @param flVal the float value
*/
public static void trace(float flVal)
{
traceImpl(String.valueOf(flVal));
}
/**
* Display the value of a double expression.
*
* @param dflVal the double value
*/
public static void trace(double dflVal)
{
traceImpl(String.valueOf(dflVal));
}
/**
* Display the value of a byte array expression.
*
* @param ab the byte array value
*/
public static void trace(byte[] ab)
{
if (ab == null)
{
traceImpl(null);
}
else
{
traceImpl("length=" + ab.length + ", binary=" + toHexEscape(ab));
}
}
/**
* Display the value of a String expression.
*
* @param sVal the String value
*/
public static void trace(String sVal)
{
traceImpl(sVal == null ? "null" : toQuotedStringEscape(sVal));
}
/**
* Display the value of an Object expression.
*
* @param oVal the Object value
*/
public static void trace(Object oVal)
{
traceImpl(String.valueOf(oVal));
}
/**
* Internal implementation for trace methods.
*
* @param sVal the Object value
*/
private static void traceImpl(String sVal)
{
String sExpr = getExpression("trace");
out((sExpr == null ? "?" : sExpr) + '=' + (sVal == null ? "null" : sVal));
}
// ----- assertion support ----------------------------------------------
/**
* Definite assertion failure.
*
* @return null
*/
public static RuntimeException azzert()
{
azzert(false, "Assertion: Unexpected execution of code at:");
return null;
}
/**
* Test an assertion.
*
* @param f the boolean to be checked
*/
public static void azzert(boolean f)
{
if (!f)
{
azzertFailed(null);
}
}
/**
* Test an assertion, and print the specified message if the assertion
* fails.
*
* @param f the boolean to be checked
* @param s the assertion message
*/
public static void azzert(boolean f, String s)
{
if (!f)
{
azzertFailed(s);
}
}
/**
* Throw an assertion exception.
*
* @param sMsg the assertion message
*/
public static void azzertFailed(String sMsg)
{
if (sMsg == null)
{
// default assertion message
sMsg = "Assertion failed:";
// try to load the source to print out the exact assertion
String sSource = getExpression("azzert");
if (sSource != null)
{
sMsg += " " + sSource;
}
}
// display the assertion
err(sMsg);
// display the code that caused the assertion
String sStack = getStackTrace();
err(sStack.substring(sStack.indexOf('\n', sStack.lastIndexOf(".azzert(")) + 1));
throw new AssertionException(sMsg);
}
/**
* Get the source code expression from the method that called the
* specified method.
*
* @param sMethod the first method on the stack after the method whose
* source code is desired
*
* @return null on any failure, otherwise the expression
*/
private static String getExpression(String sMethod)
{
StackFrame[] aframe = getStackFrames();
int i = 0;
// find method in call stack
while (!aframe[i].getMethodName().equals(sMethod))
{
++i;
}
// find calling method
while (aframe[i].getMethodName().equals(sMethod))
{
++i;
}
// get source line
String sLine = aframe[i].getLine();
if (sLine != null)
{
int of = sLine.indexOf(sMethod);
if (of >= 0)
{
// this is unavoidably imprecise but will usually work correctly
int ofLParen = sLine.indexOf('(', of);
int ofRParen = sLine.lastIndexOf(')');
if (ofLParen > of && ofRParen > ofLParen)
{
return sLine.substring(ofLParen + 1, ofRParen);
}
}
}
return null;
}
// ----- exception support ----------------------------------------------
/**
* Convert the passed exception to a RuntimeException if necessary.
*
* @param e any Throwable object
*
* @return a RuntimeException
*/
public static RuntimeException ensureRuntimeException(Throwable e)
{
return ensureRuntimeException(e, null);
}
/**
* Convert the passed exception to a RuntimeException if necessary.
*
* @param e any Throwable object
* @param s an additional description
*
* @return a RuntimeException
*/
public static RuntimeException ensureRuntimeException(Throwable e, String s)
{
if (e instanceof RuntimeException && (s == null || s.equals(e.getMessage())))
{
return (RuntimeException) e;
}
else
{
return WrapperException.ensure(e, s);
}
}
/**
* Unwind the wrapper (runtime) exception to extract the original
*
* @param e Runtime exception (wrapper)
*
* @return an original wrapped exception
*/
public static Throwable getOriginalException(RuntimeException e)
{
Throwable t = e;
while (true)
{
if (t instanceof WrapperException)
{
t = ((WrapperException) t).getOriginalException();
}
else if (t instanceof RemoteException)
{
t = ((RemoteException) t).detail;
}
// we do not want to have runtime dependency on j2ee classes
else if (t.getClass().getName().equals("javax.ejb.EJBException"))
{
try
{
t = (Throwable) ClassHelper.invoke(t,
"getCausedByException", ClassHelper.VOID);
}
catch (Exception x)
{
return t;
}
}
else
{
return t;
}
}
}
// ----- printed output support -----------------------------------------
/**
* Prints a blank line.
*/
public static void out()
{
s_out.println();
}
/**
* Prints the passed Object.
*
* @param o the Object to print.
*/
public static void out(Object o)
{
s_out.println(String.valueOf(o));
}
/**
* Prints the passed String value.
*
* @param s the String to print.
*/
public static void out(String s)
{
s_out.println(s);
}
/**
* Prints the passed class information.
*
* @param clz the class object to print.
*/
public static void out(Class clz)
{
s_out.println(toString(clz));
}
/**
* Prints the passed exception information.
*
* @param e the Throwable object to print.
*/
public static void out(Throwable e)
{
s_out.println(printStackTrace(e));
}
/**
* Prints a blank line to the trace Writer.
*/
public static void err()
{
s_err.println();
}
/**
* Prints the passed Object to the trace Writer.
*
* @param o the Object to print.
*/
public static void err(Object o)
{
s_err.println(String.valueOf(o));
}
/**
* Prints the passed String value to the trace Writer.
*
* @param s the String to print.
*/
public static void err(String s)
{
s_err.println(s);
}
/**
* Prints the passed class information to the trace Writer.
*
* @param clz the class object to print.
*/
public static void err(Class clz)
{
s_err.println(toString(clz));
}
/**
* Prints the passed exception information to the trace Writer.
*
* @param e the Throwable object to print.
*/
public static void err(Throwable e)
{
s_err.println(printStackTrace(e));
}
/**
* Prints a blank line to the log.
*/
public static void log()
{
s_log.println();
if (s_fEchoLog)
{
s_out.println();
}
}
/**
* Prints the passed Object to the log.
*
* @param o the Object to print.
*/
public static void log(Object o)
{
log(String.valueOf(o));
}
/**
* Prints the passed String value to the log.
*
* @param s the String to print.
*/
public static void log(String s)
{
s_log.println(s);
if (s_fEchoLog)
{
s_out.println(s);
}
}
/**
* Prints the passed class information to the log.
*
* @param clz the class object to print.
*/
public static void log(Class clz)
{
log(toString(clz));
}
/**
* Prints the passed exception information to the log.
*
* @param e the Throwable object to print.
*/
public static void log(Throwable e)
{
String s = printStackTrace(e);
s_log.println(s);
if (s_fEchoLog)
{
s_out.println(s);
}
}
// ----- class loader support --------------------------------------------
/**
* Obtain a non-null ClassLoader.
*
* @param loader a ClassLoader (may be null)
*
* @return the passed ClassLoader (if not null), or the ContextClassLoader
*/
public static ClassLoader ensureClassLoader(ClassLoader loader)
{
return loader == null ? getContextClassLoader() : loader;
}
/**
* Try to determine the ClassLoader that supports the current context.
*
* @return a ClassLoader to use for the current context
*/
public static ClassLoader getContextClassLoader()
{
return getContextClassLoader(null);
}
/**
* Try to determine the ClassLoader that supports the current context.
*
* @param o the calling object, or any object out of the application
* that is requesting the class loader
*
* @return a ClassLoader to use for the current context
*/
public static ClassLoader getContextClassLoader(Object o)
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null)
{
if (o != null)
{
loader = o.getClass().getClassLoader();
}
if (loader == null)
{
loader = Base.class.getClassLoader();
if (loader == null)
{
loader = ClassLoader.getSystemClassLoader();
}
}
}
return loader;
}
// ----- stack trace support --------------------------------------------
/**
* Get the StackFrame information for the caller of the current method.
*
* @return the StackFrame information for the caller of the current method
*/
public static StackFrame getCallerStackFrame()
{
// display the code that caused the assertion
String sStack = getStackTrace();
int of = sStack.indexOf('\n', sStack.lastIndexOf(".getCallerStackFrame(")) + 1;
of = sStack.indexOf('\n', of) + 1;
try
{
return new StackFrame(sStack.substring(of, sStack.indexOf('\n', of)));
}
catch (RuntimeException e)
{
return StackFrame.UNKNOWN;
}
}
/**
* Get the StackFrame information for the current method.
*
* @return the StackFrame information for the current method
*/
public static StackFrame getStackFrame()
{
// display the code that caused the assertion
String sStack = getStackTrace();
int of = sStack.indexOf('\n', sStack.lastIndexOf(".getStackFrame(")) + 1;
try
{
return new StackFrame(sStack.substring(of, sStack.indexOf('\n', of)));
}
catch (RuntimeException e)
{
return StackFrame.UNKNOWN;
}
}
/**
* Iterate the StackFrame information for all callers, going from the
* inside outwards, and starting with the caller of this method.
*
* @return an Iterator of StackFrames
*/
public static StackFrame[] getStackFrames()
{
String sStack = getStackTrace();
LineNumberReader reader = new LineNumberReader(new StringReader(
sStack.substring(sStack.indexOf('\n', sStack.lastIndexOf(
".getStackFrames(")) + 1) ));
try
{
ArrayList list = new ArrayList();
String sLine = reader.readLine();
while (sLine != null && sLine.length() > 0)
{
StackFrame frame = StackFrame.UNKNOWN;
try
{
frame = new StackFrame(sLine);
}
catch (RuntimeException e) {}
list.add(frame);
sLine = reader.readLine();
}
return (StackFrame[]) list.toArray(new StackFrame[list.size()]);
}
catch (IOException e)
{
throw ensureRuntimeException(e);
}
}
/**
* Build a stack trace for the current thread.
*
* @return a String containing a printable stack trace
*/
public static String getStackTrace()
{
String s = getStackTrace(new Exception());
return s.substring(s.indexOf('\n', s.indexOf(".getStackTrace(")) + 1);
}
/**
* Build a stack trace for the passed exception that does not include
* the exception description itself.
*
* @param e a Throwable object that contains stack trace information
*
* @return a String containing a printable stack trace
*/
public static String getStackTrace(Throwable e)
{
String s = printStackTrace(e);
if (s.startsWith(e.getClass().getName()))
{
s = s.substring(s.indexOf('\n') + 1);
}
return s;
}
/**
* Extract a throwable's message, and all causal messages.
*
* @param t the throwable
* @param sDelim the delimiter to include between messages
*
* @return the concatenated messages
*/
public static String getDeepMessage(Throwable t, String sDelim)
{
StringBuilder sb = new StringBuilder();
String sMsgLast = null;
for (; t != null; t = t.getCause())
{
String sMsg = t.getMessage();
if (!equals(sMsgLast, sMsg))
{
if (sMsgLast != null)
{
sb.append(sDelim);
}
sb.append(sMsg);
sMsgLast = sMsg;
}
}
return sb.toString();
}
/**
* Build a stack trace for the passed exception.
*
* @param e a Throwable object that contains stack trace information
*
* @return a String containing a printable stack trace
*/
public static String printStackTrace(Throwable e)
{
try
{
try (Writer writerRaw = new CharArrayWriter(1024))
{
try (PrintWriter writerOut = new PrintWriter(writerRaw))
{
e.printStackTrace(writerOut);
}
writerRaw.flush();
return writerRaw.toString();
}
}
catch (IOException eIO)
{
throw ensureRuntimeException(eIO);
}
}
/**
* Ensure the specified Number is a BigDecimal value or convert it into a
* new BigDecimal object.
*
* @param num a Number object
*
* @return a BigDecimal object that is equal to the passed in Number
*/
public static BigDecimal ensureBigDecimal(Number num)
{
return num instanceof BigDecimal ? (BigDecimal) num :
num instanceof BigInteger ? new BigDecimal((BigInteger) num) :
new BigDecimal(num.doubleValue());
}
/**
* A class that provides "stack frame" information from a line of a stack
* trace.
*/
public static class StackFrame
{
/**
* Construct a StackFrame object from a line of a stack trace.
*
* @param sExcept a line of a stack trace in the format used by the
* reference implementation of the JVM
*
* @throws RuntimeException if there is a runtime error
*/
public StackFrame(String sExcept)
{
try
{
// sExcept = " at com.tangosol.util.Test.main(Test.java:23)"
int of = sExcept.indexOf('(');
String sLeft = sExcept.substring(sExcept.lastIndexOf(' ', of) + 1, of);
String sRight = sExcept.substring(of + 1, sExcept.lastIndexOf(')'));
// sLeft = "com.tangosol.util.Test.main"
of = sLeft.lastIndexOf('.');
String sClass = sLeft.substring(0, of);
String sMethod = sLeft.substring(of + 1);
// sRight = "Test.java:23"
String sFile = "unknown";
int nLine = 0;
of = sRight.lastIndexOf(':');
if (of >= 0)
{
sFile = sRight.substring(0, of);
try
{
nLine = Integer.parseInt(sRight.substring(of + 1));
}
catch (RuntimeException e) {}
}
init(sFile, sClass, sMethod, nLine);
}
catch (RuntimeException e)
{
out("Exception constructing StackFrame for \"" + sExcept + "\"");
throw e;
}
}
/**
* Construct a StackFrame object from its constituent data members.
*
* @param sFile the source file name (e.g. Test.java)
* @param sClass the fully qualified class name (e.g. pkg.Test$1)
* @param sMethod the method name (e.g. main)
* @param nLine the line number (e.g. 17) or 0 if unknown
*/
public StackFrame(String sFile, String sClass, String sMethod, int nLine)
{
init(sFile, sClass, sMethod, nLine);
}
/**
* Initialize the fields of the StackFrame object.
*
* @param sFile the source file name (e.g. Test.java)
* @param sClass the fully qualified class name (e.g. pkg.Test$1)
* @param sMethod the method name (e.g. main)
* @param nLine the line number (e.g. 17) or 0 if unknown
*/
protected void init(String sFile, String sClass, String sMethod, int nLine)
{
m_sFile = sFile;
m_sClass = sClass;
m_sMethod = sMethod;
m_nLine = nLine;
}
/**
* @return the source file name (e.g. Test.java)
*/
public String getFileName()
{
return m_sFile;
}
/**
* @return the fully qualified class name (e.g. pkg.Test$1)
*/
public String getClassName()
{
return m_sClass;
}
/**
* @return the short class name (e.g. Test.1)
*/
public String getShortClassName()
{
String sClass = m_sClass;
sClass = sClass.substring(sClass.lastIndexOf('.') + 1);
return sClass.replace('$', '.');
}
/**
* @return the method name (e.g. main)
*/
public String getMethodName()
{
return m_sMethod;
}
/**
* @return the line number (e.g. 17) or 0 if unknown
*/
public int getLineNumber()
{
return m_nLine;
}
/**
* @return the line of source code if possible or null
*/
public String getLine()
{
int nLine = getLineNumber();
if (nLine == 0)
{
return null;
}
try
{
String sClass = getClassName();
int of = sClass.indexOf('$');
if (of >= 0)
{
sClass = sClass.substring(0, of);
}
InputStream stream = Class.forName(sClass, false,
getContextClassLoader())
.getClassLoader().getResourceAsStream(
sClass.replace('.', '/') + ".java");
if (stream != null)
{
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(stream)))
{
String sLine = null;
for (int i = 0; i < nLine; ++i)
{
sLine = reader.readLine();
}
return sLine;
}
}
}
catch (Throwable t)
{
}
return null;
}
/**
* @return a String representation of the StackFrame
*/
public String toString()
{
int nLine = getLineNumber();
String sLine = nLine == 0 ? "?" : "" + nLine;
return getClassName() + '.' + getMethodName() + '('
+ getFileName() + ':' + sLine + ')';
}
/**
* @return a short String representation of the StackFrame
*/
public String toShortString()
{
int nLine = getLineNumber();
String sLine = nLine == 0 ? "?" : "" + nLine;
return getShortClassName() + '.' + getMethodName()
+ " [" + sLine + ']';
}
public static final StackFrame UNKNOWN = new StackFrame(
"unknown", "unknown", "unknown", 0);
private String m_sFile;
private String m_sClass;
private String m_sMethod;
private int m_nLine;
}
// ----- thread factory support -----------------------------------------
/**
* Create a Thread with the specified group, runnable, and name, using
* the configured ThreadFactory, as specified by the
* tangosol.coherence.threadfactory system property.
*
* @param group (optional) the thread's thread group
* @param runnable (optional) the thread's runnable
* @param sName (optional) the thread's name
*
* @return a new thread using the specified parameters
*/
public static Thread makeThread(ThreadGroup group, Runnable runnable,
String sName)
{
ThreadFactory factory = s_threadFactory;
if (factory == null)
{
return sName == null ? new Thread(group, runnable)
: new Thread(group, runnable, sName);
}
else
{
return factory.makeThread(group, runnable, sName);
}
}
/**
* Return the configured thread factory.
*
* @return the configured thread factory, or null if none has been
* configured.
*/
public static ThreadFactory getThreadFactory()
{
return s_threadFactory;
}
/**
* Instantiate the configured thread factory.
*
* @return the configured thread factory, or null if none has been configured.
*/
private static ThreadFactory instantiateThreadFactory()
{
String sFactory = AccessController.doPrivileged(
(PrivilegedAction) () -> Config.getProperty("coherence.threadfactory"));
if (sFactory == null)
{
return null;
}
try
{
return (ThreadFactory) Class.forName(sFactory).newInstance();
}
catch (Exception e)
{
throw ensureRuntimeException(e);
}
}
// ----- thread sleep/wait support --------------------------------------
/**
* Convenience method for {@link java.lang.Thread#sleep(long)}.
*
* If the thread is interrupted before the sleep time expires, a
* RuntimeException is thrown and the thread's interrupt state is set.
*
* @param cMillis the maximum time to wait in milliseconds
*/
public static void sleep(long cMillis)
{
try
{
while (cMillis > 0)
{
long lStart = getSafeTimeMillis();
Blocking.sleep(cMillis);
// safe time ensures time only moves forward
cMillis -= (getSafeTimeMillis() - lStart);
}
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
throw ensureRuntimeException(e);
}
}
/**
* Convenience method for {@link java.lang.Object#wait(long)}.
*
* If the thread is interrupted before being notified or the wait time
* expires, a RuntimeException is thrown and the thread's interrupt state is
* set.
*
* @param o the Object to wait for
* @param cMillis the maximum time to wait in milliseconds
*/
public static void wait(Object o, long cMillis)
{
try
{
Blocking.wait(o, cMillis);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
throw ensureRuntimeException(e);
}
}
// ----- common monitor support -----------------------------------------
/**
* Return the common monitor associated with the specified integer value.
*
* @param i the common monitor identifier
*
* @return the associated monitor
*
* @see CommonMonitor
*/
public static CommonMonitor getCommonMonitor(int i)
{
return CommonMonitor.getCommonMonitor(i);
}
/**
* Return the common monitor associated with the specified long value.
*
* @param l the common monitor identifier
*
* @return the associated monitor
*
* @see CommonMonitor
*/
public static CommonMonitor getCommonMonitor(long l)
{
return CommonMonitor.getCommonMonitor(l);
}
/**
* Return the common monitor associated with the specified object based on
* its identity hashCode.
*
* @param o the object to obtain a common monitor for
*
* @return the associated monitor
*
* @see CommonMonitor
*/
public static CommonMonitor getCommonMonitor(Object o)
{
return CommonMonitor.getCommonMonitor(o);
}
// ----- class formatting support ---------------------------------------
/**
* Formats Class information for debug output purposes.
*
* @param clz the Class to print information for
*
* @return a String describing the Class in detail
*/
public static String toString(Class clz)
{
if (clz.isPrimitive())
{
return clz.toString();
}
else if (clz.isArray())
{
return "Array of " + toString(clz.getComponentType());
}
else if (clz.isInterface())
{
return toInterfaceString(clz, "");
}
else
{
return toClassString(clz, "");
}
}
/**
* Formats Class information for debug output purposes.
*
* @param clz the Class to print information for
* @param sIndent the indentation to precede each line of output
*
* @return a String describing the Class in detail
*/
private static String toClassString(Class clz, String sIndent)
{
StringBuilder sb = new StringBuilder();
sb.append(sIndent)
.append("Class ")
.append(clz.getName())
.append(" (")
.append(toString(clz.getClassLoader()))
.append(')');
sIndent += " ";
Class[] aclz = clz.getInterfaces();
for (int i = 0, c = aclz.length; i < c; ++i)
{
sb.append('\n')
.append(toInterfaceString(aclz[i], sIndent));
}
clz = clz.getSuperclass();
if (clz != null)
{
sb.append('\n')
.append(toClassString(clz, sIndent));
}
return sb.toString();
}
/**
* Formats interface information for debug output purposes.
*
* @param clz the interface Class to print information for
* @param sIndent the indentation to precede each line of output
*
* @return a String describing the interface Class in detail
*/
private static String toInterfaceString(Class clz, String sIndent)
{
StringBuilder sb = new StringBuilder();
sb.append(sIndent)
.append("Interface ")
.append(clz.getName())
.append(" (")
.append(toString(clz.getClassLoader()))
.append(')');
Class[] aclz = clz.getInterfaces();
for (int i = 0, c = aclz.length; i < c; ++i)
{
clz = aclz[i];
sb.append('\n')
.append(toInterfaceString(clz, sIndent + " "));
}
return sb.toString();
}
/**
* Format a description for the specified ClassLoader object.
*
* @param loader the ClassLoader instance (or null)
*
* @return a String description of the ClassLoader
*/
private static String toString(ClassLoader loader)
{
if (loader == null)
{
return "System ClassLoader";
}
return "ClassLoader class=" + loader.getClass().getName()
+ ", hashCode=" + loader.hashCode();
}
// ----- formatting support: decimal values -----------------------------
/**
* Returns true if the passed character is a decimal digit.
*
* @param ch The character to check
*
* @return {@code true} if the passed character is a decimal digit
*/
public static boolean isDecimal(char ch)
{
return (ch >= '0') && (ch <= '9');
}
/**
* Returns the integer value of a decimal digit.
*
* @param ch The character to convert
*
* @return the integer value of a decimal digit
*/
public static int decimalValue(char ch)
{
if ((ch >= '0') && (ch <= '9'))
{
return ch - '0';
}
else
{
throw new IllegalArgumentException("Character \"" + ch
+ "\" is not a valid decimal digit.");
}
}
/**
* Calculate the number of decimal digits needed to display the passed
* value.
*
* @param n the value
*
* @return the number of decimal digits needed to display the value
*/
public static int getMaxDecDigits(int n)
{
int cDigits = 0;
do
{
cDigits += 1;
n /= 10;
}
while (n != 0);
return cDigits;
}
/**
* Format the passed non-negative integer as a fixed-length decimal string.
*
* @param n the value
* @param cDigits the length of the resulting decimal string
*
* @return the decimal value formatted to the specified length string
*/
public static String toDecString(int n, int cDigits)
{
char[] ach = new char[cDigits];
while (cDigits > 0)
{
ach[--cDigits] = (char) ('0' + n % 10);
n /= 10;
}
return new String(ach);
}
/**
* Return the smallest value that is not less than the first argument and
* is a multiple of the second argument. Effectively rounds the first
* argument up to a multiple of the second.
*
* @param lMin the smallest value to return
* @param lMultiple the return value will be a multiple of this argument
*
* @return the smallest multiple of the second argument that is not less
* than the first
*/
public static long pad(long lMin, long lMultiple)
{
return ((lMin + lMultiple - 1) / lMultiple) * lMultiple;
}
// ----- formatting support: octal values -------------------------------
/**
* Returns true if the passed character is an octal digit.
*
* @param ch The character to check
*
* @return {@code true} if the passed character is an octal digit
*/
public static boolean isOctal(char ch)
{
return (ch >= '0') && (ch <= '7');
}
/**
* Returns the integer value of an octal digit.
*
* @param ch The character to convert
*
* @return the integer value of an octal digit
*/
public static int octalValue(char ch)
{
if ((ch >= '0') && (ch <= '7'))
{
return ch - '0';
}
else
{
throw new IllegalArgumentException("Character \"" + ch + "\" is not a valid octal digit.");
}
}
// ----- formatting support: hex values ---------------------------------
/**
* Returns true if the passed character is a hexadecimal digit.
*
* @param ch The character to check
*
* @return {@code true} if the passed character is a hexadecimal digit
*/
public static boolean isHex(char ch)
{
return ((ch >= '0') && (ch <= '9'))
|| ((ch >= 'A') && (ch <= 'F'))
|| ((ch >= 'a') && (ch <= 'f'));
}
/**
* Returns the integer value of a hexadecimal digit.
*
* @param ch The character to convert
*
* @return the integer value
*/
public static int hexValue(char ch)
{
if ((ch >= '0') && (ch <= '9'))
{
return ch -'0';
}
else if ((ch >= 'A') && (ch <= 'F'))
{
return ch - 'A' + 10;
}
else if ((ch >= 'a') && (ch <= 'f'))
{
return ch - 'a' + 10;
}
else
{
throw new IllegalArgumentException("Character \"" + ch + "\" is not a valid hexadecimal digit.");
}
}
/**
* Calculate the number of hex digits needed to display the passed value.
*
* @param n the value
*
* @return the number of hex digits needed to display the value
*/
public static int getMaxHexDigits(int n)
{
int cDigits = 0;
do
{
cDigits++;
n >>>= 4;
}
while (n != 0);
return cDigits;
}
/**
* Format the passed integer as a fixed-length hex string.
*
* @param n the value
* @param cDigits the length of the resulting hex string
*
* @return the hex value formatted to the specified length string
*/
public static String toHexString(int n, int cDigits)
{
char[] ach = new char[cDigits];
while (cDigits > 0)
{
ach[--cDigits] = HEX[n & 0x0F];
n >>>= 4;
}
return new String(ach);
}
/**
* Convert a byte to the hex sequence of 2 hex digits.
*
* @param b the byte
*
* @return the hex sequence
*/
public static String toHex(int b)
{
int n = b & 0xFF;
char[] ach = new char[2];
ach[0] = HEX[n >> 4];
ach[1] = HEX[n & 0x0F];
return new String(ach);
}
/**
* Convert a byte array to the hex sequence of 2 hex digits per byte.
*
* This is a replacement for Text.toString(char[]).
*
* @param ab the byte array
*
* @return the hex sequence
*/
public static String toHex(byte[] ab)
{
int cb = ab.length;
char[] ach = new char[cb * 2];
for (int ofb = 0, ofch = 0; ofb < cb; ++ofb)
{
int n = ab[ofb] & 0xFF;
ach[ofch++] = HEX[n >> 4];
ach[ofch++] = HEX[n & 0x0F];
}
return new String(ach);
}
/**
* Convert a byte to a hex sequence of '0' + 'x' + 2 hex digits.
*
* @param b the byte
*
* @return the hex sequence
*/
public static String toHexEscape(byte b)
{
int n = b & 0xFF;
char[] ach = new char[4];
ach[0] = '0';
ach[1] = 'x';
ach[2] = HEX[n >> 4];
ach[3] = HEX[n & 0x0F];
return new String(ach);
}
/**
* Convert a byte array to a hex sequence of '0' + 'x' + 2 hex digits
* per byte.
*
* @param ab the byte array
*
* @return the hex sequence
*/
public static String toHexEscape(byte[] ab)
{
return toHexEscape(ab, 0, ab.length);
}
/**
* Convert a byte array to a hex sequence of '0' + 'x' + 2 hex digits
* per byte.
*
* @param ab the byte array
* @param of the offset into array
* @param cb the number of bytes to convert
*
* @return the hex sequence
*/
public static String toHexEscape(byte[] ab, int of, int cb)
{
char[] ach = new char[2 + cb * 2];
ach[0] = '0';
ach[1] = 'x';
for (int ofb = of, ofch = 2, ofStop = of + cb; ofb < ofStop; ++ofb)
{
int n = ab[ofb] & 0xFF;
ach[ofch++] = HEX[n >> 4];
ach[ofch++] = HEX[n & 0x0F];
}
return new String(ach);
}
/**
* Convert a ByteSequence to a hex sequence of '0' + 'x' + 2 hex digits
* per byte.
*
* @param seq the ByteSequence
* @param of the offset into the byte sequence
* @param cb the number of bytes to convert
*
* @return the hex sequence
*
* @since Coherence 3.7
*/
public static String toHexEscape(ByteSequence seq, int of, int cb)
{
if (cb > 0)
{
char[] ach = new char[2 + cb * 2];
ach[0] = '0';
ach[1] = 'x';
for (int ofb = of, ofch = 2, ofStop = of + cb; ofb < ofStop; ++ofb)
{
int n = seq.byteAt(ofb) & 0xFF;
ach[ofch++] = HEX[n >> 4];
ach[ofch++] = HEX[n & 0x0F];
}
return new String(ach);
}
else
{
return "";
}
}
/**
* Convert a byte array to a hex dump.
*
* This is a replacement for Text.toString(byte[] ab, int cBytesPerLine).
*
* @param ab the byte array to format as a hex string
* @param cBytesPerLine the number of bytes to display on a line
*
* @return a multi-line hex dump
*/
public static String toHexDump(byte[] ab, int cBytesPerLine)
{
int cb = ab.length;
if (cb == 0)
{
return "";
}
// calculate number of digits required to show offset
int cDigits = 0;
int cbTemp = cb - 1;
do
{
cDigits += 2;
cbTemp /= 0x100;
}
while (cbTemp > 0);
// calculate number and size of lines
int cLines = (cb + cBytesPerLine - 1) / cBytesPerLine;
int cCharsPerLine = cDigits + 4 * cBytesPerLine + 5;
// pre-allocate buffer to build hex dump
int cch = cLines * cCharsPerLine;
char[] ach = new char [cch];
// offsets within each line for formatting stuff
int ofColon = cDigits;
int ofLF = cCharsPerLine - 1;
// offsets within each line for data
int ofHexInLine = ofColon + 3;
int ofCharInLine = ofLF - cBytesPerLine;
int ofByte = 0;
int ofLine = 0;
for (int iLine = 0; iLine < cLines; ++iLine)
{
// format offset
int nOffset = ofByte;
int ofDigit = ofLine + cDigits;
for (int i = 0; i < cDigits; ++i)
{
ach[--ofDigit] = HEX[nOffset & 0x0F];
nOffset >>= 4;
}
// formatting
int ofFmt = ofLine + cDigits;
ach[ofFmt++] = ':';
ach[ofFmt++] = ' ';
ach[ofFmt ] = ' ';
// format data
int ofHex = ofLine + ofHexInLine;
int ofChar = ofLine + ofCharInLine;
for (int i = 0; i < cBytesPerLine; ++i)
{
try
{
int n = ab[ofByte++] & 0xFF;
ach[ofHex++ ] = HEX[(n & 0xF0) >> 4];
ach[ofHex++ ] = HEX[(n & 0x0F) ];
ach[ofHex++ ] = ' ';
ach[ofChar++] = (n < 32 ? '.' : (char) n);
}
catch (ArrayIndexOutOfBoundsException e)
{
ach[ofHex++ ] = ' ';
ach[ofHex++ ] = ' ';
ach[ofHex++ ] = ' ';
ach[ofChar++] = ' ';
}
}
// spacing and newline
ach[ofHex ] = ' ';
ach[ofChar] = '\n';
ofLine += cCharsPerLine;
}
return new String(ach, 0, cch-1);
}
/**
* Parse the passed String of hexadecimal characters into a binary
* value. This implementation allows the passed String to be prefixed
* with "0x".
*
* @param s the hex String to evaluate
*
* @return the byte array value of the passed hex String
*/
public static byte[] parseHex(String s)
{
char[] ach = s.toCharArray();
int cch = ach.length;
if (cch == 0)
{
return new byte[0];
}
if ((cch & 0x1) != 0)
{
throw new IllegalArgumentException("invalid length hex string");
}
int ofch = 0;
if (ach[1] == 'x' || ach[1] == 'X')
{
ofch = 2;
}
int cb = (cch - ofch) / 2;
byte[] ab = new byte[cb];
for (int ofb = 0; ofb < cb; ++ofb)
{
ab[ofb] = (byte) (parseHex(ach[ofch++]) << 4 | parseHex(ach[ofch++]));
}
return ab;
}
/**
* Return the integer value of a hexadecimal digit.
*
* @param ch the hex character to evaluate
*
* @return the integer value of the passed hex character
*/
public static int parseHex(char ch)
{
switch (ch)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return ch - '0';
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return ch - 'A' + 0x0A;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return ch - 'a' + 0x0A;
default:
throw new IllegalArgumentException("illegal hex char: " + ch);
}
}
// ----- formatting support: double -------------------------------------
/**
* Format a double value as a String.
*
* @param dfl a double value
* @param cMinDigits the minimum number of digits of precision to display
*
* @return the double value formatted as a String
*/
public static String toString(double dfl, int cMinDigits)
{
BigDecimal decVal = new BigDecimal(dfl);
BigInteger intVal = decVal.toBigInteger();
String sIntVal = intVal.toString();
int cIntDigits = sIntVal.length() - (intVal.signum() <= 0 ? 1 : 0);
int cDecDigits = decVal.scale();
if (cIntDigits >= cMinDigits || cDecDigits == 0)
{
return sIntVal;
}
int cRemDigits = cMinDigits - cIntDigits;
if (cDecDigits > cRemDigits)
{
decVal = decVal.setScale(cRemDigits, BigDecimal.ROUND_HALF_UP);
}
String sDecVal = decVal.toString();
int of = sDecVal.length() - 1;
if (sDecVal.length() > 1 && sDecVal.charAt(of) == '0')
{
do
{
--of;
}
while (sDecVal.charAt(of) == '0');
if (sDecVal.charAt(of) == '.')
{
--of;
}
sDecVal = sDecVal.substring(0, of + 1);
}
return sDecVal;
}
// ----- formatting support: character/String ---------------------------
/**
* Format a Unicode character to the Unicode escape sequence of '\'
* + 'u' + 4 hex digits.
*
* @param ch the character
*
* @return the Unicode escape sequence
*/
public static String toUnicodeEscape(char ch)
{
int n = ch;
char[] ach = new char[6];
ach[0] = '\\';
ach[1] = 'u';
ach[2] = HEX[n >> 12 ];
ach[3] = HEX[n >> 8 & 0x0F];
ach[4] = HEX[n >> 4 & 0x0F];
ach[5] = HEX[n & 0x0F];
return new String(ach);
}
/**
* Format a char to a printable escape if necessary.
*
* @param ch the char
*
* @return a printable String representing the passed char
*/
public static String toCharEscape(char ch)
{
char[] ach = new char[6];
int cch = escape(ch, ach, 0);
return new String(ach, 0, cch);
}
/**
* Format a char to a printable escape if necessary as it would
* appear (quoted) in Java source code.
*
* This is a replacement for Text.printableChar().
*
* @param ch the character
*
* @return a printable String in single quotes representing the
* passed char
*/
public static String toQuotedCharEscape(char ch)
{
char[] ach = new char[8];
ach[0] = '\'';
int cch = escape(ch, ach, 1);
ach[cch + 1] = '\'';
return new String(ach, 0, cch + 2);
}
/**
* Format a String escaping characters as necessary.
*
* @param s the String
*
* @return a printable String representing the passed String
*/
public static String toStringEscape(String s)
{
char[] achSrc = s.toCharArray();
int cchSrc = achSrc.length;
int ofSrc = 0;
int cchDest = cchSrc * 6; // 100% safe
char[] achDest = new char[cchDest];
int ofDest = 0;
while (ofSrc < cchSrc)
{
ofDest += escape(achSrc[ofSrc++], achDest, ofDest);
}
return new String(achDest, 0, ofDest);
}
/**
* Format a String as it would appear (quoted) in Java source code,
* escaping characters as necessary.
*
* This is a replacement for Text.printableString().
*
* @param s the String
*
* @return a printable String in double quotes representing the
* passed String
*/
public static String toQuotedStringEscape(String s)
{
char[] achSrc = s.toCharArray();
int cchSrc = achSrc.length;
int ofSrc = 0;
int cchDest = cchSrc * 6 + 2; // 100% safe
char[] achDest = new char[cchDest];
int ofDest = 0;
achDest[ofDest++] = '\"';
while (ofSrc < cchSrc)
{
ofDest += escape(achSrc[ofSrc++], achDest, ofDest);
}
achDest[ofDest++] = '\"';
return new String(achDest, 0, ofDest);
}
/**
* Format a char to a printable escape if necessary, putting the result
* into the passed array. The array must be large enough to accept six
* characters.
*
* @param ch the character to format
* @param ach the array of characters to format into
* @param of the offset in the array to format at
*
* @return the number of characters used to format the char
*/
public static int escape(char ch, char[] ach, int of)
{
switch (ch)
{
case '\b':
ach[of++] = '\\';
ach[of ] = 'b';
return 2;
case '\t':
ach[of++] = '\\';
ach[of ] = 't';
return 2;
case '\n':
ach[of++] = '\\';
ach[of ] = 'n';
return 2;
case '\f':
ach[of++] = '\\';
ach[of ] = 'f';
return 2;
case '\r':
ach[of++] = '\\';
ach[of ] = 'r';
return 2;
case '\"':
ach[of++] = '\\';
ach[of ] = '\"';
return 2;
case '\'':
ach[of++] = '\\';
ach[of ] = '\'';
return 2;
case '\\':
ach[of++] = '\\';
ach[of ] = '\\';
return 2;
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x0B:
case 0x0E: case 0x0F:
case 0x10: case 0x11: case 0x12: case 0x13:
case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1A: case 0x1B:
case 0x1C: case 0x1D: case 0x1E: case 0x1F:
ach[of++] = '\\';
ach[of++] = '0';
ach[of++] = (char)(ch / 8 + '0');
ach[of ] = (char)(ch % 8 + '0');
return 4;
default:
switch (Character.getType(ch))
{
case Character.CONTROL:
case Character.PRIVATE_USE:
case Character.UNASSIGNED:
{
int n = ch;
ach[of++] = '\\';
ach[of++] = 'u';
ach[of++] = HEX[n >> 12 ];
ach[of++] = HEX[n >> 8 & 0x0F];
ach[of++] = HEX[n >> 4 & 0x0F];
ach[of ] = HEX[n & 0x0F];
}
return 6;
}
}
// character does not need to be escaped
ach[of] = ch;
return 1;
}
/**
* Escapes the string for SQL.
*
* @param s the String to escape
*
* @return the string quoted for SQL and escaped as necessary
*/
public static String toSqlString(String s)
{
if (s == null)
{
return "NULL";
}
if (s.length() == 0)
{
return "''";
}
if (s.indexOf('\'') < 0)
{
return '\'' + s + '\'';
}
char[] ach = s.toCharArray();
int cch = ach.length;
StringBuilder sb = new StringBuilder(cch + 16);
// open quotes
sb.append('\'');
// scan for characters to escape
int ofPrev = 0;
for (int ofCur = 0; ofCur < cch; ++ofCur)
{
char ch = ach[ofCur];
switch (ch)
{
case '\n':
case '\'':
{
// copy up to this point
if (ofCur > ofPrev)
{
sb.append(ach, ofPrev, ofCur - ofPrev);
}
// process escape
switch (ch)
{
case '\n':
// close quote, new line, re-open quote
sb.append("\'\n\'");
break;
case '\'':
// escape single quote with a second single quote
sb.append("\'\'");
break;
}
// processed up to the following character
ofPrev = ofCur + 1;
}
}
}
// copy the remainder of the string
if (ofPrev < cch)
{
sb.append(ach, ofPrev, cch - ofPrev);
}
// close quotes
sb.append('\'');
return sb.toString();
}
/**
* Indent the passed multi-line string.
*
* @param sText the string to indent
* @param sIndent a string used to indent each line
*
* @return the string, indented
*/
public static String indentString(String sText, String sIndent)
{
return indentString(sText, sIndent, true);
}
/**
* Textually indent the passed multi-line string.
*
* @param sText the string to indent
* @param sIndent a string used to indent each line
* @param fFirstLine true indents all lines;
* false indents all but the first
*
* @return the string, indented
*/
public static String indentString(String sText, String sIndent, boolean fFirstLine)
{
char[] ach = sText.toCharArray();
int cch = ach.length;
StringBuilder sb = new StringBuilder();
int iLine = 0;
int of = 0;
int ofPrev = 0;
while (of < cch)
{
if (ach[of++] == '\n' || of == cch)
{
if (iLine++ > 0 || fFirstLine)
{
sb.append(sIndent);
}
sb.append(sText.substring(ofPrev, of));
ofPrev = of;
}
}
return sb.toString();
}
/**
* Breaks the specified string into a multi-line string.
*
* @param sText the string to break
* @param nWidth the max width of resulting lines (including the indent)
* @param sIndent a string used to indent each line
*
* @return the string, broken and indented
*/
public static String breakLines(String sText, int nWidth, String sIndent)
{
return breakLines(sText, nWidth, sIndent, true);
}
/**
* Breaks the specified string into a multi-line string.
*
* @param sText the string to break
* @param nWidth the max width of resulting lines (including the
* indent)
* @param sIndent a string used to indent each line
* @param fFirstLine if true indents all lines;
* otherwise indents all but the first
*
* @return the string, broken and indented
*/
public static String breakLines(String sText, int nWidth, String sIndent, boolean fFirstLine)
{
if (sIndent == null)
{
sIndent = "";
}
nWidth -= sIndent.length();
if (nWidth <= 0)
{
throw new IllegalArgumentException("The width and indent are incompatible");
}
char[] ach = sText.toCharArray();
int cch = ach.length;
StringBuilder sb = new StringBuilder(cch);
int ofPrev = 0;
int of = 0;
while (of < cch)
{
char c = ach[of++];
boolean fBreak = false;
int ofBreak = of;
int ofNext = of;
if (c == '\n')
{
fBreak = true;
ofBreak--;
}
else if (of == cch)
{
fBreak = true;
}
else if (of == ofPrev + nWidth)
{
fBreak = true;
while (!Character.isWhitespace(ach[--ofBreak]) && ofBreak > ofPrev)
{
}
if (ofBreak == ofPrev)
{
ofBreak = of; // no spaces -- force the break
}
else
{
ofNext = ofBreak + 1;
}
}
if (fBreak)
{
if (ofPrev > 0)
{
sb.append('\n')
.append(sIndent);
}
else if (fFirstLine)
{
sb.append(sIndent);
}
sb.append(sText.substring(ofPrev, ofBreak));
ofPrev = ofNext;
}
}
return sb.toString();
}
/**
* Create a String of the specified length containing the specified
* character.
*
* @param ch the character to fill the String with
* @param cch the length of the String
*
* @return a String containing the character <ch> repeated <cch> times
*/
public static String dup(char ch, int cch)
{
char[] ach = new char[cch];
for (int of = 0; of < cch; ++of)
{
ach[of] = ch;
}
return new String(ach);
}
/**
* Create a String which is a duplicate of the specified number of the
* passed String.
*
* @param s the String to fill the new String with
* @param c the number of duplicates to put into the new String
*
* @return a String containing the String s repeated c
* times
*/
public static String dup(String s, int c)
{
if (c < 1)
{
return "";
}
if (c == 1)
{
return s;
}
char[] achPat = s.toCharArray();
int cchPat = achPat.length;
int cchBuf = cchPat * c;
char[] achBuf = new char[cchBuf];
for (int i = 0, of = 0; i < c; ++i, of += cchPat)
{
System.arraycopy(achPat, 0, achBuf, of, cchPat);
}
return new String(achBuf);
}
/**
* Replace all occurrences of the specified substring in the specified
* string.
*
* @param sText string to change
* @param sFrom pattern to change from
* @param sTo pattern to change to
*
* @return modified string
*/
public static String replace(String sText, String sFrom, String sTo)
{
if (sFrom.length() == 0)
{
return sText;
}
StringBuilder sbTextNew = new StringBuilder();
int iTextLen = sText.length();
int iStart = 0;
while (iStart < iTextLen)
{
int iPos = sText.indexOf(sFrom, iStart);
if (iPos != -1)
{
sbTextNew.append(sText.substring(iStart, iPos));
sbTextNew.append(sTo);
iStart = iPos + sFrom.length();
}
else
{
sbTextNew.append(sText.substring(iStart));
break;
}
}
return sbTextNew.toString();
}
/**
* Parse a character-delimited String into an array of Strings.
*
* @param s character-delimited String to parse
* @param chDelim character delimiter
*
* @return an array of String objects parsed from the passed String
*/
public static String[] parseDelimitedString(String s, char chDelim)
{
if (s == null)
{
return null;
}
List list = new ArrayList();
int ofPrev = -1;
while (true)
{
int ofNext = s.indexOf(chDelim, ofPrev + 1);
if (ofNext < 0)
{
list.add(s.substring(ofPrev + 1));
break;
}
else
{
list.add(s.substring(ofPrev + 1, ofNext));
}
ofPrev = ofNext;
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Format the content of the passed integer array as a delimited string.
*
* @param an the array
* @param sDelim the delimiter
*
* @return the formatted string
*/
public static String toDelimitedString(int[] an, String sDelim)
{
int c = an.length;
if (c > 0)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < c; i++)
{
sb.append(sDelim).append(an[i]);
}
return sb.substring(sDelim.length());
}
else
{
return "";
}
}
/**
* Format the content of the passed long array as a delimited string.
*
* @param al the array
* @param sDelim the delimiter
*
* @return the formatted string
*/
public static String toDelimitedString(long[] al, String sDelim)
{
int c = al.length;
if (c > 0)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < c; i++)
{
sb.append(sDelim).append(al[i]);
}
return sb.substring(sDelim.length());
}
else
{
return "";
}
}
/**
* Format the content of the passed Object array as a delimited string.
*
* @param ao the array
* @param sDelim the delimiter
*
* @return the formatted string
*/
public static String toDelimitedString(Object[] ao, String sDelim)
{
int c = ao.length;
if (c > 0)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < c; i++)
{
sb.append(sDelim).append(ao[i]);
}
return sb.substring(sDelim.length());
}
else
{
return "";
}
}
/**
* Format the content of the passed Iterator as a delimited string.
*
* @param iter the Iterator
* @param sDelim the delimiter
*
* @return the formatted string
*/
public static String toDelimitedString(Iterator iter, String sDelim)
{
StringBuilder sb = new StringBuilder();
while (iter.hasNext())
{
sb.append(sDelim).append(iter.next());
}
return sb.length() == 0 ? "" : sb.substring(sDelim.length());
}
/**
* Capitalize a string.
*
* @param s the string to capitalize
*
* @return the capitalized string
*/
public static String capitalize(String s)
{
return s.length() > 1
? s.substring(0, 1).toUpperCase() + s.substring(1)
: s.toUpperCase();
}
/**
* Truncate a string to the specified character count.
*
* @param s the String to be truncated
* @param cLimit expected character count
*
* @return the truncated String
*/
public static String truncateString(String s, int cLimit)
{
int cChar = s.length();
return cChar > cLimit
? s.substring(0, cLimit) + "...(" + (cChar - cLimit) + " more)"
: s;
}
/**
* Provide a string representation of elements within the collection until
* the concatenated string length exceeds {@code cLimit}.
*
* @param coll the collection of elements to describe
* @param cLimit expected character count
*
* @return the truncated string representation of the provided collection
*/
public static String truncateString(Collection coll, int cLimit)
{
StringBuilder sb = new StringBuilder(ClassHelper.getSimpleName(coll.getClass()))
.append('[');
cLimit += sb.length() + 1;
int c = 1;
for (Iterator iter = coll.iterator(); iter.hasNext() && sb.length() < cLimit; ++c)
{
if (c > 1)
{
sb.append(", ");
}
sb.append(iter.next());
}
if (c < coll.size() && sb.length() >= cLimit)
{
sb.append(", ...");
}
return sb.append(']').toString();
}
// ----- formatting support: bandwidth ----------------------------------
/**
* Parse the given string representation of a number of bytes per second.
* The supplied string must be in the format:
*
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[[B|b][P|p][S|s]]?
*
* where the first non-digit (from left to right) indicates the factor
* with which the preceding decimal value should be multiplied:
*
* - K or k (kilo, 210)
* - M or m (mega, 220)
* - G or g (giga, 230)
* - T or t (tera, 240)
*
*
* If the string value does not contain a factor, a factor of one is
* assumed.
*
* The optional last three characters indicate the unit of measure,
* [b][P|p][S|s] in the case of bits per second and
* [B][P|p][S|s] in the case of bytes per second. If the string
* value does not contain a unit, a unit of bits per second is assumed.
*
* @param s a string with the format:
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[[B|b][P|p][S|s]]?
*
* @return the number of bytes per second represented by the given string
*/
public static long parseBandwidth(String s)
{
return parseBandwidth(s, POWER_0);
}
/**
* Parse the given string representation of a number of bytes per second.
* The supplied string must be in the format:
*
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[[B|b][P|p][S|s]]?
*
* where the first non-digit (from left to right) indicates the factor
* with which the preceding decimal value should be multiplied:
*
* - K or k (kilo, 210)
* - M or m (mega, 220)
* - G or g (giga, 230)
* - T or t (tera, 240)
*
*
* If the string value does not contain an explicit or implicit factor, a
* factor calculated by raising 2 to the given default power is used. The
* default power can be one of:
*
* - {@link #POWER_0}
* - {@link #POWER_K}
* - {@link #POWER_M}
* - {@link #POWER_G}
* - {@link #POWER_T}
*
*
* The optional last three characters indicate the unit of measure,
* [b][P|p][S|s] in the case of bits per second and
* [B][P|p][S|s] in the case of bytes per second. If the string
* value does not contain a unit, a unit of bits per second is assumed.
*
* @param s a string with the format:
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[[B|b][P|p][S|s]]?
* @param nDefaultPower the exponent used to calculate the factor used in
* the conversion if one is not implied by the given
* string
*
* @return the number of bytes per second represented by the given string
*/
public static long parseBandwidth(String s, int nDefaultPower)
{
if (s == null)
{
throw new IllegalArgumentException("passed String must not be null");
}
switch (nDefaultPower)
{
case POWER_0:
case POWER_K:
case POWER_M:
case POWER_G:
case POWER_T:
break;
default:
throw new IllegalArgumentException("illegal default power: "
+ nDefaultPower);
}
// remove trailing "[[P|p][S|s]]?"
int cch = s.length();
if (cch >= 2)
{
char ch = s.charAt(cch - 1);
if (ch == 'S' || ch == 's')
{
ch = s.charAt(cch - 2);
if (ch == 'P' || ch == 'p')
{
cch -= 2;
}
else
{
throw new IllegalArgumentException("invalid bandwidth: \""
+ s + "\" (illegal bandwidth unit)");
}
}
}
// remove trailing "[B|b]?" and store it as a factor
// (default is "bps" i.e. baud)
int cBitShift = -3;
boolean fDefault = true;
if (cch >= 1)
{
switch (s.charAt(cch - 1))
{
case 'B':
cBitShift = 0;
// no break;
case 'b':
--cch;
fDefault = false;
break;
}
}
// remove trailing "[K|k|M|m|G|g|T|t]?[B|b]?" and update the factor
if (cch >= 1)
{
switch (s.charAt(--cch))
{
case 'K': case 'k':
cBitShift += POWER_K;
break;
case 'M': case 'm':
cBitShift += POWER_M;
break;
case 'G': case 'g':
cBitShift += POWER_G;
break;
case 'T': case 't':
cBitShift += POWER_T;
break;
default:
if (fDefault)
{
cBitShift += nDefaultPower;
}
++cch; // oops: shouldn't have chopped off the last char
break;
}
}
// make sure that the string contains some digits
if (cch == 0)
{
throw new NumberFormatException("passed String (\"" + s
+ "\") must contain a number");
}
// extract the digits (decimal form) to assemble the base number
long cb = 0;
boolean fDecimal = false;
int nDivisor = 1;
for (int of = 0; of < cch; ++of)
{
char ch = s.charAt(of);
switch (ch)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
cb = (cb * 10) + (ch - '0');
if (fDecimal)
{
nDivisor *= 10;
}
break;
case '.':
if (fDecimal)
{
throw new NumberFormatException("invalid bandwidth: \""
+ s + "\" (illegal second decimal point)");
}
fDecimal = true;
break;
default:
throw new NumberFormatException("invalid bandwidth: \""
+ s + "\" (illegal digit: \"" + ch + "\")");
}
}
if (cBitShift < 0)
{
cb >>>= -cBitShift;
}
else
{
cb <<= cBitShift;
}
if (fDecimal)
{
if (nDivisor == 1)
{
throw new NumberFormatException("invalid bandwidth: \""
+ s + "\" (illegal trailing decimal point)");
}
else
{
cb /= nDivisor;
}
}
return cb;
}
/**
* Format the passed bandwidth (in bytes per second) as a String that can
* be parsed by {@link #parseBandwidth} such that
* cb==parseBandwidth(toBandwidthString(cb)) holds true for
* all legal values of cbps.
*
* @param cbps the number of bytes per second
*
* @return a String representation of the given bandwidth
*/
public static String toBandwidthString(long cbps)
{
return toBandwidthString(cbps, true);
}
/**
* Format the passed bandwidth (in bytes per second) as a String. This
* method will possibly round the memory size for purposes of producing a
* more-easily read String value unless the fExact parameters is
* passed as true; if fExact is true, then
* cb==parseBandwidth(toBandwidthString(cb, true)) holds true
* for all legal values of cbps.
*
* @param cbps the number of bytes per second
* @param fExact true if the String representation must be exact, or
* false if it can be an approximation
*
* @return a String representation of the given bandwidth
*/
public static String toBandwidthString(long cbps, boolean fExact)
{
boolean fBits = (cbps & 0xF00000000000000L) == 0L;
if (fBits)
{
cbps <<= 3;
}
StringBuilder sb = new StringBuilder(toMemorySizeString(cbps, fExact));
int ofLast = sb.length() - 1;
if (sb.charAt(ofLast) == 'B')
{
if (fBits)
{
sb.setCharAt(ofLast, 'b');
}
}
else
{
sb.append(fBits ? 'b' : 'B');
}
sb.append("ps");
return sb.toString();
}
// ----- formatting support: memory size --------------------------------
/**
* Parse the given string representation of a number of bytes. The
* supplied string must be in the format:
*
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[B|b]?
*
* where the first non-digit (from left to right) indicates the factor
* with which the preceding decimal value should be multiplied:
*
* - K or k (kilo, 210)
* - M or m (mega, 220)
* - G or g (giga, 230)
* - T or t (tera, 240)
*
*
* If the string value does not contain a factor, a factor of one is
* assumed.
*
* The optional last character B or b indicates a unit
* of bytes.
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[B|b]?
*
* @return the number of bytes represented by the given string
*/
public static long parseMemorySize(String s)
{
return parseMemorySize(s, POWER_0);
}
/**
* Parse the given string representation of a number of bytes. The
* supplied string must be in the format:
*
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[B|b]?
*
* where the first non-digit (from left to right) indicates the factor
* with which the preceding decimal value should be multiplied:
*
* - K or k (kilo, 210)
* - M or m (mega, 220)
* - G or g (giga, 230)
* - T or t (tera, 240)
*
*
* If the string value does not contain an explicit or implicit factor, a
* factor calculated by raising 2 to the given default power is used. The
* default power can be one of:
*
* - {@link #POWER_0}
* - {@link #POWER_K}
* - {@link #POWER_M}
* - {@link #POWER_G}
* - {@link #POWER_T}
*
*
* The optional last character B or b indicates a unit
* of bytes.
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[K|k|M|m|G|g|T|t]?[B|b]?
* @param nDefaultPower the exponent used to calculate the factor used in
* the conversion if one is not implied by the given
* string
*
* @return the number of bytes represented by the given string
*/
public static long parseMemorySize(String s, int nDefaultPower)
{
if (s == null)
{
throw new IllegalArgumentException("passed String must not be null");
}
switch (nDefaultPower)
{
case POWER_0:
case POWER_K:
case POWER_M:
case POWER_G:
case POWER_T:
break;
default:
throw new IllegalArgumentException("illegal default power: "
+ nDefaultPower);
}
// remove trailing "[K|k|M|m|G|g|T|t]?[B|b]?" and store it as a factor
int cBitShift = POWER_0;
int cch = s.length();
if (cch > 0)
{
boolean fDefault;
char ch = s.charAt(cch - 1);
if (ch == 'B' || ch == 'b')
{
// bytes are implicit
--cch;
fDefault = false;
}
else
{
fDefault = true;
}
if (cch > 0)
{
switch (s.charAt(--cch))
{
case 'K': case 'k':
cBitShift = POWER_K;
break;
case 'M': case 'm':
cBitShift = POWER_M;
break;
case 'G': case 'g':
cBitShift = POWER_G;
break;
case 'T': case 't':
cBitShift = POWER_T;
break;
default:
if (fDefault)
{
cBitShift = nDefaultPower;
}
++cch; // oops: shouldn't have chopped off the last char
break;
}
}
}
// make sure that the string contains some digits
if (cch == 0)
{
throw new NumberFormatException("passed String (\"" + s
+ "\") must contain a number");
}
// extract the digits (decimal form) to assemble the base number
long cb = 0;
boolean fDecimal = false;
int nDivisor = 1;
for (int of = 0; of < cch; ++of)
{
char ch = s.charAt(of);
switch (ch)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
cb = (cb * 10) + (ch - '0');
if (fDecimal)
{
nDivisor *= 10;
}
break;
case '.':
if (fDecimal)
{
throw new NumberFormatException("invalid memory size: \""
+ s + "\" (illegal second decimal point)");
}
fDecimal = true;
break;
default:
throw new NumberFormatException("invalid memory size: \""
+ s + "\" (illegal digit: \"" + ch + "\")");
}
}
cb <<= cBitShift;
if (fDecimal)
{
if (nDivisor == 1)
{
throw new NumberFormatException("invalid memory size: \""
+ s + "\" (illegal trailing decimal point)");
}
else
{
cb /= nDivisor;
}
}
return cb;
}
/**
* Format the passed memory size (in bytes) as a String that can be
* parsed by {@link #parseMemorySize} such that
* cb==parseMemorySize(toMemorySizeString(cb)) holds true for
* all legal values of cb.
*
* @param cb the number of bytes of memory
*
* @return a String representation of the given memory size
*/
public static String toMemorySizeString(long cb)
{
return toMemorySizeString(cb, true);
}
/**
* Format the passed memory size (in bytes) as a String. This method will
* possibly round the memory size for purposes of producing a more-easily
* read String value unless the fExact parameters is passed as
* true; if fExact is true, then
* cb==parseMemorySize(toMemorySizeString(cb, true)) holds true
* for all legal values of cb.
*
* @param cb the number of bytes of memory
* @param fExact true if the String representation must be exact, or
* false if it can be an approximation
*
* @return a String representation of the given memory size
*/
public static String toMemorySizeString(long cb, boolean fExact)
{
if (cb < 0)
{
throw new IllegalArgumentException("negative quantity: " + cb);
}
if (cb < 1024)
{
return String.valueOf(cb);
}
int cDivs = 0;
int cMaxDivs = MEM_SUFFIX.length - 1;
if (fExact)
{
// kilobytes? megabytes? gigabytes? terabytes?
while (((((int) cb) & KB_MASK) == 0) && cDivs < cMaxDivs)
{
cb >>>= 10;
++cDivs;
}
return cb + MEM_SUFFIX[cDivs];
}
// need roughly the 3 most significant decimal digits
int cbRem = 0;
while (cb >= KB && cDivs < cMaxDivs)
{
cbRem = ((int) cb) & KB_MASK;
cb >>>= 10;
++cDivs;
}
StringBuilder sb = new StringBuilder();
sb.append(String.valueOf(cb));
int cch = sb.length();
if (cch < 3 && cbRem != 0)
{
// need the first digit or two of string value of cbRem / 1024;
// format the most significant two digits ".xx" as a string "1xx"
String sDec = String.valueOf((int) (cbRem / 10.24 + 100));
sb.append('.')
.append(sDec.substring(1, 1 + 3 - cch));
}
sb.append(MEM_SUFFIX[cDivs]);
return sb.toString();
}
// ----- formatting support: time ---------------------------------------
/**
* Parse the given string representation of a time duration and return its
* value as a number of milliseconds. The supplied string must be in the
* format:
*
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* where the first non-digits (from left to right) indicate the unit of
* time duration:
*
* - NS or ns (nanoseconds)
* - US or us (microseconds)
* - MS or ms (milliseconds)
* - S or s (seconds)
* - M or m (minutes)
* - H or h (hours)
* - D or d (days)
*
*
* If the string value does not contain a unit, a unit of milliseconds is
* assumed.
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* @return the number of milliseconds represented by the given string
* rounded down to the nearest millisecond
*
* @see #parseTimeNanos(String)
*/
public static long parseTime(String s)
{
return parseTime(s, UNIT_MS);
}
/**
* Parse the given string representation of a time duration and return its
* value as a number of milliseconds. The supplied string must be in the
* format:
*
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* where the first non-digits (from left to right) indicate the unit of
* time duration:
*
* - NS or ns (nanoseconds)
* - US or us (microseconds)
* - MS or ms (milliseconds)
* - S or s (seconds)
* - M or m (minutes)
* - H or h (hours)
* - D or d (days)
*
*
* If the string value does not contain a unit, the specified default unit
* is assumed. The default unit can be one of:
*
* - {@link #UNIT_NS}
* - {@link #UNIT_US}
* - {@link #UNIT_MS}
* - {@link #UNIT_S}
* - {@link #UNIT_M}
* - {@link #UNIT_H}
* - {@link #UNIT_D}
*
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
* @param nDefaultUnit the unit to use in the conversion to milliseconds
* if one is not specified in the supplied string
*
* @return the number of milliseconds represented by the given string
* rounded down to the nearest millisecond
*
* @see #parseTimeNanos(String, int)
*/
public static long parseTime(String s, int nDefaultUnit)
{
return parseTimeNanos(s, nDefaultUnit) / 1000000L;
}
/**
* Parse the given string representation of a time duration and return its
* value as a number of nanoseconds. The supplied string must be in the
* format:
*
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* where the first non-digits (from left to right) indicate the unit of
* time duration:
*
* - NS or ns (nanoseconds)
* - US or us (microseconds)
* - MS or ms (milliseconds)
* - S or s (seconds)
* - M or m (minutes)
* - H or h (hours)
* - D or d (days)
*
*
* If the string value does not contain a unit, a unit of nanoseconds is
* assumed.
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* @return the number of nanoseconds represented by the given string
* rounded down to the nearest nanosecond
*/
public static long parseTimeNanos(String s)
{
return parseTimeNanos(s, UNIT_NS);
}
/**
* Parse the given string representation of a time duration and return its
* value as a number of nanoseconds. The supplied string must be in the
* format:
*
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
*
* where the first non-digits (from left to right) indicate the unit of
* time duration:
*
* - NS or ns (nanoseconds)
* - US or us (microseconds)
* - MS or ms (milliseconds)
* - S or s (seconds)
* - M or m (minutes)
* - H or h (hours)
* - D or d (days)
*
*
* If the string value does not contain a unit, the specified default unit
* is assumed. The default unit can be one of:
*
* - {@link #UNIT_NS}
* - {@link #UNIT_US}
* - {@link #UNIT_MS}
* - {@link #UNIT_S}
* - {@link #UNIT_M}
* - {@link #UNIT_H}
* - {@link #UNIT_D}
*
*
* @param s a string with the format
* [\d]+[[.][\d]+]?[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?
* @param nDefaultUnit the unit to use in the conversion to nanoseconds
* if one is not specified in the supplied string
*
* @return the number of nanoseconds represented by the given string
* rounded down to the nearest nanosecond
*/
public static long parseTimeNanos(String s, int nDefaultUnit)
{
if (s == null)
{
throw new IllegalArgumentException("passed String must not be null");
}
switch (nDefaultUnit)
{
case UNIT_NS:
case UNIT_US:
case UNIT_MS:
case UNIT_S:
case UNIT_M:
case UNIT_H:
case UNIT_D:
break;
default:
throw new IllegalArgumentException("illegal default unit: "
+ nDefaultUnit);
}
// remove trailing "[NS|ns|US|us|MS|ms|S|s|M|m|H|h|D|d]?" and store it as a factor
long nMultiplier = nDefaultUnit;
int cch = s.length();
if (cch > 0)
{
switch (s.charAt(--cch))
{
case 'S': case 's':
nMultiplier = UNIT_S;
if (cch > 1)
{
char c = s.charAt(cch - 1);
switch (c)
{
case 'N': case 'n':
--cch;
nMultiplier = UNIT_NS;
break;
case 'U': case 'u':
--cch;
nMultiplier = UNIT_US;
break;
case 'M': case 'm':
--cch;
nMultiplier = UNIT_MS;
break;
}
}
break;
case 'M': case 'm':
nMultiplier = UNIT_M;
break;
case 'H': case 'h':
nMultiplier = UNIT_H;
break;
case 'D': case 'd':
nMultiplier = UNIT_D;
break;
default:
++cch; // oops: shouldn't have chopped off the last char
break;
}
}
// convert multiplier into nanos
nMultiplier = nMultiplier < 0 ? 1000000L / -nMultiplier
: 1000000L * nMultiplier;
// make sure that the string contains some digits
if (cch == 0)
{
throw new NumberFormatException("passed String (\"" + s
+ "\") must contain a number");
}
// extract the digits (decimal form) to assemble the base number
long cNanos = 0;
boolean fDecimal = false;
int nDivisor = 1;
for (int of = 0; of < cch; ++of)
{
char ch = s.charAt(of);
switch (ch)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
cNanos = (cNanos * 10) + (ch - '0');
if (fDecimal)
{
nDivisor *= 10;
}
break;
case '.':
if (fDecimal)
{
throw new NumberFormatException("invalid time: \""
+ s + "\" (illegal second decimal point)");
}
fDecimal = true;
break;
default:
throw new NumberFormatException("invalid time: \""
+ s + "\" (illegal digit: \"" + ch + "\")");
}
}
cNanos *= nMultiplier;
if (fDecimal)
{
if (nDivisor == 1)
{
throw new NumberFormatException("invalid time: \""
+ s + "\" (illegal trailing decimal point)");
}
else
{
cNanos /= nDivisor;
}
}
return cNanos;
}
/**
* Format a long value into a human readable date/time string.
*
* @param ldt a Java long containing a date/time value
*
* @return a human readable date/time string
*/
public static String formatDateTime(long ldt)
{
return ldt == 0L ? "none" : new Timestamp(ldt).toString();
}
// ----- formatting support: percentage ---------------------------------
/**
* Parse the given string representation of a percentage value and return
* its value as a float in the inclusive range of 0.0 and 1.0. The supplied
* string must be in the format:
*
* [\d]+[[.][\d]+]?[%]
*
* where the digits are within the closed interval [0.0, 100.0].
*
* @param s a string with the format [\d]+[[.][\d]+]?[%]
*
* @return a float representing the percentage value in the closed interval
* [0.0, 1.0]
*/
public static float parsePercentage(String s)
{
int ofPct = s.indexOf('%');
if (ofPct == -1)
{
throw new IllegalArgumentException("The parameter " + s + " does not contain a percentage value.");
}
int percent = Integer.parseInt(s.substring(0, ofPct));
if (percent > 100 || percent < 0)
{
throw new IllegalArgumentException("Not a percentage value between 0 - 100:" + s);
}
return percent / 100f;
}
// ----- hashing --------------------------------------------------------
/**
* Return the hash code for the supplied object or 0 for null.
*
* @param o the object to hash
*
* @return the hash code for the supplied object
*/
public static int hashCode(Object o)
{
return o == null ? 0 : o.hashCode();
}
// ----- comparisons ----------------------------------------------------
/**
* Compare two references for equality.
*
* @param o1 an object
* @param o2 an object to be compared with o1 for references equality
*
* @return true if equal, false otherwise
*/
public static boolean equals(Object o1, Object o2)
{
if (o1 == o2)
{
return true;
}
if (o1 == null || o2 == null)
{
return false;
}
try
{
return o1.equals(o2);
}
catch (RuntimeException e)
{
return false;
}
}
/**
* Deeply compare two references for equality. This dives down into
* arrays, including nested arrays.
*
* @param o1 an object
* @param o2 an ojbect to be compared with o1 for deeply equality
*
* @return true if deeply equal, false otherwise
*/
public static boolean equalsDeep(Object o1, Object o2)
{
if (o1 == o2)
{
return true;
}
if (o1 == null || o2 == null)
{
return false;
}
if (o1.getClass().isArray())
{
// the following are somewhat in order of likelihood
if (o1 instanceof byte[])
{
return o2 instanceof byte[]
&& Arrays.equals((byte[]) o1, (byte[]) o2);
}
if (o1 instanceof Object[])
{
if (o2 instanceof Object[])
{
Object[] ao1 = (Object[]) o1;
Object[] ao2 = (Object[]) o2;
int c = ao1.length;
if (c == ao2.length)
{
for (int i = 0; i < c; ++i)
{
if (!equalsDeep(ao1[i], ao2[i]))
{
return false;
}
}
return true;
}
}
return false;
}
if (o1 instanceof int[])
{
return o2 instanceof int[]
&& Arrays.equals((int[]) o1, (int[]) o2);
}
if (o1 instanceof char[])
{
return o2 instanceof char[]
&& Arrays.equals((char[]) o1, (char[]) o2);
}
if (o1 instanceof long[])
{
return o2 instanceof long[]
&& Arrays.equals((long[]) o1, (long[]) o2);
}
if (o1 instanceof double[])
{
return o2 instanceof double[]
&& Arrays.equals((double[]) o1, (double[]) o2);
}
if (o1 instanceof boolean[])
{
return o2 instanceof boolean[]
&& Arrays.equals((boolean[]) o1, (boolean[]) o2);
}
if (o1 instanceof short[])
{
return o2 instanceof short[]
&& Arrays.equals((short[]) o1, (short[]) o2);
}
if (o1 instanceof float[])
{
return o2 instanceof float[]
&& Arrays.equals((float[]) o1, (float[]) o2);
}
}
try
{
return o1.equals(o2);
}
catch (RuntimeException e)
{
return false;
}
}
// ----- CRC32 ----------------------------------------------------------
/**
* Calculate a CRC32 value from a byte array.
*
* @param ab an array of bytes
*
* @return the 32-bit CRC value
*/
public static int toCrc(byte[] ab)
{
return toCrc(ab, 0, ab.length);
}
/**
* Calculate a CRC32 value from a portion of a byte array.
*
* @param ab an array of bytes
* @param of the offset into the array
* @param cb the number of bytes to evaluate
*
* @return the 32-bit CRC value
*/
public static int toCrc(byte[] ab, int of, int cb)
{
return toCrc(ab, of, cb, 0xFFFFFFFF);
}
/**
* Continue to calculate a CRC32 value from a portion of a byte array.
*
* @param ab an array of bytes
* @param of the offset into the array
* @param cb the number of bytes to evaluate
* @param nCrc the previous CRC value
*
* @return the 32-bit CRC value
*/
public static int toCrc(byte[] ab, int of, int cb, int nCrc)
{
while (cb > 0)
{
nCrc = (nCrc >>> 8) ^ CRC32_TABLE[(nCrc ^ ab[of++]) & 0xFF];
--cb;
}
return nCrc;
}
/**
* Calculate a CRC32 value from a ByteSequence.
*
* @param seq a ByteSequence
*
* @return the 32-bit CRC value
*/
public static int toCrc(ByteSequence seq)
{
return toCrc(seq, 0, seq.length(), 0xFFFFFFFF);
}
/**
* Continue to calculate a CRC32 value from a portion of a ByteSequence .
*
* @param seq a ByteSequence
* @param of the offset into the ByteSequence
* @param cb the number of bytes to evaluate
* @param nCrc the previous CRC value
*
* @return the 32-bit CRC value
*/
public static int toCrc(ByteSequence seq, int of, int cb, int nCrc)
{
while (cb > 0)
{
nCrc = (nCrc >>> 8) ^ CRC32_TABLE[(nCrc ^ seq.byteAt(of++)) & 0xFF];
--cb;
}
return nCrc;
}
// ----- time routines --------------------------------------------------
/**
* Return the number of milliseconds which have elapsed since the JVM was
* started.
*
* @return the number of milliseconds which have elapsed since the JVM was
* started
*/
public static long getUpTimeMillis()
{
Method methodUptime = s_methodUptime;
if (methodUptime == null)
{
return System.currentTimeMillis() - s_ldtStartTime;
}
try
{
return ((Long) methodUptime.invoke(s_oRuntimeMXBean)).longValue();
}
catch (Throwable e)
{
if (e instanceof InvocationTargetException)
{
e = ((InvocationTargetException) e).getTargetException();
}
throw ensureRuntimeException(e);
}
}
/**
* Returns a "safe" current time in milliseconds.
*
* @return the difference, measured in milliseconds, between
* the corrected current time and midnight, January 1, 1970 UTC.
*
* @see SafeClock
*/
public static long getSafeTimeMillis()
{
return s_safeClock.getSafeTimeMillis(System.currentTimeMillis());
}
/**
* Returns the last "safe" time as computed by a previous call to
* the {@link #getSafeTimeMillis} method.
*
* @return the last "safe" time in milliseconds
*
* @see SafeClock
*/
public static long getLastSafeTimeMillis()
{
return s_safeClock.getLastSafeTimeMillis();
}
/**
* compute the number of milliseconds until the specified time.
*
* Note: this method will only return zero if ldtTimeout == Long.MAX_VALUE.
*
* @param ldtTimeout the timeout as computed by {@link #getSafeTimeMillis}
*
* @return the number of milliseconds to wait, or negative if the timeout
* has expired
*/
public static long computeSafeWaitTime(long ldtTimeout)
{
if (ldtTimeout == Long.MAX_VALUE)
{
return 0;
}
long ldtNow = getSafeTimeMillis();
return ldtTimeout == ldtNow ? -1 : ldtTimeout - ldtNow;
}
/**
* Gets the {@link TimeZone} for the given ID.
*
* This method will cache returned TimeZones to avoid the contention
* caused by the {@link TimeZone#getTimeZone(String)} implementation.
*
* @param sId the ID for a {@link TimeZone}
*
* @return the specified {@link TimeZone}, or the GMT zone if the
* given ID cannot be understood.
*
* @see TimeZone#getTimeZone(String)
*
* @since Coherence 12.1.3
*/
public static TimeZone getTimeZone(String sId)
{
TimeZone timeZone = (TimeZone) s_mapTimeZones.get(sId);
if (timeZone == null)
{
timeZone = TimeZone.getTimeZone(sId);
s_mapTimeZones.put(sId, timeZone);
}
return timeZone;
}
// ----- immutable intrinsic object caches ------------------------------
/**
* Factory method to produce Integer objects with an optimization that
* uses cached Integer objects for all relatively-low numbers.
*
* @param n an int
*
* @return an Integer whose value is the passed int
*
* @since Coherence 3.2
* @deprecated use {@link Integer#valueOf(int)}
*/
@Deprecated
public static Integer makeInteger(int n)
{
return Integer.valueOf(n);
}
/**
* Factory method to produce Long objects with an optimization that
* uses cached Long objects for all relatively-low numbers.
*
* @param n a long
*
* @return a Long whose value is the passed long
*
* @since Coherence 3.2
* @deprecated use {@link Long#valueOf(long)}
*/
@Deprecated
public static Long makeLong(long n)
{
return Long.valueOf(n);
}
// ----- random routines ------------------------------------------------
/**
* Return a random number assigned to this process.
*
* This value will remain the same across invocations, but is generally different across JVMs.
*
* @return the process's random number.
*/
public static int getProcessRandom()
{
return s_procRand;
}
/**
* Obtain a Random object that can be used to get random values.
*
* @return a random number generator
*
* @since Coherence 3.2
*/
public static Random getRandom()
{
Random rnd = s_rnd;
if (rnd == null)
{
// double-check locking is not required to work; the worst that
// can happen is that we create a couple extra Random objects
synchronized (Random.class)
{
rnd = s_rnd;
if (rnd == null)
{
rnd = new Random();
// spin the seed a bit
long lStop = getSafeTimeMillis() + 31 + rnd.nextInt(31);
long cMin = 1021 + rnd.nextInt(Math.max(1, (int) (lStop % 1021)));
while (getSafeTimeMillis() < lStop || --cMin > 0)
{
cMin += rnd.nextBoolean() ? 1 : -1;
rnd.setSeed(rnd.nextLong());
}
// spin the random until the clock ticks again
long lStart = getSafeTimeMillis();
do
{
if (rnd.nextBoolean())
{
if ((rnd.nextLong() & 0x01L) == (getSafeTimeMillis() & 0x01L))
{
rnd.nextBoolean();
}
}
}
while (getSafeTimeMillis() == lStart);
s_rnd = rnd;
}
}
}
return rnd;
}
/**
* Randomize the order of the elements within the passed collection.
*
* @param coll the Collection to randomize; the passed Collection is not
* altered
*
* @return a new and immutable List whose contents are identical to those
* of the passed collection except for the order in which they appear
*
* @since Coherence 3.2
*/
public static List randomize(Collection coll)
{
return new ImmutableArrayList(randomize(coll.toArray()));
}
/**
* Randomize the order of the elements within the passed array.
*
* @param a an array of objects to randomize
*
* @return the array that was passed in, and with its contents unchanged
* except for the order in which they appear
*
* @since Coherence 3.2
*/
public static Object[] randomize(Object[] a)
{
int c;
if (a == null || (c = a.length) <= 1)
{
return a;
}
Random rnd = getRandom();
for (int i1 = 0; i1 < c; ++i1)
{
int i2 = rnd.nextInt(c);
// swap i1, i2
Object o = a[i2];
a[i2] = a[i1];
a[i1] = o;
}
return a;
}
/**
* Randomize the order of the elements within the passed array.
*
* @param a an array of int values to randomize
*
* @return the array that was passed in, and with its contents unchanged
* except for the order in which they appear
*
* @since Coherence 3.2
*/
public static int[] randomize(int[] a)
{
int c;
if (a == null || (c = a.length) <= 1)
{
return a;
}
Random rnd = getRandom();
for (int i1 = 0; i1 < c; ++i1)
{
int i2 = rnd.nextInt(c);
// swap i1, i2
int n = a[i2];
a[i2] = a[i1];
a[i1] = n;
}
return a;
}
/**
* Randomize the order of the elements within the passed array.
*
* @param a an array of long values to randomize
*
* @return the array that was passed in, and with its contents unchanged
* except for the order in which they appear
*
* @since Coherence 12.2.1.4
*/
public static long[] randomize(long[] a)
{
int c;
if (a == null || (c = a.length) <= 1)
{
return a;
}
Random rnd = getRandom();
for (int i1 = 0; i1 < c; ++i1)
{
int i2 = rnd.nextInt(c);
// swap i1, i2
long l = a[i2];
a[i2] = a[i1];
a[i1] = l;
}
return a;
}
/**
* Generates a random-length Binary within the length bounds provided
* whose contents are random bytes.
*
* @param cbMin the minimum number of bytes in the resulting Binary
* @param cbMax the maximum number of bytes in the resulting Binary
*
* @return a randomly generated Binary object
*
* @since Coherence 3.2
*/
public static Binary getRandomBinary(int cbMin, int cbMax)
{
return getRandomBinary(cbMin, cbMax, (byte[]) null);
}
/**
* Generates a random-length Binary including {@code abHead} at the head of
* the Binary, in addition to random bytes within the length bounds provided.
*
* @param cbMin the minimum number of bytes in the resulting Binary
* @param cbMax the maximum number of bytes in the resulting Binary
* @param abHead the head of the returned Binary
*
* @return a randomly generated Binary object with a length of {@code
* [len(abHead) + cbMin, cbMax]}
*
* @since Coherence 12.1.3
*/
public static Binary getRandomBinary(int cbMin, int cbMax, byte...abHead)
{
assert cbMin >= 0;
assert cbMax >= cbMin;
Random rnd = getRandom();
int cbDif = cbMax - cbMin;
int cbHead = abHead == null ? 0 : abHead.length;
int cb = (cbDif <= 0 ? cbMax : cbMin + rnd.nextInt(cbDif)) + cbHead;
byte[] ab = new byte[cb];
rnd.nextBytes(ab);
if (cbHead > 0)
{
System.arraycopy(abHead, 0, ab, 0, cbHead);
}
return new Binary(ab);
}
/**
* Generates a random-length String within the length bounds provided.
* If the ASCII option is indicated, the characters will be in the range
* [32-127], otherwise the characters will be in the range
* [0x0000-0xFFFF].
*
* @param cchMin the minimum length of the resulting String
* @param cchMax the maximum length of the resulting String
* @param fAscii true if the resulting String should contain only ASCII
* values
*
* @return a randomly generated String object
*
* @since Coherence 3.2
*/
public static String getRandomString(int cchMin, int cchMax, boolean fAscii)
{
assert cchMin >= 0;
assert cchMax >= cchMin;
Random rnd = getRandom();
int cchDif = cchMax - cchMin;
int cch = cchDif <= 0 ? cchMax : cchMin + rnd.nextInt(cchDif);
if (fAscii)
{
byte[] ab = new byte[cch];
rnd.nextBytes(ab);
for (int of = 0; of < cch; ++of)
{
int b = ab[of] & 0x7F;
if (b < 0x20)
{
b = 0x20 + rnd.nextInt(0x7F - 0x20);
}
ab[of] = (byte) b;
}
return new String(ab, 0);
}
else
{
char[] ach = new char[cch];
int nLimit = Character.MAX_VALUE + 1;
for (int of = 0; of < cch; ++of)
{
ach[of] = (char) rnd.nextInt(nLimit);
}
return new String(ach);
}
}
// ----- validation methods ---------------------------------------------
/**
* Check the range of a value.
*
* @param lValue the value to check
* @param lFrom the lower limit of the range (inclusive)
* @param lTo the upper limit of the range (inclusive)
* @param sName the display name of the value
*
* @throws IllegalArgumentException if the value is out of range
*/
public static void checkRange(long lValue, long lFrom, long lTo, String sName)
{
if (lValue < lFrom || lValue > lTo)
{
throw new IllegalArgumentException(
sName + " value out of range [" + lFrom + ", " + lTo + "]: " + lValue);
}
}
/**
* Check that the specified object is non-null and return it.
*
* @param o the object to check
* @param sName the name of the corresponding parameter
* @param the type parameter for the object to check
*
* @return the specified object
*
* @throws IllegalArgumentException if o is null
*/
public static T checkNotNull(T o, String sName)
{
if (o == null)
{
throw new IllegalArgumentException(sName + " cannot be null");
}
return o;
}
/**
* Check that the specified string is neither a null nor an empty string.
*
* @param s the string to check
* @param sName the name of the corresponding parameter
*
* @throws IllegalArgumentException if s is null or empty string
*/
public static void checkNotEmpty(String s, String sName)
{
checkNotNull(s, sName);
if (s.length() == 0)
{
throw new IllegalArgumentException(sName + " cannot be empty");
}
}
// ---- miscellaneous ---------------------------------------------------
/**
* Calculate a modulo of two integer numbers. For a positive dividend the
* result is the same as the Java remainder operation (n % m
).
* For a negative dividend the result is still positive and equals to
* (n % m + m
).
*
* @param n the dividend
* @param m the divisor (must be positive)
*
* @return the modulo
*/
public static int mod(int n, int m)
{
return Hasher.mod(n, m);
}
/**
* Calculate a modulo of two long numbers. For a positive dividend the
* result is the same as the Java remainder operation (n % m
).
* For a negative dividend the result is still positive and equals to
* (n % m + m
).
*
* @param n the dividend
* @param m the divisor (must be positive)
*
* @return the modulo
*/
public static long mod(long n, long m)
{
return Hasher.mod(n, m);
}
// ----- properties -----------------------------------------------------
/**
* Obtains the current writer used for printing.
*
* @return the current writer used for printing; never null
*/
public static PrintWriter getOut()
{
return s_out;
}
/**
* Sets the current writer used for printing.
*
* @param writer the java.io.PrintWriter instance to use for printing;
* may be null
*/
public static void setOut(PrintWriter writer)
{
s_out = writer == null
? new PrintWriter(NullImplementation.getWriter(), true)
: writer;
}
/**
* Obtains the current writer used for tracing.
*
* @return the current writer used for tracing; never null
*/
public static PrintWriter getErr()
{
return s_err;
}
/**
* Sets the current writer used for tracing.
*
* @param writer the java.io.PrintWriter instance to use for tracing; may
* be null
*/
public static void setErr(PrintWriter writer)
{
s_err = writer == null
? new PrintWriter(NullImplementation.getWriter(), true)
: writer;
}
/**
* Obtains the current writer used for logging.
*
* @return the current writer used for logging; never null
*/
public static PrintWriter getLog()
{
return s_log;
}
/**
* Sets the current writer used for logging.
*
* @param writer the java.io.PrintWriter instance to use for logging; may
* be null
*/
public static void setLog(PrintWriter writer)
{
s_log = writer == null
? new PrintWriter(NullImplementation.getWriter(), true)
: writer;
}
/**
* Determine if the log is echoed to the console.
*
* @return true if the log is echoed to the console
*/
public static boolean isLogEcho()
{
return s_fEchoLog;
}
/**
* Specify whether the log should echo to the console.
*
* @param fEcho true if the log should echo to the console
*/
public static void setLogEcho(boolean fEcho)
{
s_fEchoLog = fEcho;
}
// ----- IO support -----------------------------------------------------
/**
* Read the contents out of the passed stream into the passed byte array
* and return the length read. This method will read up to the number of
* bytes that can fit into the passed array.
*
* @param stream a java.io.InputStream object to read from
* @param ab a byte array to read into
*
* @return the number of bytes read from the InputStream and stored into
* the passed byte array
*
* @throws IOException if an I/O error occurs
*/
public static int read(InputStream stream, byte[] ab)
throws IOException
{
final int MAX = ab.length;
int cb = 0;
boolean fEOF = false;
while (!fEOF && cb < MAX)
{
int cbBlock = stream.read(ab, cb, MAX - cb);
if (cbBlock < 0)
{
fEOF = true;
}
else
{
cb += cbBlock;
}
}
return cb;
}
/**
* Read the contents out of the passed stream and return the result as a
* byte array.
*
* @param stream a java.io.InputStream object to read from
*
* @return a byte array containing the contents of the passed InputStream
*
* @throws IOException if an I/O error occurs
*/
public static byte[] read(InputStream stream)
throws IOException
{
final int BLOCK = 1024;
byte[] ab = new byte[BLOCK];
ByteArrayOutputStream streamBuf = new ByteArrayOutputStream(BLOCK);
while (true)
{
try
{
int cb = stream.read(ab, 0, BLOCK);
if (cb < 0)
{
break;
}
else if (cb > 0)
{
streamBuf.write(ab, 0, cb);
}
}
catch (EOFException e)
{
break;
}
}
stream.close();
return streamBuf.toByteArray();
}
/**
* Read the contents out of the passed stream and return the result as a
* byte array.
*
* @param stream a java.io.DataInput object to read from
*
* @return a byte array containing the contents of the passed stream
*
* @throws IOException if an I/O error occurs
*/
public static byte[] read(DataInput stream)
throws IOException
{
if (stream instanceof ReadBuffer.BufferInput)
{
ReadBuffer.BufferInput in = (ReadBuffer.BufferInput) stream;
ReadBuffer buf = in.getBuffer();
if (buf != null)
{
int of = in.getOffset();
return in.getBuffer().toByteArray(of, buf.length() - of);
}
}
if (stream instanceof InputStream)
{
return read((InputStream) stream);
}
final int BLOCK = 1024;
int cb = 0;
byte[] ab = new byte[BLOCK];
ByteArrayOutputStream streamBuf = null;
try
{
while (true)
{
ab[cb++] = stream.readByte();
if (cb == BLOCK)
{
if (streamBuf == null)
{
streamBuf = new ByteArrayOutputStream(BLOCK);
}
streamBuf.write(ab, 0, cb);
cb = 0;
}
}
}
catch (EOFException e)
{
// end of input reached; eat it
}
if (streamBuf == null)
{
// contents fit in first block
if (cb == BLOCK)
{
// perfect fit
return ab;
}
// shrink block and return
byte[] abNew = new byte[cb];
System.arraycopy(ab, 0, abNew, 0, cb);
return abNew;
}
// contents span multiple blocks
if (cb != 0)
{
// copy remainder into streamBuf
streamBuf.write(ab, 0, cb);
}
return streamBuf.toByteArray();
}
/**
* Read the contents out of the passed stream and return the result as a
* byte array.
*
* @param stream a java.io.DataInputStream object to read from
*
* @return a byte array containing the contents of the passed InputStream
*
* @throws IOException if an I/O error occurs
*/
public static byte[] read(DataInputStream stream)
throws IOException
{
// this method resolves the ambiguity between the read(InputStream)
// and read(DataInput) methods for DataInputStreams and its derivatives
return read((InputStream) stream);
}
/**
* Read the contents out of the passed Reader and return the result as a
* String.
*
* @param reader a java.io.Reader object to read from
*
* @return a String containing the contents of the passed Reader
*
* @throws IOException if an I/O error occurs
*/
public static String read(Reader reader)
throws IOException
{
final int BLOCK = 1024;
char[] ach = new char[BLOCK];
CharArrayWriter writer = new CharArrayWriter(BLOCK);
while (true)
{
try
{
int cch = reader.read(ach, 0, BLOCK);
if (cch < 0)
{
break;
}
else if (cch > 0)
{
writer.write(ach, 0, cch);
}
}
catch (EOFException e)
{
break;
}
}
reader.close();
return writer.toString();
}
/**
* Read the contents out of the specified file and return the result as a
* byte array.
*
* @param file the java.io.File object to read the contents of
*
* @return the contents of the specified File as a byte array
*
* @throws IOException if an I/O error occurs
*/
public static byte[] read(File file)
throws IOException
{
if (file == null || !file.exists() || !file.isFile())
{
return null;
}
long cbFile = file.length();
azzert(cbFile < 0x7FFFFFFFL);
int cb = (int) cbFile;
byte[] ab = new byte[cb];
InputStream in = new FileInputStream(file);
try
{
int cbRead = read(in, ab);
azzert(cb == cbRead);
}
finally
{
try
{
in.close();
}
catch (Exception e) {}
}
return ab;
}
/**
* Read the contents of the specified URL and return the result as a
* byte array.
*
* @param url the java.net.URL object to read the contents of
*
* @return the contents of the specified URL as a byte array
*
* @throws IOException if an I/O error occurs
*/
public static byte[] read(URL url)
throws IOException
{
if (url == null)
{
return null;
}
URLConnection con = url.openConnection();
int cb = con.getContentLength();
byte[] ab = null;
InputStream in = con.getInputStream();
try
{
if (cb == -1)
{
// unknown content length
ab = read(in);
}
else
{
// known content length (optimize by pre-allocating fully)
ab = new byte[cb];
int cbRead = read(in, ab);
azzert(cb == cbRead);
}
}
finally
{
try
{
in.close();
}
catch (Exception e) {}
}
return ab;
}
// ----- merge primitive array support ---------------------------------
/**
* Merge two byte arrays.
*
* @param ab1 first array to merge
* @param ab2 second array to merge
*
* @return merged array
*/
public static byte[] mergeByteArray(byte[] ab1, byte[] ab2)
{
if (ab1 == null || ab1.length == 0)
{
return ab2;
}
if (ab2 == null || ab2.length == 0)
{
return ab1;
}
int nLen1 = ab1.length;
int nLen2 = ab2.length;
byte[] aMerged = Arrays.copyOf(ab1, nLen1 + nLen2);
System.arraycopy(ab2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two boolean arrays.
*
* @param af1 first array to merge
* @param af2 second array to merge
*
* @return the merged array
*/
public static boolean[] mergeBooleanArray(boolean[] af1, boolean[] af2)
{
if (af1 == null || af1.length == 0)
{
return af2;
}
if (af2 == null || af2.length == 0)
{
return af1;
}
int nLen1 = af1.length;
int nLen2 = af2.length;
boolean[] aMerged = Arrays.copyOf(af1, nLen1 + nLen2);
System.arraycopy(af2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two double arrays.
*
* @param adfl1 first array to merge
* @param adfl2 second array to merge
*
* @return the merged array
*/
public static double[] mergeDoubleArray(double[] adfl1, double[] adfl2)
{
if (adfl1 == null || adfl1.length == 0)
{
return adfl2;
}
if (adfl2 == null || adfl2.length == 0)
{
return adfl1;
}
int nLen1 = adfl1.length;
int nLen2 = adfl2.length;
double[] aMerged = Arrays.copyOf(adfl1, nLen1 + nLen2);
System.arraycopy(adfl2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two float arrays.
*
* @param afl1 first array to merge
* @param afl2 second array to merge
*
* @return merged array
*/
public static float[] mergeFloatArray(float[] afl1, float[] afl2)
{
if (afl1 == null || afl1.length == 0)
{
return afl2;
}
if (afl2 == null || afl2.length == 0)
{
return afl1;
}
int nLen1 = afl1.length;
int nLen2 = afl2.length;
float[] aMerged = Arrays.copyOf(afl1, nLen1 + nLen2);
System.arraycopy(afl2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two long arrays.
*
* @param al1 first array to merge
* @param al2 second array to merge
*
* @return merged array
*/
public static long[] mergeLongArray(long[] al1, long[] al2)
{
if (al1 == null || al1.length == 0)
{
return al2;
}
if (al2 == null || al2.length == 0)
{
return al1;
}
int nLen1 = al1.length;
int nLen2 = al2.length;
long[] aMerged = Arrays.copyOf(al1, nLen1 + nLen2);
System.arraycopy(al2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two int arrays.
*
* @param ai1 first array to merge
* @param ai2 second array to merge
*
* @return merged array
*/
public static int[] mergeIntArray(int[] ai1, int[] ai2)
{
if (ai1 == null || ai1.length == 0)
{
return ai2;
}
if (ai2 == null || ai2.length == 0)
{
return ai1;
}
int nLen1 = ai1.length;
int nLen2 = ai2.length;
int[] aMerged = Arrays.copyOf(ai1, nLen1 + nLen2);
System.arraycopy(ai2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two char arrays.
*
* @param ac1 first array to merge
* @param ac2 second array to merge
*
* @return merged array
*/
public static char[] mergeCharArray(char[] ac1, char[] ac2)
{
if (ac1 == null || ac1.length == 0)
{
return ac2;
}
if (ac2 == null || ac2.length == 0)
{
return ac1;
}
int nLen1 = ac1.length;
int nLen2 = ac2.length;
char[] aMerged = Arrays.copyOf(ac1, nLen1 + nLen2);
System.arraycopy(ac2, 0, aMerged, nLen1, nLen2);
return aMerged;
}
/**
* Merge two array with type T elements.
*
* @param a1 first array to merge
* @param a2 second array to merge
*
* @param type of array element
*
* @return the merged array
*/
public static T[] mergeArray(T[] a1, T[] a2)
{
if (a1 == null || a1.length == 0)
{
return a2;
}
if (a2 == null || a2.length == 0)
{
return a1;
}
int nLen1 = a1.length;
int nLen2 = a2.length;
T[] aMerged = (T[]) Arrays.copyOf(a1, nLen1 + nLen2);
System.arraycopy(a2, 0, aMerged, nLen1, nLen2);
return (T[]) aMerged;
}
// ----- inner class: LoggingWriter -----------------------------------
/**
* Inner class for over-riding the destination of log(), out() and err()
* calls.
*/
public static class LoggingWriter
extends PrintWriter
{
/**
* Construct a PrintWriter that logs using the
* {@link CacheFactory#log} method.
*
* @param nSev the severity to log messages with
*/
public LoggingWriter(int nSev)
{
super(new CharArrayWriter());
m_nSev = nSev;
}
/**
* Log the accumulated String using the logging severity that this
* PrintWriter was configured with.
*/
@Override
public void println()
{
CharArrayWriter out = (CharArrayWriter) this.out;
synchronized (lock)
{
String s = out.toString();
out.reset();
CacheFactory.log(s, m_nSev);
}
}
/**
* The severity that this PrintWriter logs with.
*/
private int m_nSev;
}
// ----- constants ------------------------------------------------------
/**
* Hex digits.
*/
private static final char[] HEX = "0123456789ABCDEF".toCharArray();
/**
* Memory size constants.
*/
private static final int KB = 1 << 10;
private static final int KB_MASK = KB - 1;
private static final String[] MEM_SUFFIX = {"", "KB", "MB", "GB", "TB"};
/**
* CRC32 constants.
*/
private static final int CRC32_BASE = 0xEDB88320;
private static final int[] CRC32_TABLE = new int[256];
static
{
for (int i = 0, c = CRC32_TABLE.length; i < c; ++i)
{
int nCrc = i;
for (int n = 0; n < 8; ++n)
{
if ((nCrc & 1) == 1)
{
nCrc = (nCrc >>> 1) ^ CRC32_BASE;
}
else
{
nCrc >>>= 1;
}
}
CRC32_TABLE[i] = nCrc;
}
}
/**
* Integer constant representing a unit of nanoseconds.
*
* @see #parseTimeNanos(String, int)
*/
public static final int UNIT_NS = -1000000;
/**
* Integer constant representing a unit of microseconds.
*
* @see #parseTimeNanos(String, int)
*/
public static final int UNIT_US = -1000;
/**
* Integer constant representing a unit of milliseconds.
*
* @see #parseTime(String, int)
*/
public static final int UNIT_MS = 1;
/**
* Integer constant representing a unit of seconds.
*
* @see #parseTime(String, int)
*/
public static final int UNIT_S = 1000*UNIT_MS;
/**
* Integer constant representing a unit of minutes.
*
* @see #parseTime(String, int)
*/
public static final int UNIT_M = 60*UNIT_S;
/**
* Integer constant representing a unit of hours.
*
* @see #parseTime(String, int)
*/
public static final int UNIT_H = 60*UNIT_M;
/**
* Integer constant representing a unit of days.
*
* @see #parseTime(String, int)
*/
public static final int UNIT_D = 24*UNIT_H;
/**
* Integer constant representing an exponent of zero.
*
* @see #parseBandwidth(String, int)
* @see #parseMemorySize(String, int)
*/
public static final int POWER_0 = 0;
/**
* Integer constant representing an exponent of 10.
*
* @see #parseBandwidth(String, int)
* @see #parseMemorySize(String, int)
*/
public static final int POWER_K = 10;
/**
* Integer constant representing an exponent of 20.
*
* @see #parseBandwidth(String, int)
* @see #parseMemorySize(String, int)
*/
public static final int POWER_M = 20;
/**
* Integer constant representing an exponent of 30.
*
* @see #parseBandwidth(String, int)
* @see #parseMemorySize(String, int)
*/
public static final int POWER_G = 30;
/**
* Integer constant representing an exponent of 40.
*
* @see #parseBandwidth(String, int)
* @see #parseMemorySize(String, int)
*/
public static final int POWER_T = 40;
/**
* The minimum logging level indicator.
*/
public static final int LOG_MIN = 0;
/**
* The maximum logging level indicator.
*/
public static final int LOG_MAX = 9;
/**
* It is expected that items with a log level of 0 will always be logged.
*/
public static final int LOG_ALWAYS = 0;
/**
* Log level 1 indicates an error.
*/
public static final int LOG_ERR = 1;
/**
* Log level 2 indicates a warning.
*/
public static final int LOG_WARN = 2;
/**
* Log level 3 indicates information that should likely be logged.
*/
public static final int LOG_INFO = 3;
/**
* As of Coherence 3.2, the default logging level is 5, so using the level
* of 5 will show up in the logs by default as a debug message.
*/
public static final int LOG_DEBUG = 5;
/**
* As of Coherence 3.2, the default logging level is 5, so using a level
* higher than 5 will be "quiet" by default, meaning that it will not show
* up in the logs unless the configured logging level is increased.
*/
public static final int LOG_QUIET = 6;
// ----- data members ---------------------------------------------------
/**
* The writer to use for print output.
*/
private static PrintWriter s_out = new PrintWriter(System.out, true);
/**
* The writer to use for trace output.
*/
private static PrintWriter s_err = new PrintWriter(System.err, true);
/**
* The writer to use for logging. By default, there is no persistent
* log.
*/
private static PrintWriter s_log = new PrintWriter(NullImplementation.getWriter(), true);
/**
* Option to log to the console in addition to the logging writer. By
* default, all logged messages are echoed to the console.
*/
private static boolean s_fEchoLog = true;
/**
* The java.lang.RuntimeMXBean or null if not available.
*/
private static final Object s_oRuntimeMXBean;
/**
* RuntimeMXBean.getUpTime() Method or null if not available.
*/
private static final Method s_methodUptime;
static
{
Object oRuntimeMXBean = null;
Method methodUptime = null;
try
{
oRuntimeMXBean = Class.forName(
"java.lang.management.ManagementFactory").
getMethod("getRuntimeMXBean").invoke(null);
if (oRuntimeMXBean != null)
{
methodUptime = Class.forName(
"java.lang.management.RuntimeMXBean").
getMethod("getUptime");
}
}
catch (Throwable eIgnore) {}
s_oRuntimeMXBean = oRuntimeMXBean;
s_methodUptime = methodUptime;
}
/**
* The estimated JVM start time.
*/
private static final long s_ldtStartTime = System.currentTimeMillis();
/**
* The map of cached {@link TimeZone}s keyed by ID.
*/
private static Map s_mapTimeZones = new SafeHashMap();
/**
* The shared SafeClock.
*/
private static SafeClock s_safeClock = new SafeClock(s_ldtStartTime);
/**
* A lazily-instantiated shared Random object.
*/
private static Random s_rnd;
/**
* Single random value held for the life of the process.
*/
private static final int s_procRand = ThreadLocalRandom.current().nextInt();
/**
* The configured ThreadFactory.
*/
private static ThreadFactory s_threadFactory = instantiateThreadFactory();
/**
* Initialize logging through Coherence
*/
static
{
setOut(new LoggingWriter(LOG_ALWAYS));
setErr(new LoggingWriter(LOG_ERR));
setLog(new LoggingWriter(LOG_INFO));
setLogEcho(false);
}
}