From 7ce205130140926674267155bf2277db743fb4f1 Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Mon, 23 Apr 2018 15:05:53 +0200 Subject: [PATCH 01/13] Updated repository for better reset functionality --- app/controllers/AdminController.java | 1 - app/controllers/ProjectsController.java | 1 - .../measurements/MeasurementsRepositoryMock.java | 1 - app/repositories/projects/ProjectsRepositoryMock.java | 1 + app/repositories/projects/ProjectsRepositoryMongo.java | 6 +++++- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/AdminController.java b/app/controllers/AdminController.java index 2ce3efd..decff69 100644 --- a/app/controllers/AdminController.java +++ b/app/controllers/AdminController.java @@ -29,7 +29,6 @@ public AdminController(final ProjectsRepository projectsRepository, final Measur public Result resetData() { this.projectsRepository.resetRepository(); - this.measurementsRepository.resetRepository(); final List projects = DataGenerator.generateProjects(AMOUNT_OF_PROJECTS, AMOUNT_OF_ROOMS_PER_PROJECT); diff --git a/app/controllers/ProjectsController.java b/app/controllers/ProjectsController.java index 21f3725..7a02a01 100644 --- a/app/controllers/ProjectsController.java +++ b/app/controllers/ProjectsController.java @@ -9,7 +9,6 @@ import play.mvc.BodyParser; import play.mvc.Controller; import play.mvc.Result; -import repositories.generator.DataGenerator; import repositories.projects.ProjectsRepository; import javax.inject.Inject; diff --git a/app/repositories/measurements/MeasurementsRepositoryMock.java b/app/repositories/measurements/MeasurementsRepositoryMock.java index cb05f51..ee3c4dd 100644 --- a/app/repositories/measurements/MeasurementsRepositoryMock.java +++ b/app/repositories/measurements/MeasurementsRepositoryMock.java @@ -51,7 +51,6 @@ public void addReadings(final ObjectId measurementId, final List readin measurementReadings.get().getReadings().addAll(readings); } - @Override public void resetRepository() { this.readingsList.clear(); } diff --git a/app/repositories/projects/ProjectsRepositoryMock.java b/app/repositories/projects/ProjectsRepositoryMock.java index 77ec634..769cd87 100644 --- a/app/repositories/projects/ProjectsRepositoryMock.java +++ b/app/repositories/projects/ProjectsRepositoryMock.java @@ -73,5 +73,6 @@ public long countProjects() { @Override public void resetRepository() { this.projects.clear(); + this.measurementsRepository.resetRepository(); } } diff --git a/app/repositories/projects/ProjectsRepositoryMongo.java b/app/repositories/projects/ProjectsRepositoryMongo.java index e03c2bd..38a8107 100644 --- a/app/repositories/projects/ProjectsRepositoryMongo.java +++ b/app/repositories/projects/ProjectsRepositoryMongo.java @@ -10,6 +10,7 @@ import models.Room; import org.bson.Document; import org.bson.types.ObjectId; +import repositories.measurements.MeasurementsRepository; import javax.inject.Inject; import java.util.Iterator; @@ -23,10 +24,12 @@ public class ProjectsRepositoryMongo implements ProjectsRepository { private final static String MEASUREMENT_COLLECTION_NAME = "measurements"; private final MongoClient mongoClient; + private final MeasurementsRepository measurementsRepository; @Inject - public ProjectsRepositoryMongo(final MongoClient mongoClient) { + public ProjectsRepositoryMongo(final MongoClient mongoClient, final MeasurementsRepository measurementsRepository) { this.mongoClient = mongoClient; + this.measurementsRepository = measurementsRepository; } private MongoCollection getProjectsCollection() { @@ -96,6 +99,7 @@ public long countProjects() { @Override public void resetRepository() { + this.measurementsRepository.resetRepository(); getProjectsCollection().drop(); this.mongoClient.getDatabase(DATABASE_NAME).createCollection(PROJECTS_COLLECTION_NAME); } From ae69ceb16f88e68ca260df00d4bf3205ffd279bc Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Mon, 23 Apr 2018 17:11:44 +0200 Subject: [PATCH 02/13] Broken code. Robin's birthday! --- app/controllers/AdminController.java | 44 ++++++-- app/controllers/MeasurementsController.java | 4 +- app/models/MeasurementReadings.java | 1 - app/models/Project.java | 1 - .../measurements/MeasurementsRepository.java | 3 +- .../MeasurementsRepositoryMock.java | 7 +- .../MeasurementsRepositoryMongo.java | 7 +- .../projects/ProjectsRepository.java | 3 +- .../projects/ProjectsRepositoryMock.java | 19 ++-- .../projects/ProjectsRepositoryMongo.java | 12 +- conf/application.conf | 2 +- conf/routes | 2 +- .../MeasurementsControllerTest.java | 104 ++++++++++++++++-- test/controllers/ProjectsControllerTest.java | 18 +-- 14 files changed, 174 insertions(+), 53 deletions(-) diff --git a/app/controllers/AdminController.java b/app/controllers/AdminController.java index decff69..47dd1d2 100644 --- a/app/controllers/AdminController.java +++ b/app/controllers/AdminController.java @@ -2,6 +2,7 @@ import com.google.inject.Inject; import models.MeasurementMetadata; +import models.MeasurementReadings; import models.Project; import org.bson.types.ObjectId; import play.mvc.Controller; @@ -10,13 +11,14 @@ import repositories.measurements.MeasurementsRepository; import repositories.projects.ProjectsRepository; +import java.util.ArrayList; import java.util.List; public class AdminController extends Controller { private static final int AMOUNT_OF_PROJECTS = 10; private static final int AMOUNT_OF_ROOMS_PER_PROJECT = 5; private static final int AMOUNT_OF_MEASUREMENTS_PER_ROOM = 10; - private static final int AMOUNT_OF_READINGS_PER_MEASUREMENT = 100; + private static final int AMOUNT_OF_READINGS_PER_MEASUREMENT = 1; private final ProjectsRepository projectsRepository; private final MeasurementsRepository measurementsRepository; @@ -29,20 +31,38 @@ public AdminController(final ProjectsRepository projectsRepository, final Measur public Result resetData() { this.projectsRepository.resetRepository(); - final List projects = DataGenerator.generateProjects(AMOUNT_OF_PROJECTS, AMOUNT_OF_ROOMS_PER_PROJECT); + final List measurementReadings = new ArrayList<>(AMOUNT_OF_PROJECTS * AMOUNT_OF_ROOMS_PER_PROJECT * AMOUNT_OF_MEASUREMENTS_PER_ROOM); - - projects.forEach(this.projectsRepository::addProject); - this.projectsRepository.getProjects().forEachRemaining(project -> { - project.getRooms().forEach(room -> { - final List roomMeasurements = DataGenerator.generateMeasurements(AMOUNT_OF_MEASUREMENTS_PER_ROOM); - roomMeasurements.forEach(measurementMetadata -> { - final ObjectId measurementId = this.projectsRepository.addMeasurement(project.getProjectId(), room.getName(), measurementMetadata); - this.measurementsRepository.addReadings(measurementId, DataGenerator.generateReadings(AMOUNT_OF_READINGS_PER_MEASUREMENT)); + projects.parallelStream() + .forEach(project -> { + project.getRooms().forEach(room -> { + final List roomMeasurements = DataGenerator.generateMeasurements(AMOUNT_OF_MEASUREMENTS_PER_ROOM); + roomMeasurements.forEach(measurementMetadata -> { + room.getMeasurements().add(measurementMetadata); + final MeasurementReadings readings = new MeasurementReadings(); + readings.setMeasurementId(measurementMetadata.getMeasurementId()); + readings.getReadings().addAll(DataGenerator.generateReadings(AMOUNT_OF_READINGS_PER_MEASUREMENT)); + measurementReadings.add(readings); + }); + }); }); - }); - }); + + projectsRepository.addProjects(projects); + measurementsRepository.addMeasurements(measurementReadings); + + + +// projects.forEach(this.projectsRepository::addProject); +// this.projectsRepository.getProjects().forEachRemaining(project -> { +// project.getRooms().forEach(room -> { +// final List roomMeasurements = DataGenerator.generateMeasurements(AMOUNT_OF_MEASUREMENTS_PER_ROOM); +// roomMeasurements.forEach(measurementMetadata -> { +// final ObjectId measurementId = this.projectsRepository.addMeasurement(project.getProjectId(), room.getName(), measurementMetadata); +// this.measurementsRepository.addReadings(measurementId, DataGenerator.generateReadings(AMOUNT_OF_READINGS_PER_MEASUREMENT)); +// }); +// }); +// }); return ok("Created " + AMOUNT_OF_PROJECTS + " projects with " + AMOUNT_OF_ROOMS_PER_PROJECT + " rooms each," + " " + AMOUNT_OF_MEASUREMENTS_PER_ROOM + " measurements per room" + diff --git a/app/controllers/MeasurementsController.java b/app/controllers/MeasurementsController.java index c88be3a..d6abd8c 100644 --- a/app/controllers/MeasurementsController.java +++ b/app/controllers/MeasurementsController.java @@ -98,9 +98,9 @@ public Result stopMeasurement() { return ok(); } - public Result isMeasurementActive() { + public Result getActiveMeasurement() { if(this.activeMeasurement != null){ - return Results.ok(); + return Results.ok(Json.toJson(this.activeMeasurement)); } return Results.noContent(); } diff --git a/app/models/MeasurementReadings.java b/app/models/MeasurementReadings.java index b67abce..cb7ba29 100644 --- a/app/models/MeasurementReadings.java +++ b/app/models/MeasurementReadings.java @@ -1,6 +1,5 @@ package models; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import org.bson.codecs.pojo.annotations.BsonId; diff --git a/app/models/Project.java b/app/models/Project.java index e80e948..3b61853 100644 --- a/app/models/Project.java +++ b/app/models/Project.java @@ -1,6 +1,5 @@ package models; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import org.bson.codecs.pojo.annotations.BsonId; diff --git a/app/repositories/measurements/MeasurementsRepository.java b/app/repositories/measurements/MeasurementsRepository.java index fc02a4b..964f301 100644 --- a/app/repositories/measurements/MeasurementsRepository.java +++ b/app/repositories/measurements/MeasurementsRepository.java @@ -1,6 +1,5 @@ package repositories.measurements; -import models.MeasurementMetadata; import models.MeasurementReadings; import models.Reading; import org.bson.types.ObjectId; @@ -19,4 +18,6 @@ public interface MeasurementsRepository { void addReadings(final ObjectId measurementId, final List readings); void resetRepository(); + + void addMeasurements(final List measurementReadings); } diff --git a/app/repositories/measurements/MeasurementsRepositoryMock.java b/app/repositories/measurements/MeasurementsRepositoryMock.java index ee3c4dd..fb9ceb3 100644 --- a/app/repositories/measurements/MeasurementsRepositoryMock.java +++ b/app/repositories/measurements/MeasurementsRepositoryMock.java @@ -1,11 +1,9 @@ package repositories.measurements; import com.google.inject.Singleton; -import models.MeasurementMetadata; import models.MeasurementReadings; import models.Reading; import org.bson.types.ObjectId; -import repositories.generator.DataGenerator; import java.util.ArrayList; import java.util.Iterator; @@ -54,4 +52,9 @@ public void addReadings(final ObjectId measurementId, final List readin public void resetRepository() { this.readingsList.clear(); } + + @Override + public void addMeasurements(final List measurementReadings) { + this.readingsList.addAll(measurementReadings); + } } diff --git a/app/repositories/measurements/MeasurementsRepositoryMongo.java b/app/repositories/measurements/MeasurementsRepositoryMongo.java index 176328d..901583f 100644 --- a/app/repositories/measurements/MeasurementsRepositoryMongo.java +++ b/app/repositories/measurements/MeasurementsRepositoryMongo.java @@ -45,7 +45,7 @@ public MeasurementReadings getMeasurementReadingsById(final ObjectId measurement @Override public ObjectId addMeasurement(final MeasurementReadings readings) { - if(readings.getMeasurementId() != null) { + if(readings.getMeasurementId() == null) { readings.setMeasurementId(new ObjectId()); } getCollection().insertOne(readings); @@ -62,4 +62,9 @@ public void resetRepository() { getCollection().drop(); this.mongoClient.getDatabase(DATABASE_NAME).createCollection(COLLECTION_NAME); } + + @Override + public void addMeasurements(final List measurementReadings) { + this.getCollection().insertMany(measurementReadings); + } } diff --git a/app/repositories/projects/ProjectsRepository.java b/app/repositories/projects/ProjectsRepository.java index 08e69b1..b47a4de 100644 --- a/app/repositories/projects/ProjectsRepository.java +++ b/app/repositories/projects/ProjectsRepository.java @@ -2,7 +2,6 @@ import models.MeasurementMetadata; import models.Project; -import models.Reading; import org.bson.types.ObjectId; import java.util.Iterator; @@ -13,6 +12,8 @@ public interface ProjectsRepository { ObjectId addProject(final Project project); + void addProjects(final List projects); + Project getProjectById(final ObjectId projectId); ObjectId addMeasurement(final ObjectId projectId, final String roomName, final MeasurementMetadata measurementMetadata); diff --git a/app/repositories/projects/ProjectsRepositoryMock.java b/app/repositories/projects/ProjectsRepositoryMock.java index 769cd87..7b48938 100644 --- a/app/repositories/projects/ProjectsRepositoryMock.java +++ b/app/repositories/projects/ProjectsRepositoryMock.java @@ -5,24 +5,21 @@ import models.Project; import models.Room; import org.bson.types.ObjectId; -import repositories.generator.DataGenerator; import repositories.measurements.MeasurementsRepository; import javax.inject.Inject; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Optional; public class ProjectsRepositoryMock implements ProjectsRepository { - private final static int AMOUNT_OF_PROJECTS = 10; - private final static int AMOUNT_OF_ROOMS_PER_PROJECT = 5; - private final List projects; private final MeasurementsRepository measurementsRepository; @Inject public ProjectsRepositoryMock(final MeasurementsRepository measurementsRepository) { - this.projects = DataGenerator.generateProjects(AMOUNT_OF_PROJECTS, AMOUNT_OF_ROOMS_PER_PROJECT); + this.projects = new ArrayList<>(); this.measurementsRepository = measurementsRepository; } @@ -33,10 +30,16 @@ public Iterator getProjects() { @Override public ObjectId addProject(final Project project) { - final ObjectId newId = new ObjectId(); - project.setProjectId(newId); + if(project.getProjectId() == null) { + project.setProjectId(new ObjectId()); + } this.projects.add(project); - return newId; + return project.getProjectId(); + } + + @Override + public void addProjects(List projects) { + this.projects.addAll(projects); } @Override diff --git a/app/repositories/projects/ProjectsRepositoryMongo.java b/app/repositories/projects/ProjectsRepositoryMongo.java index 38a8107..228e99c 100644 --- a/app/repositories/projects/ProjectsRepositoryMongo.java +++ b/app/repositories/projects/ProjectsRepositoryMongo.java @@ -14,6 +14,7 @@ import javax.inject.Inject; import java.util.Iterator; +import java.util.List; import java.util.Optional; import static com.mongodb.client.model.Filters.eq; @@ -49,10 +50,15 @@ public Iterator getProjects() { @Override public ObjectId addProject(final Project project) { - final ObjectId newId = new ObjectId(); - project.setProjectId(newId); + if(project.getProjectId() == null) { + project.setProjectId(new ObjectId()); + } getProjectsCollection().insertOne(project); - return newId; + return project.getProjectId(); + } + + public void addProjects(final List projects) { + getProjectsCollection().insertMany(projects); } @Override diff --git a/conf/application.conf b/conf/application.conf index c5ba5f7..2cc8240 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -14,5 +14,5 @@ play.filters { } play.editor="http://localhost:63342/api/file/?file=%s&line=%s" -flux.mongodb.uri = "mongodb://localhost:27017" # Default mongodb uri +flux.mongodb.uri = "mongodb+srv://flux-db-user:aaOlr9kT0dJZQOP1@flux-database-vemhh.mongodb.net/flux-test" # Default mongodb uri flux.mongodb.uri = ${?MONGO_URI} # Overrides the default URL with one from the environment variables (MONGO_URI) \ No newline at end of file diff --git a/conf/routes b/conf/routes index e24d38e..8e43231 100644 --- a/conf/routes +++ b/conf/routes @@ -8,7 +8,7 @@ GET /reset controllers.AdminController.resetDat GET /projects controllers.ProjectsController.getProjects(limit: Int ?=5) POST /projects controllers.ProjectsController.addProject GET /projects/:projectId controllers.ProjectsController.getProjectById(projectId: String) -GET /measurements/active controllers.MeasurementsController.isMeasurementActive +GET /measurements/active controllers.MeasurementsController.getActiveMeasurement GET /measurements/:measurementId controllers.MeasurementsController.getMeasurementById(measurementId : String) GET /measurements controllers.MeasurementsController.getMeasurements(limit: Int ?=5) POST /measurements controllers.MeasurementsController.createMeasurement diff --git a/test/controllers/MeasurementsControllerTest.java b/test/controllers/MeasurementsControllerTest.java index 5a2cbfb..39a4c05 100644 --- a/test/controllers/MeasurementsControllerTest.java +++ b/test/controllers/MeasurementsControllerTest.java @@ -1,9 +1,9 @@ package controllers; import helpers.Helpers; -import models.MeasurementMetadata; -import models.MeasurementReadings; +import models.*; import org.bson.types.ObjectId; +import org.junit.Before; import org.junit.Test; import play.Application; import play.inject.guice.GuiceApplicationBuilder; @@ -13,22 +13,28 @@ import play.test.WithApplication; import repositories.generator.DataGenerator; import repositories.measurements.MeasurementsRepository; -import repositories.measurements.MeasurementsRepositoryMock; import repositories.projects.ProjectsRepository; -import repositories.projects.ProjectsRepositoryMock; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static play.inject.Bindings.bind; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; import static play.test.Helpers.*; public class MeasurementsControllerTest extends WithApplication { @Override protected Application provideApplication() { return new GuiceApplicationBuilder() - .overrides(bind(MeasurementsRepository.class).to(MeasurementsRepositoryMock.class)) - .overrides(bind(ProjectsRepository.class).to(ProjectsRepositoryMock.class)) - .build(); + .build(); + } + + @Before + public void setUp() { + final Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/reset"); + final Result result = route(app, request); + assertEquals(OK, result.status()); } @Test @@ -88,7 +94,7 @@ public void getMeasurementById_GetExisting_OK() { final MeasurementReadings measurementReadings = new MeasurementReadings(); final MeasurementsRepository repository = app.injector().instanceOf(MeasurementsRepository.class); final ObjectId newMeasurementId = repository.addMeasurement(measurementReadings); - final MeasurementReadings expectedReading = repository.getMeasurementReadings().next(); + final MeasurementReadings expectedReading = repository.getMeasurementReadingsById(newMeasurementId); final Http.RequestBuilder request = new Http.RequestBuilder() .method(GET) .uri("/measurements/" + newMeasurementId); @@ -116,4 +122,80 @@ public void getMeasurementById_InvalidObjectId_BadRequest() { final Result result = route(app, request); assertEquals(BAD_REQUEST, result.status()); } + + @Test + public void startMeasurement_StartFirst_IsActive() { + final ProjectsRepository projectsRepository = app.injector().instanceOf(ProjectsRepository.class); + final Project project = projectsRepository.getProjects().next(); + final Room room = project.getRooms().get(0); + final MeasurementMetadata measurementMetadata = room.getMeasurements().get(0); + + final Http.RequestBuilder request = new Http.RequestBuilder() + .method(PUT) + .uri("/measurements/active/" + measurementMetadata.getMeasurementId()); + final Result result = route(app, request); + assertEquals(OK, result.status()); + } + + @Test + public void addReadings_AddOne_ReadingAdded() { + final MeasurementMetadata activeMeasurement = getOrSetActiveMeasurement(); + + final Reading reading = DataGenerator.generateReading(); + final List readingList = new ArrayList<>(1); + readingList.add(reading); + final Http.RequestBuilder request = new Http.RequestBuilder() + .method(POST) + .uri("/measurements/active/readings") + .bodyJson(Json.toJson(readingList)); + final Result result = route(app, request); + assertEquals(OK, result.status()); + + final MeasurementsRepository repository = app.injector().instanceOf(MeasurementsRepository.class); + final MeasurementReadings measurementReadings = repository.getMeasurementReadingsById(activeMeasurement.getMeasurementId()); + assertTrue(measurementReadings.getReadings().contains(reading)); + } + + @Test + public void addReadings_AddMultiple_ReadingAdded() { + final int amountOfReadings = 10; + final MeasurementMetadata activeMeasurement = getOrSetActiveMeasurement(); + + final List readingList = DataGenerator.generateReadings(amountOfReadings); + final Http.RequestBuilder request = new Http.RequestBuilder() + .method(POST) + .uri("/measurements/active/readings") + .bodyJson(Json.toJson(readingList)); + final Result result = route(app, request); + assertEquals(OK, result.status()); + + final MeasurementsRepository repository = app.injector().instanceOf(MeasurementsRepository.class); + final MeasurementReadings measurementReadings = repository.getMeasurementReadingsById(activeMeasurement.getMeasurementId()); + assertTrue(measurementReadings.getReadings().containsAll(readingList)); + } + + private MeasurementMetadata getOrSetActiveMeasurement() { + final Http.RequestBuilder getActiveRequest = new Http.RequestBuilder() + .method(GET) + .uri("/measurements/active"); + final Result getResult = route(app, getActiveRequest); + + MeasurementMetadata measurementMetadata; + if(getResult.status() == OK) { + measurementMetadata = Helpers.convertFromJSON(getResult, MeasurementMetadata.class); + } else { + final ProjectsRepository projectsRepository = app.injector().instanceOf(ProjectsRepository.class); + final Project project = projectsRepository.getProjects().next(); + final Room room = project.getRooms().get(0); + measurementMetadata = room.getMeasurements().get(0); + + final Http.RequestBuilder setActiveRequest = new Http.RequestBuilder() + .method(PUT) + .uri("/measurements/active/" + measurementMetadata.getMeasurementId()); + final Result setActiveResult = route(app, setActiveRequest); + assertEquals(OK, setActiveResult.status()); + } + + return measurementMetadata; + } } \ No newline at end of file diff --git a/test/controllers/ProjectsControllerTest.java b/test/controllers/ProjectsControllerTest.java index 43f32ee..c69f62c 100644 --- a/test/controllers/ProjectsControllerTest.java +++ b/test/controllers/ProjectsControllerTest.java @@ -2,6 +2,7 @@ import helpers.Helpers; import models.Project; +import org.junit.Before; import org.junit.Test; import play.Application; import play.inject.guice.GuiceApplicationBuilder; @@ -10,26 +11,27 @@ import play.mvc.Result; import play.test.WithApplication; import repositories.generator.DataGenerator; -import repositories.measurements.MeasurementsRepository; -import repositories.measurements.MeasurementsRepositoryMock; -import repositories.projects.ProjectsRepository; -import repositories.projects.ProjectsRepositoryMock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static play.inject.Bindings.bind; -import static play.mvc.Http.Status.CREATED; import static play.test.Helpers.*; public class ProjectsControllerTest extends WithApplication { @Override protected Application provideApplication() { return new GuiceApplicationBuilder() - .overrides(bind(MeasurementsRepository.class).to(MeasurementsRepositoryMock.class)) - .overrides(bind(ProjectsRepository.class).to(ProjectsRepositoryMock.class)) .build(); } + @Before + public void setUp() { + final Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/reset"); + final Result result = route(app, request); + assertEquals(OK, result.status()); + } + @Test public void createProjects_BestCase_OK() { final Project project = DataGenerator.generateProject(5); From 111c70571a1c64ee2f202f7c74e4107164c8e671 Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 24 Apr 2018 13:26:22 +0200 Subject: [PATCH 03/13] Updated test config and reset function --- .travis.yml | 7 +++++++ app/repositories/generator/DataGenerator.java | 2 ++ conf/application.conf | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d9f33d9..43c963e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,13 @@ addons: sonarqube: organization: flux-coordinator +services: + - mongodb + +before_script: + - sleep 15 + - mongo flux_test --eval 'db.createUser({user: "flux-db-user", pwd: "FMzy5WT/Bv+e", roles:["readWrite"]});' + script: - sbt ++$TRAVIS_SCALA_VERSION test - sonar-scanner diff --git a/app/repositories/generator/DataGenerator.java b/app/repositories/generator/DataGenerator.java index 6757ff7..154827e 100644 --- a/app/repositories/generator/DataGenerator.java +++ b/app/repositories/generator/DataGenerator.java @@ -1,6 +1,7 @@ package repositories.generator; import models.*; +import org.bson.types.ObjectId; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -139,6 +140,7 @@ public static MeasurementMetadata generateMeasurementMetadata() { try { final MeasurementMetadata measurementMetadata = new MeasurementMetadata(); + measurementMetadata.setMeasurementId(new ObjectId()); measurementMetadata.setCreator("Generated"); measurementMetadata.setDescription("Generated automatically"); measurementMetadata.setName("AutoGenenerated" + random.nextInt()); diff --git a/conf/application.conf b/conf/application.conf index 2cc8240..c5ba5f7 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -14,5 +14,5 @@ play.filters { } play.editor="http://localhost:63342/api/file/?file=%s&line=%s" -flux.mongodb.uri = "mongodb+srv://flux-db-user:aaOlr9kT0dJZQOP1@flux-database-vemhh.mongodb.net/flux-test" # Default mongodb uri +flux.mongodb.uri = "mongodb://localhost:27017" # Default mongodb uri flux.mongodb.uri = ${?MONGO_URI} # Overrides the default URL with one from the environment variables (MONGO_URI) \ No newline at end of file From c2c5e824adfc86e829c1d3ddf136624fc73284db Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 24 Apr 2018 13:30:08 +0200 Subject: [PATCH 04/13] Travis MongoDB without auth --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 43c963e..455ca3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ services: before_script: - sleep 15 - - mongo flux_test --eval 'db.createUser({user: "flux-db-user", pwd: "FMzy5WT/Bv+e", roles:["readWrite"]});' script: - sbt ++$TRAVIS_SCALA_VERSION test From b91d3673e2d3baf4807dde854f220d67a1448db5 Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 24 Apr 2018 13:36:41 +0200 Subject: [PATCH 05/13] Hide DataGenerator constructor Reorder modifiers to comply with the Java Language Specification --- app/repositories/generator/DataGenerator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/repositories/generator/DataGenerator.java b/app/repositories/generator/DataGenerator.java index 154827e..ce1e60a 100644 --- a/app/repositories/generator/DataGenerator.java +++ b/app/repositories/generator/DataGenerator.java @@ -14,7 +14,11 @@ * Helper class to generate data more easily. */ public class DataGenerator { - private final static Random random = new Random(); + private static final Random random = new Random(); + + private DataGenerator() { + + } public static List generateProjects(final int amountOfProjects, final int roomsPerProject) { try { From 17c2401e356222ef44c2688f2060183f5f4acacc Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 24 Apr 2018 13:41:34 +0200 Subject: [PATCH 06/13] Fixed several code smells from SonarQube --- .../measurements/MeasurementsRepositoryMongo.java | 4 ++-- test/helpers/Helpers.java | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/repositories/measurements/MeasurementsRepositoryMongo.java b/app/repositories/measurements/MeasurementsRepositoryMongo.java index 901583f..f6ec0be 100644 --- a/app/repositories/measurements/MeasurementsRepositoryMongo.java +++ b/app/repositories/measurements/MeasurementsRepositoryMongo.java @@ -17,8 +17,8 @@ @Singleton public class MeasurementsRepositoryMongo implements MeasurementsRepository { - private final static String DATABASE_NAME = "flux"; - private final static String COLLECTION_NAME = "measurements"; + private static final String DATABASE_NAME = "flux"; + private static final String COLLECTION_NAME = "measurements"; private final MongoClient mongoClient; diff --git a/test/helpers/Helpers.java b/test/helpers/Helpers.java index b16a057..045be19 100644 --- a/test/helpers/Helpers.java +++ b/test/helpers/Helpers.java @@ -5,6 +5,11 @@ import play.mvc.Result; public class Helpers { + + private Helpers() { + + } + public static T convertFromJSON(final Result result, Class clazz) { final JsonNode node = Json.parse(play.test.Helpers.contentAsString(result)); return Json.fromJson(node, clazz); From cac152f40dbf3abfe2240c87515ea9125996a30c Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 24 Apr 2018 14:07:12 +0200 Subject: [PATCH 07/13] Eliminated code smells --- app/controllers/AdminController.java | 20 +++---------------- app/repositories/generator/DataGenerator.java | 10 ++++------ .../MeasurementsRepositoryMock.java | 3 +-- .../projects/ProjectsRepositoryMock.java | 3 +-- .../projects/ProjectsRepositoryMongo.java | 9 ++++----- 5 files changed, 13 insertions(+), 32 deletions(-) diff --git a/app/controllers/AdminController.java b/app/controllers/AdminController.java index 47dd1d2..d00ede1 100644 --- a/app/controllers/AdminController.java +++ b/app/controllers/AdminController.java @@ -35,8 +35,7 @@ public Result resetData() { final List measurementReadings = new ArrayList<>(AMOUNT_OF_PROJECTS * AMOUNT_OF_ROOMS_PER_PROJECT * AMOUNT_OF_MEASUREMENTS_PER_ROOM); projects.parallelStream() - .forEach(project -> { - project.getRooms().forEach(room -> { + .forEach(project -> project.getRooms().forEach(room -> { final List roomMeasurements = DataGenerator.generateMeasurements(AMOUNT_OF_MEASUREMENTS_PER_ROOM); roomMeasurements.forEach(measurementMetadata -> { room.getMeasurements().add(measurementMetadata); @@ -45,25 +44,12 @@ public Result resetData() { readings.getReadings().addAll(DataGenerator.generateReadings(AMOUNT_OF_READINGS_PER_MEASUREMENT)); measurementReadings.add(readings); }); - }); - }); + }) + ); projectsRepository.addProjects(projects); measurementsRepository.addMeasurements(measurementReadings); - - -// projects.forEach(this.projectsRepository::addProject); -// this.projectsRepository.getProjects().forEachRemaining(project -> { -// project.getRooms().forEach(room -> { -// final List roomMeasurements = DataGenerator.generateMeasurements(AMOUNT_OF_MEASUREMENTS_PER_ROOM); -// roomMeasurements.forEach(measurementMetadata -> { -// final ObjectId measurementId = this.projectsRepository.addMeasurement(project.getProjectId(), room.getName(), measurementMetadata); -// this.measurementsRepository.addReadings(measurementId, DataGenerator.generateReadings(AMOUNT_OF_READINGS_PER_MEASUREMENT)); -// }); -// }); -// }); - return ok("Created " + AMOUNT_OF_PROJECTS + " projects with " + AMOUNT_OF_ROOMS_PER_PROJECT + " rooms each," + " " + AMOUNT_OF_MEASUREMENTS_PER_ROOM + " measurements per room" + " and " + AMOUNT_OF_READINGS_PER_MEASUREMENT + " readings per measurement."); diff --git a/app/repositories/generator/DataGenerator.java b/app/repositories/generator/DataGenerator.java index ce1e60a..7167ea8 100644 --- a/app/repositories/generator/DataGenerator.java +++ b/app/repositories/generator/DataGenerator.java @@ -16,9 +16,7 @@ public class DataGenerator { private static final Random random = new Random(); - private DataGenerator() { - - } + private DataGenerator() { } public static List generateProjects(final int amountOfProjects, final int roomsPerProject) { try { @@ -38,7 +36,7 @@ public static Project generateProject(final int rooms) { try { final Project project = new Project(); - project.setName("Project-" + Math.abs(random.nextInt())); + project.setName("Project-" + random.nextInt(Integer.MAX_VALUE)); project.setDescription("This is an example project and was automatically generated on " + getLocalDateTime() + "."); project.setRooms(generateRooms(rooms)); @@ -66,7 +64,7 @@ public static Room generateRoom() { try { final Room room = new Room(); - room.setName("Room-" + Math.abs(random.nextInt())); + room.setName("Room-" + random.nextInt(Integer.MAX_VALUE)); room.setDescription("This is an example room and was automatically generated on " + getLocalDateTime() + "."); room.setLength(random.nextDouble() * 100); room.setWidth(random.nextDouble() * 100); @@ -127,7 +125,7 @@ public static AnchorPosition generateAnchorPosition() { try { final AnchorPosition position = new AnchorPosition(); - position.setName("Anker-" + Math.abs(random.nextInt())); + position.setName("Anker-" + random.nextInt(Integer.MAX_VALUE)); position.setXPosition(random.nextDouble()); position.setYPosition(random.nextDouble()); position.setZPosition(random.nextDouble()); diff --git a/app/repositories/measurements/MeasurementsRepositoryMock.java b/app/repositories/measurements/MeasurementsRepositoryMock.java index fb9ceb3..55d1bd8 100644 --- a/app/repositories/measurements/MeasurementsRepositoryMock.java +++ b/app/repositories/measurements/MeasurementsRepositoryMock.java @@ -45,8 +45,7 @@ public void addReadings(final ObjectId measurementId, final List readin final Optional measurementReadings = readingsList.parallelStream() .filter(m -> m.getMeasurementId().equals(measurementId)) .findAny(); - - measurementReadings.get().getReadings().addAll(readings); + measurementReadings.orElseThrow(() -> new NullPointerException("Measurement to add the reading was not found.")).getReadings().addAll(readings); } public void resetRepository() { diff --git a/app/repositories/projects/ProjectsRepositoryMock.java b/app/repositories/projects/ProjectsRepositoryMock.java index 7b48938..7bc055a 100644 --- a/app/repositories/projects/ProjectsRepositoryMock.java +++ b/app/repositories/projects/ProjectsRepositoryMock.java @@ -62,8 +62,7 @@ public ObjectId addMeasurement(final ObjectId projectId, final String roomName, final MeasurementReadings measurementReadings = new MeasurementReadings(); measurementReadings.setMeasurementId(measurementId); - //noinspection ConstantConditions - room.get().getMeasurements().add(measurementMetadata); + room.orElseThrow(() -> new NullPointerException("Room to add the measurement into was not found.")).getMeasurements().add(measurementMetadata); measurementsRepository.addMeasurement(measurementReadings); return measurementId; } diff --git a/app/repositories/projects/ProjectsRepositoryMongo.java b/app/repositories/projects/ProjectsRepositoryMongo.java index 228e99c..6891805 100644 --- a/app/repositories/projects/ProjectsRepositoryMongo.java +++ b/app/repositories/projects/ProjectsRepositoryMongo.java @@ -20,9 +20,9 @@ import static com.mongodb.client.model.Filters.eq; public class ProjectsRepositoryMongo implements ProjectsRepository { - private final static String DATABASE_NAME = "flux"; - private final static String PROJECTS_COLLECTION_NAME = "projects"; - private final static String MEASUREMENT_COLLECTION_NAME = "measurements"; + private static final String DATABASE_NAME = "flux"; + private static final String PROJECTS_COLLECTION_NAME = "projects"; + private static final String MEASUREMENT_COLLECTION_NAME = "measurements"; private final MongoClient mongoClient; private final MeasurementsRepository measurementsRepository; @@ -75,8 +75,7 @@ public ObjectId addMeasurement(final ObjectId projectId, final String roomName, final ObjectId measurementId = new ObjectId(); measurementMetadata.setMeasurementId(measurementId); - //noinspection ConstantConditions (We want to throw here!) - roomOptional.get().getMeasurements().add(measurementMetadata); + roomOptional.orElseThrow(() -> new NullPointerException("There was no room to add the measurement")).getMeasurements().add(measurementMetadata); final MeasurementReadings measurementReadings = new MeasurementReadings(); measurementReadings.setMeasurementId(measurementId); From 4e00a2d97166dddb64b71b2b18208ab271cc246b Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Sun, 29 Apr 2018 20:35:14 +0200 Subject: [PATCH 08/13] WIP: Implementing Actors for the WebSocket Streaming --- app/actors/measurements/MeasurementActor.java | 27 ++++++++++++++++ .../MeasurementActorProtocol.java | 14 +++++++++ app/controllers/MeasurementsController.java | 31 ++++++++++++++++--- 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 app/actors/measurements/MeasurementActor.java create mode 100644 app/actors/measurements/MeasurementActorProtocol.java diff --git a/app/actors/measurements/MeasurementActor.java b/app/actors/measurements/MeasurementActor.java new file mode 100644 index 0000000..9d164ea --- /dev/null +++ b/app/actors/measurements/MeasurementActor.java @@ -0,0 +1,27 @@ +package actors.measurements; + +import akka.actor.AbstractActor; +import akka.actor.Props; +import play.mvc.WebSocket; + +import static actors.measurements.MeasurementActorProtocol.*; + +public class MeasurementActor extends AbstractActor { + public static Props getProps(final WebSocket socket) { + return Props.create(MeasurementActor.class, () -> new MeasurementActor(socket)); + } + + private final WebSocket webSocket; + + public MeasurementActor(final WebSocket socket) { + this.webSocket = socket; + } + + @Override + public Receive createReceive() { + return receiveBuilder() + .match(PutReading.class, putReading -> { + }) + .build(); + } +} diff --git a/app/actors/measurements/MeasurementActorProtocol.java b/app/actors/measurements/MeasurementActorProtocol.java new file mode 100644 index 0000000..14def97 --- /dev/null +++ b/app/actors/measurements/MeasurementActorProtocol.java @@ -0,0 +1,14 @@ +package actors.measurements; + +import models.Reading; + +public class MeasurementActorProtocol { + + public static class PutReading { + public final Reading reading; + + public PutReading(final Reading reading) { + this.reading = reading; + } + } +} diff --git a/app/controllers/MeasurementsController.java b/app/controllers/MeasurementsController.java index d6abd8c..4c5753c 100644 --- a/app/controllers/MeasurementsController.java +++ b/app/controllers/MeasurementsController.java @@ -1,5 +1,10 @@ package controllers; +import actors.measurements.MeasurementActor; +import akka.NotUsed; +import akka.actor.ActorSystem; +import akka.stream.javadsl.JavaFlowSupport; +import akka.stream.javadsl.Source; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -11,11 +16,10 @@ import play.Logger; import play.libs.Json; import play.libs.concurrent.HttpExecutionContext; -import play.mvc.BodyParser; -import play.mvc.Controller; -import play.mvc.Result; -import play.mvc.Results; +import play.libs.streams.ActorFlow; +import play.mvc.*; import repositories.measurements.MeasurementsRepository; +import scala.compat.java8.FutureConverters; import javax.inject.Inject; import java.util.ArrayList; @@ -29,11 +33,14 @@ public class MeasurementsController extends Controller { private final MeasurementsRepository measurementsRepository; private MeasurementReadings activeMeasurement; + private MeasurementActor measurementActor; @Inject - public MeasurementsController(final HttpExecutionContext httpExecutionContext, final MeasurementsRepository measurementsRepository) { + public MeasurementsController(final HttpExecutionContext httpExecutionContext, final MeasurementsRepository measurementsRepository, + final ActorSystem actorSystem) { this.httpExecutionContext = httpExecutionContext; this.measurementsRepository = measurementsRepository; +// actorSystem.actorOf(MeasurementActor.getProps()); } public CompletionStage getMeasurementById(final String measurementId) { @@ -107,6 +114,12 @@ public Result getActiveMeasurement() { @BodyParser.Of(BodyParser.Json.class) public CompletableFuture addReading() { +// final CompletableFuture future = CompletableFuture.supplyAsync(() -> { +// return new Reading(); +// }); +// +// Source source = Source.fromCompletionStage(future); + return CompletableFuture.supplyAsync(() -> { if(this.activeMeasurement == null) { return Results.badRequest(); @@ -125,4 +138,12 @@ public CompletableFuture addReading() { return Results.ok(); }, httpExecutionContext.current()); } + +// public WebSocket socket() { +// return WebSocket.Text.accept(request -> +// ActorFlow.actorRef(MyWebSocketActor::props, +// actorSystem, materializer +// ) +// ); +// } } \ No newline at end of file From 73dd16729c90830bc9a38cc11d5641a511cc66ee Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Sun, 29 Apr 2018 22:01:11 +0200 Subject: [PATCH 09/13] WIP: Updated Flow for Websocket --- app/actors/measurements/MeasurementActor.java | 14 ++++---- app/controllers/MeasurementsController.java | 34 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/actors/measurements/MeasurementActor.java b/app/actors/measurements/MeasurementActor.java index 9d164ea..064d7eb 100644 --- a/app/actors/measurements/MeasurementActor.java +++ b/app/actors/measurements/MeasurementActor.java @@ -1,26 +1,28 @@ package actors.measurements; import akka.actor.AbstractActor; +import akka.actor.ActorRef; import akka.actor.Props; import play.mvc.WebSocket; import static actors.measurements.MeasurementActorProtocol.*; public class MeasurementActor extends AbstractActor { - public static Props getProps(final WebSocket socket) { - return Props.create(MeasurementActor.class, () -> new MeasurementActor(socket)); - } + private final ActorRef out; - private final WebSocket webSocket; + public static Props props(ActorRef out) { + return Props.create(MeasurementActor.class, out); + } - public MeasurementActor(final WebSocket socket) { - this.webSocket = socket; + public MeasurementActor(final ActorRef out) { + this.out = out; } @Override public Receive createReceive() { return receiveBuilder() .match(PutReading.class, putReading -> { + out.tell(putReading.reading, self()); }) .build(); } diff --git a/app/controllers/MeasurementsController.java b/app/controllers/MeasurementsController.java index 4c5753c..b944e66 100644 --- a/app/controllers/MeasurementsController.java +++ b/app/controllers/MeasurementsController.java @@ -3,6 +3,8 @@ import actors.measurements.MeasurementActor; import akka.NotUsed; import akka.actor.ActorSystem; +import akka.stream.Materializer; +import akka.stream.javadsl.Flow; import akka.stream.javadsl.JavaFlowSupport; import akka.stream.javadsl.Source; import com.fasterxml.jackson.core.type.TypeReference; @@ -28,19 +30,25 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import static akka.pattern.Patterns.ask; + public class MeasurementsController extends Controller { private final HttpExecutionContext httpExecutionContext; private final MeasurementsRepository measurementsRepository; + private final ActorSystem actorSystem; + private final Materializer materializer; private MeasurementReadings activeMeasurement; private MeasurementActor measurementActor; + private Source readingsSource; @Inject public MeasurementsController(final HttpExecutionContext httpExecutionContext, final MeasurementsRepository measurementsRepository, - final ActorSystem actorSystem) { + final ActorSystem actorSystem, final Materializer materializer) { this.httpExecutionContext = httpExecutionContext; this.measurementsRepository = measurementsRepository; -// actorSystem.actorOf(MeasurementActor.getProps()); + this.actorSystem = actorSystem; + this.materializer = materializer; } public CompletionStage getMeasurementById(final String measurementId) { @@ -114,12 +122,10 @@ public Result getActiveMeasurement() { @BodyParser.Of(BodyParser.Json.class) public CompletableFuture addReading() { -// final CompletableFuture future = CompletableFuture.supplyAsync(() -> { -// return new Reading(); -// }); -// -// Source source = Source.fromCompletionStage(future); - + /* + TODO: Tell the flow listening to the socket that there is new data incoming. + Maybe make new Actor from the logic below. + */ return CompletableFuture.supplyAsync(() -> { if(this.activeMeasurement == null) { return Results.badRequest(); @@ -139,11 +145,9 @@ public CompletableFuture addReading() { }, httpExecutionContext.current()); } -// public WebSocket socket() { -// return WebSocket.Text.accept(request -> -// ActorFlow.actorRef(MyWebSocketActor::props, -// actorSystem, materializer -// ) -// ); -// } + public WebSocket socket() { + // The flow passes a new actor that handles the out path inside the Measurement Actor! + final Flow flow = ActorFlow.actorRef(MeasurementActor::props, actorSystem, materializer); + return WebSocket.Json.accept(request -> flow); + } } \ No newline at end of file From e095e85aa3dcda771f63839e885d6ef73d96b22c Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Mon, 30 Apr 2018 13:31:54 +0200 Subject: [PATCH 10/13] FLUX-109 Workaround to stream new readings to a websocket --- app/actors/measurements/MeasurementActor.java | 9 ++-- app/controllers/MeasurementsController.java | 42 +++++++------------ conf/routes | 1 + 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/app/actors/measurements/MeasurementActor.java b/app/actors/measurements/MeasurementActor.java index 064d7eb..8aef99a 100644 --- a/app/actors/measurements/MeasurementActor.java +++ b/app/actors/measurements/MeasurementActor.java @@ -3,26 +3,27 @@ import akka.actor.AbstractActor; import akka.actor.ActorRef; import akka.actor.Props; +import models.Reading; import play.mvc.WebSocket; import static actors.measurements.MeasurementActorProtocol.*; public class MeasurementActor extends AbstractActor { - private final ActorRef out; + public static ActorRef out; public static Props props(ActorRef out) { return Props.create(MeasurementActor.class, out); } public MeasurementActor(final ActorRef out) { - this.out = out; + MeasurementActor.out = out; } @Override public Receive createReceive() { return receiveBuilder() - .match(PutReading.class, putReading -> { - out.tell(putReading.reading, self()); + .match(Reading.class, putReading -> { + out.tell(putReading, self()); }) .build(); } diff --git a/app/controllers/MeasurementsController.java b/app/controllers/MeasurementsController.java index b944e66..c776f60 100644 --- a/app/controllers/MeasurementsController.java +++ b/app/controllers/MeasurementsController.java @@ -1,17 +1,11 @@ package controllers; import actors.measurements.MeasurementActor; -import akka.NotUsed; +import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.stream.Materializer; import akka.stream.javadsl.Flow; -import akka.stream.javadsl.JavaFlowSupport; -import akka.stream.javadsl.Source; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import java.io.IOException; import models.MeasurementReadings; import models.Reading; import org.bson.types.ObjectId; @@ -21,17 +15,15 @@ import play.libs.streams.ActorFlow; import play.mvc.*; import repositories.measurements.MeasurementsRepository; -import scala.compat.java8.FutureConverters; import javax.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import static akka.pattern.Patterns.ask; - public class MeasurementsController extends Controller { private final HttpExecutionContext httpExecutionContext; private final MeasurementsRepository measurementsRepository; @@ -39,8 +31,7 @@ public class MeasurementsController extends Controller { private final Materializer materializer; private MeasurementReadings activeMeasurement; - private MeasurementActor measurementActor; - private Source readingsSource; + private Flow measurementStreamFlow; @Inject public MeasurementsController(final HttpExecutionContext httpExecutionContext, final MeasurementsRepository measurementsRepository, @@ -122,32 +113,29 @@ public Result getActiveMeasurement() { @BodyParser.Of(BodyParser.Json.class) public CompletableFuture addReading() { - /* - TODO: Tell the flow listening to the socket that there is new data incoming. - Maybe make new Actor from the logic below. - */ return CompletableFuture.supplyAsync(() -> { if(this.activeMeasurement == null) { - return Results.badRequest(); + return Results.badRequest("No active measurement"); } try { final JsonNode json = request().body().asJson(); - final ObjectMapper mapper = new ObjectMapper(); - final ObjectReader reader = mapper.readerFor(new TypeReference>() {}); - final List readings = reader.readValue(json); + final Reading[] array = Json.fromJson(json, Reading[].class); + final List readings = new ArrayList<>(Arrays.asList(array)); measurementsRepository.addReadings(activeMeasurement.getMeasurementId(), readings); - } catch (IOException ex) { + if(measurementStreamFlow != null && MeasurementActor.out != null) { + MeasurementActor.out.tell(Json.toJson(readings), ActorRef.noSender()); + } + return ok(); + } + catch (final Exception ex) { Logger.error("Error while adding new readings to measurement" + this.activeMeasurement.getMeasurementId(), ex); return badRequest("Error while adding new readings."); } - - return Results.ok(); }, httpExecutionContext.current()); } - public WebSocket socket() { - // The flow passes a new actor that handles the out path inside the Measurement Actor! - final Flow flow = ActorFlow.actorRef(MeasurementActor::props, actorSystem, materializer); - return WebSocket.Json.accept(request -> flow); + public WebSocket streamMeasurements() { + measurementStreamFlow = ActorFlow.actorRef(MeasurementActor::props, actorSystem, materializer); + return WebSocket.Json.accept(request -> measurementStreamFlow); } } \ No newline at end of file diff --git a/conf/routes b/conf/routes index 8e43231..8b7f894 100644 --- a/conf/routes +++ b/conf/routes @@ -15,6 +15,7 @@ POST /measurements controllers.MeasurementsController.c PUT /measurements/active/:measurementId controllers.MeasurementsController.startMeasurement(measurementId : String) DELETE /measurements/active controllers.MeasurementsController.stopMeasurement POST /measurements/active/readings controllers.MeasurementsController.addReading +GET /streamMeasurements controllers.MeasurementsController.streamMeasurements # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) From 126804be4ba8ba64d857642cb358a2a04da90a14 Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Mon, 30 Apr 2018 13:51:33 +0200 Subject: [PATCH 11/13] FLUX-109 Explicitly handle WebSocket close --- app/actors/measurements/MeasurementActor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/actors/measurements/MeasurementActor.java b/app/actors/measurements/MeasurementActor.java index 8aef99a..440cef1 100644 --- a/app/actors/measurements/MeasurementActor.java +++ b/app/actors/measurements/MeasurementActor.java @@ -27,4 +27,10 @@ public Receive createReceive() { }) .build(); } + + @Override + public void postStop() throws Exception { + super.postStop(); + out = null; + } } From cdf5668720f0d4bbfc42e1bb3d0ae3ba9ca0531b Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Mon, 30 Apr 2018 14:06:11 +0200 Subject: [PATCH 12/13] Removed unused actor protocol --- app/actors/measurements/MeasurementActor.java | 12 +++++------- .../measurements/MeasurementActorProtocol.java | 14 -------------- 2 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 app/actors/measurements/MeasurementActorProtocol.java diff --git a/app/actors/measurements/MeasurementActor.java b/app/actors/measurements/MeasurementActor.java index 440cef1..0c994a0 100644 --- a/app/actors/measurements/MeasurementActor.java +++ b/app/actors/measurements/MeasurementActor.java @@ -4,11 +4,9 @@ import akka.actor.ActorRef; import akka.actor.Props; import models.Reading; -import play.mvc.WebSocket; - -import static actors.measurements.MeasurementActorProtocol.*; public class MeasurementActor extends AbstractActor { + // HACK: ELU Had to make the Actor Ref public static, until I find a way to find the actor inside the actorsystem (and tell him something). public static ActorRef out; public static Props props(ActorRef out) { @@ -22,10 +20,10 @@ public MeasurementActor(final ActorRef out) { @Override public Receive createReceive() { return receiveBuilder() - .match(Reading.class, putReading -> { - out.tell(putReading, self()); - }) - .build(); + .match(Reading.class, putReading -> { + out.tell(putReading, self()); + }) + .build(); } @Override diff --git a/app/actors/measurements/MeasurementActorProtocol.java b/app/actors/measurements/MeasurementActorProtocol.java deleted file mode 100644 index 14def97..0000000 --- a/app/actors/measurements/MeasurementActorProtocol.java +++ /dev/null @@ -1,14 +0,0 @@ -package actors.measurements; - -import models.Reading; - -public class MeasurementActorProtocol { - - public static class PutReading { - public final Reading reading; - - public PutReading(final Reading reading) { - this.reading = reading; - } - } -} From 4cea5af59f806beb81c0830f24b9fd2ab26df7aa Mon Sep 17 00:00:00 2001 From: Esteban Luchsinger Date: Tue, 1 May 2018 17:42:26 +0200 Subject: [PATCH 13/13] Updated results --- app/controllers/MeasurementsController.java | 6 ++++-- conf/routes | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/MeasurementsController.java b/app/controllers/MeasurementsController.java index c776f60..dc743d6 100644 --- a/app/controllers/MeasurementsController.java +++ b/app/controllers/MeasurementsController.java @@ -106,7 +106,9 @@ public Result stopMeasurement() { public Result getActiveMeasurement() { if(this.activeMeasurement != null){ - return Results.ok(Json.toJson(this.activeMeasurement)); + final MeasurementReadings activeMeasurement = this.measurementsRepository + .getMeasurementReadingsById(this.activeMeasurement.getMeasurementId()); + return Results.ok(Json.toJson(activeMeasurement)); } return Results.noContent(); } @@ -115,7 +117,7 @@ public Result getActiveMeasurement() { public CompletableFuture addReading() { return CompletableFuture.supplyAsync(() -> { if(this.activeMeasurement == null) { - return Results.badRequest("No active measurement"); + return Results.noContent(); } try { final JsonNode json = request().body().asJson(); diff --git a/conf/routes b/conf/routes index 8b7f894..257d420 100644 --- a/conf/routes +++ b/conf/routes @@ -15,7 +15,7 @@ POST /measurements controllers.MeasurementsController.c PUT /measurements/active/:measurementId controllers.MeasurementsController.startMeasurement(measurementId : String) DELETE /measurements/active controllers.MeasurementsController.stopMeasurement POST /measurements/active/readings controllers.MeasurementsController.addReading -GET /streamMeasurements controllers.MeasurementsController.streamMeasurements +GET /streamMeasurements controllers.MeasurementsController.streamMeasurements # Map static resources from the /public folder to the /assets URL path -GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)