user4464654
user4464654

Reputation:

Akka for Java, how to use an an Actor with generics

Akka seems like a nice framework/concept for working with asynchronous flows in your application. I am currently learning Akka for one of my projects and I was wondering about how to properly design Actors.

Imagine the following actor:

public class SampleActor extends UntypedActor {
    private final LoggingAdapter log = 
            Logging.getLogger(getContext().system(), this);

    @Override
    public void onReceive(final Object message) throws Exception {
        if (message instanceof SomeType) {
            SomeType someType = ((SomeType) message);
            // Handle SomeType
        } else if (message instance SomeOtherType) {
            SomeOtherType someOtherType = ((SomeOtherType) message);
            // Handle SomeOtherType
        } else {
            unhandled(message);
        }
    }
}

The above code is a common pattern that is e.g. described in the Akka documentation.

The pattern above seems kind of old school to me with a bunch of instanceof checks and that the actor handles Object. Is there another preferred approach for this (like some base class where you specify the types you are interested in) or similar.

One alternative that I can see is that you e.g inherit a generic actor such as:

public class SampleActor extends GenericActor<SomeType> {
    public void onReceive(final SomeType someType) throws Exception {
        // Do stuff
    }
}

So, what is the best practice for working with actors. Is it extending UntypedActor or am I missing something?

Upvotes: 5

Views: 1070

Answers (1)

hicolour
hicolour

Reputation: 784

First of all look on the UntypedActor and onReceive method contract which was designed for Scala pattern-matching and there is some beauty in ths simplified design.

Using Java, you need some sort of trade off. You can use your custom implementation of Visitor pattern for each actor but it adds unnecessary effort.

The best is to use AbstractActor with its PartialFunction<Object, BoxedUnit> receive() method, supported by your own abstraction.

public abstract class AbstractAggregateRegistryActor extends AbstractActor {

    @Override
    public PartialFunction<Object, BoxedUnit> receive() {
        return ReceiveBuilder.
                match(Protocol.AbstractComponentRegister.class, 
                                      this::handleRegistration).
                match(Protocol.AbstractComponentDeregister.class,
                                      this::handleDeregistration).
                match(Protocol.AbstractComponentRegistryRequest.class,
                                      this::handleRegistryRequest).
                matchAny(this::unhandled).build();
    }


    private void handleRegistration(Protocol.AbstractComponentRegister
                                    componentRegister) {
        .....
    }

    private void handleDeregistration(Protocol.AbstractComponentDeregister
                                      componentDeregister) {
        ...
    }

    protected abstract <T extends Protocol.AbstractComponentRegistryRequest> 
                         void handleRegistryRequest(T registryRequest);


    @Override
    public void unhandled(Object message) {
        log.warning("Unhandled message {} in registry.", message);
    }
}

Upvotes: 1

Related Questions