Search in sources :

Example 1 with LifecycleMessage

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();
    }
}
Also used : SelectiveReceiveHelper(co.paralleluniverse.actors.SelectiveReceiveHelper) ExitMessage(co.paralleluniverse.actors.ExitMessage) MessageProcessor(co.paralleluniverse.actors.MessageProcessor) LocalActor(co.paralleluniverse.actors.LocalActor) Actor(co.paralleluniverse.actors.Actor) LifecycleMessage(co.paralleluniverse.actors.LifecycleMessage)

Aggregations

Actor (co.paralleluniverse.actors.Actor)1 ExitMessage (co.paralleluniverse.actors.ExitMessage)1 LifecycleMessage (co.paralleluniverse.actors.LifecycleMessage)1 LocalActor (co.paralleluniverse.actors.LocalActor)1 MessageProcessor (co.paralleluniverse.actors.MessageProcessor)1 SelectiveReceiveHelper (co.paralleluniverse.actors.SelectiveReceiveHelper)1