!act,sam #3889 Adding Activator template FSM/become for Java with Lambda support
* Dining Hakkers Activator template for FSM and become * Cleaup of FSM event matchers to be more usable and consistent
This commit is contained in:
parent
6af33381b3
commit
07e361c684
30 changed files with 1026 additions and 103 deletions
|
|
@ -6,8 +6,6 @@ package akka.japi.pf;
|
|||
|
||||
import akka.actor.FSM;
|
||||
import scala.PartialFunction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -15,6 +13,8 @@ import java.util.List;
|
|||
*
|
||||
* @param <S> the state type
|
||||
* @param <D> the data type
|
||||
*
|
||||
* This is an EXPERIMENTAL feature and is subject to change until it has received more real world testing.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class FSMStateFunctionBuilder<S, D> {
|
||||
|
|
@ -22,6 +22,89 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
private PFBuilder<FSM.Event<D>, FSM.State<S, D>> builder =
|
||||
new PFBuilder<FSM.Event<D>, FSM.State<S, D>>();
|
||||
|
||||
/**
|
||||
* An erased processing of the event matcher. The compile time checks are enforced
|
||||
* by the public typed versions.
|
||||
*
|
||||
* It works like this.
|
||||
*
|
||||
* If eventOrType or dataOrType is a Class, then we do a isInstance check,
|
||||
* otherwise we do an equals check. The null value compares true for anything.
|
||||
* If the predicate is null, it is skipped otherwise the predicate has to match
|
||||
* as well.
|
||||
*
|
||||
* @param eventOrType an event or a type to match against
|
||||
* @param dataOrType a data instance or a type to match against
|
||||
* @param predicate a predicate to match against
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
private FSMStateFunctionBuilder<S, D> erasedEvent(final Object eventOrType,
|
||||
final Object dataOrType,
|
||||
final FI.TypedPredicate2 predicate,
|
||||
final FI.Apply2 apply) {
|
||||
builder.match(FSM.Event.class,
|
||||
new FI.TypedPredicate<FSM.Event>() {
|
||||
@Override
|
||||
public boolean defined(FSM.Event e) {
|
||||
boolean res = true;
|
||||
if (eventOrType != null) {
|
||||
if (eventOrType instanceof Class) {
|
||||
Class eventType = (Class) eventOrType;
|
||||
res = eventType.isInstance(e.event());
|
||||
}
|
||||
else {
|
||||
res = eventOrType.equals(e.event());
|
||||
}
|
||||
}
|
||||
if (res && dataOrType != null) {
|
||||
if (dataOrType instanceof Class) {
|
||||
Class dataType = (Class) dataOrType;
|
||||
res = dataType.isInstance(e.stateData());
|
||||
}
|
||||
else {
|
||||
res = dataOrType.equals(e.stateData());
|
||||
}
|
||||
}
|
||||
if (res && predicate != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
boolean ures = predicate.defined(e.event(), e.stateData());
|
||||
res = ures;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
},
|
||||
new FI.Apply<FSM.Event, FSM.State<S, D>>() {
|
||||
public FSM.State<S, D> apply(FSM.Event e) throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
FSM.State<S, D> res = (FSM.State<S, D>) apply.apply(e.event(), e.stateData());
|
||||
return res;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches on an event and data type and a predicate.
|
||||
*
|
||||
* @param eventType the event type to match on
|
||||
* @param dataType the data type to match on
|
||||
* @param predicate a predicate to evaluate on the matched types
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @param <P> the event type to match on
|
||||
* @param <Q> the data type to match on
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public final <P, Q> FSMStateFunctionBuilder<S, D> event(final Class<P> eventType,
|
||||
final Class<Q> dataType,
|
||||
final FI.TypedPredicate2<P, Q> predicate,
|
||||
final FI.Apply2<P, Q, FSM.State<S, D>> apply) {
|
||||
erasedEvent(eventType, dataType, predicate, apply);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches on an event and data type.
|
||||
*
|
||||
|
|
@ -35,25 +118,45 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
public <P, Q> FSMStateFunctionBuilder<S, D> event(final Class<P> eventType,
|
||||
final Class<Q> dataType,
|
||||
final FI.Apply2<P, Q, FSM.State<S, D>> apply) {
|
||||
builder.match(FSM.Event.class,
|
||||
new FI.TypedPredicate<FSM.Event>() {
|
||||
@Override
|
||||
public boolean defined(FSM.Event e) {
|
||||
return eventType.isInstance(e.event()) && dataType.isInstance(e.stateData());
|
||||
}
|
||||
},
|
||||
new FI.Apply<FSM.Event, FSM.State<S, D>>() {
|
||||
public FSM.State<S, D> apply(FSM.Event e) throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
P p = (P) e.event();
|
||||
@SuppressWarnings("unchecked")
|
||||
Q q = (Q) e.stateData();
|
||||
return apply.apply(p, q);
|
||||
}
|
||||
}
|
||||
);
|
||||
return erasedEvent(eventType, dataType, null, apply);
|
||||
}
|
||||
|
||||
return this;
|
||||
/**
|
||||
* Add a case statement that matches if the event type and predicate matches.
|
||||
*
|
||||
* @param eventType the event type to match on
|
||||
* @param predicate a predicate that will be evaluated on the data and the event
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public <P> FSMStateFunctionBuilder<S, D> event(final Class<P> eventType,
|
||||
final FI.TypedPredicate2<P, D> predicate,
|
||||
final FI.Apply2<P, D, FSM.State<S, D>> apply) {
|
||||
return erasedEvent(eventType, null, predicate, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches if the event type and predicate matches.
|
||||
*
|
||||
* @param eventType the event type to match on
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public <P> FSMStateFunctionBuilder<S, D> event(final Class<P> eventType,
|
||||
final FI.Apply2<P, D, FSM.State<S, D>> apply) {
|
||||
return erasedEvent(eventType, null, null, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches if the predicate matches.
|
||||
*
|
||||
* @param predicate a predicate that will be evaluated on the data and the event
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public FSMStateFunctionBuilder<S, D> event(final FI.TypedPredicate2<Object, D> predicate,
|
||||
final FI.Apply2<Object, D, FSM.State<S, D>> apply) {
|
||||
return erasedEvent(null, null, predicate, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -68,12 +171,12 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
*/
|
||||
public <Q> FSMStateFunctionBuilder<S, D> event(final List<Object> eventMatches,
|
||||
final Class<Q> dataType,
|
||||
final FI.Apply<Q, FSM.State<S, D>> apply) {
|
||||
final FI.Apply2<Object, Q, FSM.State<S, D>> apply) {
|
||||
builder.match(FSM.Event.class,
|
||||
new FI.TypedPredicate<FSM.Event>() {
|
||||
@Override
|
||||
public boolean defined(FSM.Event e) {
|
||||
if (!dataType.isInstance(e.stateData()))
|
||||
if (dataType != null && !dataType.isInstance(e.stateData()))
|
||||
return false;
|
||||
|
||||
boolean emMatch = false;
|
||||
|
|
@ -95,7 +198,7 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
public FSM.State<S, D> apply(FSM.Event e) throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
Q q = (Q) e.stateData();
|
||||
return apply.apply(q);
|
||||
return apply.apply(e.event(), q);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -103,21 +206,6 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches on the data type and if the event compares equal.
|
||||
*
|
||||
* @param event an event to compare equal against
|
||||
* @param dataType the data type to match on
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @param <Q> the data type to match on
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public <Q> FSMStateFunctionBuilder<S, D> eventEquals(final Object event,
|
||||
final Class<Q> dataType,
|
||||
final FI.Apply<Q, FSM.State<S, D>> apply) {
|
||||
return event(Arrays.asList(event), dataType, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a case statement that matches if any of the event types in the list match or
|
||||
* any of the event instances in the list compares equal.
|
||||
|
|
@ -127,36 +215,23 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
* @return the builder with the case statement added
|
||||
*/
|
||||
public FSMStateFunctionBuilder<S, D> event(final List<Object> eventMatches,
|
||||
final FI.Apply<D, FSM.State<S, D>> apply) {
|
||||
builder.match(FSM.Event.class,
|
||||
new FI.TypedPredicate<FSM.Event>() {
|
||||
@Override
|
||||
public boolean defined(FSM.Event e) {
|
||||
boolean emMatch = false;
|
||||
Object event = e.event();
|
||||
for (Object em : eventMatches) {
|
||||
if (em instanceof Class) {
|
||||
Class emc = (Class) em;
|
||||
emMatch = emc.isInstance(event);
|
||||
} else {
|
||||
emMatch = event.equals(em);
|
||||
}
|
||||
if (emMatch)
|
||||
break;
|
||||
}
|
||||
return emMatch;
|
||||
}
|
||||
},
|
||||
new FI.Apply<FSM.Event, FSM.State<S, D>>() {
|
||||
public FSM.State<S, D> apply(FSM.Event e) throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
D d = (D) e.stateData();
|
||||
return apply.apply(d);
|
||||
}
|
||||
}
|
||||
);
|
||||
final FI.Apply2<Object, D, FSM.State<S, D>> apply) {
|
||||
return event(eventMatches, null, apply);
|
||||
}
|
||||
|
||||
return this;
|
||||
/**
|
||||
* Add a case statement that matches on the data type and if the event compares equal.
|
||||
*
|
||||
* @param event an event to compare equal against
|
||||
* @param dataType the data type to match on
|
||||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @param <Q> the data type to match on
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public <P, Q> FSMStateFunctionBuilder<S, D> eventEquals(final P event,
|
||||
final Class<Q> dataType,
|
||||
final FI.Apply2<P, Q, FSM.State<S, D>> apply) {
|
||||
return erasedEvent(event, dataType, null, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -166,9 +241,9 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
* @param apply an action to apply to the event and state data if there is a match
|
||||
* @return the builder with the case statement added
|
||||
*/
|
||||
public FSMStateFunctionBuilder<S, D> eventEquals(final Object event,
|
||||
final FI.Apply<D, FSM.State<S, D>> apply) {
|
||||
return event(Arrays.asList(event), apply);
|
||||
public <P> FSMStateFunctionBuilder<S, D> eventEquals(final P event,
|
||||
final FI.Apply2<P, D, FSM.State<S, D>> apply) {
|
||||
return erasedEvent(event, null, null, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -178,16 +253,7 @@ public class FSMStateFunctionBuilder<S, D> {
|
|||
* @return the builder with the case statement added
|
||||
*/
|
||||
public FSMStateFunctionBuilder<S, D> anyEvent(final FI.Apply2<Object, D, FSM.State<S, D>> apply) {
|
||||
builder.match(FSM.Event.class,
|
||||
new FI.Apply<FSM.Event, FSM.State<S, D>>() {
|
||||
public FSM.State<S, D> apply(FSM.Event e) throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
D d = (D) e.stateData();
|
||||
return apply.apply(e.event(), d);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
return erasedEvent(null, null, null, apply);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue