/*
* 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;
}
}