Getting Started tutorial improvements (#23210)

This commit is contained in:
Arnout Engelen 2017-07-13 01:24:53 -07:00 committed by GitHub
parent d87cf4aec4
commit f38b928e13
67 changed files with 1451 additions and 1507 deletions

View file

@ -1,10 +1,8 @@
package jdocs.tutorial_1;
//#print-refs
package com.lightbend.akka.sample;
//#print-refs
import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -12,6 +10,12 @@ import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
//#print-refs
import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
class PrintMyActorRefActor extends AbstractActor {
@Override
public Receive createReceive() {
@ -106,6 +110,26 @@ class SupervisedActor extends AbstractActor {
}
//#supervise
//#print-refs
public class ActorHierarchyExperiments {
public static void main(String[] args) throws java.io.IOException {
ActorSystem system = ActorSystem.create("test");
ActorRef firstRef = system.actorOf(Props.create(PrintMyActorRefActor.class), "first-actor");
System.out.println("First: " + firstRef);
firstRef.tell("printit", ActorRef.noSender());
System.out.println(">>> Press ENTER to exit <<<");
try {
System.in.read();
} finally {
system.terminate();
}
}
}
//#print-refs
class ActorHierarchyExperimentsTest extends JUnitSuite {
static ActorSystem system;
@ -120,28 +144,19 @@ class ActorHierarchyExperimentsTest extends JUnitSuite {
system = null;
}
@Test
public void testCreateTopAndChildActor() {
//#print-refs
ActorRef firstRef = system.actorOf(Props.create(PrintMyActorRefActor.class), "first-actor");
System.out.println("First : " + firstRef);
firstRef.tell("printit", ActorRef.noSender());
//#print-refs
}
@Test
public void testStartAndStopActors() {
//#start-stop
//#start-stop-main
ActorRef first = system.actorOf(Props.create(StartStopActor1.class), "first");
first.tell("stop", ActorRef.noSender());
//#start-stop
//#start-stop-main
}
@Test
public void testSuperviseActors() {
//#supervise
//#supervise-main
ActorRef supervisingActor = system.actorOf(Props.create(SupervisingActor.class), "supervising-actor");
supervisingActor.tell("failChild", ActorRef.noSender());
//#supervise
//#supervise-main
}
}

View file

@ -1,9 +1,9 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_1;
//#iot-app
package com.lightbend.akka.sample;
import java.io.IOException;

View file

@ -1,9 +1,9 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_1;
//#iot-supervisor
package com.lightbend.akka.sample;
import akka.actor.AbstractActor;
import akka.actor.ActorLogging;

View file

@ -3,18 +3,16 @@
*/
package jdocs.tutorial_3;
//#device-with-register
//#full-device
import java.util.Optional;
import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import jdocs.tutorial_3.DeviceManager.DeviceRegistered;
import jdocs.tutorial_3.DeviceManager.RequestTrackDevice;
import java.util.Optional;
public class Device extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -82,16 +80,6 @@ public class Device extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(RequestTrackDevice.class, r -> {
if (this.groupId.equals(r.groupId) && this.deviceId.equals(r.deviceId)) {
getSender().tell(new DeviceRegistered(), getSelf());
} else {
log.warning(
"Ignoring TrackDevice request for {}-{}.This actor is responsible for {}-{}.",
r.groupId, r.deviceId, this.groupId, this.deviceId
);
}
})
.match(RecordTemperature.class, r -> {
log.info("Recorded temperature reading {} with {}", r.value, r.requestId);
lastTemperatureReading = Optional.of(r.value);
@ -103,4 +91,4 @@ public class Device extends AbstractActor {
.build();
}
}
//#device-with-register
//#full-device

View file

@ -1,11 +1,11 @@
package jdocs.tutorial_2;
package jdocs.tutorial_3;
import java.util.Optional;
import jdocs.tutorial_2.Device.ReadTemperature;
import jdocs.tutorial_2.Device.RecordTemperature;
import jdocs.tutorial_2.Device.RespondTemperature;
import jdocs.tutorial_2.Device.TemperatureRecorded;
import jdocs.tutorial_3.Device.ReadTemperature;
import jdocs.tutorial_3.Device.RecordTemperature;
import jdocs.tutorial_3.Device.RespondTemperature;
import jdocs.tutorial_3.Device.TemperatureRecorded;
class DeviceInProgress1 {

View file

@ -1,4 +1,4 @@
package jdocs.tutorial_2;
package jdocs.tutorial_3;
class DeviceInProgress3 {

View file

@ -3,9 +3,7 @@
*/
package jdocs.tutorial_3;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.javadsl.TestKit;
import java.util.Optional;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -14,7 +12,9 @@ import static org.junit.Assert.assertEquals;
import org.scalatest.junit.JUnitSuite;
import java.util.Optional;
import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import akka.testkit.javadsl.TestKit;
public class DeviceTest extends JUnitSuite {
@ -31,30 +31,6 @@ public class DeviceTest extends JUnitSuite {
system = null;
}
//#device-registration-tests
@Test
public void testReplyToRegistrationRequests() {
TestKit probe = new TestKit(system);
ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "device"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
assertEquals(deviceActor, probe.getLastSender());
}
@Test
public void testIgnoreWrongRegistrationRequests() {
TestKit probe = new TestKit(system);
ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
deviceActor.tell(new DeviceManager.RequestTrackDevice("wrongGroup", "device"), probe.getRef());
probe.expectNoMsg();
deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "wrongDevice"), probe.getRef());
probe.expectNoMsg();
}
//#device-registration-tests
//#device-read-test
@Test
public void testReplyWithEmptyReadingIfNoTemperatureIsKnown() {

View file

@ -1,4 +1,4 @@
package jdocs.tutorial_2.inprogress2;
package jdocs.tutorial_3.inprogress2;
//#device-with-read

View file

@ -3,6 +3,8 @@
*/
package jdocs.tutorial_4;
//#device-with-register
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
@ -101,3 +103,4 @@ public class Device extends AbstractActor {
.build();
}
}
//#device-with-register

View file

@ -3,20 +3,21 @@
*/
package jdocs.tutorial_4;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import scala.concurrent.duration.FiniteDuration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import jdocs.tutorial_4.Device;
import jdocs.tutorial_4.DeviceManager;
//#query-added
//#device-group-full
public class DeviceGroup extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -26,9 +27,11 @@ public class DeviceGroup extends AbstractActor {
this.groupId = groupId;
}
//#device-group-register
public static Props props(String groupId) {
return Props.create(DeviceGroup.class, groupId);
}
//#device-group-register
public static final class RequestDeviceList {
final long requestId;
@ -47,51 +50,15 @@ public class DeviceGroup extends AbstractActor {
this.ids = ids;
}
}
//#query-protocol
public static final class RequestAllTemperatures {
final long requestId;
public RequestAllTemperatures(long requestId) {
this.requestId = requestId;
}
}
public static final class RespondAllTemperatures {
final long requestId;
final Map<String, TemperatureReading> temperatures;
public RespondAllTemperatures(long requestId, Map<String, TemperatureReading> temperatures) {
this.requestId = requestId;
this.temperatures = temperatures;
}
}
public static interface TemperatureReading {
}
public static final class Temperature implements TemperatureReading {
public final double value;
public Temperature(double value) {
this.value = value;
}
}
public static final class TemperatureNotAvailable implements TemperatureReading {
}
public static final class DeviceNotAvailable implements TemperatureReading {
}
public static final class DeviceTimedOut implements TemperatureReading {
}
//#query-protocol
//#device-group-register
//#device-group-register
//#device-group-register
//#device-group-remove
final Map<String, ActorRef> deviceIdToActor = new HashMap<>();
//#device-group-register
final Map<ActorRef, String> actorToDeviceId = new HashMap<>();
final long nextCollectionId = 0L;
//#device-group-register
@Override
public void preStart() {
@ -103,19 +70,20 @@ public class DeviceGroup extends AbstractActor {
log.info("DeviceGroup {} stopped", groupId);
}
//#query-added
private void onTrackDevice(DeviceManager.RequestTrackDevice trackMsg) {
if (this.groupId.equals(trackMsg.groupId)) {
ActorRef ref = deviceIdToActor.get(trackMsg.deviceId);
if (ref != null) {
ref.forward(trackMsg, getContext());
ActorRef deviceActor = deviceIdToActor.get(trackMsg.deviceId);
if (deviceActor != null) {
deviceActor.forward(trackMsg, getContext());
} else {
log.info("Creating device actor for {}", trackMsg.deviceId);
ActorRef deviceActor = getContext().actorOf(Device.props(groupId, trackMsg.deviceId), "device-" + trackMsg.deviceId);
deviceActor = getContext().actorOf(Device.props(groupId, trackMsg.deviceId), "device-" + trackMsg.deviceId);
//#device-group-register
getContext().watch(deviceActor);
deviceActor.forward(trackMsg, getContext());
actorToDeviceId.put(deviceActor, trackMsg.deviceId);
//#device-group-register
deviceIdToActor.put(trackMsg.deviceId, deviceActor);
deviceActor.forward(trackMsg, getContext());
}
} else {
log.warning(
@ -136,24 +104,16 @@ public class DeviceGroup extends AbstractActor {
actorToDeviceId.remove(deviceActor);
deviceIdToActor.remove(deviceId);
}
//#query-added
private void onAllTemperatures(RequestAllTemperatures r) {
getContext().actorOf(DeviceGroupQuery.props(
actorToDeviceId, r.requestId, getSender(), new FiniteDuration(3, TimeUnit.SECONDS)));
}
@Override
public Receive createReceive() {
//#query-added
return receiveBuilder()
.match(DeviceManager.RequestTrackDevice.class, this::onTrackDevice)
.match(RequestDeviceList.class, this::onDeviceList)
.match(Terminated.class, this::onTerminated)
//#query-added
// ... other cases omitted
.match(RequestAllTemperatures.class, this::onAllTemperatures)
.build();
}
}
//#query-added
//#device-group-remove
//#device-group-register
//#device-group-full

View file

@ -3,10 +3,8 @@
*/
package jdocs.tutorial_4;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
@ -21,8 +19,6 @@ import static org.junit.Assert.assertNotEquals;
import org.scalatest.junit.JUnitSuite;
import static jdocs.tutorial_4.DeviceGroupQueryTest.assertEqualTemperatures;
public class DeviceGroupTest extends JUnitSuite {
static ActorSystem system;
@ -38,6 +34,7 @@ public class DeviceGroupTest extends JUnitSuite {
system = null;
}
//#device-group-test-registration
@Test
public void testRegisterDeviceActor() {
TestKit probe = new TestKit(system);
@ -67,7 +64,9 @@ public class DeviceGroupTest extends JUnitSuite {
groupActor.tell(new DeviceManager.RequestTrackDevice("wrongGroup", "device1"), probe.getRef());
probe.expectNoMsg();
}
//#device-group-test-registration
//#device-group-test3
@Test
public void testReturnSameActorForSameDeviceId() {
TestKit probe = new TestKit(system);
@ -82,7 +81,9 @@ public class DeviceGroupTest extends JUnitSuite {
ActorRef deviceActor2 = probe.getLastSender();
assertEquals(deviceActor1, deviceActor2);
}
//#device-group-test3
//#device-group-list-terminate-test
@Test
public void testListActiveDevices() {
TestKit probe = new TestKit(system);
@ -125,49 +126,12 @@ public class DeviceGroupTest extends JUnitSuite {
// to see the Terminated, that order is undefined
probe.awaitAssert(() -> {
groupActor.tell(new DeviceGroup.RequestDeviceList(1L), probe.getRef());
DeviceGroup.ReplyDeviceList r =
DeviceGroup.ReplyDeviceList r =
probe.expectMsgClass(DeviceGroup.ReplyDeviceList.class);
assertEquals(1L, r.requestId);
assertEquals(Stream.of("device2").collect(Collectors.toSet()), r.ids);
return null;
});
}
//#group-query-integration-test
@Test
public void testCollectTemperaturesFromAllActiveDevices() {
TestKit probe = new TestKit(system);
ActorRef groupActor = system.actorOf(DeviceGroup.props("group"));
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device1"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor1 = probe.getLastSender();
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device2"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor2 = probe.getLastSender();
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device3"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor3 = probe.getLastSender();
// Check that the device actors are working
deviceActor1.tell(new Device.RecordTemperature(0L, 1.0), probe.getRef());
assertEquals(0L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);
deviceActor2.tell(new Device.RecordTemperature(1L, 2.0), probe.getRef());
assertEquals(1L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);
// No temperature for device 3
groupActor.tell(new DeviceGroup.RequestAllTemperatures(0L), probe.getRef());
DeviceGroup.RespondAllTemperatures response = probe.expectMsgClass(DeviceGroup.RespondAllTemperatures.class);
assertEquals(0L, response.requestId);
Map<String, DeviceGroup.TemperatureReading> expectedTemperatures = new HashMap<>();
expectedTemperatures.put("device1", new DeviceGroup.Temperature(1.0));
expectedTemperatures.put("device2", new DeviceGroup.Temperature(2.0));
expectedTemperatures.put("device3", new DeviceGroup.TemperatureNotAvailable());
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#group-query-integration-test
//#device-group-list-terminate-test
}

View file

@ -4,6 +4,9 @@
package jdocs.tutorial_4;
import java.util.Map;
import java.util.HashMap;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
@ -11,9 +14,7 @@ import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import java.util.HashMap;
import java.util.Map;
//#device-manager-full
public class DeviceManager extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -21,6 +22,7 @@ public class DeviceManager extends AbstractActor {
return Props.create(DeviceManager.class);
}
//#device-manager-msgs
public static final class RequestTrackDevice {
public final String groupId;
public final String deviceId;
@ -34,6 +36,7 @@ public class DeviceManager extends AbstractActor {
public static final class DeviceRegistered {
}
//#device-manager-msgs
final Map<String, ActorRef> groupIdToActor = new HashMap<>();
final Map<ActorRef, String> actorToGroupId = new HashMap<>();
@ -78,3 +81,4 @@ public class DeviceManager extends AbstractActor {
}
}
//#device-manager-full

View file

@ -3,8 +3,6 @@
*/
package jdocs.tutorial_4;
import java.util.Optional;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.javadsl.TestKit;
@ -16,6 +14,8 @@ import static org.junit.Assert.assertEquals;
import org.scalatest.junit.JUnitSuite;
import java.util.Optional;
public class DeviceTest extends JUnitSuite {
static ActorSystem system;
@ -31,6 +31,7 @@ public class DeviceTest extends JUnitSuite {
system = null;
}
//#device-registration-tests
@Test
public void testReplyToRegistrationRequests() {
TestKit probe = new TestKit(system);
@ -52,7 +53,9 @@ public class DeviceTest extends JUnitSuite {
deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "wrongDevice"), probe.getRef());
probe.expectNoMsg();
}
//#device-registration-tests
//#device-read-test
@Test
public void testReplyWithEmptyReadingIfNoTemperatureIsKnown() {
TestKit probe = new TestKit(system);
@ -62,7 +65,9 @@ public class DeviceTest extends JUnitSuite {
assertEquals(42L, response.requestId);
assertEquals(Optional.empty(), response.value);
}
//#device-read-test
//#device-write-read-test
@Test
public void testReplyWithLatestTemperatureReading() {
TestKit probe = new TestKit(system);
@ -84,5 +89,6 @@ public class DeviceTest extends JUnitSuite {
assertEquals(4L, response2.requestId);
assertEquals(Optional.of(55.0), response2.value);
}
//#device-write-read-test
}

View file

@ -7,6 +7,7 @@ import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import jdocs.tutorial_5.DeviceManager.DeviceRegistered;
import jdocs.tutorial_5.DeviceManager.RequestTrackDevice;

View file

@ -16,6 +16,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
//#query-added
public class DeviceGroup extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -47,6 +48,7 @@ public class DeviceGroup extends AbstractActor {
}
}
//#query-protocol
public static final class RequestAllTemperatures {
final long requestId;
@ -84,6 +86,8 @@ public class DeviceGroup extends AbstractActor {
public static final class DeviceTimedOut implements TemperatureReading {
}
//#query-protocol
final Map<String, ActorRef> deviceIdToActor = new HashMap<>();
final Map<ActorRef, String> actorToDeviceId = new HashMap<>();
@ -99,6 +103,7 @@ public class DeviceGroup extends AbstractActor {
log.info("DeviceGroup {} stopped", groupId);
}
//#query-added
private void onTrackDevice(DeviceManager.RequestTrackDevice trackMsg) {
if (this.groupId.equals(trackMsg.groupId)) {
ActorRef ref = deviceIdToActor.get(trackMsg.deviceId);
@ -131,6 +136,7 @@ public class DeviceGroup extends AbstractActor {
actorToDeviceId.remove(deviceActor);
deviceIdToActor.remove(deviceId);
}
//#query-added
private void onAllTemperatures(RequestAllTemperatures r) {
getContext().actorOf(DeviceGroupQuery.props(
@ -139,11 +145,15 @@ public class DeviceGroup extends AbstractActor {
@Override
public Receive createReceive() {
//#query-added
return receiveBuilder()
.match(DeviceManager.RequestTrackDevice.class, this::onTrackDevice)
.match(RequestDeviceList.class, this::onDeviceList)
.match(Terminated.class, this::onTerminated)
//#query-added
// ... other cases omitted
.match(RequestAllTemperatures.class, this::onAllTemperatures)
.build();
}
}
//#query-added

View file

@ -3,16 +3,24 @@
*/
package jdocs.tutorial_5;
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import scala.concurrent.duration.FiniteDuration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import scala.concurrent.duration.FiniteDuration;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Cancellable;
import akka.actor.Props;
import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
//#query-full
//#query-outline
public class DeviceGroupQuery extends AbstractActor {
public static final class CollectionTimeout {
}
@ -52,6 +60,8 @@ public class DeviceGroupQuery extends AbstractActor {
queryTimeoutTimer.cancel();
}
//#query-outline
//#query-state
@Override
public Receive createReceive() {
return waitingForReplies(new HashMap<>(), actorToDeviceId.keySet());
@ -69,10 +79,7 @@ public class DeviceGroupQuery extends AbstractActor {
receivedResponse(deviceActor, reading, stillWaiting, repliesSoFar);
})
.match(Terminated.class, t -> {
if (stillWaiting.contains(t.getActor())) {
receivedResponse(t.getActor(), new DeviceGroup.DeviceNotAvailable(), stillWaiting, repliesSoFar);
}
// else ignore
receivedResponse(t.getActor(), new DeviceGroup.DeviceNotAvailable(), stillWaiting, repliesSoFar);
})
.match(CollectionTimeout.class, t -> {
Map<String, DeviceGroup.TemperatureReading> replies = new HashMap<>(repliesSoFar);
@ -85,7 +92,9 @@ public class DeviceGroupQuery extends AbstractActor {
})
.build();
}
//#query-state
//#query-collect-reply
public void receivedResponse(ActorRef deviceActor,
DeviceGroup.TemperatureReading reading,
Set<ActorRef> stillWaiting,
@ -105,4 +114,8 @@ public class DeviceGroupQuery extends AbstractActor {
getContext().become(waitingForReplies(newRepliesSoFar, newStillWaiting));
}
}
//#query-collect-reply
//#query-outline
}
//#query-outline
//#query-full

View file

@ -11,10 +11,10 @@ import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.scalatest.junit.JUnitSuite;
import scala.concurrent.duration.FiniteDuration;
import java.util.HashMap;
@ -37,6 +37,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
system = null;
}
//#query-test-normal
@Test
public void testReturnTemperatureValueForWorkingDevices() {
TestKit requester = new TestKit(system);
@ -69,7 +70,9 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-normal
//#query-test-no-reading
@Test
public void testReturnTemperatureNotAvailableForDevicesWithNoReadings() {
TestKit requester = new TestKit(system);
@ -102,7 +105,9 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-no-reading
//#query-test-stopped
@Test
public void testReturnDeviceNotAvailableIfDeviceStopsBeforeAnswering() {
TestKit requester = new TestKit(system);
@ -135,7 +140,9 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-stopped
//#query-test-stopped-later
@Test
public void testReturnTemperatureReadingEvenIfDeviceStopsAfterAnswering() {
TestKit requester = new TestKit(system);
@ -169,7 +176,9 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-stopped-later
//#query-test-timeout
@Test
public void testReturnDeviceTimedOutIfDeviceDoesNotAnswerInTime() {
TestKit requester = new TestKit(system);
@ -203,6 +212,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-timeout
public static void assertEqualTemperatures(Map<String, DeviceGroup.TemperatureReading> expected, Map<String, DeviceGroup.TemperatureReading> actual) {
for (Map.Entry<String, DeviceGroup.TemperatureReading> entry : expected.entrySet()) {

View file

@ -16,10 +16,11 @@ import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.scalatest.junit.JUnitSuite;
import static jdocs.tutorial_5.DeviceGroupQueryTest.assertEqualTemperatures;
public class DeviceGroupTest extends JUnitSuite {
@ -132,6 +133,7 @@ public class DeviceGroupTest extends JUnitSuite {
});
}
//#group-query-integration-test
@Test
public void testCollectTemperaturesFromAllActiveDevices() {
TestKit probe = new TestKit(system);
@ -167,4 +169,5 @@ public class DeviceGroupTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#group-query-integration-test
}

View file

@ -16,7 +16,6 @@ import static org.junit.Assert.assertEquals;
import org.scalatest.junit.JUnitSuite;
public class DeviceTest extends JUnitSuite {
static ActorSystem system;

View file

@ -1,17 +1,16 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_2;
//#full-device
import java.util.Optional;
package jdocs.tutorial_6;
import akka.actor.AbstractActor;
import akka.actor.AbstractActor.Receive;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import jdocs.tutorial_6.DeviceManager.DeviceRegistered;
import jdocs.tutorial_6.DeviceManager.RequestTrackDevice;
import java.util.Optional;
public class Device extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -80,6 +79,16 @@ public class Device extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(RequestTrackDevice.class, r -> {
if (this.groupId.equals(r.groupId) && this.deviceId.equals(r.deviceId)) {
getSender().tell(new DeviceRegistered(), getSelf());
} else {
log.warning(
"Ignoring TrackDevice request for {}-{}.This actor is responsible for {}-{}.",
r.groupId, r.deviceId, this.groupId, this.deviceId
);
}
})
.match(RecordTemperature.class, r -> {
log.info("Recorded temperature reading {} with {}", r.value, r.requestId);
lastTemperatureReading = Optional.of(r.value);
@ -91,4 +100,3 @@ public class Device extends AbstractActor {
.build();
}
}
//#full-device

View file

@ -1,11 +1,7 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_3;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
package jdocs.tutorial_6;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
@ -13,11 +9,13 @@ import akka.actor.Props;
import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import scala.concurrent.duration.FiniteDuration;
import jdocs.tutorial_3.Device;
import jdocs.tutorial_3.DeviceManager;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
//#device-group-full
public class DeviceGroup extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -27,11 +25,9 @@ public class DeviceGroup extends AbstractActor {
this.groupId = groupId;
}
//#device-group-register
public static Props props(String groupId) {
return Props.create(DeviceGroup.class, groupId);
}
//#device-group-register
public static final class RequestDeviceList {
final long requestId;
@ -50,15 +46,48 @@ public class DeviceGroup extends AbstractActor {
this.ids = ids;
}
}
//#device-group-register
//#device-group-register
//#device-group-register
//#device-group-remove
public static final class RequestAllTemperatures {
final long requestId;
public RequestAllTemperatures(long requestId) {
this.requestId = requestId;
}
}
public static final class RespondAllTemperatures {
final long requestId;
final Map<String, TemperatureReading> temperatures;
public RespondAllTemperatures(long requestId, Map<String, TemperatureReading> temperatures) {
this.requestId = requestId;
this.temperatures = temperatures;
}
}
public static interface TemperatureReading {
}
public static final class Temperature implements TemperatureReading {
public final double value;
public Temperature(double value) {
this.value = value;
}
}
public static final class TemperatureNotAvailable implements TemperatureReading {
}
public static final class DeviceNotAvailable implements TemperatureReading {
}
public static final class DeviceTimedOut implements TemperatureReading {
}
final Map<String, ActorRef> deviceIdToActor = new HashMap<>();
//#device-group-register
final Map<ActorRef, String> actorToDeviceId = new HashMap<>();
//#device-group-register
final long nextCollectionId = 0L;
@Override
public void preStart() {
@ -72,18 +101,16 @@ public class DeviceGroup extends AbstractActor {
private void onTrackDevice(DeviceManager.RequestTrackDevice trackMsg) {
if (this.groupId.equals(trackMsg.groupId)) {
ActorRef deviceActor = deviceIdToActor.get(trackMsg.deviceId);
if (deviceActor != null) {
deviceActor.forward(trackMsg, getContext());
ActorRef ref = deviceIdToActor.get(trackMsg.deviceId);
if (ref != null) {
ref.forward(trackMsg, getContext());
} else {
log.info("Creating device actor for {}", trackMsg.deviceId);
deviceActor = getContext().actorOf(Device.props(groupId, trackMsg.deviceId), "device-" + trackMsg.deviceId);
//#device-group-register
ActorRef deviceActor = getContext().actorOf(Device.props(groupId, trackMsg.deviceId), "device-" + trackMsg.deviceId);
getContext().watch(deviceActor);
actorToDeviceId.put(deviceActor, trackMsg.deviceId);
//#device-group-register
deviceIdToActor.put(trackMsg.deviceId, deviceActor);
deviceActor.forward(trackMsg, getContext());
actorToDeviceId.put(deviceActor, trackMsg.deviceId);
deviceIdToActor.put(trackMsg.deviceId, deviceActor);
}
} else {
log.warning(
@ -105,15 +132,18 @@ public class DeviceGroup extends AbstractActor {
deviceIdToActor.remove(deviceId);
}
private void onAllTemperatures(RequestAllTemperatures r) {
getContext().actorOf(DeviceGroupQuery.props(
actorToDeviceId, r.requestId, getSender(), new FiniteDuration(3, TimeUnit.SECONDS)));
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(DeviceManager.RequestTrackDevice.class, this::onTrackDevice)
.match(RequestDeviceList.class, this::onDeviceList)
.match(Terminated.class, this::onTerminated)
.match(RequestAllTemperatures.class, this::onAllTemperatures)
.build();
}
}
//#device-group-remove
//#device-group-register
//#device-group-full

View file

@ -1,26 +1,18 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_4;
package jdocs.tutorial_6;
import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import scala.concurrent.duration.FiniteDuration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import scala.concurrent.duration.FiniteDuration;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Cancellable;
import akka.actor.Props;
import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
//#query-full
//#query-outline
public class DeviceGroupQuery extends AbstractActor {
public static final class CollectionTimeout {
}
@ -60,8 +52,6 @@ public class DeviceGroupQuery extends AbstractActor {
queryTimeoutTimer.cancel();
}
//#query-outline
//#query-state
@Override
public Receive createReceive() {
return waitingForReplies(new HashMap<>(), actorToDeviceId.keySet());
@ -79,7 +69,10 @@ public class DeviceGroupQuery extends AbstractActor {
receivedResponse(deviceActor, reading, stillWaiting, repliesSoFar);
})
.match(Terminated.class, t -> {
receivedResponse(t.getActor(), new DeviceGroup.DeviceNotAvailable(), stillWaiting, repliesSoFar);
if (stillWaiting.contains(t.getActor())) {
receivedResponse(t.getActor(), new DeviceGroup.DeviceNotAvailable(), stillWaiting, repliesSoFar);
}
// else ignore
})
.match(CollectionTimeout.class, t -> {
Map<String, DeviceGroup.TemperatureReading> replies = new HashMap<>(repliesSoFar);
@ -92,9 +85,7 @@ public class DeviceGroupQuery extends AbstractActor {
})
.build();
}
//#query-state
//#query-collect-reply
public void receivedResponse(ActorRef deviceActor,
DeviceGroup.TemperatureReading reading,
Set<ActorRef> stillWaiting,
@ -114,8 +105,4 @@ public class DeviceGroupQuery extends AbstractActor {
getContext().become(waitingForReplies(newRepliesSoFar, newStillWaiting));
}
}
//#query-collect-reply
//#query-outline
}
//#query-outline
//#query-full

View file

@ -1,7 +1,7 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_4;
package jdocs.tutorial_6;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
@ -11,10 +11,10 @@ import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.scalatest.junit.JUnitSuite;
import scala.concurrent.duration.FiniteDuration;
import java.util.HashMap;
@ -37,7 +37,6 @@ public class DeviceGroupQueryTest extends JUnitSuite {
system = null;
}
//#query-test-normal
@Test
public void testReturnTemperatureValueForWorkingDevices() {
TestKit requester = new TestKit(system);
@ -70,9 +69,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-normal
//#query-test-no-reading
@Test
public void testReturnTemperatureNotAvailableForDevicesWithNoReadings() {
TestKit requester = new TestKit(system);
@ -105,9 +102,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-no-reading
//#query-test-stopped
@Test
public void testReturnDeviceNotAvailableIfDeviceStopsBeforeAnswering() {
TestKit requester = new TestKit(system);
@ -140,9 +135,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-stopped
//#query-test-stopped-later
@Test
public void testReturnTemperatureReadingEvenIfDeviceStopsAfterAnswering() {
TestKit requester = new TestKit(system);
@ -176,9 +169,7 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-stopped-later
//#query-test-timeout
@Test
public void testReturnDeviceTimedOutIfDeviceDoesNotAnswerInTime() {
TestKit requester = new TestKit(system);
@ -212,7 +203,6 @@ public class DeviceGroupQueryTest extends JUnitSuite {
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
//#query-test-timeout
public static void assertEqualTemperatures(Map<String, DeviceGroup.TemperatureReading> expected, Map<String, DeviceGroup.TemperatureReading> actual) {
for (Map.Entry<String, DeviceGroup.TemperatureReading> entry : expected.entrySet()) {

View file

@ -1,10 +1,12 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_3;
package jdocs.tutorial_6;
import java.util.stream.Stream;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
@ -14,10 +16,11 @@ import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.scalatest.junit.JUnitSuite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.scalatest.junit.JUnitSuite;
import static jdocs.tutorial_6.DeviceGroupQueryTest.assertEqualTemperatures;
public class DeviceGroupTest extends JUnitSuite {
@ -34,7 +37,6 @@ public class DeviceGroupTest extends JUnitSuite {
system = null;
}
//#device-group-test-registration
@Test
public void testRegisterDeviceActor() {
TestKit probe = new TestKit(system);
@ -49,7 +51,7 @@ public class DeviceGroupTest extends JUnitSuite {
ActorRef deviceActor2 = probe.getLastSender();
assertNotEquals(deviceActor1, deviceActor2);
// Check that the device actors are workingl
// Check that the device actors are working
deviceActor1.tell(new Device.RecordTemperature(0L, 1.0), probe.getRef());
assertEquals(0L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);
deviceActor2.tell(new Device.RecordTemperature(1L, 2.0), probe.getRef());
@ -64,9 +66,7 @@ public class DeviceGroupTest extends JUnitSuite {
groupActor.tell(new DeviceManager.RequestTrackDevice("wrongGroup", "device1"), probe.getRef());
probe.expectNoMsg();
}
//#device-group-test-registration
//#device-group-test3
@Test
public void testReturnSameActorForSameDeviceId() {
TestKit probe = new TestKit(system);
@ -81,9 +81,7 @@ public class DeviceGroupTest extends JUnitSuite {
ActorRef deviceActor2 = probe.getLastSender();
assertEquals(deviceActor1, deviceActor2);
}
//#device-group-test3
//#device-group-list-terminate-test
@Test
public void testListActiveDevices() {
TestKit probe = new TestKit(system);
@ -133,5 +131,40 @@ public class DeviceGroupTest extends JUnitSuite {
return null;
});
}
//#device-group-list-terminate-test
@Test
public void testCollectTemperaturesFromAllActiveDevices() {
TestKit probe = new TestKit(system);
ActorRef groupActor = system.actorOf(DeviceGroup.props("group"));
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device1"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor1 = probe.getLastSender();
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device2"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor2 = probe.getLastSender();
groupActor.tell(new DeviceManager.RequestTrackDevice("group", "device3"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
ActorRef deviceActor3 = probe.getLastSender();
// Check that the device actors are working
deviceActor1.tell(new Device.RecordTemperature(0L, 1.0), probe.getRef());
assertEquals(0L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);
deviceActor2.tell(new Device.RecordTemperature(1L, 2.0), probe.getRef());
assertEquals(1L, probe.expectMsgClass(Device.TemperatureRecorded.class).requestId);
// No temperature for device 3
groupActor.tell(new DeviceGroup.RequestAllTemperatures(0L), probe.getRef());
DeviceGroup.RespondAllTemperatures response = probe.expectMsgClass(DeviceGroup.RespondAllTemperatures.class);
assertEquals(0L, response.requestId);
Map<String, DeviceGroup.TemperatureReading> expectedTemperatures = new HashMap<>();
expectedTemperatures.put("device1", new DeviceGroup.Temperature(1.0));
expectedTemperatures.put("device2", new DeviceGroup.Temperature(2.0));
expectedTemperatures.put("device3", new DeviceGroup.TemperatureNotAvailable());
assertEqualTemperatures(expectedTemperatures, response.temperatures);
}
}

View file

@ -2,10 +2,7 @@
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_3;
import java.util.Map;
import java.util.HashMap;
package jdocs.tutorial_6;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
@ -14,7 +11,9 @@ import akka.actor.Terminated;
import akka.event.Logging;
import akka.event.LoggingAdapter;
//#device-manager-full
import java.util.HashMap;
import java.util.Map;
public class DeviceManager extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@ -22,7 +21,6 @@ public class DeviceManager extends AbstractActor {
return Props.create(DeviceManager.class);
}
//#device-manager-msgs
public static final class RequestTrackDevice {
public final String groupId;
public final String deviceId;
@ -36,7 +34,6 @@ public class DeviceManager extends AbstractActor {
public static final class DeviceRegistered {
}
//#device-manager-msgs
final Map<String, ActorRef> groupIdToActor = new HashMap<>();
final Map<ActorRef, String> actorToGroupId = new HashMap<>();
@ -81,4 +78,3 @@ public class DeviceManager extends AbstractActor {
}
}
//#device-manager-full

View file

@ -1,10 +1,14 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_2;
package jdocs.tutorial_6;
import java.util.Optional;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -12,9 +16,6 @@ import static org.junit.Assert.assertEquals;
import org.scalatest.junit.JUnitSuite;
import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import akka.testkit.javadsl.TestKit;
public class DeviceTest extends JUnitSuite {
@ -31,7 +32,28 @@ public class DeviceTest extends JUnitSuite {
system = null;
}
//#device-read-test
@Test
public void testReplyToRegistrationRequests() {
TestKit probe = new TestKit(system);
ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "device"), probe.getRef());
probe.expectMsgClass(DeviceManager.DeviceRegistered.class);
assertEquals(deviceActor, probe.getLastSender());
}
@Test
public void testIgnoreWrongRegistrationRequests() {
TestKit probe = new TestKit(system);
ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
deviceActor.tell(new DeviceManager.RequestTrackDevice("wrongGroup", "device"), probe.getRef());
probe.expectNoMsg();
deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "wrongDevice"), probe.getRef());
probe.expectNoMsg();
}
@Test
public void testReplyWithEmptyReadingIfNoTemperatureIsKnown() {
TestKit probe = new TestKit(system);
@ -41,9 +63,7 @@ public class DeviceTest extends JUnitSuite {
assertEquals(42L, response.requestId);
assertEquals(Optional.empty(), response.value);
}
//#device-read-test
//#device-write-read-test
@Test
public void testReplyWithLatestTemperatureReading() {
TestKit probe = new TestKit(system);
@ -65,6 +85,5 @@ public class DeviceTest extends JUnitSuite {
assertEquals(4L, response2.requestId);
assertEquals(Optional.of(55.0), response2.value);
}
//#device-write-read-test
}

View file

@ -1,7 +1,7 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_5;
package jdocs.tutorial_6;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
@ -26,4 +26,4 @@ public class IotMain {
}
}
}
}

View file

@ -1,7 +1,7 @@
/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package jdocs.tutorial_5;
package jdocs.tutorial_6;
//#iot-supervisor