diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespajlib/src/main/java/com/yahoo/protect |
Publish
Diffstat (limited to 'vespajlib/src/main/java/com/yahoo/protect')
5 files changed, 420 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/protect/ClassValidator.java b/vespajlib/src/main/java/com/yahoo/protect/ClassValidator.java new file mode 100644 index 00000000000..79e9d49c9f5 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/protect/ClassValidator.java @@ -0,0 +1,65 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * Static utility methods to validate class properties. + * + * <p> + * Do note, this class will not be a reliable guarantee for correctness if you + * have a forest of methods only differing by return type (as + * contradistinguished from name and argument types), the current implementation + * is minimal. + * </p> + * + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public final class ClassValidator { + + /** + * Check all protected, public and package private declared methods of + * maskedClass is implemented in testClass. Note, this will by definition + * blow up on final methods in maskedClass. + * + * @param testClass + * class which wraps or masks another class + * @param maskedClass + * class which is masked or wrapped + * @return the methods which seem to miss from testClass to be complete + */ + public static List<Method> unmaskedMethods(Class<?> testClass, + Class<?> maskedClass) { + List<Method> unmasked = new ArrayList<>(); + Method[] methodsToMask = maskedClass.getDeclaredMethods(); + for (Method m : methodsToMask) { + int modifiers = m.getModifiers(); + if (Modifier.isPrivate(modifiers)) { + continue; + } + try { + testClass.getDeclaredMethod(m.getName(), m.getParameterTypes()); + } catch (NoSuchMethodException e) { + unmasked.add(m); + } + } + return unmasked; + } + + /** + * Check testClass overrides all protected, public and package private + * methods of its immediate super class. See unmaskedMethods(). + * + * @param testClass + * the class to check whether completely masks its super class + * @return the methods missing from testClass to completely override its + * immediate super class + */ + public static List<Method> unmaskedMethodsFromSuperclass(Class<?> testClass) { + return unmaskedMethods(testClass, testClass.getSuperclass()); + } + +}
\ No newline at end of file diff --git a/vespajlib/src/main/java/com/yahoo/protect/ErrorMessage.java b/vespajlib/src/main/java/com/yahoo/protect/ErrorMessage.java new file mode 100644 index 00000000000..c0cdc6017a0 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/protect/ErrorMessage.java @@ -0,0 +1,114 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + + +/** + * An error message with a code. + * This class should be treated as immutable. + * + * @author bratseth + */ +public class ErrorMessage { + + /** An error code */ + protected int code; + + /** The short message of this error, always set */ + protected String message; + + /** The detailed instance message of this error, not always set */ + protected String detailedMessage = null; + + /** The cause of this error, or null if none is recorded */ + protected Throwable cause = null; + + /** + * Create an invalid instance for a subclass to initialize. + */ + public ErrorMessage() { + } + + public ErrorMessage(int code, String message) { + this.code = code; + this.message = message; + } + + /** + * Create an application specific error message with an application + * specific code + */ + public ErrorMessage(int code, String message, String detailedMessage) { + this(code, message); + this.detailedMessage = detailedMessage; + } + + /** Create an application specific error message with an application specific code */ + public ErrorMessage(int code, String message, String detailedMessage, Throwable cause) { + this(code, message, detailedMessage); + this.cause = cause; + } + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } + + /** Returns the detailed message, or null if there is no detailed message */ + public String getDetailedMessage() { + return detailedMessage; + } + /** + * Sets the cause of this. This should be set on errors which likely have their origin in plugin component code, + * not on others. + */ + public void setCause(Throwable cause) { this.cause=cause; } + + /** Returns the cause of this, or null if none is set */ + public Throwable getCause() { return cause; } + + public int hashCode() { + return code * 7 + message.hashCode() + (detailedMessage == null ? 0 : 17 * detailedMessage.hashCode()); + } + + /** + * Two error messages are equal if they have the same code and message. + * The cause is ignored in the comparison. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof ErrorMessage)) return false; + + ErrorMessage other = (ErrorMessage) o; + + if (this.code != other.code) return false; + + if (!this.message.equals(other.message)) return false; + + if (this.detailedMessage==null) return other.detailedMessage==null; + if (other.detailedMessage==null) return false; + + return this.detailedMessage.equals(other.detailedMessage); + } + + @Override + public String toString() { + String details = ""; + + if (detailedMessage != null) { + details = detailedMessage; + } + if (cause !=null) { + if (details.length()>0) + details+=": "; + details+= com.yahoo.yolean.Exceptions.toMessageString(cause); + } + if (details.length()>0) + details=" (" + details + ")"; + + return "error : " + message + details; + } + +} diff --git a/vespajlib/src/main/java/com/yahoo/protect/Process.java b/vespajlib/src/main/java/com/yahoo/protect/Process.java new file mode 100644 index 00000000000..6f381b40cd7 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/protect/Process.java @@ -0,0 +1,97 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * A class for interacting with the global state of the running VM. + * + * @author Steinar Knutsen + */ +public final class Process { + + private static final Logger log = Logger.getLogger(Process.class.getName()); + + /** Die with a message, without dumping thread state */ + public static void logAndDie(String message) { + logAndDie(message, null); + } + + /** Die with a message, optionally dumping thread state */ + public static void logAndDie(String message, boolean dumpThreads) { + logAndDie(message, null, dumpThreads); + } + + /** Die with a message containing an exception, without dumping thread state */ + public static void logAndDie(String message, Throwable thrown) { + logAndDie(message, thrown, false); + } + + /** + * Log message as severe error, then forcibly exit runtime, without running + * exit handlers or otherwise waiting for cleanup. + * + * @param message message to log before exit + * @param thrown the throwable that caused the application to exit. + * @param dumpThreads if true the stack trace of all threads is dumped to the + * log with level info before shutting down + */ + public static void logAndDie(String message, Throwable thrown, boolean dumpThreads) { + try { + if (dumpThreads) + dumpThreads(); + if (thrown != null) + log.log(Level.SEVERE, message, thrown); + else + log.log(Level.SEVERE, message); + } finally { + try { + Runtime.getRuntime().halt(1); + } + catch (Throwable t) { + log.log(Level.SEVERE, "Runtime.halt rejected. Throwing an error."); + throw new ShutdownError("Shutdown requested, but failed to shut down"); + } + } + } + + + private static void dumpThreads() { + try { + log.log(Level.INFO, "About to shut down. Commencing full thread dump for diagnosis."); + Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces(); + for (Map.Entry<Thread, StackTraceElement[]> e : allStackTraces.entrySet()) { + Thread t = e.getKey(); + StackTraceElement[] stack = e.getValue(); + StringBuilder forOneThread = new StringBuilder(); + int initLen; + forOneThread.append("Stack for thread: ").append(t.getName()).append(": "); + initLen = forOneThread.length(); + for (StackTraceElement s : stack) { + if (forOneThread.length() > initLen) { + forOneThread.append(" "); + } + forOneThread.append(s.toString()); + } + log.log(Level.INFO, forOneThread.toString()); + } + log.log(Level.INFO, "End of diagnostic thread dump."); + } catch (Exception e) { + // just give up... + } + } + + @SuppressWarnings("serial") + public static class ShutdownError extends Error { + + public ShutdownError(String message) { + super(message); + } + + } + +} diff --git a/vespajlib/src/main/java/com/yahoo/protect/Validator.java b/vespajlib/src/main/java/com/yahoo/protect/Validator.java new file mode 100644 index 00000000000..9572fcb2ae4 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/protect/Validator.java @@ -0,0 +1,133 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + + +/** + * <p>Static utility methods for validating input.</p> + * + * @author bratseth + */ +public abstract class Validator { + + /** Throws NullPointerException if the argument is null */ + public static void ensureNotNull(String argumentDescription, Object argument) { + if (argument == null) + throw new NullPointerException(argumentDescription + " can not be null"); + } + + /** + * Throws an IllegalStateException if the given field value + * is initialized (not null) + */ + public static void ensureNotInitialized(String fieldDescription, Object fieldOwner, Object fieldValue) { + if (fieldValue != null) { + throw new IllegalStateException( + fieldDescription + " of " + fieldOwner + + " cannot be changed, it is already set " + "to " + + fieldValue); + } + } + + /** + * Throws an IllegalArgumentException if the given argument is not + * in the given range + * + * @param argumentDescription a description of the argument + * @param from the range start, inclusive + * @param to the range end, inclusive + * @param argument the argument value to check + */ + public static void ensureInRange(String argumentDescription, int from, int to, int argument) { + if (argument < from || argument > to) { + throw new IllegalArgumentException( + argumentDescription + " is " + argument + + " but must be between " + from + " and " + to); + } + } + + /** + * Throws an IllegalArgumentException if the first argument is not strictly + * smaller than the second argument + * + * @param smallDescription description of the smallest argument + * @param small the smallest argument + * @param largeDescription description of the lergest argument + * @param large the largest argument + */ + public static void ensureSmaller(String smallDescription, int small, String largeDescription, int large) { + if (small >= large) { + throw new IllegalArgumentException( + smallDescription + " is " + small + " but should be " + + "less than " + largeDescription + " " + large); + } + } + + /** + * Throws an IllegalArgumentException if the first argument is not strictly + * smaller than the second argument + * + * @param smallDescription + * description of the smallest argument + * @param small + * the smallest argument + * @param largeDescription + * description of the largest argument + * @param large + * the largest argument + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static void ensureSmaller(String smallDescription, Comparable small, String largeDescription, Comparable large) { + if (small.compareTo(large) >= 0) { + throw new IllegalArgumentException(smallDescription + " is " + + small + " but should be " + "less than " + + largeDescription + " " + large); + } + } + + /** + * Ensures that the given argument is true + * + * @param description of what is the case if the condition is false + * @param condition the condition to ensure is true + * @throws IllegalArgumentException if the given condition was false + */ + public static void ensure(String description, boolean condition) { + if (!condition) { + throw new IllegalArgumentException(description); + } + } + + /** + * Ensure the given argument is true, if not throw IllegalArgumentException + * concatenating the String representation of the description arguments. + */ + public static void ensure(boolean condition, Object... description) { + if (!condition) { + StringBuilder msg = new StringBuilder(); + for (Object part : description) { + msg.append(part.toString()); + } + throw new IllegalArgumentException(msg.toString()); + } + } + + /** + * Ensures that an item is of a particular class + * + * @param description + * a description of the item to be checked + * @param item + * the item to check the type of + * @param type + * the type the given item should be instanceof + * @throws IllegalArgumentException + * if the given item is not of the correct type + */ + public static void ensureInstanceOf(String description, Object item, Class<?> type) { + if (!type.isAssignableFrom(item.getClass())) { + throw new IllegalArgumentException(description + ", " + item + + " should " + "have been an instance of " + type); + } + } + +} diff --git a/vespajlib/src/main/java/com/yahoo/protect/package-info.java b/vespajlib/src/main/java/com/yahoo/protect/package-info.java new file mode 100644 index 00000000000..9260cd2e1e0 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/protect/package-info.java @@ -0,0 +1,11 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * Input validators, integrity checkers, error messages + * and similar classes. + */ +@ExportPackage +@PublicApi +package com.yahoo.protect; + +import com.yahoo.api.annotations.PublicApi; +import com.yahoo.osgi.annotation.ExportPackage; |