summaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java/com/yahoo/protect
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespajlib/src/main/java/com/yahoo/protect
Publish
Diffstat (limited to 'vespajlib/src/main/java/com/yahoo/protect')
-rw-r--r--vespajlib/src/main/java/com/yahoo/protect/ClassValidator.java65
-rw-r--r--vespajlib/src/main/java/com/yahoo/protect/ErrorMessage.java114
-rw-r--r--vespajlib/src/main/java/com/yahoo/protect/Process.java97
-rw-r--r--vespajlib/src/main/java/com/yahoo/protect/Validator.java133
-rw-r--r--vespajlib/src/main/java/com/yahoo/protect/package-info.java11
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;