/** * Copyright (C) 2009-2017 Lightbend Inc. */ 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. *

* Example: *

*
 * @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()
 *   );
 * }
 * 
* */ public class ReceiveBuilder { private PartialFunction statements = null; protected void addStatement(PartialFunction 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 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

ReceiveBuilder match(final Class

type, final FI.UnitApply

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. List.class and * (List<String> list) -> {}. * * @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(predicate, (FI.UnitApply) 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

ReceiveBuilder match(final Class

type, final FI.TypedPredicate

predicate, final FI.UnitApply

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. List.class and * (List<String> list) -> {}. * * @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

ReceiveBuilder matchUnchecked(final Class type, final FI.TypedPredicate predicate, final FI.UnitApply

apply) { FI.Predicate fiPredicate = new FI.Predicate() { @Override public boolean defined(Object o) { if (!type.isInstance(o)) return false; else return ((FI.TypedPredicate) predicate).defined(o); } }; addStatement(new UnitCaseStatement(fiPredicate, (FI.UnitApply) 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

ReceiveBuilder matchEquals(final P object, final FI.UnitApply

apply) { addStatement(new UnitCaseStatement(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

ReceiveBuilder matchEquals(final P object, final FI.TypedPredicate

predicate, final FI.UnitApply

apply) { addStatement(new UnitCaseStatement(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 apply) { addStatement(new UnitCaseStatement(new FI.Predicate() { @Override public boolean defined(Object o) { return true; } }, apply)); return this; } }