| /* |
| * Copyright (c) 2014-2021 by Wen Yu |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the Eclipse |
| * Public License, v. 2.0 are satisfied: GNU General Public License, version 2 |
| * or any later version. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later |
| */ |
| |
| package pixy.util; |
| |
| import java.security.ProtectionDomain; |
| import java.security.CodeSource; |
| import java.util.Arrays; |
| import java.util.regex.Pattern; |
| import java.io.PrintStream; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.AnnotatedElement; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.net.URI; |
| import java.net.URL; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| /** |
| * A common language utility class |
| * |
| * @author Wen Yu, yuwen_66@yahoo.com |
| * @version 1.0 09/19/2012 |
| */ |
| public class LangUtils { |
| // Obtain a logger instance |
| private static final Logger LOGGER = LoggerFactory.getLogger(LangUtils.class); |
| |
| private LangUtils(){} // Prevents instantiation |
| |
| // TODO: need to rewrite this method (may have to create and return a new class Rational) |
| public static long[] doubleToRational(double number) { |
| // Code below doesn't work for 0 and NaN - just check before |
| if((number == 0.0d) || Double.isNaN(number)) { |
| throw new IllegalArgumentException(number + " cannot be represented as a rational number"); |
| } |
| |
| long bits = Double.doubleToLongBits(number); |
| |
| long sign = bits >>> 63; |
| long exponent = ((bits >>> 52) ^ (sign << 11)) - 1023; |
| long fraction = bits << 12; // bits are "reversed" but that's not a problem |
| |
| long a = 1L; |
| long b = 1L; |
| |
| for (int i = 63; i >= 12; i--) { |
| a = a * 2 + ((fraction >>> i) & 1); |
| b *= 2; |
| } |
| |
| if (exponent > 0) |
| a *= 1 << exponent; |
| else |
| b *= 1 << -exponent; |
| |
| if (sign == 1) |
| a *= -1; |
| |
| return new long[]{a, b}; |
| } |
| |
| // From Effective Java 2nd Edition. |
| // Use of asSubclass to safely cast to a bounded type token |
| public static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) { |
| Class<?> annotationType = null; // Unbounded type token |
| |
| try { |
| annotationType = Class.forName(annotationTypeName); |
| } catch (Exception ex) { |
| throw new IllegalArgumentException(ex); |
| } |
| |
| return element.getAnnotation(annotationType.asSubclass(Annotation.class)); |
| } |
| |
| // Creates a friendly string representation of the class |
| public static String getClassName(Class<?> c) { |
| String name = c.getName().replace('$','.'); |
| |
| if (c.isArray()) { |
| switch (name.charAt(1)) { |
| case 'B': |
| name = "byte"; |
| break; |
| case 'C': |
| name = "char"; |
| break; |
| case 'D': |
| name = "double"; |
| break; |
| case 'F': |
| name = "float"; |
| break; |
| case 'I': |
| name = "int"; |
| break; |
| case 'J': |
| name = "long"; |
| break; |
| case 'L': |
| name = name.substring(2, name.length() - 1); |
| break; |
| case 'S': |
| name = "short"; |
| break; |
| case 'Z': |
| name = "boolean"; |
| break; |
| } |
| name = name + "[]"; |
| } |
| |
| return name; |
| } |
| |
| /** |
| * @param m Method we want to probe generic type arguments. |
| * @param i the i'th parameter of the method. |
| * @return an array of parameterized Types for the i'th argument or an empty array. |
| */ |
| public static Type[] getGenericTypeArguments(Method m, int i) { |
| try { |
| Type t = m.getGenericParameterTypes()[i]; |
| |
| if(t instanceof ParameterizedType) { |
| ParameterizedType pt = (ParameterizedType) t; |
| return pt.getActualTypeArguments(); |
| } |
| } catch(Exception e) { |
| LOGGER.error("Error probing generic type arguments!", e); |
| } |
| |
| return new Type[]{}; |
| } |
| |
| public static void log(String message, PrintStream out) { |
| StackTraceElement se = Thread.currentThread().getStackTrace()[2]; |
| out.println("; " + message + " - [" + se.getClassName() + "." + se.getMethodName() +"(): line " + se.getLineNumber() + "]"); |
| } |
| |
| /** Java language specific classes return null cSource */ |
| public static URL getLoadedClassLocation(Class<?> cls) { |
| ProtectionDomain pDomain = cls.getProtectionDomain(); |
| CodeSource cSource = pDomain.getCodeSource(); |
| URL loc = (cSource==null)?null:cSource.getLocation(); |
| |
| return loc; |
| } |
| |
| /** |
| * @param className A fully qualified class name with package information |
| * @return The location where the class has been loaded by the Java Virtual |
| * Machine or null. |
| */ |
| public static URL getLoadedClassLocation(String className) { |
| Class<?> cls = null; |
| |
| try { |
| cls = Class.forName(className); |
| } catch (ClassNotFoundException ex) { |
| return null; |
| } |
| |
| return getLoadedClassLocation(cls); |
| } |
| |
| public static URL getLoadedClassURL(String className) { |
| Class<?> cls = null; |
| |
| try { |
| cls = Class.forName(className); |
| } catch (ClassNotFoundException ex) { |
| return null; |
| } |
| |
| ClassLoader classLoader = cls.getClassLoader(); |
| |
| URL url = classLoader.getResource(className.replaceAll(Pattern.quote("."), "/") + ".class"); |
| |
| return url; |
| } |
| |
| // A convenience way to call main of other classes. |
| // Based on something I am not sure where I got it. |
| public static void invokeMain(String... args) { |
| try { |
| Class<?> c = Class.forName(args[0]); |
| Class<String[]> argTypes = String[].class; |
| Method main = c.getDeclaredMethod("main", argTypes); |
| Object mainArgs = Arrays.copyOfRange(args, 1, args.length); |
| LOGGER.info("invoking {}.main()\n", c.getName()); |
| main.invoke(null, mainArgs); |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Converts long value to int hash code. |
| * |
| * @param value long value |
| * @return int hash code for the long |
| */ |
| public static int longToIntHashCode(long value) { |
| return Long.valueOf(value).hashCode(); |
| } |
| |
| // From stackoverflow.com |
| public static URI relativize(URI base, URI child) { |
| // Normalize paths to remove . and .. segments |
| base = base.normalize(); |
| child = child.normalize(); |
| |
| // Split paths into segments |
| String[] bParts = base.getPath().split("/"); |
| String[] cParts = child.getPath().split("/"); |
| |
| // Discard trailing segment of base path |
| if (bParts.length > 0 && !base.getPath().endsWith("/")) { |
| System.arraycopy(bParts, 0, bParts, 0, bParts.length - 1); |
| // JDK1.6+ |
| //bParts = java.util.Arrays.copyOf(bParts, bParts.length - 1); |
| } |
| |
| // Remove common prefix segments |
| int i = 0; |
| |
| while (i < bParts.length && i < cParts.length && bParts[i].equals(cParts[i])) { |
| i++; |
| } |
| |
| // Construct the relative path |
| StringBuilder sb = new StringBuilder(); |
| |
| for (int j = 0; j < (bParts.length - i); j++) { |
| sb.append("../"); |
| } |
| |
| for (int j = i; j < cParts.length; j++) { |
| if (j != i) { |
| sb.append("/"); |
| } |
| sb.append(cParts[j]); |
| } |
| |
| return URI.create(sb.toString()); |
| } |
| } |