+ actor #15446 add external predicate to ReceiveBuilder (#24221)

This commit is contained in:
kerr 2018-01-03 17:23:31 +08:00 committed by Konrad `ktoso` Malawski
parent 9ccf71076a
commit 7edf3bfecf
3 changed files with 95 additions and 0 deletions

View file

@ -191,6 +191,21 @@ public class ReceiveBuilderTest extends JUnitSuite {
assertFalse(rcv.onMessage().isDefinedAt(42)); assertFalse(rcv.onMessage().isDefinedAt(42));
} }
private boolean externalPredicateAlwaysTrue(){
return true;
}
@Test
public void shouldMatchByExternalPredicate(){
Receive rcv = ReceiveBuilder.create()
.match(Msg1.class, this::externalPredicateAlwaysTrue, m -> result("match Msg1"))
.build();
assertTrue(rcv.onMessage().isDefinedAt(new Msg1()));
rcv.onMessage().apply(new Msg1());
assertEquals("match Msg1", result());
assertFalse(rcv.onMessage().isDefinedAt(new Msg2("foo")));
}
@Test @Test
public void shouldMatchEquals() { public void shouldMatchEquals() {
Msg2 msg2 = new Msg2("foo"); Msg2 msg2 = new Msg2("foo");

View file

@ -130,6 +130,24 @@ public class ReceiveBuilder {
return matchUnchecked(type, predicate, apply); return matchUnchecked(type, predicate, apply);
} }
/**
* Add a new case statement to this builder.
*
* @param type
* a type to match the argument against
* @param externalPredicate
* a external predicate that will be evaluated if the type matches
* @param apply
* an action to apply to the argument if the type matches and the
* predicate returns true
* @return a builder with the case statement added
*/
public <P> ReceiveBuilder match(final Class<P> type,
final java.util.function.BooleanSupplier externalPredicate,
final FI.UnitApply<P> apply) {
return matchUnchecked(type, externalPredicate, apply);
}
/** /**
* Add a new case statement to this builder without compile time type check. * Add a new case statement to this builder without compile time type check.
* Should normally not be used, but when matching on class with generic type * Should normally not be used, but when matching on class with generic type
@ -164,6 +182,38 @@ public class ReceiveBuilder {
return this; return this;
} }
/**
* Add a new case statement to this builder without compile time type check.
* Should normally not be used, but when matching on class with generic type
* argument it can be useful, e.g. <code>List.class</code> and
* <code>(List&lt;String&gt; list) -> {}</code>.
*
* @param type
* a type to match the argument against
* @param externalPredicate
* a external predicate that will be evaluated if the type matches
* @param apply
* an action to apply to the argument if the type matches and the
* predicate returns true
* @return a builder with the case statement added
*/
@SuppressWarnings("unchecked")
public <P> ReceiveBuilder matchUnchecked(final Class<?> type,
final java.util.function.BooleanSupplier externalPredicate,
final FI.UnitApply<P> apply) {
FI.Predicate fiPredicate = new FI.Predicate() {
@Override
public boolean defined(Object o) {
return type.isInstance(o) &&
externalPredicate.getAsBoolean();
}
};
addStatement(new UnitCaseStatement<Object, Object>(fiPredicate, (FI.UnitApply<Object>) apply));
return this;
}
/** /**
* Add a new case statement to this builder. * Add a new case statement to this builder.
* *

View file

@ -117,6 +117,21 @@ public class InitializationDocTest extends AbstractJavaTest {
} }
} }
static class GenericActorWithPredicateAlwaysResponse extends AbstractActor {
private boolean alwaysResponse() {
return true;
}
@Override
public Receive createReceive() {
return receiveBuilder()
.matchUnchecked(GenericMessage.class, this::alwaysResponse, (GenericMessage<String> msg) -> {
getSender().tell(msg.value.toUpperCase(), getSelf());
})
.build();
}
}
@Test @Test
public void testIt() { public void testIt() {
@ -158,4 +173,19 @@ public class InitializationDocTest extends AbstractJavaTest {
expectMsgEquals("A"); expectMsgEquals("A");
}}; }};
} }
@Test
public void actorShouldAlwaysRespondForEmptyMessage() {
new TestKit(system) {{
ActorRef genericTestActor = system.actorOf(Props.create(GenericActorWithPredicateAlwaysResponse.class), "genericActorWithPredicateAlwaysResponse");
GenericMessage<String> emptyGenericMessage = new GenericMessage<String>("");
GenericMessage<String> nonEmptyGenericMessage = new GenericMessage<String>("a");
genericTestActor.tell(emptyGenericMessage, getRef());
expectMsg("");
genericTestActor.tell(nonEmptyGenericMessage, getRef());
expectMsgEquals("A");
}};
}
} }