* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
232 lines
7 KiB
Java
232 lines
7 KiB
Java
/**
|
|
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
|
*/
|
|
|
|
package akka.japi.pf;
|
|
|
|
import scala.PartialFunction;
|
|
import scala.runtime.BoxedUnit;
|
|
import akka.actor.AbstractActor;
|
|
import akka.actor.AbstractActor.Receive;
|
|
|
|
/**
|
|
* Used for building a partial function for {@link akka.actor.Actor#receive() Actor.receive()}.
|
|
*
|
|
* There is both a match on type only, and a match on type and predicate.
|
|
*
|
|
* Inside an actor you can use it like this with Java 8 to define your receive method.
|
|
* <p>
|
|
* Example:
|
|
* </p>
|
|
* <pre>
|
|
* @Override
|
|
* public Actor() {
|
|
* receive(ReceiveBuilder.
|
|
* match(Double.class, d -> {
|
|
* sender().tell(d.isNaN() ? 0 : d, self());
|
|
* }).
|
|
* match(Integer.class, i -> {
|
|
* sender().tell(i * 10, self());
|
|
* }).
|
|
* match(String.class, s -> s.startsWith("foo"), s -> {
|
|
* sender().tell(s.toUpperCase(), self());
|
|
* }).build()
|
|
* );
|
|
* }
|
|
* </pre>
|
|
*
|
|
*/
|
|
public class ReceiveBuilder {
|
|
|
|
private PartialFunction<Object, BoxedUnit> statements = null;
|
|
|
|
protected void addStatement(PartialFunction<Object, BoxedUnit> statement) {
|
|
if (statements == null)
|
|
statements = statement;
|
|
else
|
|
statements = statements.orElse(statement);
|
|
}
|
|
|
|
/**
|
|
* Build a {@link scala.PartialFunction} from this builder. After this call
|
|
* the builder will be reset.
|
|
*
|
|
* @return a PartialFunction for this builder.
|
|
*/
|
|
public Receive build() {
|
|
PartialFunction<Object, BoxedUnit> empty = CaseStatement.empty();
|
|
|
|
if (statements == null)
|
|
return new Receive(empty);
|
|
else
|
|
return new Receive(statements.orElse(empty)); // FIXME why no new Receive(statements)?
|
|
}
|
|
|
|
/**
|
|
* Return a new {@link ReceiveBuilder} with no case statements. They can be
|
|
* added later as the returned {@link ReceiveBuilder} is a mutable object.
|
|
*
|
|
* @return a builder with no case statements
|
|
*/
|
|
public static ReceiveBuilder create() {
|
|
return new ReceiveBuilder();
|
|
}
|
|
|
|
/**
|
|
* Add a new case statement to this builder.
|
|
*
|
|
* @param type
|
|
* a type to match the argument against
|
|
* @param apply
|
|
* an action to apply to the argument if the type matches
|
|
* @return a builder with the case statement added
|
|
*/
|
|
public <P> ReceiveBuilder match(final Class<P> type, final FI.UnitApply<P> apply) {
|
|
return matchUnchecked(type, apply);
|
|
}
|
|
|
|
/**
|
|
* 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<String> list) -> {}</code>.
|
|
*
|
|
* @param type
|
|
* a type to match the argument against
|
|
* @param apply
|
|
* an action to apply to the argument if the type matches
|
|
* @return a builder with the case statement added
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public ReceiveBuilder matchUnchecked(final Class<?> type, final FI.UnitApply<?> apply) {
|
|
|
|
FI.Predicate predicate = new FI.Predicate() {
|
|
@Override
|
|
public boolean defined(Object o) {
|
|
return type.isInstance(o);
|
|
}
|
|
};
|
|
|
|
addStatement(new UnitCaseStatement<Object, Object>(predicate, (FI.UnitApply<Object>) apply));
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a new case statement to this builder.
|
|
*
|
|
* @param type
|
|
* a type to match the argument against
|
|
* @param predicate
|
|
* a predicate that will be evaluated on the argument 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 FI.TypedPredicate<P> predicate,
|
|
final FI.UnitApply<P> apply) {
|
|
return matchUnchecked(type, predicate, apply);
|
|
}
|
|
|
|
/**
|
|
* 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<String> list) -> {}</code>.
|
|
*
|
|
* @param type
|
|
* a type to match the argument against
|
|
* @param predicate
|
|
* a predicate that will be evaluated on the argument 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 FI.TypedPredicate<?> predicate,
|
|
final FI.UnitApply<P> apply) {
|
|
FI.Predicate fiPredicate = new FI.Predicate() {
|
|
@Override
|
|
public boolean defined(Object o) {
|
|
if (!type.isInstance(o))
|
|
return false;
|
|
else
|
|
return ((FI.TypedPredicate<Object>) predicate).defined(o);
|
|
}
|
|
};
|
|
|
|
addStatement(new UnitCaseStatement<Object, Object>(fiPredicate, (FI.UnitApply<Object>) apply));
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a new case statement to this builder.
|
|
*
|
|
* @param object
|
|
* the object to compare equals with
|
|
* @param apply
|
|
* an action to apply to the argument if the object compares equal
|
|
* @return a builder with the case statement added
|
|
*/
|
|
public <P> ReceiveBuilder matchEquals(final P object, final FI.UnitApply<P> apply) {
|
|
addStatement(new UnitCaseStatement<Object, P>(new FI.Predicate() {
|
|
@Override
|
|
public boolean defined(Object o) {
|
|
return object.equals(o);
|
|
}
|
|
}, apply));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a new case statement to this builder.
|
|
*
|
|
* @param object
|
|
* the object to compare equals with
|
|
* @param predicate
|
|
* a predicate that will be evaluated on the argument if the object
|
|
* compares equal
|
|
* @param apply
|
|
* an action to apply to the argument if the object compares equal
|
|
* @return a builder with the case statement added
|
|
*/
|
|
public <P> ReceiveBuilder matchEquals(final P object, final FI.TypedPredicate<P> predicate,
|
|
final FI.UnitApply<P> apply) {
|
|
addStatement(new UnitCaseStatement<Object, P>(new FI.Predicate() {
|
|
@Override
|
|
public boolean defined(Object o) {
|
|
if (!object.equals(o))
|
|
return false;
|
|
else {
|
|
@SuppressWarnings("unchecked")
|
|
P p = (P) o;
|
|
return predicate.defined(p);
|
|
}
|
|
}
|
|
}, apply));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a new case statement to this builder, that matches any argument.
|
|
*
|
|
* @param apply
|
|
* an action to apply to the argument
|
|
* @return a builder with the case statement added
|
|
*/
|
|
public ReceiveBuilder matchAny(final FI.UnitApply<Object> apply) {
|
|
addStatement(new UnitCaseStatement<Object, Object>(new FI.Predicate() {
|
|
@Override
|
|
public boolean defined(Object o) {
|
|
return true;
|
|
}
|
|
}, apply));
|
|
return this;
|
|
}
|
|
|
|
}
|