All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.commons.util.Util Maven / Gradle / Ivy

There is a newer version: 15.1.0.Dev04
Show newest version
package org.infinispan.commons.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import javax.naming.Context;
import javax.security.auth.Subject;

import org.infinispan.commons.CacheConfigurationException;
import org.infinispan.commons.CacheException;
import org.infinispan.commons.configuration.ClassAllowList;
import org.infinispan.commons.hash.Hash;
import org.infinispan.commons.logging.Log;
import org.infinispan.commons.logging.LogFactory;
import org.infinispan.commons.marshall.Marshaller;

/**
 * General utility methods used throughout the Infinispan code base.
 *
 * @author Brian Stansberry
 * @author Galder Zamarreño
 * @since 4.0
 */
public final class Util {

   private static final boolean IS_ARRAYS_DEBUG = Boolean.getBoolean("infinispan.arrays.debug");
   private static final int COLLECTIONS_LIMIT = Integer.getInteger("infinispan.collections.limit", 8);
   public static final int HEX_DUMP_LIMIT = Integer.getInteger("infinispan.hexdump.limit", 64);

   public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
   public static final String[] EMPTY_STRING_ARRAY = new String[0];
   public static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
   public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
   public static final byte[][] EMPTY_BYTE_ARRAY_ARRAY = new byte[0][];
   public static final String GENERIC_JBOSS_MARSHALLING_CLASS = "org.infinispan.jboss.marshalling.commons.GenericJBossMarshaller";
   public static final String JBOSS_USER_MARSHALLER_CLASS = "org.infinispan.jboss.marshalling.core.JBossUserMarshaller";

   private static final Log log = LogFactory.getLog(Util.class);

   private static final Set> BASIC_TYPES;

   private static final String HEX_VALUES = "0123456789ABCDEF";
   private static final char[] HEX_DUMP_CHARS = new char[256 * 2];

   static {
      BASIC_TYPES = new HashSet<>();
      BASIC_TYPES.add(Boolean.class);
      BASIC_TYPES.add(Byte.class);
      BASIC_TYPES.add(Character.class);
      BASIC_TYPES.add(Double.class);
      BASIC_TYPES.add(Float.class);
      BASIC_TYPES.add(Integer.class);
      BASIC_TYPES.add(Long.class);
      BASIC_TYPES.add(Short.class);
      BASIC_TYPES.add(String.class);
      BASIC_TYPES.add(char[].class);

      for (char b = 0; b < 256; b++) {
         if (0x20 <= b && b <= 0x7e) {
            HEX_DUMP_CHARS[b * 2] = '\\';
            HEX_DUMP_CHARS[b * 2 + 1] = b;
         } else {
            HEX_DUMP_CHARS[b * 2] = HEX_VALUES.charAt((b & 0xF0) >> 4);
            HEX_DUMP_CHARS[b * 2 + 1] = HEX_VALUES.charAt((b & 0x0F));
         }

      }
   }

