package rocks.inspectit.server.diagnosis.engine.rule; import static com.google.common.base.Preconditions.checkNotNull; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.lang.StringUtils; import rocks.inspectit.server.diagnosis.engine.rule.annotation.Condition; import rocks.inspectit.server.diagnosis.engine.rule.exception.RuleDefinitionException; import rocks.inspectit.server.diagnosis.engine.rule.exception.RuleExecutionException; import rocks.inspectit.server.diagnosis.engine.util.ReflectionUtils; /** * Defines a condition method of a rule implementation. A <code>ConditionMethod</code> reflects the * {@link Condition} annotation. * * @author Claudio Waldvogel, Alexander Wert * @see Condition */ public class ConditionMethod { /** * The name of the condition. * * @see Condition#name() */ private final String name; /** * A hint why the condition failed. * * @see Condition#hint() */ private final String hint; /** * The actual condition implementation of a rule. As shown in listing, a valid condition method * implementation has no parameters and returns a boolean. * <p> * * <pre> * {@code * @literal @Condition(name = "MyCondition", hint = "Some useful information") * public boolean condition(){ * return true | false; * } * } * </pre> */ private final Method method; /** * Default Constructor. * * @param name * The name of the condition * @param hint * A hint why the condition failed * @param method * The actual backing implementation of the condition method * @throws RuleDefinitionException * If the {@link ConditionMethod} is invalid. A condition method must be public, * with zero arguments and boolean/Boolean return type. */ public ConditionMethod(String name, String hint, Method method) throws RuleDefinitionException { this.method = checkNotNull(method); this.name = StringUtils.defaultIfEmpty(name, this.method.getName()); this.hint = hint; validate(); } /** * Executes this {@link ConditionMethod}. If the #method does not succeed a * {@link ConditionFailure} is returned. Otherwise null is returned. * * @param context * The current executing {@link ExecutionContext} * @return A {@link ConditionFailure} if condition fails, null otherwise * @throws RuleExecutionException * If execution of the condition method fails with an exception. * @see ExecutionContext * @see ConditionFailure */ public ConditionFailure execute(ExecutionContext context) throws RuleExecutionException { try { boolean valid = (boolean) ReflectionUtils.invokeMethod(getMethod(), context.getInstance()); if (!valid) { // Store information about the failed condition for later usage return new ConditionFailure(getName(), getHint()); } return null; } catch (Exception e) { throw new RuleExecutionException("Invocation of condition method failed.", context, e); } } /** * Validates the properties of the {@link ConditionMethod}. * * @throws RuleDefinitionException * If the {@link ConditionMethod} is invalid. A condition method must be public, * with zero arguments and boolean/Boolean return type. */ private void validate() throws RuleDefinitionException { boolean valid = Modifier.isPublic(method.getModifiers()); valid = valid && (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)); valid = valid && (method.getParameterTypes().length == 0); if (!valid) { String msg = method.getDeclaringClass().getName() + " defines an invalid condition method with name: " + method.getName(); msg += "\nValid condition methods are public with a boolean return type and zero arguments (e.g. " + "public" + " boolean condition())"; throw new RuleDefinitionException(msg); } } // ------------------------------------------------------------- // Methods: Accessors // ------------------------------------------------------------- /** * Gets {@link #name}. * * @return {@link #name} */ public String getName() { return name; } /** * Gets {@link #hint}. * * @return {@link #hint} */ public String getHint() { return hint; } /** * Gets {@link #method}. * * @return {@link #method} */ public Method getMethod() { return method; } // ------------------------------------------------------------- // Methods: Generated // ------------------------------------------------------------- /** * {@inheritDoc} */ @Override public String toString() { return "ConditionMethod{" + "name='" + name + '\'' + ", hint='" + hint + '\'' + ", method=" + method + '}'; } /** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + ((hint == null) ? 0 : hint.hashCode()); result = (prime * result) + ((method == null) ? 0 : method.hashCode()); result = (prime * result) + ((name == null) ? 0 : name.hashCode()); return result; } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ConditionMethod other = (ConditionMethod) obj; if (hint == null) { if (other.hint != null) { return false; } } else if (!hint.equals(other.hint)) { return false; } if (method == null) { if (other.method != null) { return false; } } else if (!method.equals(other.method)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } }