Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Akka With Java

DZone's Guide to

Using Akka With Java

Follow along with this walkthrough of a simple example of using Akka AbstractActor.

· Java Zone
Free Resource

Just released, a free O’Reilly book on Reactive Microsystems: The Evolution of Microservices at Scale. Brought to you in partnership with Lightbend.

In the past few days, I've been working on a project with Akka using Java. It was an amazing experience, so I'm going to discuss how to use Akka in Java and write a test case.

If we look at the Akka's documentation, there is a class named UntypedActor to create an actor. But here, we're going to discuss the AbstractActor, which seems pretty concise.

First, add the following dependency for Akka and the test case:

"com.typesafe.akka" %% "akka-slf4j" % "2.4.8"

Then, to create an actor, we first we need to create Props:

public static Props props() {
    return Props.create(HappyBdayActor.class);
}

Then, we write the responsibility of an actor as:

class HappyBdayActor extends AbstractActor {

    public static Props props() {
        return Props.create(HappyBdayActor.class);
    }

    @Override
    public PartialFunction<Object, BoxedUnit> receive() {
      //responsiblity of this actor can be here 
    }
}

Now we need to find out the message passed to this actor and react accordingly. We can do this as:

@Override
public PartialFunction<Object, BoxedUnit> receive() {
       return ReceiveBuilder
            .match(String.class, message -> {
                logger.info("Message received from someone : {}"+ message);
            })
            .matchAny(message -> logger.error("Some unknown things happened : {}", message))
            .build();
}


Now everybody will need a Supervisor. As we know, a Supervisor is an Actor that supervises other actors. Here's how we'll implement it.

private final SupervisorStrategy strategy = new OneForOneStrategy(false,
        match(InterruptedException.class, e ->
                SupervisorStrategy.resume()
        ).
                match(Throwable.class, e ->
                        SupervisorStrategy.restart()
                ).build());

@Override
public SupervisorStrategy supervisorStrategy() {
    return strategy;
}

Now we have an architecture for an Akka actor.

After that, I decided to introduce a Google Guice injection. To proceed with this, we need to add the following dependency:

“com.google.inject” % “guice” % “4.1.0”


We will inject our service to the actor, so we create a simple service:

@Singleton
public class MessageHandlerService {

    static final String BEAN_NAME = "messageHandlerService";

    public final String substr(String message , int index){
        return "Happy bday "+message.substring(index);
    }
}


Now create an another class to define injections:

public class Config extends AbstractModule {

    @Override
    protected final void configure() {
        bind(ActorSystem.class).toInstance(ActorSystem.apply());
        bind(MessageHandlerService.class).annotatedWith(Names.named(MessageHandlerService.BEAN_NAME)).
                to(MessageHandlerService.class);
    }

    @Singleton
    @Provides
    @Named(value = Supervisor.BEAN_NAME)
    public final ActorRef supervisorRef(final ActorSystem system) {
        return system.actorOf(Supervisor.props());
    }

    @Provides
    @Inject
    @Named(value = HappyBdayActor.BEAN_NAME)
    public final ActorRef HappyBdayActorRef(@Named(Supervisor.BEAN_NAME) final ActorRef supervisor,
                                            @Named(MessageHandlerService.BEAN_NAME) final MessageHandlerService messageHandlerService) throws Exception {

        CompletionStage<Object> eventFuture = ask(supervisor, HappyBdayActor.props(messageHandlerService),
                Timeout.apply(50, TimeUnit.MILLISECONDS));
        return (ActorRef) eventFuture.toCompletableFuture().get(60, TimeUnit.MILLISECONDS);
    }
}


And also modify the actor as:

final LoggingAdapter logger = Logging.getLogger(context().system(), this);
public static final String BEAN_NAME = "HappyBdayActorRef";
private final MessageHandlerService messageHandlerService;

HappyBdayActor(MessageHandlerService messageHandlerServie) {
    this.messageHandlerService = messageHandlerServie;
}

public static Props props(MessageHandlerService messageHandlerService) {
    return Props.create(HappyBdayActor.class, messageHandlerService);
}


Now we can write our launcher to start the actor’s execution as:

public class Launcher {

    private ActorRef happyBdayActorRef;

    @Inject
    public Launcher(@Named(HappyBdayActor.BEAN_NAME) ActorRef happyBdayActorRef) {
        this.happyBdayActorRef = happyBdayActorRef;
    }

    public ActorRef getHappyBdayActorRef() {
        return happyBdayActorRef;
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new Config());
        Launcher app = injector.getInstance(Launcher.class);
        app.getHappyBdayActorRef().tell("Hello",ActorRef.noSender());

    }

}


Now, we developers are always curious about how to write unit test cases. Add the following sbt dependency:

"junit" % "junit" % "4.12" % "test" exclude("hamcrest-core", "org.hamcrest"),
"com.typesafe.akka" %% "akka-http-testkit" % "2.4.8" % "test",
"org.mockito" % "mockito-core" % "1.10.19" % "test" exclude("hamcrest-core", "org.hamcrest"),
"org.hamcrest" % "hamcrest-all" % "1.3" % "test"


And now, our unit test case:

public classHappyBdayActor {

    private static ActorSystem system;
    private static MessageHandlerService messageHandlerService;

    @BeforeClass
    public static void setup() {
        system = ActorSystem.create();
        messageHandlerService = mock(MessageHandlerService.class);
    }

    @AfterClass
    public static void teardown() {
        JavaTestKit.shutdownActorSystem(system);
        system = null;
    }

    @Test
    public void testProps() {
        final JavaTestKit probe = new JavaTestKit(system);
        Props props = HappyBdayActor.props(messageHandlerService);
        assertThat(props.actorClass(), is(equalTo(HappyBdayActor.class)));
    }

    @Test
    public void testEventLoggerActorFirebaseRequestMatch() {

        TestProbe probe = TestProbe.apply(system);

        final Props props = HappyBdayActor.props(messageHandlerService);


       when(messageHandlerService.substr("RahulKumar",5))
       .thenReturn(String.valueOf("Kumar"));

    final TestActorRef<HappyBdayActor>happyBdayActorTestActorRef = TestActorRef.create(system, props);
    happyBdayActorTestActorRef.tell("RahulKumar", happyBdayActorTestActorRef);

    probe.expectNoMsg();

    }
}


For the complete code, click here.

Strategies and techniques for building scalable and resilient microservices to refactor a monolithic application step-by-step, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:
java ,akka ,actor ,google guice

Published at DZone with permission of Rahul Kumar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}