@Override public ActionMethod visit(Action annotation, Method method) throws RuleDefinitionException { return new ActionMethod(method, annotation.resultTag(), annotation.resultQuantity()); } });
/** * 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); } }
} else { Collection<Tag> transformed = Lists.newArrayList(); switch (getResultQuantity()) { case MULTIPLE: Object[] values; if (result.getClass().isArray()) { values = getObjectArray(result); } else if (result instanceof Iterable<?>) { values = Iterables.toArray((Iterable<?>) result, Object.class); throw new RuleExecutionException("If resultQuantity is MULTIPLE ensure that either an Array or a Collection is defined as return value", context); transformed.addAll(Tags.tags(getResultTag(), context.getRuleInput().getRoot(), values)); break; case SINGLE: default: transformed.add(Tags.tag(getResultTag(), result, context.getRuleInput().getRoot()));
@Test(expectedExceptions = RuleDefinitionException.class) public void shouldFailDueToQuantityAndResultMismatch() throws RuleDefinitionException, RuleExecutionException { Tag rootTag = Tags.rootTag("Input"); when(dummy.action()).thenReturn("Fail"); when(this.input.getRoot()).thenReturn(rootTag); // Execute and fail. ActionMethod would expect array/collection as result from ruleImpl // implementation. // But receives "Fail" String new ActionMethod(RuleDummy.actionMethod(), "T2", Action.Quantity.MULTIPLE).execute(context); } }
if (CollectionUtils.isEmpty(conditionFailures)) { conditionFailures = Collections.emptyList(); tags = getActionMethod().execute(ctx); } else { tags = Collections.emptyList(); return new RuleOutput(getName(), getActionMethod().getResultTag(), conditionFailures, tags);
/** * Default Constructor. * * @param method * The method to be invoked * @param resultTag * The type of tags this action produces * @param resultQuantity * The result Quantity * @throws RuleDefinitionException * If the {@link ActionMethod} is invalid. The action method must be public, with * zero arguments and void return type. */ public ActionMethod(Method method, String resultTag, Action.Quantity resultQuantity) throws RuleDefinitionException { this.method = checkNotNull(method, "The method must not be null."); this.resultTag = checkNotNull(resultTag, "The result tag must not be null."); this.resultQuantity = checkNotNull(resultQuantity, "The output quantity must not be null."); validate(); }
/** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + ((this.actionMethod == null) ? 0 : this.actionMethod.hashCode()); result = (prime * result) + ((this.conditionMethods == null) ? 0 : this.conditionMethods.hashCode()); result = (prime * result) + ((this.description == null) ? 0 : this.description.hashCode()); result = (prime * result) + ((this.fireCondition == null) ? 0 : this.fireCondition.hashCode()); result = (prime * result) + ((this.implementation == null) ? 0 : this.implementation.hashCode()); result = (prime * result) + ((this.name == null) ? 0 : this.name.hashCode()); result = (prime * result) + ((this.tagInjections == null) ? 0 : this.tagInjections.hashCode()); result = (prime * result) + ((this.variableInjections == null) ? 0 : this.variableInjections.hashCode()); return result; }
return false; } else if (!this.actionMethod.equals(other.actionMethod)) { return false;
@Test public void shouldProduceMultipleTagsFromCollection() throws Exception { // prepare Mocks Tag rootTag = Tags.rootTag("Input"); when(dummy.action2()).thenReturn(new String[] { "one", "two", "three" }); when(this.input.getRoot()).thenReturn(rootTag); // Create TestMethod ActionMethod action = new ActionMethod(RuleDummy.action2Method(), "T2", Action.Quantity.MULTIPLE); // execute Collection<Tag> result = action.execute(context); // verify Collection<Tag> tags = Tags.tags("T2", rootTag, "one", "two", "three"); assertThat(result, containsInAnyOrder(tags.toArray())); }
@Test public void shouldProduceSingleTagWithArrayValue() throws Exception { // prepare Mocks Tag rootTag = Tags.rootTag("Input"); Tag expectedResultTag = new Tag("T1", new String[] { "one", "two", "three" }, rootTag); when(dummy.action()).thenReturn(new String[] { "one", "two", "three" }); when(this.input.getRoot()).thenReturn(rootTag); // Create TestMethod ActionMethod action = new ActionMethod(RuleDummy.actionMethod(), "T1", Action.Quantity.SINGLE); // execute Collection<Tag> result = action.execute(context); // verify assertThat(result, hasSize(1)); assertThat(result, containsInAnyOrder(expectedResultTag)); }
@Test public void testWithRuleAnnotation() throws Exception { RuleDefinition definition = Rules.define(ValidAndAnnotated.class); assertThat(definition.getName(), is("AnnotatedRule")); assertThat(definition.getDescription(), is("Description")); assertThat(definition.getFireCondition().getTagTypes(), containsInAnyOrder("T1", "T2")); // Test tag injections TagInjection tagInjection = new TagInjection("T1", ValidAndAnnotated.class.getDeclaredField("t1AsTag"), TagValue.InjectionStrategy.BY_TAG); TagInjection tagInjection1 = new TagInjection("T2", ValidAndAnnotated.class.getDeclaredField("t2TagValue"), TagValue.InjectionStrategy.BY_VALUE); assertThat(definition.getTagInjections(), is(notNullValue())); assertThat(definition.getTagInjections(), containsInAnyOrder(tagInjection, tagInjection1)); // Test session variables SessionVariableInjection s1 = new SessionVariableInjection("baseline", false, ValidAndAnnotated.class.getDeclaredField("baseline")); SessionVariableInjection s2 = new SessionVariableInjection("baseline2", true, ValidAndAnnotated.class.getDeclaredField("baseline2")); assertThat(definition.getSessionVariableInjections(), containsInAnyOrder(s1, s2)); // Test action method assertThat(definition.getActionMethod(), is(new ActionMethod(ValidAndAnnotated.class.getDeclaredMethod("action"), "T2", Action.Quantity.SINGLE))); // Test condition method ConditionMethod conditionMethod = new ConditionMethod("myCondition", "No way out", ValidAndAnnotated.class.getDeclaredMethod("condition")); assertThat(definition.getConditionMethods(), containsInAnyOrder(conditionMethod)); }
@Test public void shouldProduceMultipleTagsFromSingleArray() throws Exception { Tag rootTag = Tags.rootTag("Input"); // prepare Mocks when(dummy.action2()).thenReturn(new String[] { "one", "two", "three" }); when(this.input.getRoot()).thenReturn(rootTag); // Create TestMethod ActionMethod action = new ActionMethod(RuleDummy.action2Method(), "T2", Action.Quantity.MULTIPLE); // execute Collection<Tag> result = action.execute(context); // verify Collection<Tag> tags = Tags.tags("T2", rootTag, "one", "two", "three"); assertThat(result, containsInAnyOrder(tags.toArray())); }
@Test public void shouldProduceSingleTagWithSingleObjectValue() throws Exception { // prepare Mocks Tag rootTag = Tags.rootTag("Input"); Tag expectedResultTag = new Tag("T1", "oneResult", rootTag); when(dummy.action()).thenReturn("oneResult"); when(input.getRoot()).thenReturn(rootTag); // Create TestMethod ActionMethod action = new ActionMethod(RuleDummy.actionMethod(), "T1", Action.Quantity.SINGLE); // execute Collection<Tag> result = action.execute(context); // verify assertThat(result, hasSize(1)); assertThat(result, hasItem(expectedResultTag)); }