   /**
    * 

* Loads the specified class using the passed classloader, or, if it is null the Infinispan classes' * classloader. *

* *

* If loadtime instrumentation via GenerateInstrumentedClassLoader is used, this class may be loaded by the bootstrap * classloader. *

*

* If the class is not found, the {@link ClassNotFoundException} or {@link NoClassDefFoundError} is wrapped as a * {@link CacheConfigurationException} and is re-thrown. *

* * @param classname name of the class to load * @param cl the application classloader which should be used to load the class, or null if the class is * always packaged with Infinispan * @return the class * @throws CacheConfigurationException if the class cannot be loaded */ public static Class loadClass(String classname, ClassLoader cl) { try { return loadClassStrict(classname, cl); } catch (ClassNotFoundException e) { throw Log.CONTAINER.cannotInstantiateClass(classname, e); } } public static ClassLoader[] getClassLoaders(ClassLoader appClassLoader) { return new ClassLoader[]{ appClassLoader, // User defined classes Util.class.getClassLoader(), // Infinispan classes (not always on TCCL [modular env]) ClassLoader.getSystemClassLoader(), // Used when load time instrumentation is in effect Thread.currentThread().getContextClassLoader() //Used by jboss-as stuff }; } /** *

* Loads the specified class using the passed classloader, or, if it is null the Infinispan classes' * classloader. *

* *

* If loadtime instrumentation via GenerateInstrumentedClassLoader is used, this class may be loaded by the bootstrap * classloader. *

* * @param classname name of the class to load * @param userClassLoader the application classloader which should be used to load the class, or null if the class is * always packaged with Infinispan * @return the class * @throws ClassNotFoundException if the class cannot be loaded */ @SuppressWarnings("unchecked") public static Class loadClassStrict(String classname, ClassLoader userClassLoader) throws ClassNotFoundException { ClassLoader[] cls = getClassLoaders(userClassLoader); ClassNotFoundException e = null; NoClassDefFoundError ne = null; for (ClassLoader cl : cls) { if (cl == null) continue; try { return (Class) Class.forName(classname, true, cl); } catch (ClassNotFoundException ce) { e = ce; } catch (NoClassDefFoundError ce) { ne = ce; } } if (ne != null) { //Always log the NoClassDefFoundError errors first: //if one happened they will contain critically useful details. log.unableToLoadClass(classname, Arrays.toString(cls), ne); } if (e != null) throw e; else if (ne != null) { throw new ClassNotFoundException(classname, ne); } else throw new IllegalStateException(); } public static InputStream getResourceAsStream(String resourcePath, ClassLoader userClassLoader) { if (resourcePath.startsWith("/")) { resourcePath = resourcePath.substring(1); } InputStream is = null; for (ClassLoader cl : getClassLoaders(userClassLoader)) { if (cl != null) { is = cl.getResourceAsStream(resourcePath); if (is != null) { break; } } } return is; } public static String getResourceAsString(String resourcePath, ClassLoader userClassLoader) throws IOException { return read(getResourceAsStream(resourcePath, userClassLoader)); } private static Method getFactoryMethod(Class c) { for (Method m : c.getMethods()) { if (m.getName().equals("getInstance") && m.getParameterCount() == 0 && Modifier.isStatic(m.getModifiers())) return m; } return null; } /** * Instantiates a class by invoking the constructor that matches the provided parameter types passing the given * arguments. If no matching constructor is found this will return null. Note that the constructor must be public. *

* Any exceptions encountered are wrapped in a {@link CacheConfigurationException} and rethrown. * * @param clazz class to instantiate * @param the instance type * @return the new instance if a matching constructor was found otherwise null */ public static T newInstanceOrNull(Class clazz, Class[] parameterTypes, Object... arguments) { if (parameterTypes.length != arguments.length) { throw new IllegalArgumentException("Parameter type count: " + parameterTypes.length + " does not match parameter arguments count: " + arguments.length); } try { Constructor constructor = clazz.getDeclaredConstructor(parameterTypes); if (constructor != null) { return constructor.newInstance(arguments); } } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new CacheConfigurationException("Unable to instantiate class '" + clazz.getName() + "' with constructor " + "taking parameters " + Arrays.toString(arguments), e); } return null; } /** * Instantiates a class by first attempting a static factory method named getInstance() on the class * and then falling back to an empty constructor. *

* Any exceptions encountered are wrapped in a {@link CacheConfigurationException} and rethrown. * * @param clazz class to instantiate * @return an instance of the class */ public static T getInstance(Class clazz) { try { return getInstanceStrict(clazz); } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException iae) { throw new CacheConfigurationException("Unable to instantiate class '" + clazz.getName() + "'", iae); } } /** * Similar to {@link #getInstance(Class)} except that exceptions are propagated to the caller. * * @param clazz class to instantiate * @return an instance of the class * @throws IllegalAccessException * @throws InstantiationException */ @SuppressWarnings("unchecked") public static T getInstanceStrict(Class clazz) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { // first look for a getInstance() constructor T instance = null; try { Method factoryMethod = getFactoryMethod(clazz); if (factoryMethod != null) instance = (T) factoryMethod.invoke(null); } catch (Exception e) { // no factory method or factory method failed. Try a constructor. instance = null; } if (instance == null) { instance = clazz.getDeclaredConstructor().newInstance(); } return instance; } /** * Instantiates a class based on the class name provided. Instantiation is attempted via an appropriate, static * factory method named getInstance() first, and failing the existence of an appropriate factory, falls back * to an empty constructor. *

* Any exceptions encountered loading and instantiating the class is wrapped in a * {@link CacheConfigurationException}. * * @param classname class to instantiate * @return an instance of classname */ public static T getInstance(String classname, ClassLoader cl) { if (classname == null) throw new IllegalArgumentException("Cannot load null class!"); Class clazz = loadClass(classname, cl); return getInstance(clazz); } /** * Similar to {@link #getInstance(String, ClassLoader)} except that exceptions are propagated to the caller. * * @param classname class to instantiate * @return an instance of classname * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException * @throws NoSuchMethodException * @throws InvocationTargetException */ public static T getInstanceStrict(String classname, ClassLoader cl) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { if (classname == null) throw new IllegalArgumentException("Cannot load null class!"); Class clazz = loadClassStrict(classname, cl); return getInstanceStrict(clazz); } /** * Given two Runnables, return a Runnable that executes both in sequence, even if the first throws an exception, and * if both throw exceptions, add any exceptions thrown by the second as suppressed exceptions of the first. */ public static Runnable composeWithExceptions(Runnable a, Runnable b) { return () -> { try { a.run(); } catch (Throwable e1) { try { b.run(); } catch (Throwable e2) { try { e1.addSuppressed(e2); } catch (Throwable ignore) { } } throw e1; } b.run(); }; } /** * Prevent instantiation */ private Util() { } public static String prettyPrintTime(long time, TimeUnit unit) { return prettyPrintTime(unit.toMillis(time)); } /** * {@link System#nanoTime()} is less expensive than {@link System#currentTimeMillis()} and better suited to measure * time intervals. It's NOT suited to know the current time, for example to be compared with the time of other * nodes. * * @return the value of {@link System#nanoTime()}, but converted in Milliseconds. */ public static long currentMillisFromNanotime() { return TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS); } /** * Prints a time for display * * @param millis time in millis * @return the time, represented as millis, seconds, minutes or hours as appropriate, with suffix */ public static String prettyPrintTime(long millis) { if (millis < 1000) return millis + " milliseconds"; NumberFormat nf = NumberFormat.getNumberInstance(); nf.setMaximumFractionDigits(2); double toPrint = ((double) millis) / 1000; if (toPrint < 300) { return nf.format(toPrint) + " seconds"; } toPrint = toPrint / 60; if (toPrint < 120) { return nf.format(toPrint) + " minutes"; } toPrint = toPrint / 60; return nf.format(toPrint) + " hours"; } /** * Reads the given InputStream fully, closes the stream and returns the result as a String. * * @param is the stream to read * @return the UTF-8 string * @throws java.io.IOException in case of stream read errors */ public static String read(InputStream is) throws IOException { try (is) { final Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8); StringWriter writer = new StringWriter(); char[] buf = new char[1024]; int len; while ((len = reader.read(buf)) != -1) { writer.write(buf, 0, len); } return writer.toString(); } } public static void close(AutoCloseable cl) { if (cl == null) return; try { cl.close(); } catch (Exception e) { //Ignore } } public static void close(Socket s) { if (s == null) return; try { s.close(); } catch (Exception e) { } } public static void close(AutoCloseable... cls) { for (AutoCloseable cl : cls) { close(cl); } } public static void close(Context ctx) { if (ctx == null) return; try { ctx.close(); } catch (Exception e) { } } public static String formatString(Object message, Object... params) { if (params.length == 0) return message == null ? "null" : message.toString(); return String.format(message.toString(), params); } public static String toStr(Object o) { if (o == null) { return "null"; } else if (o.getClass().isArray()) { // as Java arrays are covariant, this cast is safe unless it's primitive if (o.getClass().getComponentType().isPrimitive()) { if (o instanceof byte[]) { return printArray((byte[]) o, false); } else if (o instanceof int[]) { return Arrays.toString((int[]) o); } else if (o instanceof long[]) { return Arrays.toString((long[]) o); } else if (o instanceof short[]) { return Arrays.toString((short[]) o); } else if (o instanceof double[]) { return Arrays.toString((double[]) o); } else if (o instanceof float[]) { return Arrays.toString((float[]) o); } else if (o instanceof char[]) { return Arrays.toString((char[]) o); } else if (o instanceof boolean[]) { return Arrays.toString((boolean[]) o); } } return Arrays.toString((Object[]) o); } else { return o.toString(); } } public static String toStr(Collection collection) { if (collection == null) return "[]"; Iterator i = collection.iterator(); if (!i.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (int counter = 0; ; ) { E e = i.next(); sb.append(e == collection ? "(this Collection)" : toStr(e)); if (!i.hasNext()) return sb.append(']').toString(); if (++counter >= COLLECTIONS_LIMIT) { return sb.append("...<") .append(collection.size() - COLLECTIONS_LIMIT) .append(" other elements>]").toString(); } sb.append(", "); } } public static String printArray(byte[] array) { return printArray(array, false); } public static String printArray(byte[] array, boolean withHash) { if (array == null) return "null"; int limit = 16; StringBuilder sb = new StringBuilder(); sb.append("[B0x"); if (array.length <= limit || IS_ARRAYS_DEBUG) { // Convert the entire byte array sb.append(toHexString(array)); if (withHash) { sb.append(",h="); sb.append(Integer.toHexString(Arrays.hashCode(array))); sb.append(']'); } } else { // Pick the first limit characters and convert that part sb.append(toHexString(array, limit)); sb.append("..["); sb.append(array.length); if (withHash) { sb.append("],h="); sb.append(Integer.toHexString(Arrays.hashCode(array))); } sb.append(']'); } return sb.toString(); } public static String toHexString(byte[] input) { return toHexString(input, input != null ? input.length : 0); } public static String toHexString(byte[] input, int limit) { return toHexString(input, 0, limit); } public static String toHexString(byte[] input, int offset, int limit) { if (input == null) return "null"; int length = Math.min(limit - offset, input.length - offset); char[] result = new char[length * 2]; for (int i = 0; i < length; ++i) { result[2 * i] = HEX_VALUES.charAt((input[i + offset] >> 4) & 0x0F); result[2 * i + 1] = HEX_VALUES.charAt((input[i + offset] & 0x0F)); } return String.valueOf(result); } public static String padString(String s, int minWidth) { if (s.length() < minWidth) { StringBuilder sb = new StringBuilder(s); while (sb.length() < minWidth) sb.append(" "); return sb.toString(); } return s; } private final static String INDENT = " "; public static String threadDump() { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String timestamp = dateFormat.format(new Date()); StringBuilder threadDump = new StringBuilder(); threadDump.append(timestamp); threadDump.append("\nFull thread dump "); threadDump.append("\n"); Thread.getAllStackTraces().forEach((thread, elements) -> { threadDump.append("\"").append(thread.getName()) .append("\" nid=").append(thread.getId()) .append(" state=").append(thread.getState()) .append("\n"); for (StackTraceElement e : elements) { threadDump.append(INDENT).append("at ").append(e.toString()).append("\n"); } }); return threadDump.toString(); } public static CacheException rewrapAsCacheException(Throwable t) { if (t instanceof CompletionException) throw new IllegalArgumentException("CompletionException should never be wrapped"); if (t instanceof CacheException) return (CacheException) t; else return new CacheException(t); } @SafeVarargs public static Set asSet(T... a) { if (a.length > 1) return new HashSet<>(Arrays.asList(a)); else return Collections.singleton(a[0]); } /** * Prints the identity hash code of the object passed as parameter in an hexadecimal format in order to safe space. */ public static String hexIdHashCode(Object o) { return Integer.toHexString(System.identityHashCode(o)); } public static String hexDump(byte[] data) { return hexDump(data, 0, data.length); } public static String hexDump(ByteBuffer buffer) { return hexDump(buffer::get, buffer.position(), buffer.remaining()); } public static String hexDump(byte[] buffer, int offset, int actualLength) { assert actualLength + offset <= buffer.length; int dumpLength = Math.min(actualLength, HEX_DUMP_LIMIT); StringBuilder sb = new StringBuilder(dumpLength * 2 + 30); for (int i = 0; i < dumpLength; ++i) { addHexByte(sb, buffer[offset + i]); } if (dumpLength < actualLength) { sb.append("..."); } sb.append(" (").append(actualLength).append(" bytes)"); return sb.toString(); } public static String hexDump(ByteGetter byteGetter, int offset, int actualLength) { int dumpLength = Math.min(actualLength, HEX_DUMP_LIMIT); StringBuilder sb = new StringBuilder(dumpLength * 2 + 30); for (int i = 0; i < dumpLength; ++i) { addHexByte(sb, byteGetter.get(offset + i)); } if (dumpLength < actualLength) { sb.append("..."); } sb.append(" (").append(actualLength).append(" bytes)"); return sb.toString(); } public static void addHexByte(StringBuilder buf, byte b) { int offset = (b & 0xFF) * 2; buf.append(HEX_DUMP_CHARS, offset, 2); } private static void addSingleHexChar(StringBuilder buf, byte b) { buf.append(HEX_VALUES.charAt(b & 0x0F)); } /** * Applies the given hash function to the hash code of a given object, and then normalizes it to ensure a positive * value is always returned. * * @param object to hash * @param hashFct hash function to apply * @return a non-null, non-negative normalized hash code for a given object */ public static int getNormalizedHash(Object object, Hash hashFct) { // make sure no negative numbers are involved. return hashFct.hash(object) & Integer.MAX_VALUE; } /** * Returns the size of each segment, given a number of segments. This assumes * a 32 bit hash is used and we ignore the most significant bit. * * @param numSegments number of segments required * @return the size of each segment */ public static int getSegmentSize(int numSegments) { return (int) Math.ceil((double) (1L << 31) / numSegments); } public static int getSegmentSize(Hash hash, int numSegments) { return getSegmentSize(hash.maxHashBits(), numSegments); } public static int getSegmentSize(int maxHashBits, int numSegments) { assert maxHashBits <= 32; // If using all 32 bits we ignore one as we don't want negative segments if (maxHashBits == 32) { maxHashBits--; } return (int) Math.ceil((double) (1L << maxHashBits) / numSegments); } /** * Returns whether the provided integer is a power of two or not. That is any number that is divisible by * two even if negative. * @param n the number to test * @return whether the number is a power of two or not. */ public static boolean isPow2(int n) { // Just in case it is negative n = Math.abs(n); // If `n` is pow2 the binary is a 1 followed by only zeroes and `n - 1` is a 0 followed by only ones. // The binary and always resolves to 0. return (n & (n - 1)) == 0; } public static String join(List strings, String separator) { StringBuilder sb = new StringBuilder(); boolean first = true; for (String string : strings) { if (!first) { sb.append(separator); } else { first = false; } sb.append(string); } return sb.toString(); } /** * Returns a number such that the number is a power of two that is equal to, or greater than, the number passed in as * an argument. The smallest number returned will be 1. Due to having to be a power of two, the highest int this can * return is 231 since int is signed. */ public static int findNextHighestPowerOfTwo(int num) { if (num <= 1) { return 1; } else if (num >= 0x40000000) { return 0x40000000; } int highestBit = Integer.highestOneBit(num); return num <= highestBit ? highestBit : highestBit << 1; } /** * A function that calculates hash code of a byte array based on its contents but using the given size parameter as * deliminator for the content. */ public static int hashCode(byte[] bytes, int size) { int contentLimit = size; if (size > bytes.length) contentLimit = bytes.length; int hashCode = 1; for (int i = 0; i < contentLimit; i++) hashCode = 31 * hashCode + bytes[i]; return hashCode; } /** * Prints {@link Subject}'s principals as a one-liner (as opposed to default Subject's toString() * method, which prints every principal on separate line). */ public static String prettyPrintSubject(Subject subject) { return (subject == null) ? "null" : "Subject with principal(s): " + toStr(subject.getPrincipals()); } /** * Uses a {@link ThreadLocalRandom} to generate a UUID. Faster, but not secure */ public static UUID threadLocalRandomUUID() { byte[] data = new byte[16]; ThreadLocalRandom.current().nextBytes(data); data[6] &= 0x0f; /* clear version */ data[6] |= 0x40; /* set to version 4 */ data[8] &= 0x3f; /* clear variant */ data[8] |= 0x80; /* set to IETF variant */ long msb = 0; long lsb = 0; for (int i = 0; i < 8; i++) msb = (msb << 8) | (data[i] & 0xff); for (int i = 8; i < 16; i++) lsb = (lsb << 8) | (data[i] & 0xff); return new UUID(msb, lsb); } public static String unicodeEscapeString(String s) { int len = s.length(); StringBuilder out = new StringBuilder(len * 2); for (int x = 0; x < len; x++) { char aChar = s.charAt(x); if ((aChar > 61) && (aChar < 127)) { if (aChar == '\\') { out.append('\\'); out.append('\\'); continue; } out.append(aChar); continue; } switch (aChar) { case ' ': if (x == 0) out.append('\\'); out.append(' '); break; case '\t': out.append('\\'); out.append('t'); break; case '\n': out.append('\\'); out.append('n'); break; case '\r': out.append('\\'); out.append('r'); break; case '\f': out.append('\\'); out.append('f'); break; case '=': case ':': case '#': case '!': out.append('\\'); out.append(aChar); break; default: if ((aChar < 0x0020) || (aChar > 0x007e)) { out.append('\\'); out.append('u'); addSingleHexChar(out, (byte) ((aChar >> 12) & 0xF)); addSingleHexChar(out, (byte) ((aChar >> 8) & 0xF)); addSingleHexChar(out, (byte) ((aChar >> 4) & 0xF)); addSingleHexChar(out, (byte) (aChar & 0xF)); } else { out.append(aChar); } } } return out.toString(); } public static String unicodeUnescapeString(String s) { int len = s.length(); StringBuilder out = new StringBuilder(len); for (int x = 0; x < len; x++) { char ch = s.charAt(x); if (ch == '\\') { ch = s.charAt(++x); if (ch == 'u') { int value = 0; for (int i = 0; i < 4; i++) { ch = s.charAt(++x); if (ch >= '0' && ch <= '9') { value = (value << 4) + ch - '0'; } else if (ch >= 'a' && ch <= 'f') { value = (value << 4) + 10 + ch - 'a'; } else if (ch >= 'A' && ch <= 'F') { value = (value << 4) + 10 + ch - 'A'; } else throw new IllegalArgumentException("Malformed \\uxxxx encoding."); } out.append((char) value); } else { if (ch == 't') ch = '\t'; else if (ch == 'r') ch = '\r'; else if (ch == 'n') ch = '\n'; else if (ch == 'f') ch = '\f'; out.append(ch); } } else { out.append(ch); } } return out.toString(); } public static Supplier getInstanceSupplier(String className, ClassLoader classLoader) { return () -> getInstance(className, classLoader); } /** * Deletes directory recursively. * * @param directoryName Directory to be deleted */ public static void recursiveFileRemove(String directoryName) { File file = new File(directoryName); recursiveFileRemove(file); } public static void recursiveFileRemove(Path path) { recursiveFileRemove(path.toFile()); } /** * Deletes directory recursively. * * @param directory Directory to be deleted */ public static void recursiveFileRemove(File directory) { if (directory.exists()) { log.tracef("Deleting file %s", directory); recursiveDelete(directory); } } private static void recursiveDelete(File f) { try { Files.walkFileTree(f.toPath(), new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { if (e == null) { Files.delete(dir); return FileVisitResult.CONTINUE; } else { throw e; } } }); } catch (Exception e) { throw new IllegalStateException(e); } } public static void recursiveDirectoryCopy(Path source, Path target) throws IOException { Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new FileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { try { if (!source.equals(dir)) { String relativize = source.relativize(dir).toString(); Path resolve = target.resolve(relativize); Files.copy(dir, resolve); } } catch (FileAlreadyExistsException x) { // do nothing } catch (IOException x) { return FileVisitResult.SKIP_SUBTREE; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.copy(file, target.resolve(source.relativize(file).toString())); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { return FileVisitResult.CONTINUE; } }); } public static char[] toCharArray(String s) { return s == null ? null : s.toCharArray(); } public static Object[] objectArray(int length) { return length == 0 ? EMPTY_OBJECT_ARRAY : new Object[length]; } public static String[] stringArray(int length) { return length == 0 ? EMPTY_STRING_ARRAY : new String[length]; } public static Throwable[] throwableArray(int length) { return length == 0 ? EMPTY_THROWABLE_ARRAY : new Throwable[length]; } public static void renameTempFile(File tempFile, File lockFile, File dstFile) throws IOException { FileLock lock = null; try (FileOutputStream lockFileOS = new FileOutputStream(lockFile)) { lock = lockFileOS.getChannel().lock(); Files.move(tempFile.toPath(), dstFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } finally { if (lock != null && lock.isValid()) { lock.release(); } if (!lockFile.delete()) { log.debugf("Unable to delete lock file %s", lockFile); } } } public static Throwable getRootCause(Throwable re) { if (re == null) return null; Throwable cause = re.getCause(); if (cause != null) return getRootCause(cause); else return re; } public static Marshaller getJBossMarshaller(ClassLoader classLoader, ClassAllowList classAllowList) { try { Class marshallerClass = classLoader.loadClass(GENERIC_JBOSS_MARSHALLING_CLASS); return Util.newInstanceOrNull(marshallerClass.asSubclass(Marshaller.class), new Class[]{ClassLoader.class, ClassAllowList.class}, classLoader, classAllowList); } catch (ClassNotFoundException e) { return null; } } // TODO: Replace with Objects.requireNonNullElse(T obj, T defaultObj) when upgrading to JDK 9+ public static T requireNonNullElse(T obj, T defaultObj) { return (obj != null) ? obj : Objects.requireNonNull(defaultObj, "defaultObj"); } public static void longToBytes(long val, byte[] array, int offset) { for (int i = 7; i > 0; i--) { array[offset + i] = (byte) val; val >>>= 8; } array[offset] = (byte) val; } public static String unquote(String s) { if (s.charAt(0) == '"' || s.charAt(0) == '\'') { return s.substring(1, s.length() - 1); } else { return s; } } public static Object fromString(Class klass, String value) { if (klass == Character.class) { if (value.length() == 1) { return value.charAt(0); } else { throw new IllegalArgumentException("Expected a single character, got '" + value + "'"); } } else if (klass == Byte.class) { return Byte.valueOf(value); } else if (klass == Short.class) { return Short.valueOf(value); } else if (klass == Integer.class) { return Integer.valueOf(value); } else if (klass == Long.class) { return Long.valueOf(value); } else if (klass == Boolean.class) { return parseBoolean(value); } else if (klass == String.class) { return value; } else if (klass == String[].class) { return value != null ? value.split(" ") : null; } else if (klass == Set.class) { return value != null ? new HashSet<>(Arrays.asList(value.split(" "))) : null; } else if (klass == List.class) { return value != null ? Arrays.asList(value.split(" ")) : null; } else if (klass == char[].class) { return value.toCharArray(); } else if (klass == Float.class) { return Float.valueOf(value); } else if (klass == Double.class) { return Double.valueOf(value); } else if (klass == BigDecimal.class) { return new BigDecimal(value); } else if (klass == BigInteger.class) { return new BigInteger(value); } else if (klass == File.class) { return new File(value); } else if (klass.isEnum()) { return parseEnum((Class)klass, value); } else if (klass == Properties.class) { try { Properties props = new Properties(); props.load(new ByteArrayInputStream(value.getBytes())); return props; } catch (IOException e) { throw new CacheConfigurationException("Failed to load Properties from: " + value, e); } } throw new CacheConfigurationException("Cannot convert " + value + " to type " + klass.getName()); } public static boolean parseBoolean(String value) { switch (value.toLowerCase()) { case "true": case "yes": case "y": case "on": return true; case "false": case "no": case "n": case "off": return false; default: throw Log.CONFIG.illegalBooleanValue(value); } } public static > T parseEnum(Class enumClass, String value) { try { return Enum.valueOf(enumClass, value); } catch (IllegalArgumentException e) { throw Log.CONFIG.illegalEnumValue(value, EnumSet.allOf(enumClass)); } } public static void unwrapSuppressed(Throwable t, Throwable t1) { if (t1.getSuppressed().length > 0) { for (Throwable suppressed : t1.getSuppressed()) { t.addSuppressed(suppressed); } } else { t.addSuppressed(t1); } } public static String unwrapExceptionMessage(Throwable t) { // Avoid duplicate messages LinkedHashSet messages = new LinkedHashSet<>(); String rootMessage = t.getMessage(); if (rootMessage != null) { messages.add(rootMessage); } for(Throwable suppressed : t.getSuppressed()) { messages.add(suppressed.getMessage()); } return String.join("\n ", messages); } /** * Returns the byte at {@code index}. */ public interface ByteGetter { byte get(int index); } /** * This method is to be replaced by Java 9 Arrays#equals with the same arguments. * * @param a first array to test contents * @param aFromIndex the offset into the first array to start comparison * @param aToIndex the last element (exclusive) of the first array to compare * @param b second array to test contents * @param bFromIndex the offset into the second array to start comparison * @param bToIndex the last element (exclusive) of the second array to compare * @return if the bytes in the two array ranges are equal */ public static boolean arraysEqual(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) { int totalAmount = aToIndex - aFromIndex; if (totalAmount != bToIndex - bFromIndex) { return false; } for (int i = 0; i < totalAmount; ++i) { if (a[aFromIndex + i] != b[bFromIndex + i]) { return false; } } return true; } public static byte[] concat(byte[] a, byte[] b) { int aLen = a.length; int bLen = b.length; byte[] ret = new byte[aLen + bLen]; System.arraycopy(a, 0, ret, 0, aLen); System.arraycopy(b, 0, ret, aLen, bLen); return ret; } public static T[] concat(T[] a, T b) { int aLen = a.length; T[] ret = Arrays.copyOf(a, aLen + 1); ret[aLen] = b; return ret; } public static RuntimeException unchecked(Throwable t) { if (t instanceof RuntimeException) { return (RuntimeException) t; } else { return new RuntimeException(t); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy