Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
Copyright (C) GridGain Systems. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* _________ _____ __________________ _____
* __ ____/___________(_)______ /__ ____/______ ____(_)_______
* _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
* / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
* \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
*/
package org.gridgain.grid.util;
import org.apache.commons.codec.binary.*;
import org.apache.commons.codec.digest.*;
import org.gridgain.grid.*;
import org.gridgain.grid.cache.*;
import org.gridgain.grid.compute.*;
import org.gridgain.grid.events.*;
import org.gridgain.grid.kernal.*;
import org.gridgain.grid.kernal.managers.deployment.*;
import org.gridgain.grid.kernal.processors.cache.*;
import org.gridgain.grid.kernal.processors.streamer.*;
import org.gridgain.grid.lang.*;
import org.gridgain.grid.logger.*;
import org.gridgain.grid.product.*;
import org.gridgain.grid.spi.*;
import org.gridgain.grid.spi.discovery.*;
import org.gridgain.grid.util.lang.*;
import org.gridgain.grid.util.mbean.*;
import org.gridgain.grid.util.typedef.*;
import org.gridgain.grid.util.typedef.internal.*;
import org.gridgain.grid.util.worker.*;
import org.jdk8.backport.*;
import org.jetbrains.annotations.*;
import org.springframework.beans.*;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.xml.*;
import org.springframework.context.*;
import org.springframework.context.support.*;
import org.springframework.core.io.*;
import sun.misc.*;
import javax.mail.*;
import javax.mail.Authenticator;
import javax.mail.internet.*;
import javax.management.*;
import javax.naming.*;
import javax.net.ssl.*;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.management.*;
import java.lang.reflect.Array;
import java.lang.reflect.*;
import java.math.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.security.*;
import java.security.cert.*;
import java.sql.*;
import java.text.*;
import java.util.*;
import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.jar.*;
import java.util.regex.*;
import java.util.zip.*;
import static org.gridgain.grid.GridSystemProperties.*;
import static org.gridgain.grid.events.GridEventType.*;
import static org.gridgain.grid.kernal.GridNodeAttributes.*;
/**
* Collection of utility methods used throughout the system.
*/
@SuppressWarnings({"UnusedReturnValue", "UnnecessaryFullyQualifiedName"})
public abstract class GridUtils {
/** Unsafe. */
private static final Unsafe UNSAFE = GridUnsafe.unsafe();
/** {@code True} if {@code unsafe} should be used for array copy. */
private static final boolean UNSAFE_BYTE_ARR_CP = unsafeByteArrayCopyAvailable();
/** Offset. */
private static final int BYTE_ARRAY_DATA_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
/** Sun-specific JDK constructor factory for objects that don't have empty constructor. */
private static final Method CTOR_FACTORY;
/** Sun JDK reflection factory. */
private static final Object SUN_REFLECT_FACTORY;
/** Public {@code java.lang.Object} no-argument constructor. */
private static final Constructor OBJECT_CTOR;
/** All grid event names. */
private static final Map GRID_EVT_NAMES = new HashMap<>();
/** All grid events. */
private static final int[] GRID_EVTS;
/** Empty integers array. */
private static final int[] EMPTY_INTS = new int[0];
/** Empty longs. */
private static final long[] EMPTY_LONGS = new long[0];
/** System line separator. */
private static final String NL = System.getProperty("line.separator");
/** Path to {@code gridgain.xml} file. */
public static final String GRIDGAIN_XML_PATH = "META-INF/gridgain.xml";
/** Default user version. */
public static final String DFLT_USER_VERSION = "0";
/** System class loader user version. */
private static final AtomicReference SYS_LDR_VER = new AtomicReference<>(null);
/** Cache for {@link GridPeerDeployAware} fields to speed up reflection. */
private static final ConcurrentMap, Collection>> p2pFields =
new ConcurrentHashMap8<>();
/** Secure socket protocol to use. */
private static final String HTTPS_PROTOCOL = "TLS";
/** Project home directory. */
private static volatile GridTuple ggHome;
/** OS JDK string. */
private static String osJdkStr;
/** OS string. */
private static String osStr;
/** JDK string. */
private static String jdkStr;
/** Indicates whether current OS is Windows 95. */
private static boolean win95;
/** Indicates whether current OS is Windows 98. */
private static boolean win98;
/** Indicates whether current OS is Windows NT. */
private static boolean winNt;
/** Indicates whether current OS is Windows Vista. */
private static boolean winVista;
/** Indicates whether current OS is Windows 7. */
private static boolean win7;
/** Indicates whether current OS is some version of Windows. */
private static boolean unknownWin;
/** Indicates whether current OS is Windows 2000. */
private static boolean win2k;
/** Indicates whether current OS is Windows XP. */
private static boolean winXp;
/** Indicates whether current OS is Windows Server 2003. */
private static boolean win2003;
/** Indicates whether current OS is Windows Server 2008. */
private static boolean win2008;
/** Indicates whether current OS is UNIX flavor. */
private static boolean unix;
/** Indicates whether current OS is Solaris. */
private static boolean solaris;
/** Indicates whether current OS is Linux flavor. */
private static boolean linux;
/** Indicates whether current OS is NetWare. */
private static boolean netware;
/** Indicates whether current OS is Mac OS. */
private static boolean mac;
/** Indicates whether current OS architecture is Sun Sparc. */
private static boolean sparc;
/** Indicates whether current OS architecture is Intel X86. */
private static boolean x86;
/** Name of the underlying OS. */
private static String osName;
/** Version of the underlying OS. */
private static String osVer;
/** CPU architecture of the underlying OS. */
private static String osArch;
/** Name of the Java Runtime. */
private static String javaRtName;
/** Name of the Java Runtime version. */
private static String javaRtVer;
/** Name of the JDK vendor. */
private static String jdkVendor;
/** Name of the JDK. */
private static String jdkName;
/** Version of the JDK. */
private static String jdkVer;
/** Name of JVM specification. */
private static String jvmSpecName;
/** Version of JVM implementation. */
private static String jvmImplVer;
/** Vendor's name of JVM implementation. */
private static String jvmImplVendor;
/** Name of the JVM implementation. */
private static String jvmImplName;
/** JMX domain as 'xxx.gridgain'. */
public static final String JMX_DOMAIN = GridUtils.class.getName().substring(0, GridUtils.class.getName().
indexOf('.', GridUtils.class.getName().indexOf('.') + 1));
/** Network packet header. */
public static final byte[] GG_HEADER = U.intToBytes(0x00004747);
/** Default buffer size = 4K. */
private static final int BUF_SIZE = 4096;
/** Byte bit-mask. */
private static final int MASK = 0xf;
/** Long date format pattern for log messages. */
private static final SimpleDateFormat LONG_DATE_FMT = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
/**
* Short date format pattern for log messages in "quiet" mode.
* Only time is included since we don't expect "quiet" mode to be used
* for longer runs.
*/
private static final SimpleDateFormat SHORT_DATE_FMT = new SimpleDateFormat("HH:mm:ss");
/** Debug date format. */
private static final SimpleDateFormat DEBUG_DATE_FMT = new SimpleDateFormat("HH:mm:ss,SSS");
/** Cached local host address to make sure that every time the same local host is returned. */
private static InetAddress locHost;
/** */
private static volatile long curTimeMillis = System.currentTimeMillis();
/** Primitive class map. */
private static final Map> primitiveMap = new HashMap<>(16, .5f);
/** Boxed class map. */
private static final Map, Class>> boxedClsMap = new HashMap<>(16, .5f);
/** Class loader used to load GridGain. */
private static final ClassLoader gridClassLoader = GridUtils.class.getClassLoader();
/** MAC OS invalid argument socket error message. */
public static final String MAC_INVALID_ARG_MSG = "On MAC OS you may have too many file descriptors open " +
"(simple restart usually solves the issue)";
/** Default help pages. */
public static final List DFLT_HELP_LINKS = Arrays.asList(
"Troubleshooting: http://bit.ly/GridGain-Troubleshooting",
"Documentation Center: http://bit.ly/GridGain-Documentation");
/**
* Initializes enterprise check.
*/
static {
String osName = System.getProperty("os.name");
String osLow = osName.toLowerCase();
// OS type detection.
if (osLow.contains("win")) {
if (osLow.contains("95"))
win95 = true;
else if (osLow.contains("98"))
win98 = true;
else if (osLow.contains("nt"))
winNt = true;
else if (osLow.contains("2000"))
win2k = true;
else if (osLow.contains("vista"))
winVista = true;
else if (osLow.contains("xp"))
winXp = true;
else if (osLow.contains("2003"))
win2003 = true;
else if (osLow.contains("2008"))
win2008 = true;
else if (osLow.contains("7"))
win7 = true;
else
unknownWin = true;
}
else if (osLow.contains("netware"))
netware = true;
else if (osLow.contains("mac os"))
mac = true;
else {
// UNIXs flavors tokens.
for (CharSequence os : new String[]{"ix", "inux", "olaris", "un", "ux", "sco", "bsd", "att"})
if (osLow.contains(os)) {
unix = true;
break;
}
// UNIX name detection.
if (osLow.contains("olaris"))
solaris = true;
else if (osLow.contains("inux"))
linux = true;
}
String osArch = System.getProperty("os.arch");
String archStr = osArch.toLowerCase();
// OS architecture detection.
if (archStr.contains("x86"))
x86 = true;
else if (archStr.contains("sparc"))
sparc = true;
String javaRtName = System.getProperty("java.runtime.name");
String javaRtVer = System.getProperty("java.runtime.version");
String jdkVendor = System.getProperty("java.specification.vendor");
String jdkName = System.getProperty("java.specification.name");
String jdkVer = System.getProperty("java.specification.version");
String osVer = System.getProperty("os.version");
String jvmSpecName = System.getProperty("java.vm.specification.name");
String jvmImplVer = System.getProperty("java.vm.version");
String jvmImplVendor = System.getProperty("java.vm.vendor");
String jvmImplName = System.getProperty("java.vm.name");
String jdkStr = javaRtName + ' ' + javaRtVer + ' ' + jvmImplVendor + ' ' + jvmImplName + ' ' +
jvmImplVer;
osStr = osName + ' ' + osVer + ' ' + osArch;
osJdkStr = osLow + ", " + jdkStr;
// Copy auto variables to static ones.
GridUtils.osName = osName;
GridUtils.jdkName = jdkName;
GridUtils.jdkVendor = jdkVendor;
GridUtils.jdkVer = jdkVer;
GridUtils.jdkStr = jdkStr;
GridUtils.osVer = osVer;
GridUtils.osArch = osArch;
GridUtils.jvmSpecName = jvmSpecName;
GridUtils.jvmImplVer = jvmImplVer;
GridUtils.jvmImplVendor = jvmImplVendor;
GridUtils.jvmImplName = jvmImplName;
GridUtils.javaRtName = javaRtName;
GridUtils.javaRtVer = javaRtVer;
primitiveMap.put("byte", byte.class);
primitiveMap.put("short", short.class);
primitiveMap.put("int", int.class);
primitiveMap.put("long", long.class);
primitiveMap.put("float", float.class);
primitiveMap.put("double", double.class);
primitiveMap.put("char", char.class);
primitiveMap.put("boolean", boolean.class);
boxedClsMap.put(byte.class, Byte.class);
boxedClsMap.put(short.class, Short.class);
boxedClsMap.put(int.class, Integer.class);
boxedClsMap.put(long.class, Long.class);
boxedClsMap.put(float.class, Float.class);
boxedClsMap.put(double.class, Double.class);
boxedClsMap.put(char.class, Character.class);
boxedClsMap.put(boolean.class, Boolean.class);
try {
OBJECT_CTOR = Object.class.getConstructor();
}
catch (NoSuchMethodException e) {
throw withCause(new AssertionError("Object class does not have empty constructor (is JDK corrupted?)."), e);
}
// Constructor factory.
Method ctorFac = null;
Object refFac = null;
try {
Class> refFactoryCls = Class.forName("sun.reflect.ReflectionFactory");
refFac = refFactoryCls.getMethod("getReflectionFactory").invoke(null);
ctorFac = refFac.getClass().getMethod("newConstructorForSerialization", Class.class,
Constructor.class);
}
catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException ignored) {
// No-op.
}
CTOR_FACTORY = ctorFac;
SUN_REFLECT_FACTORY = refFac;
// Disable hostname SSL verification for development and testing with self-signed certificates.
if (Boolean.parseBoolean(System.getProperty(GG_DISABLE_HOSTNAME_VERIFIER))) {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override public boolean verify(String hostname, SSLSession sslSes) {
return true;
}
});
}
// Event names initialization.
for (Field field : GridEventType.class.getFields()) {
if (field.getType().equals(int.class)) {
try {
assert field.getName().startsWith("EVT_") : "Invalid event name (should start with 'EVT_': " +
field.getName();
int type = field.getInt(null);
String prev = GRID_EVT_NAMES.put(type, field.getName().substring(4));
// Check for duplicate event types.
assert prev == null : "Duplicate event [type=" + type + ", name1=" + prev +
", name2=" + field.getName() + ']';
}
catch (IllegalAccessException e) {
throw new GridRuntimeException(e);
}
}
}
// Event array initialization.
GRID_EVTS = toIntArray(GRID_EVT_NAMES.keySet());
// Sort for fast event lookup.
Arrays.sort(GRID_EVTS);
// We need to re-initialize EVTS_ALL and EVTS_ALL_MINUS_METRIC_UPDATE
// because they may have been initialized to null before GRID_EVTS were initialized.
if (EVTS_ALL == null || EVTS_ALL_MINUS_METRIC_UPDATE == null) {
try {
Field f1 = GridEventType.class.getDeclaredField("EVTS_ALL");
Field f2 = GridEventType.class.getDeclaredField("EVTS_ALL_MINUS_METRIC_UPDATE");
assert f1 != null;
assert f2 != null;
// We use unsafe operations to update static fields on interface because
// they are treated as static final and cannot be updated via standard reflection.
UNSAFE.putObjectVolatile(UNSAFE.staticFieldBase(f1), UNSAFE.staticFieldOffset(f1), gridEvents());
UNSAFE.putObjectVolatile(UNSAFE.staticFieldBase(f2), UNSAFE.staticFieldOffset(f2),
gridEvents(EVT_NODE_METRICS_UPDATED));
assert EVTS_ALL != null;
assert EVTS_ALL.length == GRID_EVTS.length;
assert EVTS_ALL_MINUS_METRIC_UPDATE != null;
assert EVTS_ALL_MINUS_METRIC_UPDATE.length == GRID_EVTS.length - 1;
// Validate correctness.
for (int type : GRID_EVTS) {
assert containsIntArray(EVTS_ALL, type);
if (type != EVT_NODE_METRICS_UPDATED)
assert containsIntArray(EVTS_ALL_MINUS_METRIC_UPDATE, type);
}
assert !containsIntArray(EVTS_ALL_MINUS_METRIC_UPDATE, EVT_NODE_METRICS_UPDATED);
}
catch (NoSuchFieldException e) {
throw new GridRuntimeException(e);
}
}
Thread timer = new Thread(new Runnable() {
@SuppressWarnings({"BusyWait", "InfiniteLoopStatement"})
@Override public void run() {
while (true) {
curTimeMillis = System.currentTimeMillis();
try {
Thread.sleep(10);
}
catch (InterruptedException ignored) {
U.log(null, "Timer thread has been interrupted.");
}
}
}
}, "gridgain-clock");
timer.setDaemon(true);
timer.setPriority(10);
timer.start();
}
/**
* @return System time approximated by 10 ms.
*/
public static long currentTimeMillis() {
return curTimeMillis;
}
/**
* @return Value of {@link System#nanoTime()} in microseconds.
*/
public static long microTime() {
return System.nanoTime() / 1000;
}
/**
* Gets nearest power of 2 larger or equal than v.
*
* @param v Value.
* @return Nearest power of 2.
*/
public static int ceilPow2(int v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ++v;
}
/**
* @param i Value.
* @return {@code true} If the given value is power of 2 (0 is not power of 2).
*/
public static boolean isPow2(int i) {
return i > 0 && (i & (i - 1)) == 0;
}
/**
* Return SUN specific constructor factory.
*
* @return SUN specific constructor factory.
*/
@Nullable public static Method ctorFactory() {
return CTOR_FACTORY;
}
/**
* @return Empty constructor for object class.
*/
public static Constructor objectConstructor() {
return OBJECT_CTOR;
}
/**
* SUN JDK specific reflection factory for objects without public constructor.
*
* @return Reflection factory for objects without public constructor.
*/
@Nullable public static Object sunReflectionFactory() {
return SUN_REFLECT_FACTORY;
}
/**
* Gets name for given grid event type.
*
* @param type Event type.
* @return Event name.
*/
public static String gridEventName(int type) {
String name = GRID_EVT_NAMES.get(type);
return name != null ? name : Integer.toString(type);
}
/**
* Gets all event types.
*
* @param excl Optional exclude events.
* @return All events minus excluded ones.
*/
public static int[] gridEvents(final int... excl) {
if (F.isEmpty(excl))
return GRID_EVTS;
List evts = toIntList(GRID_EVTS, new P1() {
@Override public boolean apply(Integer i) {
return !containsIntArray(excl, i);
}
});
return toIntArray(evts);
}
/**
* @param discoSpi Discovery SPI.
* @return {@code True} if ordering is supported.
*/
public static boolean discoOrdered(GridDiscoverySpi discoSpi) {
GridDiscoverySpiOrderSupport ann = U.getAnnotation(discoSpi.getClass(), GridDiscoverySpiOrderSupport.class);
return ann != null && ann.value();
}
/**
* @return Checks if disco ordering should be enforced.
*/
public static boolean relaxDiscoveryOrdered() {
return "true".equalsIgnoreCase(System.getProperty(GG_NO_DISCO_ORDER));
}
/**
* This method should be used for adding quick debug statements in code
* while debugging. Calls to this method should never be committed to master.
*
* @param msg Message to debug.
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void debug(Object msg) {
X.println(debugPrefix() + msg);
}
/**
* This method should be used for adding quick debug statements in code
* while debugging. Calls to this method should never be committed to master.
*
* @param msg Message to debug.
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void debugx(String msg) {
X.printerrln(debugPrefix() + msg);
}
/**
* This method should be used for adding quick debug statements in code
* while debugging. Calls to this method should never be committed to master.
*
* @param log Logger.
* @param msg Message to debug.
*
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void debug(GridLogger log, String msg) {
log.info(msg);
}
/**
* Prints stack trace of the current thread to {@code System.out}.
*
* @deprecated Calls to this method should never be committed to master.
*/
@SuppressWarnings("deprecation")
@Deprecated
public static void dumpStack() {
dumpStack("Dumping stack.");
}
/**
* Prints stack trace of the current thread to {@code System.out}.
*
* @param msg Message to print with the stack.
*
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void dumpStack(String msg) {
new Exception(debugPrefix() + msg).printStackTrace(System.out);
}
/**
* @param log Logger.
* @param msg Message.
*/
public static void dumpStack(@Nullable GridLogger log, String msg) {
U.error(log, "Dumping stack.", new Exception(msg));
}
/**
* Prints stack trace of the current thread to provided output stream.
*
* @param msg Message to print with the stack.
* @param out Output to dump stack to.
*
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void dumpStack(String msg, PrintStream out) {
new Exception(msg).printStackTrace(out);
}
/**
* Prints stack trace of the current thread to provided logger.
*
* @param log Logger.
* @param msg Message to print with the stack.
*
* @deprecated Calls to this method should never be committed to master.
*/
@Deprecated
public static void debugStack(GridLogger log, String msg) {
log.error(msg, new Exception(debugPrefix() + msg));
}
/**
* @return Common prefix for debug messages.
*/
private static String debugPrefix() {
return '<' + DEBUG_DATE_FMT.format(new Date(System.currentTimeMillis())) + "><" +
Thread.currentThread().getName() + '>' + ' ';
}
/**
* Prints heap usage.
*/
public static void debugHeapUsage() {
System.gc();
Runtime runtime = Runtime.getRuntime();
X.println('<' + DEBUG_DATE_FMT.format(new Date(System.currentTimeMillis())) + "><" +
Thread.currentThread().getName() + "> Heap stats [free=" + runtime.freeMemory() / (1024 * 1024) +
"M, total=" + runtime.totalMemory() / (1024 * 1024) + "M]");
}
/**
* Gets heap size in GB rounded to specified precision.
*
* @param node Node.
* @param precision Precision.
* @return Heap size in GB.
*/
public static double heapSize(GridNode node, int precision) {
return heapSize(Collections.singleton(node), precision);
}
/**
* Gets total heap size in GB rounded to specified precision.
*
* @param nodes Nodes.
* @param precision Precision.
* @return Total heap size in GB.
*/
public static double heapSize(Iterable nodes, int precision) {
// In bytes.
double heap = 0.0;
for (GridNode n : nodes) {
GridNodeMetrics m = n.metrics();
heap += Math.max(m.getHeapMemoryInitialized(), m.getHeapMemoryMaximum());
}
return roundedHeapSize(heap, precision);
}
/**
* Returns current JVM maxMemory in the same format as {@link #heapSize(GridNode, int)}.
*
* @param precision Precision.
* @return Maximum memory size in GB.
*/
public static double heapSize(int precision) {
return roundedHeapSize(Runtime.getRuntime().maxMemory(), precision);
}
/**
* Rounded heap size in gigabytes.
*
* @param heap Heap.
* @param precision Precision.
* @return Rounded heap size.
*/
private static double roundedHeapSize(double heap, int precision) {
double rounded = new BigDecimal(heap / (1024 * 1024 * 1024d)).round(new MathContext(precision)).doubleValue();
return rounded < 0.1 ? 0.1 : rounded;
}
/**
* Performs thread dump and prints all available info to the given log.
*
* @param log Logger.
*/
public static void dumpThreads(@Nullable GridLogger log) {
ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos =
mxBean.dumpAllThreads(mxBean.isObjectMonitorUsageSupported(), mxBean.isSynchronizerUsageSupported());
GridStringBuilder sb = new GridStringBuilder("Thread dump at ")
.a(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(U.currentTimeMillis()))).a(NL);
for (ThreadInfo info : threadInfos) {
printThreadInfo(info, sb);
sb.a(NL);
if (info.getLockedSynchronizers() != null && info.getLockedSynchronizers().length > 0) {
printSynchronizersInfo(info.getLockedSynchronizers(), sb);
sb.a(NL);
}
}
sb.a(NL);
warn(log, sb.toString());
}
/**
* Prints single thread info to a buffer.
*
* @param threadInfo Thread info.
* @param sb Buffer.
*/
private static void printThreadInfo(ThreadInfo threadInfo, GridStringBuilder sb) {
sb.a("Thread [name=\"").a(threadInfo.getThreadName())
.a("\", id=").a(threadInfo.getThreadId())
.a(", state=").a(threadInfo.getThreadState())
.a(", blockCnt=").a(threadInfo.getBlockedCount())
.a(", waitCnt=").a(threadInfo.getWaitedCount()).a("]").a(NL);
LockInfo lockInfo = threadInfo.getLockInfo();
if (lockInfo != null) {
sb.a(" Lock [object=").a(lockInfo)
.a(", ownerName=").a(threadInfo.getLockOwnerName())
.a(", ownerId=").a(threadInfo.getLockOwnerId()).a("]").a(NL);
}
MonitorInfo[] monitors = threadInfo.getLockedMonitors();
StackTraceElement[] elements = threadInfo.getStackTrace();
for (int i = 0; i < elements.length; i++) {
StackTraceElement e = elements[i];
sb.a(" at ").a(e.toString());
for (MonitorInfo monitor : monitors) {
if (monitor.getLockedStackDepth() == i)
sb.a(NL).a(" - locked ").a(monitor);
}
sb.a(NL);
}
}
/**
* Prints Synchronizers info to a buffer.
*
* @param syncs Synchronizers info.
* @param sb Buffer.
*/
private static void printSynchronizersInfo(LockInfo[] syncs, GridStringBuilder sb) {
sb.a(" Locked synchronizers:");
for (LockInfo info : syncs)
sb.a(NL).a(" ").a(info);
}
/**
*
* @param smtpHost SMTP host.
* @param smtpPort SMTP port.
* @param ssl SMTP SSL.
* @param startTls Start TLS flag.
* @param username Email authentication user name.
* @param pwd Email authentication password.
* @param from From email.
* @param subj Email subject.
* @param body Email body.
* @param html HTML format flag.
* @param addrs Addresses to send email to.
* @throws GridException Thrown in case when sending email failed.
*/
public static void sendEmail(String smtpHost, int smtpPort, boolean ssl, boolean startTls,
final String username, final String pwd, String from, String subj, String body,
boolean html, Collection addrs) throws GridException {
assert smtpHost != null;
assert smtpPort > 0;
assert from != null;
assert subj != null;
assert body != null;
assert addrs != null;
assert !addrs.isEmpty();
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.smtp.host", smtpHost);
props.setProperty("mail.smtp.port", Integer.toString(smtpPort));
if (ssl)
props.setProperty("mail.smtp.ssl", "true");
if (startTls)
props.setProperty("mail.smtp.starttls.enable", "true");
Authenticator auth = null;
// Add property for authentication by username.
if (username != null && !username.isEmpty()) {
props.setProperty("mail.smtp.auth", "true");
auth = new Authenticator() {
@Override public javax.mail.PasswordAuthentication getPasswordAuthentication() {
return new javax.mail.PasswordAuthentication(username, pwd);
}
};
}
Session ses = Session.getInstance(props, auth);
MimeMessage email = new MimeMessage(ses);
try {
email.setFrom(new InternetAddress(from));
email.setSubject(subj);
email.setSentDate(new Date());
if (html)
email.setText(body, "UTF-8", "html");
else
email.setText(body);
Address[] rcpts = new Address[addrs.size()];
int i = 0;
for (String addr : addrs)
rcpts[i++] = new InternetAddress(addr);
email.setRecipients(MimeMessage.RecipientType.TO, rcpts);
Transport.send(email);
}
catch (MessagingException e) {
throw new GridException("Failed to send email.", e);
}
}
/**
* Gets empty constructor for class even if the class does not have empty constructor
* declared. This method is guaranteed to work with SUN JDK and other JDKs still need
* to be tested.
*
* @param cls Class to get empty constructor for.
* @return Empty constructor if one could be found or {@code null} otherwise.
* @throws GridException If failed.
*/
@Nullable public static Constructor> forceEmptyConstructor(Class> cls) throws GridException {
Constructor> ctor = null;
try {
return cls.getDeclaredConstructor();
}
catch (Exception ignore) {
Method ctorFac = U.ctorFactory();
Object sunRefFac = U.sunReflectionFactory();
if (ctorFac != null && sunRefFac != null)
try {
ctor = (Constructor)ctorFac.invoke(sunRefFac, cls, U.objectConstructor());
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new GridException("Failed to get object constructor for class: " + cls, e);
}
}
return ctor;
}
/**
* Creates new instance of a class only if it has an empty constructor (can be non-public).
*
* @param cls Class to instantiate.
* @return New instance of the class or {@code null} if empty constructor could not be assigned.
* @throws GridException If failed.
*/
@Nullable public static T newInstance(Class cls) throws GridException {
boolean set = false;
Constructor ctor = null;
try {
ctor = cls.getDeclaredConstructor();
if (ctor == null)
return null;
if (!ctor.isAccessible()) {
ctor.setAccessible(true);
set = true;
}
return ctor.newInstance();
}
catch (NoSuchMethodException e) {
throw new GridException("Failed to find empty constructor for class: " + cls, e);
}
catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new GridException("Failed to create new instance for class: " + cls, e);
} finally {
if (ctor != null && set)
ctor.setAccessible(false);
}
}
/**
* Creates new instance of a class even if it does not have public constructor.
*
* @param cls Class to instantiate.
* @return New instance of the class or {@code null} if empty constructor could not be assigned.
* @throws GridException If failed.
*/
@SuppressWarnings({"unchecked"})
@Nullable public static T forceNewInstance(Class> cls) throws GridException {
Constructor ctor = forceEmptyConstructor(cls);
if (ctor == null)
return null;
boolean set = false;
try {
if (!ctor.isAccessible()) {
ctor.setAccessible(true);
set = true;
}
return (T)ctor.newInstance();
}
catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new GridException("Failed to create new instance for class: " + cls, e);
} finally {
if (set)
ctor.setAccessible(false);
}
}
/**
* Pretty-formatting for minutes.
*
* @param mins Minutes to format.
* @return Formatted presentation of minutes.
*/
public static String formatMins(long mins) {
assert mins >= 0;
if (mins == 0)
return "< 1 min";
SB sb = new SB();
long dd = mins / 1440; // 1440 mins = 60 mins * 24 hours
if (dd > 0)
sb.a(dd).a(dd == 1 ? " day " : " days ");
mins %= 1440;
long hh = mins / 60;
if (hh > 0)
sb.a(hh).a(hh == 1 ? " hour " : " hours ");
mins %= 60;
if (mins > 0)
sb.a(mins).a(mins == 1 ? " min " : " mins ");
return sb.toString().trim();
}
/**
* Gets 8-character substring of UUID (for terse logging).
*
* @param id Input ID.
* @return 8-character ID substring.
*/
public static String id8(UUID id) {
return id.toString().substring(0, 8);
}
/**
* Gets 8-character substring of {@link GridUuid} (for terse logging).
* The ID8 will be constructed as follows:
*
*
Take first 4 digits for global ID, i.e. {@code GridUuid.globalId()}.
*
Take last 4 digits for local ID, i.e. {@code GridUuid.localId()}.
*
*
* @param id Input ID.
* @return 8-character representation of {@code GridUuid}.
*/
public static String id8(GridUuid id) {
String s = id.toString();
return s.substring(0, 4) + s.substring(s.length() - 4);
}
/**
*
* @param len Number of characters to fill in.
* @param ch Character to fill with.
* @return String.
*/
public static String filler(int len, char ch) {
char[] a = new char[len];
Arrays.fill(a, ch);
return new String(a);
}
/**
* Writes array to output stream.
*
* @param out Output stream.
* @param arr Array to write.
* @param Array type.
* @throws IOException If failed.
*/
public static void writeArray(ObjectOutput out, T[] arr) throws IOException {
int len = arr == null ? 0 : arr.length;
out.writeInt(len);
if (arr != null && arr.length > 0)
for (T t : arr)
out.writeObject(t);
}
/**
* Reads array from input stream.
*
* @param in Input stream.
* @return Deserialized array.
* @throws IOException If failed.
* @throws ClassNotFoundException If class not found.
*/
@Nullable public static Object[] readArray(ObjectInput in) throws IOException, ClassNotFoundException {
int len = in.readInt();
Object[] arr = null;
if (len > 0) {
arr = new Object[len];
for (int i = 0; i < len; i++)
arr[i] = in.readObject();
}
return arr;
}
/**
* Reads array from input stream.
*
* @param in Input stream.
* @return Deserialized array.
* @throws IOException If failed.
* @throws ClassNotFoundException If class not found.
*/
@SuppressWarnings("unchecked")
@Nullable public static GridPredicate>[] readEntryFilterArray(ObjectInput in)
throws IOException, ClassNotFoundException {
int len = in.readInt();
GridPredicate>[] arr = null;
if (len > 0) {
arr = new GridPredicate[len];
for (int i = 0; i < len; i++)
arr[i] = (GridPredicate>)in.readObject();
}
return arr;
}
/**
*
* @param out Output.
* @param col Set to write.
* @throws IOException If write failed.
*/
public static void writeCollection(ObjectOutput out, Collection> col) throws IOException {
if (col != null) {
out.writeInt(col.size());
for (Object o : col)
out.writeObject(o);
}
else
out.writeInt(-1);
}
/**
* Writes collection of byte arrays to data output.
*
* @param out Output to write to.
* @param bytes Collection with byte arrays.
* @throws IOException If write failed.
*/
public static void writeBytesCollection(DataOutput out, Collection bytes) throws IOException {
if (bytes != null) {
out.writeInt(bytes.size());
for (byte[] b : bytes)
writeByteArray(out, b);
}
else
out.writeInt(-1);
}
/**
* Reads collection of byte arrays from data input.
*
* @param in Data input to read from.
* @return List of byte arrays.
* @throws IOException If read failed.
*/
public static List readBytesList(DataInput in) throws IOException {
int size = in.readInt();
if (size < 0)
return null;
List res = new ArrayList<>(size);
for (int i = 0; i < size; i++)
res.add(readByteArray(in));
return res;
}
/**
*
* @param out Output.
* @param col Set to write.
* @throws IOException If write failed.
*/
public static void writeIntCollection(DataOutput out, Collection col) throws IOException {
if (col != null) {
out.writeInt(col.size());
for (Integer i : col)
out.writeInt(i);
}
else
out.writeInt(-1);
}
/**
* @param in Input.
* @return Deserialized set.
* @throws IOException If deserialization failed.
* @throws ClassNotFoundException If deserialized class could not be found.
*/
@Nullable public static Collection readCollection(ObjectInput in)
throws IOException, ClassNotFoundException {
return readList(in);
}
/**
* @param in Input.
* @return Deserialized set.
* @throws IOException If deserialization failed.
*/
@Nullable public static Collection readIntCollection(DataInput in) throws IOException {
int size = in.readInt();
// Check null flag.
if (size == -1)
return null;
Collection col = new ArrayList<>(size);
for (int i = 0; i < size; i++)
col.add(in.readInt());
return col;
}
/**
*
* @param m Map to copy.
* @param Key type.
* @param Value type
* @return Copied map.
*/
public static Map copyMap(Map m) {
return new HashMap<>(m);
}
/**
*
* @param m Map to seal.
* @param Key type.
* @param Value type
* @return Sealed map.
*/
public static Map sealMap(Map m) {
assert m != null;
return Collections.unmodifiableMap(new HashMap<>(m));
}
/**
* Seal collection.
*
* @param c Collection to seal.
* @param Entry type
* @return Sealed collection.
*/
public static List sealList(Collection c) {
return Collections.unmodifiableList(new ArrayList<>(c));
}
/**
* Gets display name of the network interface this IP address belongs to.
*
* @param addr IP address for which to find network interface name.
* @return Network interface name or {@code null} if can't be found.
*/
@Nullable public static String getNetworkInterfaceName(String addr) {
assert addr != null;
try {
InetAddress inetAddr = InetAddress.getByName(addr);
for (NetworkInterface itf : asIterable(NetworkInterface.getNetworkInterfaces()))
for (InetAddress itfAddr : asIterable(itf.getInetAddresses()))
if (itfAddr.equals(inetAddr))
return itf.getDisplayName();
}
catch (UnknownHostException ignore) {
return null;
}
catch (SocketException ignore) {
return null;
}
return null;
}
/**
* Tries to resolve host by name, returning local host if input is empty.
* This method reflects how {@link GridConfiguration#getLocalHost()} should
* be handled in most places.
*
* @param hostName Hostname or {@code null} if local host should be returned.
* @return Address of given host or of localhost.
* @throws IOException If attempt to get local host failed.
*/
public static InetAddress resolveLocalHost(@Nullable String hostName) throws IOException {
return F.isEmpty(hostName) ?
// Should default to InetAddress#anyLocalAddress which is package-private.
new InetSocketAddress(0).getAddress() :
InetAddress.getByName(hostName);
}
/**
* Determines whether current local host is different from previously cached.
*
* @return {@code true} or {@code false} depending on whether or not local host
* has changed from the cached value.
* @throws IOException If attempt to get local host failed.
*/
public static synchronized boolean isLocalHostChanged() throws IOException {
InetAddress locHost0 = locHost;
return locHost0 != null && !resetLocalHost().equals(locHost0);
}
/**
* Returns host names consistent with {@link #resolveLocalHost(String)}. So when it returns
* a common address this method returns single host name, and when a wildcard address passed
* this method tries to collect addresses of all available interfaces.
*
* @param locAddr Local address to resolve.
* @return Resolved available addresses of given local address.
* @throws IOException If failed.
* @throws GridException If no network interfaces found.
*/
public static GridBiTuple, Collection> resolveLocalAddresses(InetAddress locAddr)
throws IOException, GridException {
assert locAddr != null;
Collection addrs = new ArrayList<>();
Collection hostNames = new ArrayList<>();
if (locAddr.isAnyLocalAddress()) {
// It should not take longer than 2 seconds to reach
// local address on any network.
int reachTimeout = 2000;
for (NetworkInterface itf : asIterable(NetworkInterface.getNetworkInterfaces())) {
for (InetAddress addr : asIterable(itf.getInetAddresses())) {
if (!addr.isLinkLocalAddress() && reachable(itf, addr, reachTimeout))
addresses(addr, addrs, hostNames);
}
}
if (F.isEmpty(addrs))
throw new GridException("No network addresses found (is networking enabled?).");
}
else
addresses(locAddr, addrs, hostNames);
return F.t(addrs, hostNames);
}
/**
* @param addr Address.
* @param addrs Addresses.
* @param hostNames Host names.
*/
private static void addresses(InetAddress addr, Collection addrs, Collection hostNames) {
String hostName = addr.getHostName();
String ipAddr = addr.getHostAddress();
hostName = F.isEmpty(hostName) || hostName.equals(ipAddr) || addr.isLoopbackAddress() ? "" : hostName;
addrs.add(ipAddr);
hostNames.add(hostName);
}
/**
* Gets local host. Implementation will first attempt to get a non-loopback
* address. If that fails, then loopback address will be returned.
*
* Note that this method is synchronized to make sure that local host
* initialization happens only once.
*
* @return Address representing local host.
* @throws IOException If attempt to get local host failed.
*/
public static synchronized InetAddress getLocalHost() throws IOException {
if (locHost == null)
// Cache it.
resetLocalHost();
return locHost;
}
/**
* @return Local host.
* @throws IOException If attempt to get local host failed.
*/
private static synchronized InetAddress resetLocalHost() throws IOException {
locHost = null;
String sysLocHost = X.getSystemOrEnv(GG_LOCAL_HOST);
if (sysLocHost != null)
sysLocHost = sysLocHost.trim();
if (!F.isEmpty(sysLocHost))
locHost = InetAddress.getByName(sysLocHost);
else {
List itfs = new ArrayList<>();
for (NetworkInterface itf : asIterable(NetworkInterface.getNetworkInterfaces()))
itfs.add(itf);
Collections.sort(itfs, new Comparator() {
@Override public int compare(NetworkInterface itf1, NetworkInterface itf2) {
// Interfaces whose name starts with 'e' should go first.
return itf1.getName().compareTo(itf2.getName());
}
});
// It should not take longer than 2 seconds to reach
// local address on any network.
int reachTimeout = 2000;
for (NetworkInterface itf : itfs) {
boolean found = false;
for (InetAddress addr : asIterable(itf.getInetAddresses())) {
if (!addr.isLoopbackAddress() && !addr.isLinkLocalAddress() && reachable(itf, addr, reachTimeout)) {
locHost = addr;
found = true;
break;
}
}
if (found)
break;
}
}
if (locHost == null)
locHost = InetAddress.getLocalHost();
return locHost;
}
/**
* Checks if address can be reached using three argument InetAddress.isReachable() version.
*
* @param itf Network interface to use for test.
* @param addr Address to check.
* @param reachTimeout Timeout for the check.
* @return {@code True} if address is reachable.
*/
public static boolean reachable(NetworkInterface itf, InetAddress addr, int reachTimeout) {
try {
return addr.isReachable(itf, 0, reachTimeout);
}
catch (IOException ignore) {
return false;
}
}
/**
* Checks if address can be reached using one argument InetAddress.isReachable() version.
*
* @param addr Address to check.
* @param reachTimeout Timeout for the check.
* @return {@code True} if address is reachable.
*/
public static boolean reachable(InetAddress addr, int reachTimeout) {
try {
return addr.isReachable(reachTimeout);
}
catch (IOException ignore) {
return false;
}
}
/**
* @param loc Local node.
* @param rmt Remote node.
* @return Whether given nodes have the same macs.
*/
public static boolean sameMacs(GridNode loc, GridNode rmt) {
assert loc != null;
assert rmt != null;
String locMacs = loc.attribute(GridNodeAttributes.ATTR_MACS);
String rmtMacs = rmt.attribute(GridNodeAttributes.ATTR_MACS);
return locMacs != null && locMacs.equals(rmtMacs);
}
/**
* Gets a list of all local non-loopback IPs known to this JVM.
* Note that this will include both IPv4 and IPv6 addresses (even if one "resolves"
* into another). Loopbacks will be skipped.
*
* @return List of all known local IPs (empty list if no addresses available).
*/
public static synchronized Collection allLocalIps() {
Collection ips = new HashSet<>(4);
try {
Enumeration itfs = NetworkInterface.getNetworkInterfaces();
if (itfs != null) {
for (NetworkInterface itf : asIterable(itfs)) {
if (!itf.isLoopback()) {
Enumeration addrs = itf.getInetAddresses();
if (addrs != null)
for (InetAddress addr : asIterable(addrs))
if (!addr.isLoopbackAddress())
ips.add(addr.getHostAddress());
}
}
}
}
catch (SocketException ignore) {
return Collections.emptyList();
}
return ips;
}
/**
* Gets a list of all local enabled MACs known to this JVM. It
* is using hardware address of the network interface that is not guaranteed to be
* MAC addresses (but in most cases it is).
*
* Note that if network interface is disabled - its MAC won't be included. All
* local network interfaces are probed including loopbacks. Virtual interfaces
* (sub-interfaces) are skipped.
*
* Note that on linux getHardwareAddress() can return null from time to time
* if NetworkInterface.getHardwareAddress() method is called from many threads.
*
* @return List of all known enabled local MACs or empty list
* if no MACs could be found.
*/
public static synchronized Collection allLocalMACs() {
Collection macs = new HashSet<>(3);
try {
Enumeration itfs = NetworkInterface.getNetworkInterfaces();
if (itfs != null) {
for (NetworkInterface itf : asIterable(itfs)) {
byte[] hwAddr = itf.getHardwareAddress();
// Loopback produces empty MAC.
if (hwAddr != null && hwAddr.length > 0) {
String mac = byteArray2HexString(hwAddr);
macs.add(mac);
}
}
}
}
catch (SocketException ignore) {
return Collections.emptyList();
}
return macs;
}
/**
* Gets user version for given class loader by checking
* {@code META-INF/gridgain.xml} file for {@code userVersion} attribute. If
* {@code gridgain.xml} file is not found, or user version is not specified there,
* then default version (empty string) is returned.
*
* @param ldr Class loader.
* @param log Logger.
* @return User version for given class loader or empty string if no version
* was explicitly specified.
*/
public static String getUserVersion(ClassLoader ldr, GridLogger log) {
assert ldr != null;
assert log != null;
// For system class loader return cached version.
if (ldr == gridClassLoader() && SYS_LDR_VER.get() != null)
return SYS_LDR_VER.get();
String usrVer = DFLT_USER_VERSION;
InputStream in = ldr.getResourceAsStream(GRIDGAIN_XML_PATH);
if (in != null) {
// Note: use ByteArrayResource instead of InputStreamResource because
// InputStreamResource doesn't work.
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
copy(in, out);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new ByteArrayResource(out.toByteArray()));
usrVer = (String)factory.getBean("userVersion");
usrVer = usrVer == null ? DFLT_USER_VERSION : usrVer.trim();
}
catch (NoSuchBeanDefinitionException ignored) {
if (log.isInfoEnabled())
log.info("User version is not explicitly defined (will use default version) [file=" +
GRIDGAIN_XML_PATH + ", clsLdr=" + ldr + ']');
usrVer = DFLT_USER_VERSION;
}
catch (BeansException e) {
U.error(log, "Failed to parse Spring XML file (will use default user version) [file=" +
GRIDGAIN_XML_PATH + ", clsLdr=" + ldr + ']', e);
usrVer = DFLT_USER_VERSION;
}
catch (IOException e) {
U.error(log, "Failed to read Spring XML file (will use default user version) [file=" +
GRIDGAIN_XML_PATH + ", clsLdr=" + ldr + ']', e);
usrVer = DFLT_USER_VERSION;
}
finally {
close(out, log);
}
}
// For system class loader return cached version.
if (ldr == gridClassLoader())
SYS_LDR_VER.compareAndSet(null, usrVer);
return usrVer;
}
/**
* Downloads resource by URL.
*
* @param url URL to download.
* @param file File where downloaded resource should be stored.
* @return File where downloaded resource should be stored.
* @throws IOException If error occurred.
*/
public static File downloadUrl(URL url, File file) throws IOException {
assert url != null;
assert file != null;
InputStream in = null;
OutputStream out = null;
try {
URLConnection conn = url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection https = (HttpsURLConnection)conn;
https.setHostnameVerifier(new DeploymentHostnameVerifier());
SSLContext ctx = SSLContext.getInstance(HTTPS_PROTOCOL);
ctx.init(null, getTrustManagers(), null);
// Initialize socket factory.
https.setSSLSocketFactory(ctx.getSocketFactory());
}
in = conn.getInputStream();
if (in == null)
throw new IOException("Failed to open connection: " + url.toString());
out = new BufferedOutputStream(new FileOutputStream(file));
copy(in, out);
}
catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new IOException("Failed to open HTTPs connection [url=" + url.toString() + ", msg=" + e + ']', e);
} finally {
close(in, null);
close(out, null);
}
return file;
}
/**
* Construct array with one trust manager which don't reject input certificates.
*
* @return Array with one X509TrustManager implementation of trust manager.
*/
private static TrustManager[] getTrustManagers() {
return new TrustManager[]{
new X509TrustManager() {
@Nullable @Override public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override public void checkClientTrusted(X509Certificate[] certs, String authType) {
/* No-op. */
}
@Override public void checkServerTrusted(X509Certificate[] certs, String authType) {
/* No-op. */
}
}
};
}
/**
* Copies metadata from given object into the passed in metadata aware
* instance - if object is not {@code null} and implements {@link GridMetadataAware}.
* Otherwise - returns passed metadata aware instance unchanged.
*
* @param t Passed in metadata aware instance.
* @param obj Object to copy metadata from.
* @param Type of the metadata aware instance.
* @return Metadata aware instance with metadata potentially copied.
*/
public static T withMeta(T t, @Nullable Object obj) {
assert t != null;
if (obj instanceof GridMetadataAware)
t.copyMeta((GridMetadataAware)obj);
return t;
}
/**
* Replace password in URI string with a single '*' character.
*
* Parses given URI by applying ".*://(.*:.*)@.*"
* regular expression pattern and than if URI matches it
* replaces password strings between '/' and '@' with '*'.
*
* @param uri URI which password should be replaced.
* @return Converted URI string
*/
@Nullable public static String hidePassword(@Nullable String uri) {
if (uri == null)
return null;
if (Pattern.matches(".*://(.*:.*)@.*", uri)) {
int userInfoLastIdx = uri.indexOf('@');
assert userInfoLastIdx != -1;
String str = uri.substring(0, userInfoLastIdx);
int userInfoStartIdx = str.lastIndexOf('/');
str = str.substring(userInfoStartIdx + 1);
String[] params = str.split(";");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < params.length; i++) {
int idx;
if ((idx = params[i].indexOf(':')) != -1)
params[i] = params[i].substring(0, idx + 1) + '*';
builder.append(params[i]);
if (i != params.length - 1)
builder.append(';');
}
return new StringBuilder(uri).replace(userInfoStartIdx + 1, userInfoLastIdx,
builder.toString()).toString();
}
return uri;
}
/**
* @return Class loader used to load GridGain itself.
*/
public static ClassLoader gridClassLoader() {
return gridClassLoader;
}
/**
* @param parent Parent to find.
* @param ldr Loader to check.
* @return {@code True} if parent found.
*/
public static boolean hasParent(@Nullable ClassLoader parent, ClassLoader ldr) {
if (parent != null) {
for (; ldr != null; ldr = ldr.getParent()) {
if (ldr.equals(parent))
return true;
}
return false;
}
return true;
}
/**
* Verifier always returns successful result for any host.
*/
private static class DeploymentHostnameVerifier implements HostnameVerifier {
/** {@inheritDoc} */
@Override public boolean verify(String hostname, SSLSession ses) {
// Remote host trusted by default.
return true;
}
}
/**
* Makes a {@code '+---+'} dash line.
*
* @param len Length of the dash line to make.
* @return Dash line.
*/
public static String dash(int len) {
char[] dash = new char[len];
Arrays.fill(dash, '-');
dash[0] = dash[len - 1] = '+';
return new String(dash);
}
/**
* Creates space filled string of given length.
*
* @param len Number of spaces.
* @return Space filled string of given length.
*/
public static String pad(int len) {
char[] dash = new char[len];
Arrays.fill(dash, ' ');
return new String(dash);
}
/**
* Formats system time in milliseconds for printing in logs.
*
* @param sysTime System time.
* @return Formatted time string.
*/
public static String format(long sysTime) {
return LONG_DATE_FMT.format(new java.util.Date(sysTime));
}
/**
* Takes given collection, shuffles it and returns iterable instance.
*
* @param Type of elements to create iterator for.
* @param col Collection to shuffle.
* @return Iterable instance over randomly shuffled collection.
*/
public static Iterable randomIterable(Collection col) {
List list = new ArrayList<>(col);
Collections.shuffle(list);
return list;
}
/**
* Converts enumeration to iterable so it can be used in {@code foreach} construct.
*
* @param Types of instances for iteration.
* @param e Enumeration to convert.
* @return Iterable over the given enumeration.
*/
public static Iterable asIterable(final Enumeration e) {
return new Iterable() {
@Override public Iterator iterator() {
return new Iterator() {
@Override public boolean hasNext() {
return e.hasMoreElements();
}
@SuppressWarnings({"IteratorNextCanNotThrowNoSuchElementException"})
@Override public T next() {
return e.nextElement();
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
/**
* Copy source file (or folder) to destination file (or folder). Supported source & destination:
*
*
File to File
*
File to Folder
*
Folder to Folder (Copy the content of the directory and not the directory itself)
*
*
* @param src Source file or folder.
* @param dest Destination file or folder.
* @param overwrite Whether or not overwrite existing files and folders.
* @throws IOException Thrown if an I/O error occurs.
*/
public static void copy(File src, File dest, boolean overwrite) throws IOException {
assert src != null;
assert dest != null;
/*
* Supported source & destination:
* ===============================
* 1. File -> File
* 2. File -> Directory
* 3. Directory -> Directory
*/
// Source must exist.
if (!src.exists())
throw new FileNotFoundException("Source can't be found: " + src);
// Check that source and destination are not the same.
if (src.getAbsoluteFile().equals(dest.getAbsoluteFile()))
throw new IOException("Source and destination are the same [src=" + src + ", dest=" + dest + ']');
if (dest.exists()) {
if (!dest.isDirectory() && !overwrite)
throw new IOException("Destination already exists: " + dest);
if (!dest.canWrite())
throw new IOException("Destination is not writable:" + dest);
}
else {
File parent = dest.getParentFile();
if (parent != null && !parent.exists())
// Ignore any errors here.
// We will get errors when we'll try to open the file stream.
//noinspection ResultOfMethodCallIgnored
parent.mkdirs();
// If source is a directory, we should create destination directory.
if (src.isDirectory())
//noinspection ResultOfMethodCallIgnored
dest.mkdir();
}
if (src.isDirectory()) {
// In this case we have Directory -> Directory.
// Note that we copy the content of the directory and not the directory itself.
File[] files = src.listFiles();
for (File file : files) {
if (file.isDirectory()) {
File dir = new File(dest, file.getName());
if (!dir.exists() && !dir.mkdirs())
throw new IOException("Can't create directory: " + dir);
copy(file, dir, overwrite);
}
else
copy(file, dest, overwrite);
}
}
else {
// In this case we have File -> File or File -> Directory.
File file = dest.exists() && dest.isDirectory() ? new File(dest, src.getName()) : dest;
if (!overwrite && file.exists())
throw new IOException("Destination already exists: " + file);
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(file);
copy(in, out);
}
finally {
if (in != null)
in.close();
if (out != null) {
out.getFD().sync();
out.close();
}
}
}
}
/**
* Copies input byte stream to output byte stream.
*
* @param in Input byte stream.
* @param out Output byte stream.
* @return Number of the copied bytes.
* @throws IOException Thrown if an I/O error occurs.
*/
public static int copy(InputStream in, OutputStream out) throws IOException {
assert in != null;
assert out != null;
byte[] buf = new byte[BUF_SIZE];
int cnt = 0;
for (int n; (n = in.read(buf)) > 0;) {
out.write(buf, 0, n);
cnt += n;
}
return cnt;
}
/**
* Copies input character stream to output character stream.
*
* @param in Input character stream.
* @param out Output character stream.
* @return Number of the copied characters.
* @throws IOException Thrown if an I/O error occurs.
*/
public static int copy(Reader in, Writer out) throws IOException {
assert in != null;
assert out != null;
char[] buf = new char[BUF_SIZE];
int cnt = 0;
for (int n; (n = in.read(buf)) > 0;) {
out.write(buf, 0, n);
cnt += n;
}
return cnt;
}
/**
* Utility method that sets cause into exception and returns it.
*
* @param e Exception to set cause to and return.
* @param cause Optional cause to set (if not {@code null}).
* @param Type of the exception.
* @return Passed in exception with optionally set cause.
*/
public static E withCause(E e, @Nullable Throwable cause) {
assert e != null;
if (cause != null)
e.initCause(cause);
return e;
}
/**
* Deletes file or directory with all sub-directories and files.
*
* @param file File or directory to delete.
* @return {@code true} if and only if the file or directory is successfully deleted,
* {@code false} otherwise
*/
public static boolean delete(File file) {
assert file != null;
boolean res = true;
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0)
for (File file1 : files)
if (file1.isDirectory())
res &= delete(file1);
else if (file1.getName().endsWith("jar"))
try {
// Why do we do this?
new JarFile(file1, false).close();
res &= file1.delete();
}
catch (IOException ignore) {
// Ignore it here...
}
else
res &= file1.delete();
res &= file.delete();
}
else
res = file.delete();
return res;
}
/**
* @param dir Directory to create along with all non-existent parent directories.
* @return {@code True} if directory exists (has been created or already existed),
* {@code false} if has not been created and does not exist.
*/
public static boolean mkdirs(File dir) {
assert dir != null;
return dir.mkdirs() || dir.exists();
}
/**
* Gets boolean system or environment property.
*
* @param name Property name.
* @return {@code True} if system or environment property is set to {@code true}. Otherwise returns {@code false}.
*/
public static boolean getBoolean(String name) {
String v = X.getSystemOrEnv(name);
return v != null && "true".equalsIgnoreCase(v.trim());
}
/**
* Resolve project home directory based on source code base.
*
* @return Project home directory (or {@code null} if it cannot be resolved).
*/
@Nullable private static String resolveProjectHome() {
assert Thread.holdsLock(GridUtils.class);
// Resolve GridGain home via environment variables.
String ggHome0 = X.getSystemOrEnv(GG_HOME);
if (!F.isEmpty(ggHome0))
return ggHome0;
// Order: gridgain.jar, 'libs'.
for (Class> cls : Arrays.asList(GridUtils.class, Hex.class)) {
URI uri;
try {
ProtectionDomain domain = cls.getProtectionDomain();
// Should not happen, but to make sure our code is not broken.
if (domain == null || domain.getCodeSource() == null || domain.getCodeSource().getLocation() == null) {
logResolveFailed(cls, null);
continue;
}
// Resolve path to class-file.
uri = domain.getCodeSource().getLocation().toURI();
}
catch (URISyntaxException | SecurityException e) {
logResolveFailed(cls, e);
continue;
}
for (File cur = new File(uri).getAbsoluteFile(); cur != null; cur = cur.getParentFile()) {
// Check 'cur' is project home directory.
if (!new File(cur, "bin").isDirectory() ||
!new File(cur, "libs").isDirectory() ||
!new File(cur, "config").isDirectory())
continue;
return cur.getPath();
}
}
return null;
}
/**
* @param cls Class.
* @param e Exception.
*/
private static void logResolveFailed(Class cls, Exception e) {
warn(null, "Failed to resolve GRIDGAIN_HOME automatically for class codebase " +
"[class=" + cls + (e == null ? "" : ", e=" + e.getMessage()) + ']');
}
/**
* Retrieves {@code GRIDGAIN_HOME} property. The property is retrieved from system
* properties or from environment in that order.
*
* @return {@code GRIDGAIN_HOME} property.
*/
@Nullable public static String getGridGainHome() {
GridTuple ggHomeTup = ggHome;
String ggHome0;
if (ggHomeTup == null) {
synchronized (GridUtils.class) {
// Double check.
ggHomeTup = ggHome;
if (ggHomeTup == null) {
// Resolve GridGain installation home directory.
ggHome = F.t(ggHome0 = resolveProjectHome());
if (ggHome0 != null)
System.setProperty(GG_HOME, ggHome0);
}
else
ggHome0 = ggHomeTup.get();
}
}
else
ggHome0 = ggHomeTup.get();
return ggHome0;
}
/**
* @param path GridGain home. May be {@code null}.
*/
public static void setGridGainHome(@Nullable String path) {
GridTuple ggHomeTup = ggHome;
String ggHome0;
if (ggHomeTup == null) {
synchronized (GridUtils.class) {
// Double check.
ggHomeTup = ggHome;
if (ggHomeTup == null) {
if (F.isEmpty(path))
System.clearProperty(GG_HOME);
else
System.setProperty(GG_HOME, path);
ggHome = F.t(path);
return;
}
else
ggHome0 = ggHomeTup.get();
}
}
else
ggHome0 = ggHomeTup.get();
if (ggHome0 != null && !ggHome0.equals(path))
throw new GridRuntimeException("Failed to set GRIDGAIN_HOME after it has been already resolved " +
"[ggHome=" + ggHome0 + ", newGgHome=" + path + ']');
}
/**
* Gets file associated with path.
*
* First check if path is relative to {@code GRIDGAIN_HOME}.
* If not, check if path is absolute.
* If all checks fail, then {@code null} is returned.
*
* See {@link #getGridGainHome()} for information on how {@code GRIDGAIN_HOME} is retrieved.
*
* @param path Path to resolve.
* @return Resolved path as file, or {@code null} if path cannot be resolved.
*/
@Nullable public static File resolveGridGainPath(String path) {
assert path != null;
/*
* 1. Check relative to GRIDGAIN_HOME specified in
* configuration, if any.
*/
String home = getGridGainHome();
if (home != null) {
File file = new File(home, path);
if (file.exists())
return file;
file = new File(home, "os/" + path);
if (file.exists())
return file;
}
/*
* 2. Check given path as absolute.
*/
File file = new File(path);
if (file.exists())
// Note: we use that method's chain instead of File.getURL() with due
// Sun bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6179468
return file;
return null;
}
/**
* Gets URL representing the path passed in. First the check is made if path is absolute.
* If not, then the check is made if path is relative to {@code META-INF} folder in classpath.
* If not, then the check is made if path is relative to ${GRIDGAIN_HOME}.
* If all checks fail,
* then {@code null} is returned, otherwise URL representing path is returned.
*
* See {@link #getGridGainHome()} for information on how {@code GRIDGAIN_HOME} is retrieved.
*
* @param path Path to resolve.
* @return Resolved path as URL, or {@code null} if path cannot be resolved.
* @see #getGridGainHome()
*/
@Nullable public static URL resolveGridGainUrl(String path) {
return resolveGridGainUrl(path, true);
}
/**
* Gets URL representing the path passed in. First the check is made if path is absolute.
* If not, then the check is made if path is relative to {@code META-INF} folder in classpath.
* If not, then the check is made if path is relative to ${GRIDGAIN_HOME}.
* If all checks fail,
* then {@code null} is returned, otherwise URL representing path is returned.
*
* See {@link #getGridGainHome()} for information on how {@code GRIDGAIN_HOME} is retrieved.
*
* @param path Path to resolve.
* @param metaInf Flag to indicate whether META-INF folder should be checked or class path root.
* @return Resolved path as URL, or {@code null} if path cannot be resolved.
* @see #getGridGainHome()
*/
@SuppressWarnings({"UnusedCatchParameter"})
@Nullable public static URL resolveGridGainUrl(String path, boolean metaInf) {
File f = resolveGridGainPath(path);
if (f == null)
f = resolveGridGainPath("os/" + path);
if (f != null) {
try {
// Note: we use that method's chain instead of File.getURL() with due
// Sun bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6179468
return f.toURI().toURL();
}
catch (MalformedURLException e) {
// No-op.
}
}
String locPath = (metaInf ? "META-INF/" : "") + path.replaceAll("\\\\", "/");
return Thread.currentThread().getContextClassLoader().getResource(locPath);
}
/**
* Join byte arrays into single one.
*
* @param bufs list of byte arrays to concatenate.
* @return Concatenated byte's array.
*/
public static byte[] join(byte[]... bufs) {
int size = 0;
for (byte[] buf : bufs) {
size += buf.length;
}
byte[] res = new byte[size];
int position = 0;
for (byte[] buf : bufs) {
arrayCopy(buf, 0, res, position, buf.length);
position += buf.length;
}
return res;
}
/**
* Converts byte array to formatted string. If calling:
*
*
* @param arr Array of byte.
* @param hdrFmt C-style string format for the first element.
* @param bodyFmt C-style string format for second and following elements, if any.
* @return String with converted bytes.
*/
public static String byteArray2String(byte[] arr, String hdrFmt, String bodyFmt) {
assert arr != null;
assert hdrFmt != null;
assert bodyFmt != null;
SB sb = new SB();
sb.a('{');
boolean first = true;
for (byte b : arr)
if (first) {
sb.a(String.format(hdrFmt, b));
first = false;
}
else
sb.a(String.format(bodyFmt, b));
sb.a('}');
return sb.toString();
}
/**
* Converts byte array to hex string.
*
* @param arr Array of bytes.
* @return Hex string.
*/
public static String byteArray2HexString(byte[] arr) {
SB sb = new SB(arr.length << 1);
for (byte b : arr)
sb.a(Integer.toHexString(MASK & b >>> 4)).a(Integer.toHexString(MASK & b));
return sb.toString().toUpperCase();
}
/**
* Convert string with hex values to byte array.
*
* @param hex Hexadecimal string to convert.
* @return array of bytes defined as hex in string.
* @throws IllegalArgumentException If input character differs from certain hex characters.
*/
public static byte[] hexString2ByteArray(String hex) throws IllegalArgumentException {
// If Hex string has odd character length.
if (hex.length() % 2 != 0)
hex = '0' + hex;
char[] chars = hex.toCharArray();
byte[] bytes = new byte[chars.length / 2];
int byteCnt = 0;
for (int i = 0; i < chars.length; i += 2) {
int newByte = 0;
newByte |= hexCharToByte(chars[i]);
newByte <<= 4;
newByte |= hexCharToByte(chars[i + 1]);
bytes[byteCnt] = (byte)newByte;
byteCnt++;
}
return bytes;
}
/**
* Return byte value for certain character.
*
* @param ch Character
* @return Byte value.
* @throws IllegalArgumentException If input character differ from certain hex characters.
*/
@SuppressWarnings({"UnnecessaryFullyQualifiedName", "fallthrough"})
private static byte hexCharToByte(char ch) throws IllegalArgumentException {
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return (byte)(ch - '0');
case 'a':
case 'A':
return 0xa;
case 'b':
case 'B':
return 0xb;
case 'c':
case 'C':
return 0xc;
case 'd':
case 'D':
return 0xd;
case 'e':
case 'E':
return 0xe;
case 'f':
case 'F':
return 0xf;
default:
throw new IllegalArgumentException("Hex decoding wrong input character [character=" + ch + ']');
}
}
/**
* Converts primitive double to byte array.
*
* @param d Double to convert.
* @return Byte array.
*/
public static byte[] doubleToBytes(double d) {
return longToBytes(Double.doubleToLongBits(d));
}
/**
* Converts primitive {@code double} type to byte array and stores
* it in the specified byte array.
*
* @param d Double to convert.
* @param bytes Array of bytes.
* @param off Offset.
* @return New offset.
*/
public static int doubleToBytes(double d, byte[] bytes, int off) {
return longToBytes(Double.doubleToLongBits(d), bytes, off);
}
/**
* Converts primitive float to byte array.
*
* @param f Float to convert.
* @return Array of bytes.
*/
public static byte[] floatToBytes(float f) {
return intToBytes(Float.floatToIntBits(f));
}
/**
* Converts primitive float to byte array.
*
* @param f Float to convert.
* @param bytes Array of bytes.
* @param off Offset.
* @return New offset.
*/
public static int floatToBytes(float f, byte[] bytes, int off) {
return intToBytes(Float.floatToIntBits(f), bytes, off);
}
/**
* Converts primitive {@code long} type to byte array.
*
* @param l Long value.
* @return Array of bytes.
*/
public static byte[] longToBytes(long l) {
return GridClientByteUtils.longToBytes(l);
}
/**
* Converts primitive {@code long} type to byte array and stores it in specified
* byte array.
*
* @param l Long value.
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Number of bytes overwritten in {@code bytes} array.
*/
public static int longToBytes(long l, byte[] bytes, int off) {
return off + GridClientByteUtils.longToBytes(l, bytes, off);
}
/**
* Converts primitive {@code int} type to byte array.
*
* @param i Integer value.
* @return Array of bytes.
*/
public static byte[] intToBytes(int i) {
return GridClientByteUtils.intToBytes(i);
}
/**
* Converts primitive {@code int} type to byte array and stores it in specified
* byte array.
*
* @param i Integer value.
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Number of bytes overwritten in {@code bytes} array.
*/
public static int intToBytes(int i, byte[] bytes, int off) {
return off + GridClientByteUtils.intToBytes(i, bytes, off);
}
/**
* Converts primitive {@code short} type to byte array.
*
* @param s Short value.
* @return Array of bytes.
*/
public static byte[] shortToBytes(short s) {
return GridClientByteUtils.shortToBytes(s);
}
/**
* Converts primitive {@code short} type to byte array and stores it in specified
* byte array.
*
* @param s Short value.
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Number of bytes overwritten in {@code bytes} array.
*/
public static int shortToBytes(short s, byte[] bytes, int off) {
return off + GridClientByteUtils.shortToBytes(s, bytes, off);
}
/**
* Encodes {@link java.util.UUID} into a sequence of bytes using the {@link java.nio.ByteBuffer},
* storing the result into a new byte array.
*
* @param uuid Unique identifier.
* @param arr Byte array to fill with result.
* @param off Offset in {@code arr}.
* @return Number of bytes overwritten in {@code bytes} array.
*/
public static int uuidToBytes(@Nullable UUID uuid, byte[] arr, int off) {
return off + GridClientByteUtils.uuidToBytes(uuid, arr, off);
}
/**
* Converts an UUID to byte array.
*
* @param uuid UUID value.
* @return Encoded into byte array {@link java.util.UUID}.
*/
public static byte[] uuidToBytes(@Nullable UUID uuid) {
return GridClientByteUtils.uuidToBytes(uuid);
}
/**
* Constructs {@code short} from byte array.
*
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Short value.
*/
public static short bytesToShort(byte[] bytes, int off) {
assert bytes != null;
int bytesCnt = Short.SIZE >> 3;
if (off + bytesCnt > bytes.length)
// Just use the remainder.
bytesCnt = bytes.length - off;
short res = 0;
for (int i = 0; i < bytesCnt; i++) {
int shift = bytesCnt - i - 1 << 3;
res |= (0xffL & bytes[off++]) << shift;
}
return res;
}
/**
* Constructs {@code int} from byte array.
*
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Integer value.
*/
public static int bytesToInt(byte[] bytes, int off) {
assert bytes != null;
int bytesCnt = Integer.SIZE >> 3;
if (off + bytesCnt > bytes.length)
// Just use the remainder.
bytesCnt = bytes.length - off;
int res = 0;
for (int i = 0; i < bytesCnt; i++) {
int shift = bytesCnt - i - 1 << 3;
res |= (0xffL & bytes[off++]) << shift;
}
return res;
}
/**
* Constructs {@code long} from byte array.
*
* @param bytes Array of bytes.
* @param off Offset in {@code bytes} array.
* @return Long value.
*/
public static long bytesToLong(byte[] bytes, int off) {
assert bytes != null;
int bytesCnt = Long.SIZE >> 3;
if (off + bytesCnt > bytes.length)
bytesCnt = bytes.length - off;
long res = 0;
for (int i = 0; i < bytesCnt; i++) {
int shift = bytesCnt - i - 1 << 3;
res |= (0xffL & bytes[off++]) << shift;
}
return res;
}
/**
* Reads an {@link UUID} form byte array.
* If given array contains all 0s then {@code null} will be returned.
*
* @param bytes array of bytes.
* @param off Offset in {@code bytes} array.
* @return UUID value or {@code null}.
*/
public static UUID bytesToUuid(byte[] bytes, int off) {
return GridClientByteUtils.bytesToUuid(bytes, off);
}
/**
* Constructs double from byte array.
*
* @param bytes Byte array.
* @param off Offset in {@code bytes} array.
* @return Double value.
*/
public static double bytesToDouble(byte[] bytes, int off) {
return Double.longBitsToDouble(bytesToLong(bytes, off));
}
/**
* Constructs float from byte array.
*
* @param bytes Byte array.
* @param off Offset in {@code bytes} array.
* @return Float value.
*/
public static float bytesToFloat(byte[] bytes, int off) {
return Float.intBitsToFloat(bytesToInt(bytes, off));
}
/**
* Compares fragments of byte arrays.
*
* @param a First array.
* @param aOff First array offset.
* @param b Second array.
* @param bOff Second array offset.
* @param len Length of fragments.
* @return {@code true} if fragments are equal, {@code false} otherwise.
*/
public static boolean bytesEqual(byte[] a, int aOff, byte[] b, int bOff, int len) {
if (aOff + len > a.length || bOff + len > b.length)
return false;
else {
for (int i = 0; i < len; i++)
if (a[aOff + i] != b[bOff + i])
return false;
return true;
}
}
/**
* Checks for containment of the value in the array.
* Both array cells and value may be {@code null}. Two {@code null}s are considered equal.
*
* @param arr Array of objects.
* @param val Value to check for containment inside of array.
* @param vals Additional values.
* @return {@code true} if contains object, {@code false} otherwise.
*/
public static boolean containsObjectArray(@Nullable Object[] arr, Object val, @Nullable Object... vals) {
if (arr == null || arr.length == 0)
return false;
for (Object o : arr) {
if (F.eq(o, val))
return true;
if (vals != null && vals.length > 0)
for (Object v : vals)
if (F.eq(o, v))
return true;
}
return false;
}
/**
* Checks for containment of the value in the array.
* Both array cells and value may be {@code null}. Two {@code null}s are considered equal.
*
* @param arr Array of objects.
* @param c Collection to check.
* @return {@code true} if contains object, {@code false} otherwise.
*/
public static boolean containsObjectArray(@Nullable Object[] arr, @Nullable Collection