/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. */ package org.opends.server.util; import org.opends.messages.Message; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.loggers.ErrorLogger; /** * This utility class provides static methods that make parameter checking * easier (e.g. in constructors and setters). * In particular the ensureNotNull methods provide an easy way to validate that * certain parameters are not null, and the ensureTrue methods provide the * ability to check arbitrary boolean conditions. * <p> * Invocation of these methods should be limited to situations where the only * way that they should fail is if there is a defect somewhere in the * system (including 3rd-party plugins). * <p> * You can think of these methods as being similar to <code>assert</code>, * but there are some additional advantages: * <ul> * <li>All failures are logged to the debug and error logs</li> * <li>Checks are always enabled (even if asserts are off)</li> * <li>This class tracks the number of failures, allowing it to * be exposed via monitoring, etc.<li> * <li>The unit tests can track unnoticed internal failures and * report on them.</li> * <li>Developers can catch all Validator failures with a single * break point.</li> * </ul> * * In general, you should not worry about the performance impact of calling * these methods. Some micro-benchmarking has shown that ensureNotNull can be * called 200M times per second on a single CPU laptop. The value of catching * defects early will almost always out-weigh any overhead that is introduced. * There are a couple of exceptions to this. Any execution overhead that * happens before the method is invoked cannot be eliminated, e.g. * <code>Validator.ensureTrue(someExpensiveCheck())</code> will always invoke * <code>someExpensiveCheck()</code>. When this code is on the critical path, * and we do not expect the validation to fail, you can guard the call with * an <code>assert</code> because each method returns true, and this code will * only be executed when asserts are enabled. * <p> * These methods are provided primarily to check parameter values for * constructors, setters, etc, and when they are used in this way, the javadoc * for the method must be updated to reflect what constraints are placed on the * parameters (e.g. attributeType cannot be null). * <p> * Feel free to add any method to this class that makes sense. Be sure to * ensure that they don't violate the spirit of this class in that performance * is second only to correctness. * <p> * There are a few issues open for remaining tasks: * <ul> * <li>757 Validator should expose a way to turn it off</li> * <li>758 Validator should provide a way to throttle it's error messages</li> * <li>759 Unit tests should always check that no unexpected Validator checks * failed</li> * </ul> */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, mayInstantiate=false, mayExtend=false, mayInvoke=true) public class Validator { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** This static final variable theoretically allows us to compile out all of * these checks. Since all of the code below is guarded with this check, * the compiler should eliminate it if ENABLE_CHECKS is false. * From doing a little bit of micro-benchmarking, it appears that setting * ENABLE_CHECKS=false speeds the code up by about a factor of four, but * it's still not the same as not having the invocation in the first place. * On a single CPU laptop, I was able to get 200M * invocations per second with ENABLE_CHECKS=true, and 350M with * ENABLE_CHECKS=false. * <p> * Setting this to false, will not eliminate any expensive computation * done in a parameter list (e.g. some self-check that returns true).*/ public static final boolean ENABLE_CHECKS = true; /** A one-based array for parameter descriptions. */ private static final String[] PARAM_DESCRIPTIONS = {"** A ZERO-BASED INDEX IS INVALID **", "(1st parameter)", "(2nd parameter)", "(3rd parameter)", "(4th parameter)", "(5th parameter)", "(6th parameter)", "(7th parameter)", "(8th parameter)", "(9th parameter)", "(10th parameter)"}; /** A count of the errors detected by the methods in this class since the * last time that resetErrorCount was called. */ private static long _errorCount = 0; /** * This method validates that the specified parameter is not null. It * throws an AssertionError if it is null after logging this error. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. * * @param param the parameter to validate as non-null. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if and only if param is null * if assertions are enabled */ public static boolean ensureNotNull(Object param) throws AssertionError { if (ENABLE_CHECKS) { if (param == null) throwNull(""); } return true; } /** * This method validates that the specified parameters are not null. It * throws an AssertionError if one of them are null after logging this error. * It's similar to the ensureNotNull(Object) call except it provides the * convenience of checking two parameters at once. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. * <p> * See the class level javadoc for why we did not use varargs to * implement this method. * * @param param1 the first parameter to validate as non-null. * @param param2 the second parameter to validate as non-null. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if and only if any of the parameters is null */ public static boolean ensureNotNull(Object param1, Object param2) throws AssertionError { if (ENABLE_CHECKS) { if (param1 == null) throwNull(PARAM_DESCRIPTIONS[1]); if (param2 == null) throwNull(PARAM_DESCRIPTIONS[2]); } return true; } /** * This method validates that the specified parameters are not null. It * throws an AssertionError if one of them are null after logging this error. * It's similar to the ensureNotNull(Object) call except it provides the * convenience of checking three parameters at once. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. * <p> * See the class level javadoc for why we did not use varargs to * implement this method. * * @param param1 the first parameter to validate as non-null. * @param param2 the second parameter to validate as non-null. * @param param3 the third parameter to validate as non-null. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if and only if one of the parameters is null */ public static boolean ensureNotNull(Object param1, Object param2, Object param3) throws AssertionError { if (ENABLE_CHECKS) { if (param1 == null) throwNull(PARAM_DESCRIPTIONS[1]); if (param2 == null) throwNull(PARAM_DESCRIPTIONS[2]); if (param3 == null) throwNull(PARAM_DESCRIPTIONS[3]); } return true; } /** * This method validates that the specified parameters are not null. It * throws an AssertionError if one of them are null after logging this error. * It's similar to the ensureNotNull(Object) call except it provides the * convenience of checking four parameters at once. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. * <p> * See the class level javadoc for why we did not use varargs to * implement this method. * * @param param1 the first parameter to validate as non-null. * @param param2 the second parameter to validate as non-null. * @param param3 the third parameter to validate as non-null. * @param param4 the fourth parameter to validate as non-null. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if and only if one of the parameters is null */ public static boolean ensureNotNull(Object param1, Object param2, Object param3, Object param4) throws AssertionError { if (ENABLE_CHECKS) { if (param1 == null) throwNull(PARAM_DESCRIPTIONS[1]); if (param2 == null) throwNull(PARAM_DESCRIPTIONS[2]); if (param3 == null) throwNull(PARAM_DESCRIPTIONS[3]); if (param4 == null) throwNull(PARAM_DESCRIPTIONS[4]); } return true; } /** * This method validates that the specified parameter is true. It * throws an AssertionError if it is not true. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. The other advantage of * using this method instead of an assert is that it logs the error to the * debug and error logs. * * @param condition the condition that must be true. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if condition is false */ public static boolean ensureTrue(boolean condition) throws AssertionError { if (ENABLE_CHECKS) { if (!condition) { ensureTrue(condition, ""); } } return true; } /** * This method validates that the specified parameter is true. It * throws an AssertionError if it is not true. The supplied message is * included in the error message. * <p> * This should be used like an assert, except it is not turned * off at runtime. That is, it should only be used in situations where * there is a bug in someone's code if param is null. The other advantage of * using this method instead of an assert is that it logs the error to the * debug and error logs. * * @param condition the condition that must be true. * @param message the textual message to include in the error message. * @return true always. This allows this call to be used in an assert * statement, which can skip this check and remove all * overhead from the calling code. This idiom should only be used when * performance testing proves that it is necessary. * * @throws AssertionError if condition is false */ public static boolean ensureTrue(boolean condition, String message) throws AssertionError { if (ENABLE_CHECKS) { if (!condition) { StringBuilder mb = new StringBuilder(); mb.append("The specified condition must be true. "); mb.append(message); String fullString = generateLineSpecificErrorString(mb.toString()); logError(fullString); throw new AssertionError(fullString); } } return true; } //////////////////////////////////////////////////////////////////////////// // // ERROR COUNT // //////////////////////////////////////////////////////////////////////////// /** * Returns the number of errors that this class has detected since the * system started or the last time that resetErrorCount() was called. * <p> * This could be useful in the unit tests to validate that no background * errors occurred during a test. It could also be exposed by the monitoring * framekwork. * * @return the number of errors detected by this class since the error count * was last reset. */ public static synchronized long getErrorCount() { return _errorCount; } /** * Resets the error count to zero. */ public static synchronized void resetErrorCount() { _errorCount = 0; } private static synchronized void incrementErrorCount() { _errorCount++; } //////////////////////////////////////////////////////////////////////////// // // PRIVATE // //////////////////////////////////////////////////////////////////////////// private static String generateLineSpecificErrorString(String message) { StringBuilder mb = new StringBuilder(); mb.append(message); mb.append(" The error occurred at "); mb.append(getOriginalCallerLineInfo()); return mb.toString(); } private static void throwNull(String message) throws AssertionError { StringBuilder mb = new StringBuilder(); mb.append("The specified parameter must not be null. "); mb.append(message); String fullString = generateLineSpecificErrorString(mb.toString()); logError(fullString); throw new AssertionError(fullString); } private static void logError(String message) { incrementErrorCount(); StringBuilder mb = new StringBuilder(); mb.append(message); mb.append(ServerConstants.EOL); mb.append(getCallingStack()); String messageWithStack = mb.toString(); // Log to the debug log. if (debugEnabled()) { TRACER.debugError(messageWithStack.toString()); } // Log to the error log. ErrorLogger.logError(Message.raw(messageWithStack)); } /* * @return a String representation of the line that called the * Validator method. */ private static String getOriginalCallerLineInfo() { StackTraceElement stackElements[] = Thread.currentThread().getStackTrace(); int callerIndex = getOriginalCallerStackIndex(stackElements); return stackElements[callerIndex].toString(); } /* * @return a stack trace rooted at the line that called the first * Validator method. */ private static String getCallingStack() { StackTraceElement stackElements[] = Thread.currentThread().getStackTrace(); int callerIndex = getOriginalCallerStackIndex(stackElements); StringBuilder buffer = new StringBuilder(); for (int i = callerIndex; i < stackElements.length; i++) { StackTraceElement stackElement = stackElements[i]; buffer.append(stackElement).append(ServerConstants.EOL); } return buffer.toString(); } /* * @return the index in the supplied stack trace of the first non-Validator * method. */ private static int getOriginalCallerStackIndex(StackTraceElement stack[]) { // Go up the stack until we find who called the first Validator method. StackTraceElement element = null; int i; for (i = 0; i < stack.length; i++) { element = stack[i]; // The stack trace of this thread looks like // java.lang.Thread.dumpThreads(Native Method) // java.lang.Thread.getStackTrace(Thread.java:1383) // org.opends.server.util.Validator.getOriginalCallerLineInfo... // ... // original caller <---- this is what we want to return // more stack if (!element.getClassName().equals(Validator.class.getName()) && !element.getClassName().equals(Thread.class.getName())) { break; } } return i; } }