/** * Constructor that allows definition of the technical root cause. * * @param message * The error message * @param context * A reference to the failed {@link ExecutionContext} * @param cause * The technical root cause * @see ExecutionContext */ public RuleExecutionException(String message, ExecutionContext context, Throwable cause) { super(prefix(message, context), cause); }
/** * Extracts the {@link Action} from the given class by processing the {@link Action} annotation. * * @param clazz * The class to be analyzed. * @return List of ActionMethod * @throws RuleDefinitionException * If {@link Action} annotation is invalid. */ public static ActionMethod describeActionMethod(Class<?> clazz) throws RuleDefinitionException { List<ActionMethod> actionMethods = ReflectionUtils.visitMethodsAnnotatedWith(Action.class, clazz, new Visitor<Action, Method, ActionMethod>() { @Override public ActionMethod visit(Action annotation, Method method) throws RuleDefinitionException { return new ActionMethod(method, annotation.resultTag(), annotation.resultQuantity()); } }); if ((null == actionMethods) || (actionMethods.size() != 1)) { throw new RuleDefinitionException("A rule must define exactly one method annotated with @Action. Otherwise the rule could never be exectued."); } else { return actionMethods.get(0); } }
/** * Performs the injection. * * @param context * The current valid {@link ExecutionContext} * @throws RuleExecutionException * If injection fails. * @see ExecutionContext Throws: RuleExecutionException if an exception soccurs */ public void execute(ExecutionContext context) throws RuleExecutionException { Object toInject = determineValueToInject(context); try { getInjectee().set(context.getInstance(), toInject); } catch (IllegalAccessException e) { throw new RuleExecutionException("Failed to injected \'" + toInject + "\' to \'" + getInjectee().getName() + "\'", 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); } }
/** * {@inheritDoc} */ @Override public Object determineValueToInject(ExecutionContext context) throws RuleExecutionException { // Fail fast if value is missing completely and not optional. if (!isOptional() && !context.getSessionParameters().containsKey(getVariableName())) { throw new RuleExecutionException("Non optional session variable \'" + getVariableName() + "\' not available.", context); } // This might return null if a null value is available for a certain key. // Needs to be discussed how to handle this. return context.getSessionParameters().get(getVariableName()); }
@Override public String visit(Action annotation, Method method) throws RuleDefinitionException { if (method.getName().endsWith("C")) { throw new RuleDefinitionException("test exception"); } else { return "ok"; } } });
/** * Executes the action. Throws: RuleExecutionException in case of any error * * @param context * The current executing {@link ExecutionContext} * @return A collection of {@link Tags}s * @throws RuleExecutionException * If rule execution fails with an exception. * @see ExecutionContext * @see Tag */ public Collection<Tag> execute(ExecutionContext context) throws RuleExecutionException { try { Object result = ReflectionUtils.invokeMethod(getMethod(), context.getInstance()); return transform(result, context); } catch (Exception e) { throw new RuleExecutionException("Failed to invoke action method (" + getMethod().getName() + ")", context, e); } }
@Override public String visit(TagValue annotation, Field field) throws RuleDefinitionException { if (field.getName().endsWith("2")) { throw new RuleDefinitionException("test exception"); } else { return "ok"; } } });
/** * {@inheritDoc} * * @throws RuleExecutionException * If tag injection fails. */ @Override public Object determineValueToInject(ExecutionContext context) throws RuleExecutionException { // extract the required type form the unraveled list of input Tags for (Tag tag : context.getRuleInput().getUnraveled()) { if (tag.getType().equals(getType())) { return InjectionStrategy.BY_VALUE.equals(getInjectionStrategy()) ? tag.getValue() : tag; } } throw new RuleExecutionException("Unable to find Tag: " + getType() + " in RuleInput.", context); }
/** * Extracts the {@link TagInjection}s from the given class by processing the * {@link TagInjection} annotations. * * @param clazz * The class to be analyzed. * @return List of TagInjection * @throws RuleDefinitionException * If {@link TagInjection} annotations are invalid. Contract is that a class must * defined at least one field annotated with {@link TagValue}. Otherwise the rule * could never fire, because no input could be determined. */ public static List<TagInjection> describeTagInjection(Class<?> clazz) throws RuleDefinitionException { List<TagInjection> tagInjections = ReflectionUtils.visitFieldsAnnotatedWith(TagValue.class, clazz, new Visitor<TagValue, Field, TagInjection>() { @Override public TagInjection visit(TagValue annotation, Field field) { return new TagInjection(annotation.type(), field, annotation.injectionStrategy()); } }); if (CollectionUtils.isEmpty(tagInjections)) { throw new RuleDefinitionException(clazz.getName() + " must annotate at least one field with @Value. Otherwise the " + "rule will never fire and is useless."); } else { return tagInjections; } }
/** * 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 ActionMethod}. * * @throws RuleDefinitionException * If the {@link ActionMethod} is invalid. The action method must be public, with * zero arguments and void return type. */ private void validate() throws RuleDefinitionException { boolean valid = Modifier.isPublic(method.getModifiers()); Class<?> returnType = method.getReturnType(); valid = valid && !returnType.equals(Void.class); valid = valid && (method.getParameterTypes().length == 0); if (!valid) { String msg = method.getDeclaringClass().getName() + " defines an invalid action method with name: " + method.getName(); msg += "\nValid action methods are public with a non void return type and zero arguments (e.g. public" + " String action())"; throw new RuleDefinitionException(msg); } // ensure proper return type in case of MULTIPLE outputQuantity if (Action.Quantity.MULTIPLE.equals(resultQuantity)) { if (!returnType.isArray() && !Iterable.class.isAssignableFrom(returnType)) { throw new RuleDefinitionException(method.getDeclaringClass().getName() + " defines an MULTIPLE outputQuantity, but return type is neither Array nor Collection."); } } }
values = Iterables.toArray((Iterable<?>) result, Object.class); } else { throw new RuleExecutionException("If resultQuantity is MULTIPLE ensure that either an Array or a Collection is defined as return value", context);
Rule annotation = ReflectionUtils.findAnnotation(clazz, Rule.class); if (annotation == null) { throw new RuleDefinitionException(clazz.getName() + " must be annotated with @Rule annotation."); throw new RuleDefinitionException(clazz.getName() + " must define an empty default constructor.");