use of co.paralleluniverse.actors.LifecycleMessage in project quasar by puniverse.
the class RequestReplyHelper method call.
/**
* Sends a request message to an actor, awaits a response value (but no longer than the given timeout) and returns it.
* This method can be called by any code, even non-actor code.
* If the actor responds with an error message, a {@link RuntimeException} will be thrown by this method.
* <br>
* The message's {@code id} and {@code from} properties may be left unset.
* <p>
* This method should be used as in the following example (assuming a {@code String} return value:</p>
* <pre> {@code
* String res = call(actor, new MyRequest());
* }</pre>
* In the example, {@code MyRequest} extends {@link RequestMessage}. Note how the result of the {@link #from() from} method is passed to the
* request's constructor, but the message ID isn't.
*
* @param <V> the return value's type
* @param actor the actor to which the request is sent
* @param timeout the maximum duration to wait for a response
* @param unit the time unit of the timeout
* @return the value sent by the actor as a response
* @throws RuntimeException if the actor responds with an error message, its contained exception will be thrown, possibly wrapped by a {@link RuntimeException}.
* @throws TimeoutException if the timeout expires before a response is received from the actor.
* @throws InterruptedException
*/
public static <V> V call(final ActorRef actor, RequestMessage<V> m, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException, SuspendExecution {
assert !actor.equals(LocalActor.self()) : "Can't \"call\" self - deadlock guaranteed";
if (m.getFrom() == null || LocalActor.isInstance(m.getFrom(), TempActor.class))
m.setFrom(from());
final boolean tmpActor = m.getFrom() instanceof TempActorRef;
final Actor currentActor = tmpActor ? (Actor) ((TempActorRef) m.getFrom()).getImpl() : Actor.currentActor();
assert currentActor != null;
currentActor.link(actor);
if (m.getId() == null)
m.setId(new Object());
final Object id = m.getId();
final SelectiveReceiveHelper<Object> helper = new SelectiveReceiveHelper<Object>(currentActor) {
@Override
protected void handleLifecycleMessage(LifecycleMessage m) {
if (m instanceof ExitMessage) {
final ExitMessage exit = (ExitMessage) m;
if (Objects.equals(exit.getActor(), actor) && exit.getWatch() == null)
throw Exceptions.rethrow(exit.getCause());
}
super.handleLifecycleMessage(m);
}
};
try {
actor.sendSync(m);
final ResponseMessage response = (ResponseMessage) helper.receive(timeout, unit, new MessageProcessor<Object, Object>() {
@Override
public Object process(Object m) throws SuspendExecution, InterruptedException {
return (m instanceof ResponseMessage && id.equals(((ResponseMessage) m).getId())) ? m : null;
}
});
// no need to unlink in case of receiver death, so not done in finally block
currentActor.unlink(actor);
if (response instanceof ErrorResponseMessage)
throw Exceptions.rethrow(((ErrorResponseMessage) response).getError());
return ((ValueResponseMessage<V>) response).getValue();
} catch (InterruptedException e) {
if (tmpActor)
currentActor.checkThrownIn();
throw e;
} finally {
// if (tmpActor)
// ((TempActor) m.getFrom()).done();
}
}
Aggregations