From e806c188094381c7634d549999a1fc1d9450ffe8 Mon Sep 17 00:00:00 2001
From: tommi27
Date: Tue, 3 Mar 2020 11:04:58 +0100
Subject: [PATCH 01/21] added uniqueness constraints
---
.../ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java | 2 +-
.../usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java | 6 +++++-
.../ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java | 4 ++--
.../ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java | 6 +++---
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
index 7aa65e8..e8a621b 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
@@ -30,7 +30,7 @@ public abstract class Device {
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
*/
- @Column(name = "room_id", nullable = false)
+ @Column(name = "room_id", nullable = false, unique = true)
@NotNull
private Long roomId;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
index 0a90998..7f4056b 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
@@ -33,7 +33,11 @@ public class KnobDimmer extends Dimmer {
dl.setIntensity((dl.getIntensity() + 5) % 105);
} else {
dl.setIntensity(dl.getIntensity() + (5 - remainder));
- dl.setIntensity((dl.getIntensity() - 5) % 105);
+ if (dl.getIntensity() == 0) {
+ dl.setIntensity(100);
+ } else {
+ dl.setIntensity(dl.getIntensity() - 5);
+ }
}
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
index e15805b..f6edfd3 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
@@ -10,7 +10,7 @@ public class Room {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
- @Column(name = "id", updatable = false, nullable = false)
+ @Column(name = "id", updatable = false, nullable = false, unique = true)
@ApiModelProperty(hidden = true)
private Long id;
@@ -33,7 +33,7 @@ public class Room {
* inserting from a REST call.
*/
@NotNull
- @Column(name = "user_id", nullable = false)
+ @Column(name = "user_id", nullable = false, unique = true)
private Long userId;
/** The user given name of this room (e.g. 'Master bedroom') */
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
index 67f95d4..e33b130 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
@@ -14,7 +14,7 @@ public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
- @Column(name = "id", updatable = false, nullable = false)
+ @Column(name = "id", updatable = false, nullable = false, unique = true)
@ApiModelProperty(hidden = true)
private Long id;
@@ -24,9 +24,9 @@ public class User {
@NotEmpty(message = "Please provide a full name")
private String name;
- /** The full name of the user */
+ /** The full username of the user */
@NotNull
- @Column(nullable = false)
+ @Column(nullable = false, unique = true)
@NotEmpty(message = "Please provide a username")
private String username;
From 7cd2b44a447dd4c13b7d8799040c34f04f53bb76 Mon Sep 17 00:00:00 2001
From: tommi27
Date: Wed, 4 Mar 2020 15:25:53 +0100
Subject: [PATCH 02/21] added gitignore for iml files
---
.gitignore | 3 +++
backend.iml | 12 ------------
2 files changed, 3 insertions(+), 12 deletions(-)
delete mode 100644 backend.iml
diff --git a/.gitignore b/.gitignore
index 1b1a367..ee01dda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,3 +136,6 @@ gradle-app.setting
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
+
+# IntelliJ
+*.iml
\ No newline at end of file
diff --git a/backend.iml b/backend.iml
deleted file mode 100644
index 1eae0df..0000000
--- a/backend.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
From 749d79d51e5149fd33fd293d79f2c09ae34d5666 Mon Sep 17 00:00:00 2001
From: tommi27
Date: Wed, 4 Mar 2020 16:07:23 +0100
Subject: [PATCH 03/21] added skeleton for websockets
---
build.gradle | 1 +
.../smarthut/websocket/HouseEndpoint.java | 24 +++++++++++++++++
.../smarthut/websocket/WebSocketConfig.java | 26 +++++++++++++++++++
3 files changed, 51 insertions(+)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
diff --git a/build.gradle b/build.gradle
index d511c0b..4f4082f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,6 +15,7 @@ repositories {
dependencies {
compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
+ compile "org.springframework.boot:spring-boot-starter-websocket"
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
new file mode 100644
index 0000000..2e6de11
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
@@ -0,0 +1,24 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.websocket;
+
+import java.io.IOException;
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(
+ value =
+ "theEndpointMustHaveAShotNameBecauseAndreaBritesMartesMaronesIsAVeryNiceProgrammerThatMustTypeThisByHand.exe") // DONE: choose path
+public class HouseEndpoint {
+ private Session session;
+
+ @OnOpen
+ public void onOpen(Session session) throws IOException {}
+
+ @OnMessage
+ public void onMessage() throws IOException {}
+
+ @OnClose
+ public void onClose() {}
+
+ @OnError
+ public void onError() {}
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
new file mode 100644
index 0000000..d5ea39a
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
@@ -0,0 +1,26 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.websocket;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.messaging.simp.config.MessageBrokerRegistry;
+import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
+import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
+import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
+
+@Configuration
+@EnableWebSocketMessageBroker
+public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
+
+ @Override
+ public void registerStompEndpoints(StompEndpointRegistry registry) {
+ registry.addEndpoint("/house")
+ .setAllowedOrigins("domainURL")
+ .withSockJS(); // TODO: set domain URL
+ }
+
+ /** Creates message brokers in-memory to send and receive messages for topic and queue route */
+ @Override
+ public void configureMessageBroker(MessageBrokerRegistry config) {
+ config.enableSimpleBroker("/topic/", "/queue/");
+ config.setApplicationDestinationPrefixes("/app");
+ }
+}
From 5995bfcad220dba7eb1222a4d4f3504580c20e50 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Thu, 12 Mar 2020 17:47:40 +0100
Subject: [PATCH 04/21] Allowed failures (for now) for CPD check
---
.gitlab-ci.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 948be0a..fc62202 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -58,3 +58,4 @@ code_quality:
- build/reports/cpd/cpdCheck.xml
#create a report on the quality of the code
expose_as: 'Code Quality Report'
+ allow_failure: true
From 7bb05b705f721e6411690f7afd71ce0428733945 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Fri, 13 Mar 2020 15:48:03 +0100
Subject: [PATCH 05/21] Neutralized id value from client in device routes for
creation. Reconfigured Springfox for authentication in device and room
routes.
---
.../smarthut/config/SpringFoxConfig.java | 43 ++++++++++++------
.../smarthut/controller/DeviceController.java | 44 +++++++++++++++++++
.../controller/DimmableLightController.java | 1 +
.../controller/KnobDimmerController.java | 1 +
.../controller/MotionSensorController.java | 1 +
.../controller/RegularLightController.java | 1 +
.../smarthut/controller/RoomController.java | 4 +-
.../smarthut/controller/SensorController.java | 1 +
.../controller/SmartPlugController.java | 1 +
.../smarthut/controller/SwitchController.java | 1 +
.../controller/WelcomeController.java | 15 -------
.../smarthut/dto/ButtonDimmerSaveRequest.java | 4 ++
.../smarthut/dto/DeviceSaveRequest.java | 42 ++++++++++++++++++
.../dto/DimmableLightSaveRequest.java | 4 ++
.../smarthut/dto/KnobDimmerSaveRequest.java | 4 ++
.../smarthut/dto/MotionSensorSaveRequest.java | 4 ++
.../smarthut/dto/RegularLightSaveRequest.java | 4 ++
.../smarthut/dto/SensorSaveRequest.java | 4 ++
.../smarthut/dto/SmartPlugSaveRequest.java | 4 ++
.../smarthut/dto/SwitchSaveRequest.java | 4 ++
.../smarthut/error/BadDataException.java | 11 +++++
.../sa4/sanmarinoes/smarthut/models/Room.java | 14 +++---
22 files changed, 174 insertions(+), 38 deletions(-)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/WelcomeController.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DeviceSaveRequest.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/BadDataException.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java
index 4011592..2fdab4e 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java
@@ -1,6 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
-import static springfox.documentation.builders.PathSelectors.regex;
import java.util.List;
import java.util.function.Predicate;
@@ -10,10 +9,9 @@ import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.ApiKey;
-import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@@ -39,7 +37,8 @@ public class SpringFoxConfig {
.paths(paths()::test)
.build()
.apiInfo(apiInfo())
- .securitySchemes(securitySchemes());
+ .securitySchemes(securitySchemes())
+ .securityContexts(List.of(securityContext()));
}
/**
@@ -51,14 +50,32 @@ public class SpringFoxConfig {
return List.of(new ApiKey("Bearer", "Authorization", "header"));
}
- /**
- * Return a Java functional API predicate for regex matches
- *
- * @param regex the regex to match on
- * @return a Java functional API predicate
- */
- private Predicate regexPredicate(final String regex) {
- return regex(regex)::apply;
+ private SecurityContext securityContext() {
+ return SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .forPaths(authenticatedPaths()::test)
+ .build();
+ }
+
+ private List defaultAuth() {
+ final AuthorizationScope authorizationScope =
+ new AuthorizationScope("global", "accessEverything");
+ return List.of(
+ new SecurityReference("Bearer", new AuthorizationScope[] {authorizationScope}));
+ }
+
+ private Predicate authenticatedPaths() {
+ return ((Predicate) PathSelectors.regex("/auth/update")::apply)
+ .or(PathSelectors.regex("/room.*")::apply)
+ .or(PathSelectors.regex("/device.*")::apply)
+ .or(PathSelectors.regex("/buttonDimmer.*")::apply)
+ .or(PathSelectors.regex("/dimmableLight.*")::apply)
+ .or(PathSelectors.regex("/knobDimmer.*")::apply)
+ .or(PathSelectors.regex("/regularLight.*")::apply)
+ .or(PathSelectors.regex("/sensor.*")::apply)
+ .or(PathSelectors.regex("/smartPlug.*")::apply)
+ .or(PathSelectors.regex("/switch.*")::apply)
+ .or(PathSelectors.regex("/motionSensor.*")::apply);
}
/**
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
new file mode 100644
index 0000000..fa3242d
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
@@ -0,0 +1,44 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
+
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DeviceSaveRequest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.error.BadDataException;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RoomRepository;
+import javax.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@EnableAutoConfiguration
+@RequestMapping("/device")
+public class DeviceController {
+
+ @Autowired private DeviceRepository deviceRepository;
+ @Autowired private RoomRepository roomRepository;
+
+ @PutMapping
+ public Device update(@Valid @RequestBody DeviceSaveRequest deviceSaveRequest)
+ throws NotFoundException, BadDataException {
+ final Device d =
+ deviceRepository
+ .findById(deviceSaveRequest.getId())
+ .orElseThrow(NotFoundException::new);
+
+ // check if roomId is valid
+ roomRepository
+ .findById(deviceSaveRequest.getRoomId())
+ .orElseThrow(() -> new BadDataException("roomId is not a valid room id"));
+
+ d.setRoomId(deviceSaveRequest.getRoomId());
+ d.setName(deviceSaveRequest.getName());
+
+ deviceRepository.save(d);
+ return d;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
index 3220b76..063a4a6 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
@@ -42,6 +42,7 @@ public class DimmableLightController {
@PutMapping
public DimmableLight update(@Valid @RequestBody DimmableLightSaveRequest dl) {
+ dl.setId(0);
return this.create(dl);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
index 81f54ea..6544c8d 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
@@ -42,6 +42,7 @@ public class KnobDimmerController {
@PutMapping
public KnobDimmer update(@Valid @RequestBody KnobDimmerSaveRequest kd) {
+ kd.setId(0);
return this.create(kd);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
index a09f900..c0ba65a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
@@ -42,6 +42,7 @@ public class MotionSensorController {
@PutMapping
public MotionSensor update(@Valid @RequestBody MotionSensorSaveRequest ms) {
+ ms.setId(0);
return this.create(ms);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
index 061f12c..acffb30 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
@@ -49,6 +49,7 @@ public class RegularLightController {
@PutMapping
public RegularLight update(@Valid @RequestBody RegularLightSaveRequest rl) {
+ rl.setId(0);
return this.create(rl);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
index 3a2ba78..a5e6436 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
@@ -44,12 +44,12 @@ public class RoomController {
newRoom.setUserId(userId);
newRoom.setName(r.getName());
if (img != null) {
- newRoom.setImage(img.getBytes());
+ newRoom.setImage(img);
} else if (setWhenNull) {
newRoom.setImage(null);
}
if (icon != null) {
- newRoom.setIcon(icon.getBytes());
+ newRoom.setIcon(icon);
} else if (setWhenNull) {
newRoom.setIcon(null);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
index d738a37..cceb05a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
@@ -43,6 +43,7 @@ public class SensorController {
@PutMapping
public Sensor update(@Valid @RequestBody SensorSaveRequest s) {
+ s.setId(0);
return this.create(s);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
index 43b66d9..e05ce72 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
@@ -42,6 +42,7 @@ public class SmartPlugController {
@PutMapping
public SmartPlug update(@Valid @RequestBody SmartPlugSaveRequest sp) {
+ sp.setId(0);
return this.create(sp);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
index 5df72cf..9166e15 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
@@ -42,6 +42,7 @@ public class SwitchController {
@PutMapping
public Switch update(@Valid @RequestBody SwitchSaveRequest s) {
+ s.setId(0);
return this.create(s);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/WelcomeController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/WelcomeController.java
deleted file mode 100644
index a81eec6..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/WelcomeController.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
-
-import org.springframework.boot.autoconfigure.*;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@EnableAutoConfiguration
-public class WelcomeController {
-
- @GetMapping
- ResponseEntity testConnection() {
- return ResponseEntity.ok(null);
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
index 31a22d8..7dda699 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
@@ -60,4 +60,8 @@ public class ButtonDimmerSaveRequest {
public String getName() {
return name;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DeviceSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DeviceSaveRequest.java
new file mode 100644
index 0000000..a975117
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DeviceSaveRequest.java
@@ -0,0 +1,42 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class DeviceSaveRequest {
+ /** Device identifier */
+ private long id;
+
+ /**
+ * The room this device belongs in, as a foreign key id. To use when updating and inserting from
+ * a REST call.
+ */
+ @NotNull private Long roomId;
+
+ /** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
+ @NotNull @NotEmpty private String name;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public Long getRoomId() {
+ return roomId;
+ }
+
+ public void setRoomId(Long roomId) {
+ this.roomId = roomId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
index 8edff94..75fb74e 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
@@ -66,4 +66,8 @@ public class DimmableLightSaveRequest {
}
this.intensity = intensity;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
index ce053e3..73d44d2 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
@@ -48,4 +48,8 @@ public class KnobDimmerSaveRequest {
public Set getLights() {
return lights;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
index ba73495..a44c343 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
@@ -44,4 +44,8 @@ public class MotionSensorSaveRequest {
public void setDetected(boolean detected) {
this.detected = detected;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RegularLightSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RegularLightSaveRequest.java
index ac1324d..99211e5 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RegularLightSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RegularLightSaveRequest.java
@@ -45,4 +45,8 @@ public class RegularLightSaveRequest {
public void setOn(boolean on) {
this.on = on;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
index 421523c..0985db2 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
@@ -78,4 +78,8 @@ public class SensorSaveRequest {
public void setValue(int newValue) {
this.value = newValue;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SmartPlugSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SmartPlugSaveRequest.java
index 3318505..6b2f9b5 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SmartPlugSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SmartPlugSaveRequest.java
@@ -45,4 +45,8 @@ public class SmartPlugSaveRequest {
public void setOn(boolean on) {
this.on = on;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
index c7516f2..88050c0 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
@@ -45,4 +45,8 @@ public class SwitchSaveRequest {
public void setOn(boolean on) {
this.on = on;
}
+
+ public void setId(long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/BadDataException.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/BadDataException.java
new file mode 100644
index 0000000..2c6c4d4
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/BadDataException.java
@@ -0,0 +1,11 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.error;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.BAD_REQUEST)
+public class BadDataException extends Exception {
+ public BadDataException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
index e15805b..72859d5 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
@@ -20,13 +20,11 @@ public class Room {
* https://www.baeldung.com/java-base64-image-string
* https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html
*/
- @Lob
- @Column(name = "icon", columnDefinition = "TEXT")
- private byte[] icon;
+ @Column private String icon;
@Lob
@Column(name = "image", columnDefinition = "TEXT")
- private byte[] image;
+ private String image;
/**
* User that owns the house this room is in as a foreign key id. To use when updating and
@@ -65,19 +63,19 @@ public class Room {
this.name = name;
}
- public byte[] getIcon() {
+ public String getIcon() {
return icon;
}
- public void setIcon(byte[] icon) {
+ public void setIcon(String icon) {
this.icon = icon;
}
- public byte[] getImage() {
+ public String getImage() {
return image;
}
- public void setImage(byte[] image) {
+ public void setImage(String image) {
this.image = image;
}
From 3a97d408580a9a9d0064d7d1bdefd5b738fe55e9 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Fri, 13 Mar 2020 18:20:16 +0100
Subject: [PATCH 06/21] Button dimmer now with new rest conversation scheme
---
.../smarthut/config/GsonConfig.java | 14 ++++
.../smarthut/config/GsonExclude.java | 10 +++
.../controller/ButtonDimmerController.java | 64 ++++++++++++---
.../controller/DimmableLightController.java | 7 --
.../InputDeviceConnectionController.java | 81 +++++++++++++++++++
.../smarthut/dto/ButtonDimmerDimRequest.java | 34 ++++++++
.../smarthut/dto/ButtonDimmerSaveRequest.java | 37 ---------
.../dto/DimmableLightSaveRequest.java | 28 +------
.../smarthut/error/NotFoundException.java | 6 +-
.../smarthut/models/ButtonDimmer.java | 21 +++--
.../smarthut/models/DimmableLight.java | 51 ++++++++++--
.../smarthut/models/InputConnectable.java | 18 +++++
.../smarthut/models/OutputConnectable.java | 18 +++++
.../sanmarinoes/smarthut/models/Sensor.java | 2 +
14 files changed, 293 insertions(+), 98 deletions(-)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonExclude.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerDimRequest.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
index 3a2ab37..e12d9f0 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
@@ -23,6 +23,7 @@ public class GsonConfig {
private Gson gson() {
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());
+ builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
return builder.create();
}
}
@@ -34,3 +35,16 @@ class SpringfoxJsonToGsonAdapter implements JsonSerializer {
return JsonParser.parseString(json.value());
}
}
+
+/** GSON exclusion strategy to exclude attributes with @GsonExclude */
+class AnnotationExclusionStrategy implements ExclusionStrategy {
+ @Override
+ public boolean shouldSkipField(FieldAttributes f) {
+ return f.getAnnotation(GsonExclude.class) != null;
+ }
+
+ @Override
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonExclude.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonExclude.java
new file mode 100644
index 0000000..1be5551
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonExclude.java
@@ -0,0 +1,10 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface GsonExclude {}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
index 3d59036..c7984ea 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
@@ -2,11 +2,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerDimRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ButtonDimmer;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ButtonDimmerRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.List;
+import java.util.Set;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -15,37 +16,74 @@ import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@RequestMapping("/buttonDimmer")
-public class ButtonDimmerController {
- @Autowired private ButtonDimmerRepository buttonDimmerService;
+public class ButtonDimmerController
+ extends InputDeviceConnectionController {
+ private ButtonDimmerRepository buttonDimmerRepository;
+ private DimmableLightRepository dimmableLightRepository;
+
+ @Autowired
+ protected ButtonDimmerController(
+ ButtonDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
+ super(inputRepository, outputRepository);
+ this.buttonDimmerRepository = inputRepository;
+ this.dimmableLightRepository = outputRepository;
+ }
@GetMapping
public List findAll() {
- return toList(buttonDimmerService.findAll());
+ return toList(buttonDimmerRepository.findAll());
}
@GetMapping("/{id}")
public ButtonDimmer findById(@PathVariable("id") long id) throws NotFoundException {
- return buttonDimmerService.findById(id).orElseThrow(NotFoundException::new);
+ return buttonDimmerRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping
public ButtonDimmer create(@Valid @RequestBody final ButtonDimmerSaveRequest bd) {
ButtonDimmer newBD = new ButtonDimmer();
- newBD.setLights(bd.getLights());
- newBD.setId(bd.getId());
newBD.setName(bd.getName());
newBD.setRoomId(bd.getRoomId());
- return buttonDimmerService.save(newBD);
+ return buttonDimmerRepository.save(newBD);
}
- @PutMapping
- public ButtonDimmer update(@Valid @RequestBody ButtonDimmerSaveRequest bd) {
- return this.create(bd);
+ @PutMapping("/dim")
+ public Set dim(@Valid @RequestBody final ButtonDimmerDimRequest bd)
+ throws NotFoundException {
+ final ButtonDimmer buttonDimmer =
+ buttonDimmerRepository.findById(bd.getId()).orElseThrow(NotFoundException::new);
+
+ switch (bd.getDimType()) {
+ case UP:
+ buttonDimmer.increaseIntensity();
+ break;
+ case DOWN:
+ buttonDimmer.decreaseIntensity();
+ break;
+ }
+
+ dimmableLightRepository.saveAll(buttonDimmer.getLights());
+
+ return buttonDimmer.getOutputs();
+ }
+
+ @PostMapping("/{id}/lights")
+ public Set addLight(
+ @PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
+ throws NotFoundException {
+ return addOutput(inputId, lightId);
+ }
+
+ @DeleteMapping("/{id}/lights")
+ public Set removeLight(
+ @PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
+ throws NotFoundException {
+ return removeOutput(inputId, lightId);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) {
- buttonDimmerService.deleteById(id);
+ buttonDimmerRepository.deleteById(id);
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
index 063a4a6..898b035 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
@@ -33,19 +33,12 @@ public class DimmableLightController {
public DimmableLight create(@Valid @RequestBody DimmableLightSaveRequest dl) {
DimmableLight newDL = new DimmableLight();
newDL.setIntensity(dl.getIntensity());
- newDL.setId(dl.getId());
newDL.setName(dl.getName());
newDL.setRoomId(dl.getRoomId());
return dimmableLightService.save(newDL);
}
- @PutMapping
- public DimmableLight update(@Valid @RequestBody DimmableLightSaveRequest dl) {
- dl.setId(0);
- return this.create(dl);
- }
-
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) {
dimmableLightService.deleteById(id);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
new file mode 100644
index 0000000..37e17e1
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
@@ -0,0 +1,81 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
+
+import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
+import java.util.Set;
+
+/**
+ * An abstract controller for an input device that has output connected to it. Aids to create the
+ * output add and output remove route
+ *
+ * @param the type of device this controller is for
+ * @param the output device attached to I
+ */
+public abstract class InputDeviceConnectionController<
+ I extends InputDevice & OutputConnectable,
+ O extends OutputDevice & InputConnectable> {
+
+ private class IOPair {
+ private final I input;
+ private final O output;
+
+ private IOPair(I input, O output) {
+ this.input = input;
+ this.output = output;
+ }
+ }
+
+ private DeviceRepository inputRepository;
+
+ private DeviceRepository outputReposiory;
+
+ protected InputDeviceConnectionController(
+ DeviceRepository inputRepository, DeviceRepository outputRepository) {
+ this.inputRepository = inputRepository;
+ this.outputReposiory = outputRepository;
+ }
+
+ private IOPair checkConnectionIDs(Long inputId, Long outputId) throws NotFoundException {
+ final I input =
+ inputRepository
+ .findById(inputId)
+ .orElseThrow(() -> new NotFoundException("input device"));
+ final O output =
+ outputReposiory
+ .findById(outputId)
+ .orElseThrow(() -> new NotFoundException("output device"));
+ return new IOPair(input, output);
+ }
+
+ /**
+ * Implements the output device connection creation (add) route
+ *
+ * @param inputId input device id
+ * @param outputId output device id
+ * @return the list of output devices attached to the input device of id inputId
+ * @throws NotFoundException if inputId or outputId are not valid
+ */
+ protected Set addOutput(Long inputId, Long outputId) throws NotFoundException {
+ final IOPair pair = checkConnectionIDs(inputId, outputId);
+ pair.input.getOutputs().add(pair.output);
+ pair.output.connect(pair.input.getId());
+ outputReposiory.save(pair.output);
+ return pair.input.getOutputs();
+ }
+
+ /**
+ * Implements the output device connection destruction (remove) route
+ *
+ * @param inputId input device id
+ * @param outputId output device id
+ * @return the list of output devices attached to the input device of id inputId
+ * @throws NotFoundException if inputId or outputId are not valid
+ */
+ protected Set removeOutput(Long inputId, Long outputId) throws NotFoundException {
+ final IOPair pair = checkConnectionIDs(inputId, outputId);
+ pair.input.getOutputs().remove(pair.output);
+ pair.output.connect(null);
+ outputReposiory.save(pair.output);
+ return pair.input.getOutputs();
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerDimRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerDimRequest.java
new file mode 100644
index 0000000..8e07015
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerDimRequest.java
@@ -0,0 +1,34 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+
+import javax.validation.constraints.NotNull;
+
+/** A 'dim' event from a button dimmer. */
+public class ButtonDimmerDimRequest {
+
+ /** The device id */
+ @NotNull private Long id;
+
+ public enum DimType {
+ UP,
+ DOWN;
+ }
+
+ /** Whether the dim is up or down */
+ @NotNull private DimType dimType;
+
+ public DimType getDimType() {
+ return dimType;
+ }
+
+ public void setDimType(DimType dimType) {
+ this.dimType = dimType;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
index 7dda699..bb0b0df 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
@@ -1,21 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLight;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Room;
-import java.util.HashSet;
-import java.util.Set;
-import javax.persistence.*;
import javax.validation.constraints.NotNull;
public class ButtonDimmerSaveRequest {
- @Lob private Set lights = new HashSet();
-
- /** Device identifier */
- private long id;
-
- /** The room this device belongs in */
- private Room room;
-
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@@ -25,18 +12,6 @@ public class ButtonDimmerSaveRequest {
/** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
@NotNull private String name;
- public Set getLights() {
- return this.lights;
- }
-
- public void setLights(Set newLights) {
- this.lights = newLights;
- }
-
- public void setRoom(Room room) {
- this.room = room;
- }
-
public void setRoomId(Long roomId) {
this.roomId = roomId;
}
@@ -45,14 +20,6 @@ public class ButtonDimmerSaveRequest {
this.name = name;
}
- public long getId() {
- return id;
- }
-
- public Room getRoom() {
- return room;
- }
-
public Long getRoomId() {
return roomId;
}
@@ -60,8 +27,4 @@ public class ButtonDimmerSaveRequest {
public String getName() {
return name;
}
-
- public void setId(long id) {
- this.id = id;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
index 75fb74e..03e3eb0 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
@@ -1,6 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Room;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
@@ -13,12 +12,6 @@ public class DimmableLightSaveRequest {
@Max(100)
private Integer intensity = 0;
- /** Device identifier */
- private long id;
-
- /** The room this device belongs in */
- private Room room;
-
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@@ -28,10 +21,6 @@ public class DimmableLightSaveRequest {
/** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
@NotNull private String name;
- public void setRoom(Room room) {
- this.room = room;
- }
-
public void setRoomId(Long roomId) {
this.roomId = roomId;
}
@@ -40,14 +29,6 @@ public class DimmableLightSaveRequest {
this.name = name;
}
- public long getId() {
- return id;
- }
-
- public Room getRoom() {
- return room;
- }
-
public Long getRoomId() {
return roomId;
}
@@ -60,14 +41,7 @@ public class DimmableLightSaveRequest {
return intensity;
}
- public void setIntensity(Integer intensity) throws IllegalArgumentException {
- if (intensity < 0 || intensity > 100) {
- throw new IllegalArgumentException("The intensity level can't go below 0 or above 100");
- }
+ public void setIntensity(Integer intensity) {
this.intensity = intensity;
}
-
- public void setId(long id) {
- this.id = id;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/NotFoundException.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/NotFoundException.java
index 1d5f90d..471107f 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/NotFoundException.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/NotFoundException.java
@@ -6,6 +6,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class NotFoundException extends Exception {
public NotFoundException() {
- super("Not Found");
+ super("Not found");
+ }
+
+ public NotFoundException(String what) {
+ super(what + " not found");
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
index 1e5f702..2e96a73 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
@@ -1,6 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
@@ -10,7 +9,10 @@ import javax.persistence.OneToMany;
* dimmer with a '+' and a '-' button)
*/
@Entity
-public class ButtonDimmer extends Dimmer {
+public class ButtonDimmer extends Dimmer implements OutputConnectable {
+ /** The delta amount to apply to a increase or decrease intensity */
+ public static final int DIM_INCREMENT = 10;
+
public ButtonDimmer() {
super("button-dimmer");
}
@@ -18,17 +20,19 @@ public class ButtonDimmer extends Dimmer {
@OneToMany(mappedBy = "dimmer")
private Set lights;
- /** Increases the current intensity level of the dimmable light by 1 */
+ /** Increases the current intensity level of the dimmable light by DIM_INCREMENT */
public void increaseIntensity() {
for (DimmableLight dl : lights) {
- dl.setIntensity(dl.getIntensity() + 1);
+ dl.setIntensity(dl.getIntensity() + DIM_INCREMENT);
+ System.out.println("malusa: " + dl.getIntensity());
}
}
- /** Decreases the current intensity level of the dimmable light by 1 */
+ /** Decreases the current intensity level of the dimmable light by DIM_INCREMENT */
public void decreaseIntensity() {
for (DimmableLight dl : lights) {
- dl.setIntensity(dl.getIntensity() - 1);
+ dl.setIntensity(dl.getIntensity() - DIM_INCREMENT);
+ System.out.println("malusa: " + dl.getIntensity());
}
}
@@ -64,6 +68,11 @@ public class ButtonDimmer extends Dimmer {
return this.lights;
}
+ @Override
+ public Set getOutputs() {
+ return this.lights;
+ }
+
public void setLights(Set newLights) {
this.lights = newLights;
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
index a71afbc..9f82dc9 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
@@ -1,7 +1,9 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
@@ -9,18 +11,24 @@ import javax.validation.constraints.NotNull;
/** Represent a dimmable light */
@Entity
-public class DimmableLight extends Light {
+public class DimmableLight extends Light implements InputConnectable {
public DimmableLight() {
super("light");
}
- @ManyToOne private Dimmer dimmer;
+ @ManyToOne
+ @GsonExclude
+ @JoinColumn(name = "dimmer_id", updatable = false, insertable = false)
+ private Dimmer dimmer;
+
+ @Column(name = "dimmer_id")
+ private Long dimmerId;
/** The light intensity value. Goes from 0 (off) to 100 (on) */
@NotNull
@Column(nullable = false)
- @Min(1)
+ @Min(0)
@Max(100)
private Integer intensity = 0;
@@ -28,10 +36,39 @@ public class DimmableLight extends Light {
return intensity;
}
- public void setIntensity(Integer intensity) throws IllegalArgumentException {
- if (intensity < 0 || intensity > 100) {
- throw new IllegalArgumentException("The intensity level can't go below 0 or above 100");
+ /**
+ * Sets the intensity to a certain level. Out of bound values are corrected to the respective
+ * extremums. An intensity level of 0 turns the light off, but keeps the old intensity level
+ * stored.
+ *
+ * @param intensity the intensity level (may be out of bounds)
+ */
+ public void setIntensity(Integer intensity) {
+ if (intensity <= 0) {
+ this.intensity = 0;
+ setOn(false);
+ } else {
+ setOn(true);
+ if (intensity > 100) {
+ this.intensity = 100;
+ } else {
+ this.intensity = intensity;
+ }
}
- this.intensity = intensity;
+ }
+
+ @Override
+ public void setOn(boolean on) {
+ super.setOn(on);
+ if (on) {
+ intensity = 100;
+ } else {
+ intensity = 0;
+ }
+ }
+
+ @Override
+ public void connect(Long inputId) {
+ this.dimmerId = inputId;
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
new file mode 100644
index 0000000..74b6487
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
@@ -0,0 +1,18 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+
+
+/**
+ * An output device to which an input can be connected
+ *
+ * @param the type of input device that can be connected to this device
+ */
+public interface InputConnectable {
+
+ /**
+ * Connect an input device to this output device. This method should set the corresponding FK in
+ * the entity.
+ *
+ * @param inputId the input device id, null for deleting the connection
+ */
+ void connect(Long inputId);
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
new file mode 100644
index 0000000..c6360e9
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
@@ -0,0 +1,18 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+
+import java.util.Set;
+
+/**
+ * An input device to which outputs can be connected
+ *
+ * @param the type of output device that can be connected to this device
+ */
+public interface OutputConnectable {
+
+ /**
+ * Get the set of all output devices connected to this device
+ *
+ * @return The set of outputs connected to this device
+ */
+ Set getOutputs();
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
index e352a52..b1d98a2 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
@@ -42,6 +42,8 @@ public class Sensor extends InputDevice {
public void setSensor(SensorType sensor) {
this.sensor = sensor;
+
+ // TODO: setup hook for sockets live update
}
public int getValue() {
From 6fef7663dd6fb016de93200f6fec2e0ef1a310b9 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Fri, 13 Mar 2020 18:48:19 +0100
Subject: [PATCH 07/21] Knob dimmer now with new rest conversation scheme
---
.../InputDeviceConnectionController.java | 2 +-
.../controller/KnobDimmerController.java | 57 ++++++++++++++-----
.../smarthut/dto/KnobDimmerDimRequest.java | 33 +++++++++++
.../smarthut/dto/KnobDimmerSaveRequest.java | 25 --------
.../smarthut/models/ButtonDimmer.java | 2 -
.../smarthut/models/DimmableLight.java | 2 +-
.../smarthut/models/KnobDimmer.java | 47 ++++-----------
7 files changed, 88 insertions(+), 80 deletions(-)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerDimRequest.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
index 37e17e1..cbcdc98 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
@@ -13,7 +13,7 @@ import java.util.Set;
*/
public abstract class InputDeviceConnectionController<
I extends InputDevice & OutputConnectable,
- O extends OutputDevice & InputConnectable> {
+ O extends OutputDevice & InputConnectable super I>> {
private class IOPair {
private final I input;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
index 6544c8d..82d9507 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
@@ -2,11 +2,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerDimRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.KnobDimmer;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.KnobDimmerRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.List;
+import java.util.Set;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -15,39 +16,67 @@ import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@RequestMapping("/knobDimmer")
-public class KnobDimmerController {
+public class KnobDimmerController
+ extends InputDeviceConnectionController {
- @Autowired private KnobDimmerRepository knobDimmerService;
+ @Autowired private KnobDimmerRepository knobDimmerRepository;
+ @Autowired private DimmableLightRepository dimmableLightRepository;
+
+ @Autowired
+ protected KnobDimmerController(
+ KnobDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
+ super(inputRepository, outputRepository);
+ this.knobDimmerRepository = inputRepository;
+ this.dimmableLightRepository = outputRepository;
+ }
@GetMapping
public List findAll() {
- return toList(knobDimmerService.findAll());
+ return toList(knobDimmerRepository.findAll());
}
@GetMapping("/{id}")
public KnobDimmer findById(@PathVariable("id") long id) throws NotFoundException {
- return knobDimmerService.findById(id).orElseThrow(NotFoundException::new);
+ return knobDimmerRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping
public KnobDimmer create(@Valid @RequestBody KnobDimmerSaveRequest kd) {
KnobDimmer newKD = new KnobDimmer();
- newKD.setLights(kd.getLights());
- newKD.setId(kd.getId());
newKD.setName(kd.getName());
newKD.setRoomId(kd.getRoomId());
- return knobDimmerService.save(newKD);
+ return knobDimmerRepository.save(newKD);
}
- @PutMapping
- public KnobDimmer update(@Valid @RequestBody KnobDimmerSaveRequest kd) {
- kd.setId(0);
- return this.create(kd);
+ @PutMapping("/dimTo")
+ public Set dimTo(@Valid @RequestBody final KnobDimmerDimRequest bd)
+ throws NotFoundException {
+ final KnobDimmer dimmer =
+ knobDimmerRepository.findById(bd.getId()).orElseThrow(NotFoundException::new);
+
+ dimmer.setLightIntensity(bd.getIntensity());
+ dimmableLightRepository.saveAll(dimmer.getLights());
+
+ return dimmer.getOutputs();
+ }
+
+ @PostMapping("/{id}/lights")
+ public Set addLight(
+ @PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
+ throws NotFoundException {
+ return addOutput(inputId, lightId);
+ }
+
+ @DeleteMapping("/{id}/lights")
+ public Set removeLight(
+ @PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
+ throws NotFoundException {
+ return removeOutput(inputId, lightId);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) {
- knobDimmerService.deleteById(id);
+ knobDimmerRepository.deleteById(id);
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerDimRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerDimRequest.java
new file mode 100644
index 0000000..6df303a
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerDimRequest.java
@@ -0,0 +1,33 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+public class KnobDimmerDimRequest {
+
+ /** The device id */
+ @NotNull private Long id;
+
+ /** The absolute intensity value */
+ @NotNull
+ @Min(0)
+ @Max(100)
+ private Integer intensity;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getIntensity() {
+ return intensity;
+ }
+
+ public void setIntensity(Integer intensity) {
+ this.intensity = intensity;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
index 73d44d2..b1c0075 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
@@ -1,17 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLight;
-import java.util.HashSet;
-import java.util.Set;
-import javax.persistence.Lob;
import javax.validation.constraints.NotNull;
public class KnobDimmerSaveRequest {
- @Lob private Set lights = new HashSet();
-
- /** Device identifier */
- private long id;
-
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@@ -29,10 +20,6 @@ public class KnobDimmerSaveRequest {
this.name = name;
}
- public long getId() {
- return id;
- }
-
public Long getRoomId() {
return roomId;
}
@@ -40,16 +27,4 @@ public class KnobDimmerSaveRequest {
public String getName() {
return name;
}
-
- public void setLights(Set lights) {
- this.lights = lights;
- }
-
- public Set getLights() {
- return lights;
- }
-
- public void setId(long id) {
- this.id = id;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
index 2e96a73..17c09f5 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
@@ -24,7 +24,6 @@ public class ButtonDimmer extends Dimmer implements OutputConnectable {
+public class DimmableLight extends Light implements InputConnectable {
public DimmableLight() {
super("light");
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
index 0a90998..35d243c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
@@ -9,7 +9,7 @@ import javax.persistence.OneToMany;
* value, like a knob)
*/
@Entity
-public class KnobDimmer extends Dimmer {
+public class KnobDimmer extends Dimmer implements OutputConnectable {
public KnobDimmer() {
super("knob-dimmer");
}
@@ -18,49 +18,17 @@ public class KnobDimmer extends Dimmer {
private Set lights;
/**
- * Increases or decreases the current intensity level by 5, moving between absolute multiples of
- * 5 between 0 and 100, of all dimmable lights mapped to this knob
+ * Sets absolutely the intensity level of all lights connected
*
- * @param inc The direction the knob is turned with
+ * @param intensity the intensity (must be from 0 to 100)
*/
- public void modifyIntensity(boolean inc) {
+ public void setLightIntensity(int intensity) {
for (DimmableLight dl : lights) {
- int remainder = dl.getIntensity() / 5;
-
- if (inc) {
- dl.setIntensity(dl.getIntensity() - remainder);
- dl.setIntensity((dl.getIntensity() + 5) % 105);
- } else {
- dl.setIntensity(dl.getIntensity() + (5 - remainder));
- dl.setIntensity((dl.getIntensity() - 5) % 105);
- }
+ dl.setIntensity(intensity);
}
}
- /**
- * Adds a DimmableLight to this set of DimmableLights
- *
- * @param dl The DimmableLight to be added
- */
- public void addLight(DimmableLight dl) {
- lights.add(dl);
- }
-
- /**
- * Removes the given DimmableLight
- *
- * @param dl The DimmableLight to be removed
- */
- public void removeLight(DimmableLight dl) {
- lights.remove(dl);
- }
-
- /** Clears this set */
- public void clearSet() {
- lights.clear();
- }
-
public void setLights(Set lights) {
this.lights = lights;
}
@@ -68,4 +36,9 @@ public class KnobDimmer extends Dimmer {
public Set getLights() {
return lights;
}
+
+ @Override
+ public Set getOutputs() {
+ return lights;
+ }
}
From ed2900a3bc4d5e54d666252bcf7c08add800089f Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sat, 14 Mar 2020 12:40:28 +0100
Subject: [PATCH 08/21] New abstraction for connections
---
.../controller/ButtonDimmerController.java | 8 +--
.../InputDeviceConnectionController.java | 29 +++++++---
.../controller/KnobDimmerController.java | 8 +--
.../smarthut/models/ButtonDimmer.java | 58 +++----------------
.../smarthut/models/Connector.java | 47 +++++++++++++++
.../smarthut/models/DimmableLight.java | 31 +++++-----
.../sanmarinoes/smarthut/models/Dimmer.java | 15 +++++
.../smarthut/models/InputConnectable.java | 18 ------
.../smarthut/models/InputDevice.java | 5 ++
.../smarthut/models/KnobDimmer.java | 27 ++-------
.../sanmarinoes/smarthut/models/Light.java | 31 ----------
.../smarthut/models/OutputConnectable.java | 18 ------
.../smarthut/models/OutputDevice.java | 4 +-
.../smarthut/models/RegularLight.java | 21 ++++++-
.../smarthut/models/SmartPlug.java | 4 +-
.../smarthut/models/Switchable.java | 24 ++++++++
16 files changed, 170 insertions(+), 178 deletions(-)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Light.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
index c7984ea..92d14db 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
@@ -24,7 +24,7 @@ public class ButtonDimmerController
@Autowired
protected ButtonDimmerController(
ButtonDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
- super(inputRepository, outputRepository);
+ super(inputRepository, outputRepository, ButtonDimmer.CONNECTOR);
this.buttonDimmerRepository = inputRepository;
this.dimmableLightRepository = outputRepository;
}
@@ -63,20 +63,20 @@ public class ButtonDimmerController
break;
}
- dimmableLightRepository.saveAll(buttonDimmer.getLights());
+ dimmableLightRepository.saveAll(buttonDimmer.getOutputs());
return buttonDimmer.getOutputs();
}
@PostMapping("/{id}/lights")
- public Set addLight(
+ public Set extends OutputDevice> addLight(
@PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
throws NotFoundException {
return addOutput(inputId, lightId);
}
@DeleteMapping("/{id}/lights")
- public Set removeLight(
+ public Set extends OutputDevice> removeLight(
@PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
throws NotFoundException {
return removeOutput(inputId, lightId);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
index cbcdc98..52f3483 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java
@@ -12,8 +12,7 @@ import java.util.Set;
* @param the output device attached to I
*/
public abstract class InputDeviceConnectionController<
- I extends InputDevice & OutputConnectable,
- O extends OutputDevice & InputConnectable super I>> {
+ I extends InputDevice, O extends OutputDevice> {
private class IOPair {
private final I input;
@@ -29,10 +28,22 @@ public abstract class InputDeviceConnectionController<
private DeviceRepository outputReposiory;
+ private Connector connector;
+
+ /**
+ * Contstructs the controller by requiring essential object for the controller implementation
+ *
+ * @param inputRepository the input device repository
+ * @param outputRepository the output device repository
+ * @param connector a appropriate Connector instance for the I and O tyoes.
+ */
protected InputDeviceConnectionController(
- DeviceRepository inputRepository, DeviceRepository outputRepository) {
+ DeviceRepository inputRepository,
+ DeviceRepository outputRepository,
+ Connector connector) {
this.inputRepository = inputRepository;
this.outputReposiory = outputRepository;
+ this.connector = connector;
}
private IOPair checkConnectionIDs(Long inputId, Long outputId) throws NotFoundException {
@@ -55,10 +66,10 @@ public abstract class InputDeviceConnectionController<
* @return the list of output devices attached to the input device of id inputId
* @throws NotFoundException if inputId or outputId are not valid
*/
- protected Set addOutput(Long inputId, Long outputId) throws NotFoundException {
+ protected Set extends OutputDevice> addOutput(Long inputId, Long outputId)
+ throws NotFoundException {
final IOPair pair = checkConnectionIDs(inputId, outputId);
- pair.input.getOutputs().add(pair.output);
- pair.output.connect(pair.input.getId());
+ connector.connect(pair.input, pair.output, true);
outputReposiory.save(pair.output);
return pair.input.getOutputs();
}
@@ -71,10 +82,10 @@ public abstract class InputDeviceConnectionController<
* @return the list of output devices attached to the input device of id inputId
* @throws NotFoundException if inputId or outputId are not valid
*/
- protected Set removeOutput(Long inputId, Long outputId) throws NotFoundException {
+ protected Set extends OutputDevice> removeOutput(Long inputId, Long outputId)
+ throws NotFoundException {
final IOPair pair = checkConnectionIDs(inputId, outputId);
- pair.input.getOutputs().remove(pair.output);
- pair.output.connect(null);
+ connector.connect(pair.input, pair.output, false);
outputReposiory.save(pair.output);
return pair.input.getOutputs();
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
index 82d9507..4d51733 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
@@ -25,7 +25,7 @@ public class KnobDimmerController
@Autowired
protected KnobDimmerController(
KnobDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
- super(inputRepository, outputRepository);
+ super(inputRepository, outputRepository, KnobDimmer.CONNECTOR);
this.knobDimmerRepository = inputRepository;
this.dimmableLightRepository = outputRepository;
}
@@ -56,20 +56,20 @@ public class KnobDimmerController
knobDimmerRepository.findById(bd.getId()).orElseThrow(NotFoundException::new);
dimmer.setLightIntensity(bd.getIntensity());
- dimmableLightRepository.saveAll(dimmer.getLights());
+ dimmableLightRepository.saveAll(dimmer.getOutputs());
return dimmer.getOutputs();
}
@PostMapping("/{id}/lights")
- public Set addLight(
+ public Set extends OutputDevice> addLight(
@PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
throws NotFoundException {
return addOutput(inputId, lightId);
}
@DeleteMapping("/{id}/lights")
- public Set removeLight(
+ public Set extends OutputDevice> removeLight(
@PathVariable("id") long inputId, @RequestParam("lightId") Long lightId)
throws NotFoundException {
return removeOutput(inputId, lightId);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
index 17c09f5..85d4fe0 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
@@ -1,77 +1,35 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-import java.util.Set;
import javax.persistence.Entity;
-import javax.persistence.OneToMany;
/**
* Represents a dimmer that can only instruct an increase or decrease of intensity (i.e. like a
* dimmer with a '+' and a '-' button)
*/
@Entity
-public class ButtonDimmer extends Dimmer implements OutputConnectable {
+public class ButtonDimmer extends Dimmer {
+
+ public static final Connector CONNECTOR =
+ Connector.basic(ButtonDimmer::getOutputs, DimmableLight::setDimmerId);
+
/** The delta amount to apply to a increase or decrease intensity */
- public static final int DIM_INCREMENT = 10;
+ private static final int DIM_INCREMENT = 10;
public ButtonDimmer() {
super("button-dimmer");
}
- @OneToMany(mappedBy = "dimmer")
- private Set lights;
-
/** Increases the current intensity level of the dimmable light by DIM_INCREMENT */
public void increaseIntensity() {
- for (DimmableLight dl : lights) {
+ for (DimmableLight dl : getOutputs()) {
dl.setIntensity(dl.getIntensity() + DIM_INCREMENT);
}
}
/** Decreases the current intensity level of the dimmable light by DIM_INCREMENT */
public void decreaseIntensity() {
- for (DimmableLight dl : lights) {
+ for (DimmableLight dl : getOutputs()) {
dl.setIntensity(dl.getIntensity() - DIM_INCREMENT);
}
}
-
- /**
- * Adds a DimmableLight to this set of DimmableLights
- *
- * @param dl The DimmableLight to be added
- */
- public void addLight(DimmableLight dl) {
- lights.add(dl);
- }
-
- /**
- * Removes the given DimmableLight
- *
- * @param dl The DimmableLight to be removed
- */
- public void removeLight(DimmableLight dl) {
- lights.remove(dl);
- }
-
- /** Clears this set */
- public void clearSet() {
- lights.clear();
- }
-
- /**
- * Get the lights
- *
- * @return duh
- */
- public Set getLights() {
- return this.lights;
- }
-
- @Override
- public Set getOutputs() {
- return this.lights;
- }
-
- public void setLights(Set newLights) {
- this.lights = newLights;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
new file mode 100644
index 0000000..dd68b10
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
@@ -0,0 +1,47 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+/**
+ * A rule on how to connect an input device type to an output device type
+ *
+ * @param the input device type
+ * @param the output device type
+ */
+@FunctionalInterface
+public interface Connector {
+
+ /**
+ * Connects or disconnects input to output
+ *
+ * @param input the input device
+ * @param output the output device
+ * @param connect true if connection, false if disconnection
+ */
+ void connect(I input, O output, boolean connect);
+
+ /**
+ * Produces a basic implementation of a connector, assuming there is a OneToMany relationship
+ * between J and K
+ *
+ * @param outputsGetter the getter method of the set of outputs on the input class
+ * @param inputSetter the setter method for the input id on the output class
+ * @param the input device type
+ * @param the output device type
+ * @return a Connector implementation for the pair of types J and K
+ */
+ static Connector basic(
+ Function> outputsGetter, BiConsumer inputSetter) {
+ return (i, o, connect) -> {
+ if (connect) {
+ outputsGetter.apply(i).add(o);
+ } else {
+ outputsGetter.apply(i).remove(o);
+ }
+
+ inputSetter.accept(o, connect ? i.getId() : null);
+ };
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
index 486203b..277a7e9 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
@@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull;
/** Represent a dimmable light */
@Entity
-public class DimmableLight extends Light implements InputConnectable {
+public class DimmableLight extends OutputDevice implements Switchable {
public DimmableLight() {
super("light");
@@ -46,29 +46,24 @@ public class DimmableLight extends Light implements InputConnectable {
public void setIntensity(Integer intensity) {
if (intensity <= 0) {
this.intensity = 0;
- setOn(false);
+ } else if (intensity > 100) {
+ this.intensity = 100;
} else {
- setOn(true);
- if (intensity > 100) {
- this.intensity = 100;
- } else {
- this.intensity = intensity;
- }
+ this.intensity = intensity;
}
}
+ @Override
+ public boolean isOn() {
+ return intensity != 0;
+ }
+
@Override
public void setOn(boolean on) {
- super.setOn(on);
- if (on) {
- intensity = 100;
- } else {
- intensity = 0;
- }
+ intensity = on ? 100 : 0;
}
- @Override
- public void connect(Long inputId) {
- this.dimmerId = inputId;
- }
+ public void setDimmerId(Long dimmerId) {
+ this.dimmerId = dimmerId;
+ };
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java
index 2658b35..af00025 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java
@@ -1,8 +1,10 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
+import javax.persistence.OneToMany;
/** Represents a generic dimmer input device */
@Entity
@@ -11,4 +13,17 @@ public abstract class Dimmer extends InputDevice {
public Dimmer(String kind) {
super(kind);
}
+
+ @OneToMany(mappedBy = "dimmer")
+ private Set lights;
+
+ /**
+ * Get the lights connected to this dimmer
+ *
+ * @return duh
+ */
+ @Override
+ public Set getOutputs() {
+ return this.lights;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
deleted file mode 100644
index 74b6487..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputConnectable.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-
-
-/**
- * An output device to which an input can be connected
- *
- * @param the type of input device that can be connected to this device
- */
-public interface InputConnectable {
-
- /**
- * Connect an input device to this output device. This method should set the corresponding FK in
- * the entity.
- *
- * @param inputId the input device id, null for deleting the connection
- */
- void connect(Long inputId);
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
index e632178..ad96347 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
@@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import java.util.Set;
import javax.persistence.Entity;
/**
@@ -11,4 +12,8 @@ public abstract class InputDevice extends Device {
public InputDevice(String kind) {
super(kind, FlowType.INPUT);
}
+
+ public Set extends OutputDevice> getOutputs() {
+ return Set.of();
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
index 35d243c..d4eea0e 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
@@ -1,44 +1,29 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-import java.util.Set;
import javax.persistence.Entity;
-import javax.persistence.OneToMany;
/**
* Represents a dimmer able to set absolute intensity values (i.e. knowing the absolute intensity
* value, like a knob)
*/
@Entity
-public class KnobDimmer extends Dimmer implements OutputConnectable {
+public class KnobDimmer extends Dimmer {
+
+ public static final Connector CONNECTOR =
+ Connector.basic(KnobDimmer::getOutputs, DimmableLight::setDimmerId);
+
public KnobDimmer() {
super("knob-dimmer");
}
- @OneToMany(mappedBy = "dimmer")
- private Set lights;
-
/**
* Sets absolutely the intensity level of all lights connected
*
* @param intensity the intensity (must be from 0 to 100)
*/
public void setLightIntensity(int intensity) {
-
- for (DimmableLight dl : lights) {
+ for (DimmableLight dl : getOutputs()) {
dl.setIntensity(intensity);
}
}
-
- public void setLights(Set lights) {
- this.lights = lights;
- }
-
- public Set getLights() {
- return lights;
- }
-
- @Override
- public Set getOutputs() {
- return lights;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Light.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Light.java
deleted file mode 100644
index 68a819b..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Light.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Inheritance;
-import javax.persistence.InheritanceType;
-import javax.validation.constraints.NotNull;
-
-/** Represents a generic light */
-@Entity
-@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public abstract class Light extends OutputDevice {
-
- /** Whether the light is on or not */
- @Column(name = "light_on", nullable = false)
- @NotNull
- boolean on;
-
- protected Light(String kind) {
- super(kind);
- this.on = false;
- }
-
- public boolean isOn() {
- return on;
- }
-
- public void setOn(boolean on) {
- this.on = on;
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
deleted file mode 100644
index c6360e9..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputConnectable.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-
-import java.util.Set;
-
-/**
- * An input device to which outputs can be connected
- *
- * @param the type of output device that can be connected to this device
- */
-public interface OutputConnectable {
-
- /**
- * Get the set of all output devices connected to this device
- *
- * @return The set of outputs connected to this device
- */
- Set getOutputs();
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputDevice.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputDevice.java
index 39e5dd0..c5b401f 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputDevice.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/OutputDevice.java
@@ -1,8 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-import javax.persistence.Entity;
-import javax.persistence.Inheritance;
-import javax.persistence.InheritanceType;
+import javax.persistence.*;
/**
* Represents a generic output device, i.e. something that causes some behaviour (light, smartPlugs,
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
index 8f07377..02b5f35 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
@@ -1,11 +1,30 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.validation.constraints.NotNull;
/** Represents a standard non-dimmable light */
@Entity
-public class RegularLight extends Light {
+public class RegularLight extends OutputDevice implements Switchable {
+
+ /** Whether the light is on or not */
+ @Column(name = "light_on", nullable = false)
+ @NotNull
+ boolean on;
+
public RegularLight() {
super("regular-light");
+ this.on = false;
+ }
+
+ @Override
+ public boolean isOn() {
+ return on;
+ }
+
+ @Override
+ public void setOn(boolean on) {
+ this.on = on;
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
index e0d7981..6a77a13 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
@@ -6,17 +6,19 @@ import javax.validation.constraints.NotNull;
/** A smart plug that can be turned either on or off */
@Entity
-public class SmartPlug extends OutputDevice {
+public class SmartPlug extends OutputDevice implements Switchable {
/** Whether the smart plug is on */
@Column(name = "smart_plug_on", nullable = false)
@NotNull
private boolean on;
+ @Override
public boolean isOn() {
return on;
}
+ @Override
public void setOn(boolean on) {
this.on = on;
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
new file mode 100644
index 0000000..e13eea1
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
@@ -0,0 +1,24 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+
+/** A device that can be turned either on or off */
+public interface Switchable {
+
+ /**
+ * Returns whether the device is on (true) or not (false)
+ *
+ * @return whether the device is on (true) or not (false)
+ */
+ boolean isOn();
+
+ /**
+ * Sets the on status of the device
+ *
+ * @param on the new on status: true for on, false for off
+ */
+ void setOn(boolean on);
+
+ /** Toggle between on are off state */
+ default void toggle() {
+ setOn(!isOn());
+ }
+}
From f52a38082ccddcb8fd4af7ca08b1f650f1dd254f Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sat, 14 Mar 2020 16:59:56 +0100
Subject: [PATCH 09/21] General rewrite of device controllers. Now only output
devices can be changes with a PUT call on their controller. Other devices use
the generic controller.
---
.../controller/ButtonDimmerController.java | 9 ++-
.../controller/DimmableLightController.java | 20 ++++--
.../controller/KnobDimmerController.java | 9 ++-
.../controller/MotionSensorController.java | 12 +---
.../controller/RegularLightController.java | 17 +++--
.../smarthut/controller/SensorController.java | 8 ---
.../controller/SmartPlugController.java | 15 +++--
.../smarthut/controller/SwitchController.java | 64 ++++++++++++++++---
.../dto/DimmableLightSaveRequest.java | 11 ++++
...est.java => GenericDeviceSaveReguest.java} | 2 +-
.../smarthut/dto/KnobDimmerSaveRequest.java | 30 ---------
.../smarthut/dto/MotionSensorSaveRequest.java | 51 ---------------
.../smarthut/dto/SensorSaveRequest.java | 22 -------
.../smarthut/dto/SwitchOperationRequest.java | 35 ++++++++++
.../smarthut/dto/SwitchSaveRequest.java | 52 ---------------
.../smarthut/models/ButtonDimmer.java | 3 -
.../smarthut/models/Connector.java | 2 +-
.../smarthut/models/DimmableLight.java | 16 ++++-
.../models/DimmableLightRepository.java | 2 +-
.../smarthut/models/InputDevice.java | 3 +
.../smarthut/models/KnobDimmer.java | 3 -
.../smarthut/models/RegularLight.java | 2 +-
.../models/RegularLightRepository.java | 2 +-
.../smarthut/models/SmartPlug.java | 2 +-
.../smarthut/models/SmartPlugRepository.java | 2 +-
.../sanmarinoes/smarthut/models/Switch.java | 19 ++++++
.../smarthut/models/Switchable.java | 35 ++++++++--
.../smarthut/models/SwitchableRepository.java | 7 ++
28 files changed, 228 insertions(+), 227 deletions(-)
rename src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/{ButtonDimmerSaveRequest.java => GenericDeviceSaveReguest.java} (94%)
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchOperationRequest.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableRepository.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
index 92d14db..061c6b9 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java
@@ -3,7 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerDimRequest;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerSaveRequest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.List;
@@ -24,7 +24,10 @@ public class ButtonDimmerController
@Autowired
protected ButtonDimmerController(
ButtonDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
- super(inputRepository, outputRepository, ButtonDimmer.CONNECTOR);
+ super(
+ inputRepository,
+ outputRepository,
+ DimmableLight.BUTTON_DIMMER_DIMMABLE_LIGHT_CONNECTOR);
this.buttonDimmerRepository = inputRepository;
this.dimmableLightRepository = outputRepository;
}
@@ -40,7 +43,7 @@ public class ButtonDimmerController
}
@PostMapping
- public ButtonDimmer create(@Valid @RequestBody final ButtonDimmerSaveRequest bd) {
+ public ButtonDimmer create(@Valid @RequestBody final GenericDeviceSaveReguest bd) {
ButtonDimmer newBD = new ButtonDimmer();
newBD.setName(bd.getName());
newBD.setRoomId(bd.getRoomId());
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
index 898b035..dd2e1e3 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java
@@ -29,14 +29,24 @@ public class DimmableLightController {
return dimmableLightService.findById(id).orElseThrow(NotFoundException::new);
}
+ private DimmableLight save(DimmableLight initial, DimmableLightSaveRequest dl) {
+ initial.setIntensity(dl.getIntensity());
+ initial.setName(dl.getName());
+ initial.setRoomId(dl.getRoomId());
+
+ return dimmableLightService.save(initial);
+ }
+
@PostMapping
public DimmableLight create(@Valid @RequestBody DimmableLightSaveRequest dl) {
- DimmableLight newDL = new DimmableLight();
- newDL.setIntensity(dl.getIntensity());
- newDL.setName(dl.getName());
- newDL.setRoomId(dl.getRoomId());
+ return save(new DimmableLight(), dl);
+ }
- return dimmableLightService.save(newDL);
+ @PutMapping
+ public DimmableLight update(@Valid @RequestBody DimmableLightSaveRequest sp)
+ throws NotFoundException {
+ return save(
+ dimmableLightService.findById(sp.getId()).orElseThrow(NotFoundException::new), sp);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
index 4d51733..9f59889 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java
@@ -2,8 +2,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerDimRequest;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.List;
@@ -25,7 +25,10 @@ public class KnobDimmerController
@Autowired
protected KnobDimmerController(
KnobDimmerRepository inputRepository, DimmableLightRepository outputRepository) {
- super(inputRepository, outputRepository, KnobDimmer.CONNECTOR);
+ super(
+ inputRepository,
+ outputRepository,
+ DimmableLight.KNOB_DIMMER_DIMMABLE_LIGHT_CONNECTOR);
this.knobDimmerRepository = inputRepository;
this.dimmableLightRepository = outputRepository;
}
@@ -41,7 +44,7 @@ public class KnobDimmerController
}
@PostMapping
- public KnobDimmer create(@Valid @RequestBody KnobDimmerSaveRequest kd) {
+ public KnobDimmer create(@Valid @RequestBody GenericDeviceSaveReguest kd) {
KnobDimmer newKD = new KnobDimmer();
newKD.setName(kd.getName());
newKD.setRoomId(kd.getRoomId());
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
index c0ba65a..4ba03b1 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
@@ -2,7 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.MotionSensorSaveRequest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensor;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository;
@@ -30,22 +30,14 @@ public class MotionSensorController {
}
@PostMapping
- public MotionSensor create(@Valid @RequestBody MotionSensorSaveRequest ms) {
+ public MotionSensor create(@Valid @RequestBody GenericDeviceSaveReguest ms) {
MotionSensor newMS = new MotionSensor();
- newMS.setDetected(ms.isDetected());
- newMS.setId(ms.getId());
newMS.setName(ms.getName());
newMS.setRoomId(ms.getRoomId());
return motionSensorService.save(newMS);
}
- @PutMapping
- public MotionSensor update(@Valid @RequestBody MotionSensorSaveRequest ms) {
- ms.setId(0);
- return this.create(ms);
- }
-
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) {
motionSensorService.deleteById(id);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
index acffb30..15ce2e8 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java
@@ -36,10 +36,7 @@ public class RegularLightController {
return regularLightService.findById(id).orElseThrow(NotFoundException::new);
}
- @PostMapping
- public RegularLight create(@Valid @RequestBody RegularLightSaveRequest rl) {
- RegularLight newRL = new RegularLight();
- newRL.setId(rl.getId());
+ private RegularLight save(RegularLight newRL, RegularLightSaveRequest rl) {
newRL.setName(rl.getName());
newRL.setRoomId(rl.getRoomId());
newRL.setOn(rl.isOn());
@@ -47,10 +44,16 @@ public class RegularLightController {
return regularLightService.save(newRL);
}
+ @PostMapping
+ public RegularLight create(@Valid @RequestBody RegularLightSaveRequest rl) {
+ return save(new RegularLight(), rl);
+ }
+
@PutMapping
- public RegularLight update(@Valid @RequestBody RegularLightSaveRequest rl) {
- rl.setId(0);
- return this.create(rl);
+ public RegularLight update(@Valid @RequestBody RegularLightSaveRequest rl)
+ throws NotFoundException {
+ return save(
+ regularLightService.findById(rl.getId()).orElseThrow(NotFoundException::new), rl);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
index cceb05a..3412e0c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
@@ -33,20 +33,12 @@ public class SensorController {
public Sensor create(@Valid @RequestBody SensorSaveRequest s) {
Sensor newSensor = new Sensor();
newSensor.setSensor(s.getSensor());
- newSensor.setValue(s.getValue());
- newSensor.setId(s.getId());
newSensor.setName(s.getName());
newSensor.setRoomId(s.getRoomId());
return sensorRepository.save(newSensor);
}
- @PutMapping
- public Sensor update(@Valid @RequestBody SensorSaveRequest s) {
- s.setId(0);
- return this.create(s);
- }
-
@DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) {
sensorRepository.deleteById(id);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
index e05ce72..8a57430 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java
@@ -29,9 +29,7 @@ public class SmartPlugController {
return smartPlugRepository.findById(id).orElseThrow(NotFoundException::new);
}
- @PostMapping
- public SmartPlug create(@Valid @RequestBody SmartPlugSaveRequest sp) {
- SmartPlug newSP = new SmartPlug();
+ private SmartPlug save(SmartPlug newSP, SmartPlugSaveRequest sp) {
newSP.setOn(sp.isOn());
newSP.setId(sp.getId());
newSP.setName(sp.getName());
@@ -40,10 +38,15 @@ public class SmartPlugController {
return smartPlugRepository.save(newSP);
}
+ @PostMapping
+ public SmartPlug create(@Valid @RequestBody SmartPlugSaveRequest sp) {
+ return save(new SmartPlug(), sp);
+ }
+
@PutMapping
- public SmartPlug update(@Valid @RequestBody SmartPlugSaveRequest sp) {
- sp.setId(0);
- return this.create(sp);
+ public SmartPlug update(@Valid @RequestBody SmartPlugSaveRequest sp) throws NotFoundException {
+ return save(
+ smartPlugRepository.findById(sp.getId()).orElseThrow(NotFoundException::new), sp);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
index 9166e15..f90108c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java
@@ -2,7 +2,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchSaveRequest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchOperationRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.*;
@@ -15,9 +16,24 @@ import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@RequestMapping("/switch")
-public class SwitchController {
+public class SwitchController extends InputDeviceConnectionController {
- @Autowired private SwitchRepository switchRepository;
+ private SwitchRepository switchRepository;
+ private SwitchableRepository switchableRepository;
+
+ /**
+ * Contstructs the controller by requiring essential object for the controller implementation
+ *
+ * @param inputRepository the input device repository
+ * @param outputRepository the output device repository
+ */
+ @Autowired
+ protected SwitchController(
+ SwitchRepository inputRepository, SwitchableRepository outputRepository) {
+ super(inputRepository, outputRepository, Switchable.SWITCH_SWITCHABLE_CONNECTOR);
+ this.switchRepository = inputRepository;
+ this.switchableRepository = outputRepository;
+ }
@GetMapping
public List findAll() {
@@ -30,20 +46,48 @@ public class SwitchController {
}
@PostMapping
- public Switch create(@Valid @RequestBody SwitchSaveRequest s) {
+ public Switch create(@Valid @RequestBody GenericDeviceSaveReguest s) {
Switch newSwitch = new Switch();
- newSwitch.setId(s.getId());
newSwitch.setName(s.getName());
newSwitch.setRoomId(s.getRoomId());
- newSwitch.setOn(s.isOn());
return switchRepository.save(newSwitch);
}
- @PutMapping
- public Switch update(@Valid @RequestBody SwitchSaveRequest s) {
- s.setId(0);
- return this.create(s);
+ @PutMapping("/operate")
+ public Set operate(@Valid @RequestBody final SwitchOperationRequest sr)
+ throws NotFoundException {
+ final Switch s = switchRepository.findById(sr.getId()).orElseThrow(NotFoundException::new);
+
+ switch (sr.getType()) {
+ case ON:
+ s.setOn(true);
+ break;
+ case OFF:
+ s.setOn(false);
+ break;
+ case TOGGLE:
+ s.toggle();
+ break;
+ }
+
+ switchableRepository.saveAll(s.getOutputs());
+
+ return s.getOutputs();
+ }
+
+ @PostMapping("/{id}/lights")
+ public Set extends OutputDevice> addSwitchable(
+ @PathVariable("id") long inputId, @RequestParam("switchableId") Long switchableId)
+ throws NotFoundException {
+ return addOutput(inputId, switchableId);
+ }
+
+ @DeleteMapping("/{id}/lights")
+ public Set extends OutputDevice> removeSwitchable(
+ @PathVariable("id") long inputId, @RequestParam("switchableId") Long switchableId)
+ throws NotFoundException {
+ return removeOutput(inputId, switchableId);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
index 03e3eb0..01bec1a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableLightSaveRequest.java
@@ -6,6 +6,9 @@ import javax.validation.constraints.NotNull;
public class DimmableLightSaveRequest {
+ /** Device id (used only for update requests) */
+ private Long id;
+
/** The light intensity value. Goes from 0 (off) to 100 (on) */
@NotNull
@Min(1)
@@ -44,4 +47,12 @@ public class DimmableLightSaveRequest {
public void setIntensity(Integer intensity) {
this.intensity = intensity;
}
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GenericDeviceSaveReguest.java
similarity index 94%
rename from src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
rename to src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GenericDeviceSaveReguest.java
index bb0b0df..8ec2671 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ButtonDimmerSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GenericDeviceSaveReguest.java
@@ -2,7 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
import javax.validation.constraints.NotNull;
-public class ButtonDimmerSaveRequest {
+public class GenericDeviceSaveReguest {
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
deleted file mode 100644
index b1c0075..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/KnobDimmerSaveRequest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-
-import javax.validation.constraints.NotNull;
-
-public class KnobDimmerSaveRequest {
- /**
- * The room this device belongs in, as a foreign key id. To use when updating and inserting from
- * a REST call.
- */
- @NotNull private Long roomId;
-
- /** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
- @NotNull private String name;
-
- public void setRoomId(Long roomId) {
- this.roomId = roomId;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Long getRoomId() {
- return roomId;
- }
-
- public String getName() {
- return name;
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
deleted file mode 100644
index a44c343..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/MotionSensorSaveRequest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-
-import javax.validation.constraints.NotNull;
-
-public class MotionSensorSaveRequest {
- private boolean detected;
-
- /** Device identifier */
- private long id;
-
- /**
- * The room this device belongs in, as a foreign key id. To use when updating and inserting from
- * a REST call.
- */
- @NotNull private Long roomId;
-
- /** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
- @NotNull private String name;
-
- public void setRoomId(Long roomId) {
- this.roomId = roomId;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public long getId() {
- return id;
- }
-
- public Long getRoomId() {
- return roomId;
- }
-
- public String getName() {
- return name;
- }
-
- public boolean isDetected() {
- return detected;
- }
-
- public void setDetected(boolean detected) {
- this.detected = detected;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
index 0985db2..e9a5c68 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
@@ -23,17 +23,11 @@ public class SensorSaveRequest {
LIGHT
}
- /** The value of this sensor according to its sensor type */
- private int value;
-
/** The type of this sensor */
@NotNull
@Enumerated(value = EnumType.STRING)
private Sensor.SensorType sensor;
- /** Device identifier */
- private long id;
-
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@@ -51,10 +45,6 @@ public class SensorSaveRequest {
this.name = name;
}
- public long getId() {
- return id;
- }
-
public Long getRoomId() {
return roomId;
}
@@ -70,16 +60,4 @@ public class SensorSaveRequest {
public void setSensor(Sensor.SensorType sensor) {
this.sensor = sensor;
}
-
- public int getValue() {
- return this.value;
- }
-
- public void setValue(int newValue) {
- this.value = newValue;
- }
-
- public void setId(long id) {
- this.id = id;
- }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchOperationRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchOperationRequest.java
new file mode 100644
index 0000000..3fb552b
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchOperationRequest.java
@@ -0,0 +1,35 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+
+import javax.validation.constraints.NotNull;
+
+/** An on/off/toggle operation on a switch */
+public class SwitchOperationRequest {
+
+ /** The device id */
+ @NotNull private Long id;
+
+ public enum OperationType {
+ ON,
+ OFF,
+ TOGGLE
+ }
+
+ /** The type of switch operation */
+ @NotNull private SwitchOperationRequest.OperationType type;
+
+ public OperationType getType() {
+ return type;
+ }
+
+ public void setType(OperationType type) {
+ this.type = type;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
deleted file mode 100644
index 88050c0..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchSaveRequest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
-
-import javax.validation.constraints.NotNull;
-
-public class SwitchSaveRequest {
- /** The state of this switch */
- private boolean on;
-
- /** Device identifier */
- private long id;
-
- /**
- * The room this device belongs in, as a foreign key id. To use when updating and inserting from
- * a REST call.
- */
- @NotNull private Long roomId;
-
- /** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
- @NotNull private String name;
-
- public void setRoomId(Long roomId) {
- this.roomId = roomId;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public long getId() {
- return id;
- }
-
- public Long getRoomId() {
- return roomId;
- }
-
- public String getName() {
- return name;
- }
-
- public boolean isOn() {
- return on;
- }
-
- public void setOn(boolean on) {
- this.on = on;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
index 85d4fe0..fc91c22 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ButtonDimmer.java
@@ -9,9 +9,6 @@ import javax.persistence.Entity;
@Entity
public class ButtonDimmer extends Dimmer {
- public static final Connector CONNECTOR =
- Connector.basic(ButtonDimmer::getOutputs, DimmableLight::setDimmerId);
-
/** The delta amount to apply to a increase or decrease intensity */
private static final int DIM_INCREMENT = 10;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
index dd68b10..91b1e88 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Connector.java
@@ -33,7 +33,7 @@ public interface Connector {
* @return a Connector implementation for the pair of types J and K
*/
static Connector basic(
- Function> outputsGetter, BiConsumer inputSetter) {
+ Function> outputsGetter, BiConsumer inputSetter) {
return (i, o, connect) -> {
if (connect) {
outputsGetter.apply(i).add(o);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
index 277a7e9..9a75471 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLight.java
@@ -11,7 +11,14 @@ import javax.validation.constraints.NotNull;
/** Represent a dimmable light */
@Entity
-public class DimmableLight extends OutputDevice implements Switchable {
+public class DimmableLight extends Switchable {
+
+ public static final Connector
+ BUTTON_DIMMER_DIMMABLE_LIGHT_CONNECTOR =
+ Connector.basic(ButtonDimmer::getOutputs, DimmableLight::setDimmerId);
+
+ public static final Connector KNOB_DIMMER_DIMMABLE_LIGHT_CONNECTOR =
+ Connector.basic(KnobDimmer::getOutputs, DimmableLight::setDimmerId);
public DimmableLight() {
super("light");
@@ -65,5 +72,12 @@ public class DimmableLight extends OutputDevice implements Switchable {
public void setDimmerId(Long dimmerId) {
this.dimmerId = dimmerId;
+ super.setSwitchId(null);
};
+
+ @Override
+ public void setSwitchId(Long switchId) {
+ super.setSwitchId(switchId);
+ this.dimmerId = null;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightRepository.java
index 484084b..a32b3c6 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightRepository.java
@@ -1,3 +1,3 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-public interface DimmableLightRepository extends DeviceRepository {}
+public interface DimmableLightRepository extends SwitchableRepository {}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
index ad96347..da45b67 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/InputDevice.java
@@ -2,12 +2,15 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.Set;
import javax.persistence.Entity;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
/**
* A generic abstraction for an input device, i.e. something that captures input either from the
* environment (sensor) or the user (switch / dimmer).
*/
@Entity
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class InputDevice extends Device {
public InputDevice(String kind) {
super(kind, FlowType.INPUT);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
index d4eea0e..ce3745c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
@@ -9,9 +9,6 @@ import javax.persistence.Entity;
@Entity
public class KnobDimmer extends Dimmer {
- public static final Connector CONNECTOR =
- Connector.basic(KnobDimmer::getOutputs, DimmableLight::setDimmerId);
-
public KnobDimmer() {
super("knob-dimmer");
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
index 02b5f35..de9c10a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLight.java
@@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull;
/** Represents a standard non-dimmable light */
@Entity
-public class RegularLight extends OutputDevice implements Switchable {
+public class RegularLight extends Switchable {
/** Whether the light is on or not */
@Column(name = "light_on", nullable = false)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLightRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLightRepository.java
index 43c4e17..cad8831 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLightRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RegularLightRepository.java
@@ -1,3 +1,3 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-public interface RegularLightRepository extends DeviceRepository {}
+public interface RegularLightRepository extends SwitchableRepository {}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
index 6a77a13..fe936b3 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlug.java
@@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull;
/** A smart plug that can be turned either on or off */
@Entity
-public class SmartPlug extends OutputDevice implements Switchable {
+public class SmartPlug extends Switchable {
/** Whether the smart plug is on */
@Column(name = "smart_plug_on", nullable = false)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlugRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlugRepository.java
index 0b2fd344..08d145d 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlugRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SmartPlugRepository.java
@@ -1,3 +1,3 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
-public interface SmartPlugRepository extends DeviceRepository {}
+public interface SmartPlugRepository extends SwitchableRepository {}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java
index 2576d38..d819dfe 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java
@@ -1,12 +1,18 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import java.util.HashSet;
+import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.OneToMany;
/** A switch input device */
@Entity
public class Switch extends InputDevice {
+ @OneToMany(mappedBy = "switchDevice")
+ private Set switchables = new HashSet<>();
+
/** The state of this switch */
@Column(nullable = false, name = "switch_on")
private boolean on;
@@ -22,6 +28,15 @@ public class Switch extends InputDevice {
*/
public void setOn(boolean state) {
on = state;
+
+ for (final Switchable s : switchables) {
+ s.setOn(on);
+ }
+ }
+
+ /** Toggle between on and off state */
+ public void toggle() {
+ setOn(!isOn());
}
/**
@@ -32,4 +47,8 @@ public class Switch extends InputDevice {
public boolean isOn() {
return on;
}
+
+ public Set getOutputs() {
+ return switchables;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
index e13eea1..5ba0702 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switchable.java
@@ -1,24 +1,47 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
+import javax.persistence.*;
+
/** A device that can be turned either on or off */
-public interface Switchable {
+@Entity
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public abstract class Switchable extends OutputDevice {
+
+ public static final Connector SWITCH_SWITCHABLE_CONNECTOR =
+ Connector.basic(Switch::getOutputs, Switchable::setSwitchId);
+
+ @ManyToOne
+ @GsonExclude
+ @JoinColumn(name = "switch_id", updatable = false, insertable = false)
+ private Switch switchDevice;
+
+ @Column(name = "switch_id")
+ private Long switchId;
+
+ protected Switchable(String kind) {
+ super(kind);
+ }
/**
* Returns whether the device is on (true) or not (false)
*
* @return whether the device is on (true) or not (false)
*/
- boolean isOn();
+ public abstract boolean isOn();
/**
* Sets the on status of the device
*
* @param on the new on status: true for on, false for off
*/
- void setOn(boolean on);
+ public abstract void setOn(boolean on);
- /** Toggle between on are off state */
- default void toggle() {
- setOn(!isOn());
+ public Long getSwitchId() {
+ return switchId;
+ }
+
+ public void setSwitchId(Long switchId) {
+ this.switchId = switchId;
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableRepository.java
new file mode 100644
index 0000000..589542d
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableRepository.java
@@ -0,0 +1,7 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+
+/**
+ * SwitchableRepository acts as a superclass for the other repositories so to mirror in the database
+ * the class inheritance present among the various switchable devices.
+ */
+public interface SwitchableRepository extends DeviceRepository {}
From 5683bbe3e370116e2e4eeeb101cbb98a84855e12 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sat, 14 Mar 2020 19:51:01 +0100
Subject: [PATCH 10/21] Added room icons in model as enum
---
.../smarthut/controller/RoomController.java | 2 +-
.../smarthut/dto/RoomSaveRequest.java | 12 +-
.../sa4/sanmarinoes/smarthut/models/Room.java | 112 +++++++++++++++++-
3 files changed, 115 insertions(+), 11 deletions(-)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
index a5e6436..fb42037 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java
@@ -39,7 +39,7 @@ public class RoomController {
final String username = principal.getName();
final Long userId = userRepository.findByUsername(username).getId();
final String img = r.getImage();
- final String icon = r.getIcon();
+ final Room.Icon icon = r.getIcon();
newRoom.setUserId(userId);
newRoom.setName(r.getName());
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RoomSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RoomSaveRequest.java
index f813b1c..ca8fa0f 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RoomSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/RoomSaveRequest.java
@@ -1,17 +1,19 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Room;
import javax.persistence.Lob;
import javax.validation.constraints.NotNull;
public class RoomSaveRequest {
+
+ @NotNull private Room.Icon icon;
+
/**
- * Icon and image are to be given as byte[]. In order to get an encoded string from it, the
+ * Image is to be given as byte[]. In order to get an encoded string from it, the
* Base64.getEncoder().encodeToString(byte[] content) should be used. For further information:
* https://www.baeldung.com/java-base64-image-string
* https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html
*/
- @Lob private String icon;
-
@Lob private String image;
/** The user given name of this room (e.g. 'Master bedroom') */
@@ -25,11 +27,11 @@ public class RoomSaveRequest {
this.name = name;
}
- public String getIcon() {
+ public Room.Icon getIcon() {
return icon;
}
- public void setIcon(String icon) {
+ public void setIcon(Room.Icon icon) {
this.icon = icon;
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
index 72859d5..c5b196a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
@@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@@ -8,20 +9,121 @@ import javax.validation.constraints.NotNull;
@Entity
public class Room {
+ /** A collection of Semantic UI icons */
+ @SuppressWarnings("unused")
+ public enum Icon {
+ @SerializedName("home")
+ HOME("home"),
+ @SerializedName("coffee")
+ COFFEE("coffee"),
+ @SerializedName("beer")
+ BEER("beer"),
+ @SerializedName("glass martini")
+ GLASS_MARTINI("glass martini"),
+ @SerializedName("film")
+ FILM("film"),
+ @SerializedName("video")
+ VIDEO("video"),
+ @SerializedName("music")
+ MUSIC("music"),
+ @SerializedName("headphones")
+ HEADPHONES("headphones"),
+ @SerializedName("fax")
+ FAX("fax"),
+ @SerializedName("phone")
+ PHONE("phone"),
+ @SerializedName("laptop")
+ LAPTOP("laptop"),
+ @SerializedName("bath")
+ BATH("bath"),
+ @SerializedName("shower")
+ SHOWER("shower"),
+ @SerializedName("bed")
+ BED("bed"),
+ @SerializedName("child")
+ CHILD("child"),
+ @SerializedName("warehouse")
+ WAREHOUSE("warehouse"),
+ @SerializedName("car")
+ CAR("car"),
+ @SerializedName("bicycle")
+ BICYCLE("bicycle"),
+ @SerializedName("motorcycle")
+ MOTORCYCLE("motorcycle"),
+ @SerializedName("archive")
+ ARCHIVE("archive"),
+ @SerializedName("boxes")
+ BOXES("boxes"),
+ @SerializedName("cubes")
+ CUBES("cubes"),
+ @SerializedName("chess")
+ CHESS("chess"),
+ @SerializedName("gamepad")
+ GAMEPAD("gamepad"),
+ @SerializedName("futbol")
+ FUTBOL("futbol"),
+ @SerializedName("table tennis")
+ TABLE_TENNIS("table tennis"),
+ @SerializedName("server")
+ SERVER("server"),
+ @SerializedName("tv")
+ TV("tv"),
+ @SerializedName("heart")
+ HEART("heart"),
+ @SerializedName("camera")
+ CAMERA("camera"),
+ @SerializedName("trophy")
+ TROPHY("trophy"),
+ @SerializedName("wrench")
+ WRENCH("wrench"),
+ @SerializedName("image")
+ IMAGE("image"),
+ @SerializedName("book")
+ BOOK("book"),
+ @SerializedName("university")
+ UNIVERSITY("university"),
+ @SerializedName("medkit")
+ MEDKIT("medkit"),
+ @SerializedName("paw")
+ PAW("paw"),
+ @SerializedName("tree")
+ TREE("tree"),
+ @SerializedName("utensils")
+ UTENSILS("utensils"),
+ @SerializedName("male")
+ MALE("male"),
+ @SerializedName("female")
+ FEMALE("female"),
+ @SerializedName("life ring outline")
+ LIFE_RING_OUTLINE("life ring outline");
+
+ private String iconName;
+
+ Icon(String s) {
+ this.iconName = s;
+ }
+
+ @Override
+ public String toString() {
+ return iconName;
+ }
+ }
+
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
@ApiModelProperty(hidden = true)
private Long id;
+ /** The room icon, out of a set of Semantic UI icons */
+ @Column private Icon icon;
+
/**
- * Icon and image are to be given as byte[]. In order to get an encoded string from it, the
+ * Image is to be given as byte[]. In order to get an encoded string from it, the
* Base64.getEncoder().encodeToString(byte[] content) should be used. For further information:
* https://www.baeldung.com/java-base64-image-string
* https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html
*/
- @Column private String icon;
-
@Lob
@Column(name = "image", columnDefinition = "TEXT")
private String image;
@@ -63,11 +165,11 @@ public class Room {
this.name = name;
}
- public String getIcon() {
+ public Icon getIcon() {
return icon;
}
- public void setIcon(String icon) {
+ public void setIcon(Icon icon) {
this.icon = icon;
}
From 73e1328d7046ff37400bbc48f4d9d66a3076358b Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sat, 14 Mar 2020 20:07:58 +0100
Subject: [PATCH 11/21] Branch cleaning
---
build.gradle | 3 +--
.../smarthut/models/KnobDimmer.java | 6 +----
.../smarthut/websocket/HouseEndpoint.java | 24 -----------------
.../smarthut/websocket/WebSocketConfig.java | 26 -------------------
4 files changed, 2 insertions(+), 57 deletions(-)
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
diff --git a/build.gradle b/build.gradle
index 4f4082f..c7b20f6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,6 @@ repositories {
dependencies {
compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
- compile "org.springframework.boot:spring-boot-starter-websocket"
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
@@ -25,7 +24,7 @@ dependencies {
implementation 'org.postgresql:postgresql'
compile "io.springfox:springfox-swagger2:2.9.2"
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
-
+
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-json'
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
index 7f4056b..0a90998 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java
@@ -33,11 +33,7 @@ public class KnobDimmer extends Dimmer {
dl.setIntensity((dl.getIntensity() + 5) % 105);
} else {
dl.setIntensity(dl.getIntensity() + (5 - remainder));
- if (dl.getIntensity() == 0) {
- dl.setIntensity(100);
- } else {
- dl.setIntensity(dl.getIntensity() - 5);
- }
+ dl.setIntensity((dl.getIntensity() - 5) % 105);
}
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
deleted file mode 100644
index 2e6de11..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/HouseEndpoint.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.websocket;
-
-import java.io.IOException;
-import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-
-@ServerEndpoint(
- value =
- "theEndpointMustHaveAShotNameBecauseAndreaBritesMartesMaronesIsAVeryNiceProgrammerThatMustTypeThisByHand.exe") // DONE: choose path
-public class HouseEndpoint {
- private Session session;
-
- @OnOpen
- public void onOpen(Session session) throws IOException {}
-
- @OnMessage
- public void onMessage() throws IOException {}
-
- @OnClose
- public void onClose() {}
-
- @OnError
- public void onError() {}
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
deleted file mode 100644
index d5ea39a..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/websocket/WebSocketConfig.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.websocket;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.messaging.simp.config.MessageBrokerRegistry;
-import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
-import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
-import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
-
-@Configuration
-@EnableWebSocketMessageBroker
-public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
-
- @Override
- public void registerStompEndpoints(StompEndpointRegistry registry) {
- registry.addEndpoint("/house")
- .setAllowedOrigins("domainURL")
- .withSockJS(); // TODO: set domain URL
- }
-
- /** Creates message brokers in-memory to send and receive messages for topic and queue route */
- @Override
- public void configureMessageBroker(MessageBrokerRegistry config) {
- config.enableSimpleBroker("/topic/", "/queue/");
- config.setApplicationDestinationPrefixes("/app");
- }
-}
From 589ef8c3cc4de247c65d59717d4b10004427a720 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Mon, 9 Mar 2020 23:38:57 +0100
Subject: [PATCH 12/21] Imported code from secret source for websockets
(@tommi27 you don't know anything about it, right?)
---
.../smarthut/socket/SensorSocketConfig.java | 26 ++++++++++++
.../smarthut/socket/SensorSocketDecoder.java | 32 +++++++++++++++
.../smarthut/socket/SensorSocketEncoder.java | 24 +++++++++++
.../smarthut/socket/SensorSocketEndpoint.java | 41 +++++++++++++++++++
4 files changed, 123 insertions(+)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
new file mode 100644
index 0000000..7d04538
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
@@ -0,0 +1,26 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+
+import javax.websocket.server.ServerEndpointConfig;
+
+public class SensorSocketConfig extends ServerEndpointConfig.Configurator {
+
+ public static SensorSocketEndpoint getInstance() {
+ return instance;
+ }
+
+ private static SensorSocketEndpoint instance = new SensorSocketEndpoint();
+
+ @Override
+ public T getEndpointInstance(Class endpointClass) throws InstantiationException {
+ try {
+ @SuppressWarnings("unchecked")
+ final T instance = (T) SensorSocketConfig.instance;
+ return instance;
+ } catch (ClassCastException e) {
+ final var e2 =
+ new InstantiationException("Cannot cast SensorSocketEndpoint to desired type");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
new file mode 100644
index 0000000..ad3a76e
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
@@ -0,0 +1,32 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import javax.websocket.*;
+
+public class SensorSocketDecoder implements Decoder.Text {
+ private Gson decoder;
+
+ @Override
+ public void init(EndpointConfig endpointConfig) {
+ decoder = new Gson();
+ }
+
+ @Override
+ public void destroy() {}
+
+ @Override
+ public JsonObject decode(String s) throws DecodeException {
+ try {
+ return decoder.fromJson(s, JsonObject.class);
+ } catch (JsonSyntaxException e) {
+ throw new DecodeException(s, "Cannot decode sensor message", e);
+ }
+ }
+
+ @Override
+ public boolean willDecode(String s) {
+ return true;
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
new file mode 100644
index 0000000..be04293
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
@@ -0,0 +1,24 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import javax.websocket.EncodeException;
+import javax.websocket.Encoder;
+import javax.websocket.EndpointConfig;
+
+public class SensorSocketEncoder implements Encoder.Text {
+ private Gson encoder;
+
+ @Override
+ public String encode(JsonObject object) throws EncodeException {
+ return encoder.toJson(object);
+ }
+
+ @Override
+ public void init(EndpointConfig endpointConfig) {
+ encoder = new Gson();
+ }
+
+ @Override
+ public void destroy() {}
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
new file mode 100644
index 0000000..82ab767
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -0,0 +1,41 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(
+ value = "/service",
+ configurator = SensorSocketConfig.class,
+ encoders = SensorSocketEncoder.class,
+ decoders = SensorSocketDecoder.class)
+public class SensorSocketEndpoint {
+
+ private Set clients = Collections.synchronizedSet(new HashSet<>());
+
+ public Set getClients() {
+ return clients;
+ }
+
+ @OnOpen
+ public void onOpen(Session userSession) {
+ clients.add(userSession);
+ }
+
+ @OnClose
+ public void onClose(Session userSession) {
+ clients.remove(userSession);
+ }
+
+ public int broadcast(JsonObject message) throws IOException, EncodeException {
+ for (Session session : clients) {
+ System.out.println(message);
+ session.getBasicRemote().sendObject(message);
+ }
+ return clients.size();
+ }
+}
From 707291e637adcd70781dbd8496f41356780a1027 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Wed, 11 Mar 2020 16:23:58 +0100
Subject: [PATCH 13/21] Unauthenticated socket works
---
build.gradle | 2 +
gradle.yml | 39 +++++++++++++++++++
.../smarthut/config/WebSecurityConfig.java | 1 +
.../smarthut/socket/SensorSocketConfig.java | 15 +++++++
.../smarthut/socket/SensorSocketDecoder.java | 32 ---------------
.../smarthut/socket/SensorSocketEncoder.java | 24 ------------
.../smarthut/socket/SensorSocketEndpoint.java | 37 ++++++++----------
test.html | 26 +++++++++++++
8 files changed, 100 insertions(+), 76 deletions(-)
create mode 100644 gradle.yml
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
create mode 100644 test.html
diff --git a/build.gradle b/build.gradle
index d23270b..5140ea7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -23,6 +23,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-mail'
+ implementation 'org.springframework.boot:spring-boot-starter-websocket'
+ implementation 'org.springframework:spring-websocket:5.2.4.RELEASE'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'org.springframework.security:spring-security-web'
implementation 'org.postgresql:postgresql'
diff --git a/gradle.yml b/gradle.yml
new file mode 100644
index 0000000..51fefa4
--- /dev/null
+++ b/gradle.yml
@@ -0,0 +1,39 @@
+# vim: set ts=2 sw=2 et tw=80:
+image: gradle:jdk13
+
+stages:
+ - build
+ - test
+ - deploy
+
+smarthut_build:
+ stage: build
+ script:
+ - gradle assemble
+ artifacts:
+ paths:
+ - build/libs/*.jar
+ expire_in: 1 week
+
+smarthut_test:
+ stage: test
+ script:
+ - gradle check
+
+smarthut_deploy:
+ stage: deploy
+ image: docker:latest
+ services:
+ - docker:dind
+ variables:
+ DOCKER_DRIVER: overlay
+ before_script:
+ - docker version
+ - docker info
+ - docker login -u smarthutsm -p $CI_DOCKER_PASS
+ script:
+ - "docker build -t smarthutsm/smarthut:${CI_COMMIT_BRANCH} --pull ."
+ - "docker push smarthutsm/smarthut:${CI_COMMIT_BRANCH}"
+ after_script:
+ - docker logout
+
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java
index 253998d..ec116c3 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/WebSecurityConfig.java
@@ -51,6 +51,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// dont authenticate this particular request
.authorizeRequests()
.antMatchers(
+ "/sensor-socket",
"/auth/login",
"/swagger-ui.html",
"/register",
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
index 7d04538..4e032bf 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
@@ -1,7 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
import javax.websocket.server.ServerEndpointConfig;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+import org.springframework.web.socket.server.standard.ServerEndpointRegistration;
+@Configuration
public class SensorSocketConfig extends ServerEndpointConfig.Configurator {
public static SensorSocketEndpoint getInstance() {
@@ -10,6 +15,16 @@ public class SensorSocketConfig extends ServerEndpointConfig.Configurator {
private static SensorSocketEndpoint instance = new SensorSocketEndpoint();
+ @Bean
+ public ServerEndpointRegistration sensorSocketEndpoint() {
+ return new ServerEndpointRegistration("/sensor-socket", instance);
+ }
+
+ @Bean
+ public ServerEndpointExporter endpointExporter() {
+ return new ServerEndpointExporter();
+ }
+
@Override
public T getEndpointInstance(Class endpointClass) throws InstantiationException {
try {
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
deleted file mode 100644
index ad3a76e..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketDecoder.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonSyntaxException;
-import javax.websocket.*;
-
-public class SensorSocketDecoder implements Decoder.Text {
- private Gson decoder;
-
- @Override
- public void init(EndpointConfig endpointConfig) {
- decoder = new Gson();
- }
-
- @Override
- public void destroy() {}
-
- @Override
- public JsonObject decode(String s) throws DecodeException {
- try {
- return decoder.fromJson(s, JsonObject.class);
- } catch (JsonSyntaxException e) {
- throw new DecodeException(s, "Cannot decode sensor message", e);
- }
- }
-
- @Override
- public boolean willDecode(String s) {
- return true;
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
deleted file mode 100644
index be04293..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEncoder.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import javax.websocket.EncodeException;
-import javax.websocket.Encoder;
-import javax.websocket.EndpointConfig;
-
-public class SensorSocketEncoder implements Encoder.Text {
- private Gson encoder;
-
- @Override
- public String encode(JsonObject object) throws EncodeException {
- return encoder.toJson(object);
- }
-
- @Override
- public void init(EndpointConfig endpointConfig) {
- encoder = new Gson();
- }
-
- @Override
- public void destroy() {}
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
index 82ab767..36565c8 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -1,19 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.IOException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
import javax.websocket.*;
-import javax.websocket.server.ServerEndpoint;
-@ServerEndpoint(
- value = "/service",
- configurator = SensorSocketConfig.class,
- encoders = SensorSocketEncoder.class,
- decoders = SensorSocketDecoder.class)
-public class SensorSocketEndpoint {
+public class SensorSocketEndpoint extends Endpoint {
+
+ private Gson gson = new Gson();
private Set clients = Collections.synchronizedSet(new HashSet<>());
@@ -21,16 +16,6 @@ public class SensorSocketEndpoint {
return clients;
}
- @OnOpen
- public void onOpen(Session userSession) {
- clients.add(userSession);
- }
-
- @OnClose
- public void onClose(Session userSession) {
- clients.remove(userSession);
- }
-
public int broadcast(JsonObject message) throws IOException, EncodeException {
for (Session session : clients) {
System.out.println(message);
@@ -38,4 +23,16 @@ public class SensorSocketEndpoint {
}
return clients.size();
}
+
+ @Override
+ public void onOpen(Session session, EndpointConfig config) {
+ final JsonObject test = new JsonObject();
+ test.addProperty("ciao", "mamma");
+ try {
+ session.getBasicRemote().sendText(gson.toJson(test));
+ clients.add(session);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/test.html b/test.html
new file mode 100644
index 0000000..42bb82d
--- /dev/null
+++ b/test.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
From 34dce5457576e3ee9acb1e629c103f96a6d439ba Mon Sep 17 00:00:00 2001
From: tommi27
Date: Sat, 14 Mar 2020 20:17:47 +0100
Subject: [PATCH 14/21] wip
---
.../smarthut/socket/SensorSocketEndpoint.java | 38 ++++++++++++++++---
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
index 36565c8..2fde5df 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -1,27 +1,41 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtil;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.util.*;
import javax.websocket.*;
+import org.springframework.beans.factory.annotation.Autowired;
public class SensorSocketEndpoint extends Endpoint {
private Gson gson = new Gson();
- private Set clients = Collections.synchronizedSet(new HashSet<>());
+ @Autowired private JWTTokenUtil jwtTokenUtil;
- public Set getClients() {
- return clients;
+ private Set unauthorizedClients = Collections.synchronizedSet(new HashSet());
+
+ // commented out because of script not letting me push
+ // private Map< User, Set > authorizedClients = Collections.synchronizedMap(
+ // new HashMap< User, HashSet >
+ // );
+
+ public Set getUnauthorizedClients() {
+ return unauthorizedClients;
+ }
+
+ public Map> getAuthorizedClients() {
+ return authorizedClients;
}
public int broadcast(JsonObject message) throws IOException, EncodeException {
- for (Session session : clients) {
+ for (Session session : unauthorizedClients) {
System.out.println(message);
session.getBasicRemote().sendObject(message);
}
- return clients.size();
+ return unauthorizedClients.size();
}
@Override
@@ -30,9 +44,21 @@ public class SensorSocketEndpoint extends Endpoint {
test.addProperty("ciao", "mamma");
try {
session.getBasicRemote().sendText(gson.toJson(test));
- clients.add(session);
+ unauthorizedClients.add(session);
} catch (IOException e) {
e.printStackTrace();
}
}
+
+ @OnMessage
+ public void onMessage(String message) {
+ if (message != null) {
+ if (message.contains("Bearer: ")) {
+ String token = message.substring(message.lastIndexOf("Bearer "));
+ String username = jwtTokenUtil.getUsernameFromToken(token);
+ } else {
+
+ }
+ }
+ }
}
From 3c034f56d11fd197208358a3bfb0d3897634884c Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sun, 15 Mar 2020 10:44:10 +0100
Subject: [PATCH 15/21] Socket authentication works
---
socket_test.html | 36 +++++++
.../smarthut/config/JWTRequestFilter.java | 17 ++--
.../smarthut/config/JWTTokenUtil.java | 72 --------------
.../smarthut/config/JWTTokenUtils.java | 84 ++++++++++++++++
.../controller/AuthenticationController.java | 10 +-
.../socket/AuthenticationMessageListener.java | 96 +++++++++++++++++++
.../smarthut/socket/SensorSocketConfig.java | 25 +++--
.../smarthut/socket/SensorSocketEndpoint.java | 92 +++++++++++-------
.../sa4/sanmarinoes/smarthut/utils/Utils.java | 17 +++-
test.html | 26 -----
10 files changed, 320 insertions(+), 155 deletions(-)
create mode 100644 socket_test.html
delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtil.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtils.java
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
delete mode 100644 test.html
diff --git a/socket_test.html b/socket_test.html
new file mode 100644
index 0000000..90feba2
--- /dev/null
+++ b/socket_test.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
Waiting for authentication...
+
+
+
+
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java
index 853083b..e0cbb6a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTRequestFilter.java
@@ -20,7 +20,7 @@ public class JWTRequestFilter extends OncePerRequestFilter {
@Autowired private JWTUserDetailsService jwtUserDetailsService;
- @Autowired private JWTTokenUtil jwtTokenUtil;
+ @Autowired private JWTTokenUtils jwtTokenUtils;
@Override
protected void doFilterInternal(
@@ -30,13 +30,11 @@ public class JWTRequestFilter extends OncePerRequestFilter {
String username = null;
String jwtToken = null;
- // JWT Token is in th
- // e form "Bearer token". Remove Bearer word and get
- // only the Token
+ // JWT Token is in the form "Bearer token". Remove Bearer word and get only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
- username = jwtTokenUtil.getUsernameFromToken(jwtToken);
+ username = jwtTokenUtils.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
@@ -44,14 +42,15 @@ public class JWTRequestFilter extends OncePerRequestFilter {
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
- } // Once we get the token validate it.
+ }
+
+ // Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails =
this.jwtUserDetailsService.loadUserByUsername(
username); // if token is valid configure Spring Security to manually
- // set
- // authentication
- if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
+ // set authentication
+ if (jwtTokenUtils.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtil.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtil.java
deleted file mode 100644
index 40d369f..0000000
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtil.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
-
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Component;
-
-@Component
-public class JWTTokenUtil {
- public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
-
- @Value("${jwt.secret}")
- private String secret;
-
- // retrieve username from jwt token
- public String getUsernameFromToken(String token) {
- return getClaimFromToken(token, Claims::getSubject);
- }
-
- // retrieve expiration date from jwt token
- public Date getExpirationDateFromToken(String token) {
- return getClaimFromToken(token, Claims::getExpiration);
- }
-
- public T getClaimFromToken(String token, Function claimsResolver) {
- final Claims claims = getAllClaimsFromToken(token);
- return claimsResolver.apply(claims);
- }
-
- // for retrieveing any information from token we will need the secret key
- private Claims getAllClaimsFromToken(String token) {
- return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
- } // check if the token has expired
-
- private Boolean isTokenExpired(String token) {
- final Date expiration = getExpirationDateFromToken(token);
- return expiration.before(new Date());
- } // generate token for user
-
- public String generateToken(UserDetails userDetails) {
- Map claims = new HashMap<>();
- return doGenerateToken(claims, userDetails.getUsername());
- }
-
- // while creating the token -
- // 1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
- // 2. Sign the JWT using the HS512 algorithm and secret key.
- // 3. According to JWS Compact
- // Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
- // compaction of the JWT to a URL-safe string
- private String doGenerateToken(Map claims, String subject) {
- return Jwts.builder()
- .setClaims(claims)
- .setSubject(subject)
- .setIssuedAt(new Date(System.currentTimeMillis()))
- .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
- .signWith(SignatureAlgorithm.HS512, secret)
- .compact();
- }
-
- // validate token
- public Boolean validateToken(String token, UserDetails userDetails) {
- final String username = getUsernameFromToken(token);
- return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
- }
-}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtils.java
new file mode 100644
index 0000000..f6943a8
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtils.java
@@ -0,0 +1,84 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.function.Function;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+/** A utility class to handle JWTs */
+@Component
+public class JWTTokenUtils {
+ /** The duration in seconds of the validity of a single token */
+ private static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
+
+ /** The secret key used to encrypt all JWTs */
+ @Value("${jwt.secret}")
+ private String secret;
+
+ /**
+ * Retrieves the claimed username from a given token
+ *
+ * @param token the token to inspect
+ * @return the username
+ */
+ public String getUsernameFromToken(String token) {
+ return getClaimFromToken(token, Claims::getSubject);
+ }
+
+ /**
+ * Returns whether the token given is expired or not
+ *
+ * @param token the given token
+ * @return true if expired, false if not
+ */
+ public Boolean isTokenExpired(String token) {
+ final Date expiration = getClaimFromToken(token, Claims::getExpiration);
+ return expiration.before(new Date());
+ }
+
+ /**
+ * Creates a new JWT for a given user. While creating the token - 1. Define claims of the token,
+ * like Issuer, Expiration, Subject, and the ID 2. Sign the JWT using the HS512 algorithm and
+ * secret key. 3. According to JWS Compact Serialization
+ * (https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1) compaction of
+ * the JWT to a URL-safe string
+ *
+ * @param user the user to which create a JWT
+ * @return the newly generated token
+ */
+ public String generateToken(UserDetails user) {
+ return Jwts.builder()
+ .setClaims(new HashMap<>())
+ .setSubject(user.getUsername())
+ .setIssuedAt(new Date(System.currentTimeMillis()))
+ .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
+ .signWith(SignatureAlgorithm.HS512, secret)
+ .compact();
+ }
+
+ /**
+ * Validates the token given against matching userDetails
+ *
+ * @param token the token given
+ * @param userDetails user details to validate against
+ * @return true if valid, false if not
+ */
+ public Boolean validateToken(String token, UserDetails userDetails) {
+ final String username = getUsernameFromToken(token);
+ return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
+ }
+
+ private T getClaimFromToken(String token, Function claimsResolver) {
+ final Claims claims = getAllClaimsFromToken(token);
+ return claimsResolver.apply(claims);
+ }
+
+ private Claims getAllClaimsFromToken(String token) {
+ return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java
index 1a1e266..3160e1c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/AuthenticationController.java
@@ -1,6 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtil;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.JWTResponse;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserUpdateRequest;
@@ -26,7 +26,7 @@ public class AuthenticationController {
private final UserRepository userRepository;
- private final JWTTokenUtil jwtTokenUtil;
+ private final JWTTokenUtils jwtTokenUtils;
private final JWTUserDetailsService userDetailsService;
@@ -35,11 +35,11 @@ public class AuthenticationController {
public AuthenticationController(
AuthenticationManager authenticationManager,
UserRepository userRepository,
- JWTTokenUtil jwtTokenUtil,
+ JWTTokenUtils jwtTokenUtils,
JWTUserDetailsService userDetailsService) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
- this.jwtTokenUtil = jwtTokenUtil;
+ this.jwtTokenUtils = jwtTokenUtils;
this.userDetailsService = userDetailsService;
}
@@ -68,7 +68,7 @@ public class AuthenticationController {
authenticationRequest.getUsernameOrEmail());
}
- final String token = jwtTokenUtil.generateToken(userDetails);
+ final String token = jwtTokenUtils.generateToken(userDetails);
return new JWTResponse(token);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
new file mode 100644
index 0000000..e0b9249
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
@@ -0,0 +1,96 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import io.jsonwebtoken.ExpiredJwtException;
+import java.io.IOException;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/** Generates MessageHandlers for unauthenticated socket sessions */
+@Component
+public class AuthenticationMessageListener {
+
+ private Gson gson = new Gson();
+
+ private JWTTokenUtils jwtTokenUtils;
+
+ private UserRepository userRepository;
+
+ @Autowired
+ public AuthenticationMessageListener(
+ JWTTokenUtils jwtTokenUtils, UserRepository userRepository) {
+ this.jwtTokenUtils = jwtTokenUtils;
+ this.userRepository = userRepository;
+ }
+
+ /**
+ * Generates a new message handler to handle socket authentication
+ *
+ * @param session the session to which authentication must be checked
+ * @param authorizedSetter function to call once user is authenticated
+ * @return a new message handler to handle socket authentication
+ */
+ MessageHandler.Whole newHandler(
+ final Session session, BiConsumer authorizedSetter) {
+ return new MessageHandler.Whole<>() {
+ @Override
+ public void onMessage(final String message) {
+ System.out.println(message);
+
+ if (message == null) {
+ acknowledge(false);
+ return;
+ }
+
+ String token;
+ String username;
+
+ try {
+ token = gson.fromJson(message, JsonObject.class).get("token").getAsString();
+ username = jwtTokenUtils.getUsernameFromToken(token);
+ } catch (ExpiredJwtException e) {
+ System.err.println(e.getMessage());
+ acknowledge(false);
+ return;
+ } catch (Throwable ignored) {
+ System.out.println("Token format not valid");
+ acknowledge(false);
+ return;
+ }
+
+ final User user = userRepository.findByUsername(username);
+ if (user == null || jwtTokenUtils.isTokenExpired(token)) {
+ System.out.println("Token not valid");
+ acknowledge(false);
+ return;
+ }
+
+ // Here user is authenticated
+ session.removeMessageHandler(this);
+
+ // Add user-session pair in authorized list
+ authorizedSetter.accept(user, session);
+
+ // update client to acknowledge authentication
+ acknowledge(true);
+ }
+
+ private void acknowledge(boolean success) {
+ try {
+ session.getBasicRemote()
+ .sendText(gson.toJson(Map.of("authenticated", success)));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
index 4e032bf..503667a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketConfig.java
@@ -1,25 +1,38 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
import javax.websocket.server.ServerEndpointConfig;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServerEndpointRegistration;
+/** Configures the sensor socket and maps it to the /sensor-socket path */
@Configuration
public class SensorSocketConfig extends ServerEndpointConfig.Configurator {
- public static SensorSocketEndpoint getInstance() {
- return instance;
+ private SensorSocketEndpoint instance;
+
+ @Autowired
+ public SensorSocketConfig(SensorSocketEndpoint instance) {
+ this.instance = instance;
}
- private static SensorSocketEndpoint instance = new SensorSocketEndpoint();
-
+ /**
+ * Registers the sensor socket endpoint to the url /sensor-socket
+ *
+ * @return an endpoint registration object
+ */
@Bean
- public ServerEndpointRegistration sensorSocketEndpoint() {
+ public ServerEndpointRegistration serverEndpointRegistration() {
return new ServerEndpointRegistration("/sensor-socket", instance);
}
+ /**
+ * Returns a new ServerEndpointExporter
+ *
+ * @return a new ServerEndpointExporter
+ */
@Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
@@ -29,7 +42,7 @@ public class SensorSocketConfig extends ServerEndpointConfig.Configurator {
public T getEndpointInstance(Class endpointClass) throws InstantiationException {
try {
@SuppressWarnings("unchecked")
- final T instance = (T) SensorSocketConfig.instance;
+ final T instance = (T) this.instance;
return instance;
} catch (ClassCastException e) {
final var e2 =
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
index 2fde5df..d40e874 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -1,64 +1,84 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
-import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtil;
+import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.didThrow;
+
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import java.io.IOException;
import java.util.*;
import javax.websocket.*;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+/** Endpoint of socket at URL /sensor-socket used to update the client with sensor information */
+@Component
public class SensorSocketEndpoint extends Endpoint {
private Gson gson = new Gson();
- @Autowired private JWTTokenUtil jwtTokenUtil;
+ private AuthenticationMessageListener authenticationMessageListener;
- private Set unauthorizedClients = Collections.synchronizedSet(new HashSet());
+ private Set unauthorizedClients = Collections.synchronizedSet(new HashSet<>());
- // commented out because of script not letting me push
- // private Map< User, Set > authorizedClients = Collections.synchronizedMap(
- // new HashMap< User, HashSet >
- // );
+ private Multimap authorizedClients =
+ Multimaps.synchronizedMultimap(HashMultimap.create());
+ @Autowired
+ public SensorSocketEndpoint(AuthenticationMessageListener authenticationMessageListener) {
+ this.authenticationMessageListener = authenticationMessageListener;
+ }
+
+ /**
+ * Returns a synchronized set of socket sessions not yet authorized with a token
+ *
+ * @return a synchronized set of socket sessions not yet authorized with a token
+ */
public Set getUnauthorizedClients() {
return unauthorizedClients;
}
- public Map> getAuthorizedClients() {
+ /**
+ * Returns a synchronized User to Session multimap with authorized sessions
+ *
+ * @return a synchronized User to Session multimap with authorized sessions
+ */
+ public Multimap getAuthorizedClients() {
return authorizedClients;
}
- public int broadcast(JsonObject message) throws IOException, EncodeException {
- for (Session session : unauthorizedClients) {
- System.out.println(message);
- session.getBasicRemote().sendObject(message);
- }
- return unauthorizedClients.size();
+ /**
+ * Given a message and a user, broadcasts that message in json to all associated clients and
+ * returns the number of successful transfers
+ *
+ * @param message the message to send
+ * @param u the user to which to send the message
+ * @return number of successful transfer
+ */
+ public long broadcast(Object message, User u) {
+ final Collection sessions = authorizedClients.get(u);
+ return sessions.stream()
+ .parallel()
+ .filter(didThrow(s -> s.getAsyncRemote().sendObject(gson.toJson(message))))
+ .count();
}
+ /**
+ * Handles the opening of a socket session with a client
+ *
+ * @param session the newly born session
+ * @param config endpoint configuration
+ */
@Override
public void onOpen(Session session, EndpointConfig config) {
- final JsonObject test = new JsonObject();
- test.addProperty("ciao", "mamma");
- try {
- session.getBasicRemote().sendText(gson.toJson(test));
- unauthorizedClients.add(session);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @OnMessage
- public void onMessage(String message) {
- if (message != null) {
- if (message.contains("Bearer: ")) {
- String token = message.substring(message.lastIndexOf("Bearer "));
- String username = jwtTokenUtil.getUsernameFromToken(token);
- } else {
-
- }
- }
+ unauthorizedClients.add(session);
+ session.addMessageHandler(
+ authenticationMessageListener.newHandler(
+ session,
+ (u, s) -> {
+ unauthorizedClients.remove(s);
+ authorizedClients.put(u, s);
+ }));
}
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
index d9fcf12..bc8719d 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
@@ -1,14 +1,29 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.utils;
import java.util.List;
+import java.util.concurrent.Future;
+import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/** A class with a bunch of useful static methods */
-public class Utils {
+public final class Utils {
private Utils() {}
public static List toList(Iterable iterable) {
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
}
+
+ public static Predicate didThrow(Function> consumer) {
+ return (t) -> {
+ try {
+ consumer.apply(t).get();
+ return true;
+ } catch (Throwable e) {
+ System.err.println(e.getMessage());
+ return false;
+ }
+ };
+ }
}
diff --git a/test.html b/test.html
deleted file mode 100644
index 42bb82d..0000000
--- a/test.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
From 5a441a69925ee8b7bfebc0a828b7d84dbbf6b459 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sun, 15 Mar 2020 13:41:57 +0100
Subject: [PATCH 16/21] Socket now sends sensor updates
---
socket_test.html | 4 +++
.../smarthut/config/GsonConfig.java | 2 +-
.../smarthut/controller/SensorController.java | 27 +++++++++++++++++++
.../smarthut/dto/SensorSaveRequest.java | 11 ++++++++
.../sanmarinoes/smarthut/models/Device.java | 6 +++++
.../smarthut/models/DeviceRepository.java | 21 +++++++++++++++
.../sa4/sanmarinoes/smarthut/models/Room.java | 6 +++++
.../sanmarinoes/smarthut/models/Sensor.java | 23 +++++++++++-----
.../sa4/sanmarinoes/smarthut/models/User.java | 19 +++++++++++++
.../socket/AuthenticationMessageListener.java | 3 ++-
.../smarthut/socket/SensorSocketEndpoint.java | 6 +++--
.../sa4/sanmarinoes/smarthut/utils/Utils.java | 12 ++++++---
12 files changed, 126 insertions(+), 14 deletions(-)
diff --git a/socket_test.html b/socket_test.html
index 90feba2..687388b 100644
--- a/socket_test.html
+++ b/socket_test.html
@@ -1,3 +1,5 @@
+
+
@@ -25,6 +27,8 @@ connection.onmessage = function(evt) {
"";
} else if (data.authenticated === false) {
malusa.innerHTML = "Authentication error
";
+ } else {
+ malusa.innerHTML += "" + JSON.stringify(JSON.parse(evt.data), null, 2) + "
";
}
};
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
index e12d9f0..69c4fc9 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java
@@ -20,7 +20,7 @@ public class GsonConfig {
return converter;
}
- private Gson gson() {
+ public static Gson gson() {
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());
builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
index 3412e0c..400d06f 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
@@ -5,6 +5,9 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
+import java.math.BigDecimal;
+import java.security.Principal;
import java.util.*;
import java.util.List;
import javax.validation.Valid;
@@ -19,6 +22,8 @@ public class SensorController {
@Autowired private SensorRepository sensorRepository;
+ @Autowired private SensorSocketEndpoint sensorSocketEndpoint;
+
@GetMapping
public List findAll() {
return toList(sensorRepository.findAll());
@@ -35,10 +40,32 @@ public class SensorController {
newSensor.setSensor(s.getSensor());
newSensor.setName(s.getName());
newSensor.setRoomId(s.getRoomId());
+ newSensor.setValue(s.getValue());
return sensorRepository.save(newSensor);
}
+ @PutMapping("/{id}/value")
+ public Sensor updateValue(
+ @PathVariable("id") Long sensorId,
+ @RequestParam("value") BigDecimal value,
+ final Principal principal)
+ throws NotFoundException {
+
+ final Sensor sensor =
+ sensorRepository
+ .findByIdAndUsername(sensorId, principal.getName())
+ .orElseThrow(NotFoundException::new);
+ sensor.setValue(value);
+ final Sensor toReturn = sensorRepository.save(sensor);
+
+ System.out.println("sensor: " + sensor);
+
+ sensorSocketEndpoint.broadcast(sensor, sensorRepository.findUser(sensorId));
+
+ return toReturn;
+ }
+
@DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) {
sensorRepository.deleteById(id);
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
index e9a5c68..62b0b5e 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java
@@ -2,6 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor;
import com.google.gson.annotations.SerializedName;
+import java.math.BigDecimal;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.validation.constraints.NotNull;
@@ -28,6 +29,8 @@ public class SensorSaveRequest {
@Enumerated(value = EnumType.STRING)
private Sensor.SensorType sensor;
+ @NotNull private BigDecimal value;
+
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
@@ -60,4 +63,12 @@ public class SensorSaveRequest {
public void setSensor(Sensor.SensorType sensor) {
this.sensor = sensor;
}
+
+ public BigDecimal getValue() {
+ return value;
+ }
+
+ public void setValue(BigDecimal value) {
+ this.value = value;
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
index e8a621b..c564914 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
@@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.*;
@@ -26,6 +27,11 @@ public abstract class Device {
@ApiModelProperty(hidden = true)
private long id;
+ @ManyToOne
+ @JoinColumn(name = "room_id", updatable = false, insertable = false)
+ @GsonExclude
+ private Room room;
+
/**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call.
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
index fdae66e..b90639b 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
@@ -1,6 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.List;
+import java.util.Optional;
+import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
@@ -10,4 +12,23 @@ import org.springframework.data.repository.query.Param;
*/
public interface DeviceRepository extends CrudRepository {
List findByRoomId(@Param("roomId") long roomId);
+
+ /**
+ * Finds devices by their id and a username
+ *
+ * @param id the device id
+ * @param username a User's username
+ * @return an optional device, empty if none found
+ */
+ @Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1 AND u.username = ?2")
+ Optional findByIdAndUsername(Long id, String username);
+
+ /**
+ * Find the user associated with a device through a room
+ *
+ * @param deviceId the device id
+ * @return a user object
+ */
+ @Query("SELECT u FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1")
+ User findUser(Long deviceId);
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
index e54b462..68c3fc0 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
@@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.*;
@@ -128,6 +129,11 @@ public class Room {
@Column(name = "image", columnDefinition = "TEXT")
private String image;
+ @ManyToOne
+ @JoinColumn(name = "user_id", updatable = false, insertable = false)
+ @GsonExclude
+ private User user;
+
/**
* User that owns the house this room is in as a foreign key id. To use when updating and
* inserting from a REST call.
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
index b1d98a2..6dd634a 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
@@ -1,6 +1,8 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import com.google.gson.annotations.SerializedName;
+import java.math.BigDecimal;
+import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
@@ -11,6 +13,12 @@ import javax.validation.constraints.NotNull;
@Entity
public class Sensor extends InputDevice {
+ private static final Map TYPICAL_VALUES =
+ Map.of(
+ SensorType.TEMPERATURE, 17,
+ SensorType.HUMIDITY, 40,
+ SensorType.LIGHT, 1000);
+
/** Type of sensor, i.e. of the thing the sensor measures. */
public enum SensorType {
/** A sensor that measures temperature in degrees celsius */
@@ -27,8 +35,8 @@ public class Sensor extends InputDevice {
}
/** The value of this sensor according to its sensor type */
- @Column(nullable = false)
- private int value;
+ @Column(nullable = false, length = 10, precision = 1)
+ private BigDecimal value;
/** The type of this sensor */
@Column(nullable = false)
@@ -42,19 +50,22 @@ public class Sensor extends InputDevice {
public void setSensor(SensorType sensor) {
this.sensor = sensor;
-
- // TODO: setup hook for sockets live update
}
- public int getValue() {
+ public BigDecimal getValue() {
return this.value;
}
- public void setValue(int newValue) {
+ public void setValue(BigDecimal newValue) {
this.value = newValue;
}
public Sensor() {
super("sensor");
}
+
+ @Override
+ public String toString() {
+ return "Sensor{" + "value=" + value + ", sensor=" + sensor + '}';
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
index f1b88ca..dc6766d 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java
@@ -1,6 +1,7 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import io.swagger.annotations.ApiModelProperty;
+import java.util.Objects;
import javax.persistence.*;
/** A user of the Smarthut application */
@@ -105,4 +106,22 @@ public class User {
+ isEnabled
+ '}';
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ User user = (User) o;
+ return id.equals(user.id)
+ && name.equals(user.name)
+ && username.equals(user.username)
+ && password.equals(user.password)
+ && email.equals(user.email)
+ && isEnabled.equals(user.isEnabled);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, username, password, email, isEnabled);
+ }
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
index e0b9249..e3d97ea 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
@@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonConfig;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
@@ -18,7 +19,7 @@ import org.springframework.stereotype.Component;
@Component
public class AuthenticationMessageListener {
- private Gson gson = new Gson();
+ private Gson gson = GsonConfig.gson();
private JWTTokenUtils jwtTokenUtils;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
index d40e874..ee7ff56 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -2,6 +2,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.socket;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.didThrow;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonConfig;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
@@ -16,7 +17,7 @@ import org.springframework.stereotype.Component;
@Component
public class SensorSocketEndpoint extends Endpoint {
- private Gson gson = new Gson();
+ private Gson gson = GsonConfig.gson();
private AuthenticationMessageListener authenticationMessageListener;
@@ -58,9 +59,10 @@ public class SensorSocketEndpoint extends Endpoint {
*/
public long broadcast(Object message, User u) {
final Collection sessions = authorizedClients.get(u);
+ System.out.println(authorizedClients + " " + sessions + " " + u);
return sessions.stream()
.parallel()
- .filter(didThrow(s -> s.getAsyncRemote().sendObject(gson.toJson(message))))
+ .filter(didThrow(s -> s.getBasicRemote().sendText(gson.toJson(message))))
.count();
}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
index bc8719d..3f24d4c 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
@@ -1,8 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.utils;
import java.util.List;
-import java.util.concurrent.Future;
-import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -11,14 +9,20 @@ import java.util.stream.StreamSupport;
public final class Utils {
private Utils() {}
+ @FunctionalInterface
+ public interface ConsumerWithException {
+ void apply(T input) throws Throwable;
+ }
+
public static List toList(Iterable iterable) {
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
}
- public static Predicate didThrow(Function> consumer) {
+ public static Predicate didThrow(ConsumerWithException consumer) {
return (t) -> {
try {
- consumer.apply(t).get();
+ consumer.apply(t);
+ System.out.println("successful");
return true;
} catch (Throwable e) {
System.err.println(e.getMessage());
From cf940df6b2e06687dea219b32fc1d868be29b73a Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sun, 15 Mar 2020 13:51:14 +0100
Subject: [PATCH 17/21] Socket now sends motion sensor updates
---
.../controller/MotionSensorController.java | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
index 4ba03b1..96ba755 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
@@ -6,6 +6,8 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensor;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
+import java.security.Principal;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +21,8 @@ public class MotionSensorController {
@Autowired private MotionSensorRepository motionSensorService;
+ @Autowired private SensorSocketEndpoint sensorSocketEndpoint;
+
@GetMapping
public List findAll() {
return toList(motionSensorService.findAll());
@@ -38,6 +42,25 @@ public class MotionSensorController {
return motionSensorService.save(newMS);
}
+ @PutMapping("/{id}/detect")
+ public MotionSensor updateDetection(
+ @PathVariable("id") Long sensorId,
+ @RequestParam("detected") boolean detected,
+ final Principal principal)
+ throws NotFoundException {
+
+ final MotionSensor sensor =
+ motionSensorService
+ .findByIdAndUsername(sensorId, principal.getName())
+ .orElseThrow(NotFoundException::new);
+ sensor.setDetected(detected);
+ final MotionSensor toReturn = motionSensorService.save(sensor);
+
+ sensorSocketEndpoint.broadcast(sensor, motionSensorService.findUser(sensorId));
+
+ return toReturn;
+ }
+
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) {
motionSensorService.deleteById(id);
From 620c196393ff56fdb8ea1ffafa4d850549802ddc Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sun, 15 Mar 2020 14:49:51 +0100
Subject: [PATCH 18/21] Implemented fake updates
---
.../smarthut/SmarthutApplication.java | 2 +
.../controller/MotionSensorController.java | 27 +++++---
.../smarthut/controller/SensorController.java | 30 +++++----
.../sanmarinoes/smarthut/models/Sensor.java | 8 +--
.../smarthut/scheduled/SensorUpdateTasks.java | 62 +++++++++++++++++++
.../socket/AuthenticationMessageListener.java | 2 -
.../smarthut/socket/SensorSocketEndpoint.java | 1 -
.../sa4/sanmarinoes/smarthut/utils/Utils.java | 1 -
8 files changed, 106 insertions(+), 27 deletions(-)
create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/SensorUpdateTasks.java
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmarthutApplication.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmarthutApplication.java
index 242f03f..57f7b42 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmarthutApplication.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmarthutApplication.java
@@ -3,8 +3,10 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
+@EnableScheduling
@EnableJpaRepositories("ch.usi.inf.sa4.sanmarinoes.smarthut.models")
public class SmarthutApplication {
public static void main(String[] args) {
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
index 96ba755..59c0343 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java
@@ -42,6 +42,22 @@ public class MotionSensorController {
return motionSensorService.save(newMS);
}
+ /**
+ * Updates detection status of given motion sensor and propagates update throgh socket
+ *
+ * @param sensor the motion sensor to update
+ * @param detected the new detection status
+ * @return the updated motion sensor
+ */
+ public MotionSensor updateDetectionFromMotionSensor(MotionSensor sensor, boolean detected) {
+ sensor.setDetected(detected);
+ final MotionSensor toReturn = motionSensorService.save(sensor);
+
+ sensorSocketEndpoint.broadcast(sensor, motionSensorService.findUser(sensor.getId()));
+
+ return toReturn;
+ }
+
@PutMapping("/{id}/detect")
public MotionSensor updateDetection(
@PathVariable("id") Long sensorId,
@@ -49,16 +65,11 @@ public class MotionSensorController {
final Principal principal)
throws NotFoundException {
- final MotionSensor sensor =
+ return updateDetectionFromMotionSensor(
motionSensorService
.findByIdAndUsername(sensorId, principal.getName())
- .orElseThrow(NotFoundException::new);
- sensor.setDetected(detected);
- final MotionSensor toReturn = motionSensorService.save(sensor);
-
- sensorSocketEndpoint.broadcast(sensor, motionSensorService.findUser(sensorId));
-
- return toReturn;
+ .orElseThrow(NotFoundException::new),
+ detected);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
index 400d06f..ee1be81 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java
@@ -45,25 +45,33 @@ public class SensorController {
return sensorRepository.save(newSensor);
}
+ /**
+ * Updates the sensor with new measurement and propagates update through websocket
+ *
+ * @param sensor the sensor to update
+ * @param value the new measurement
+ * @return the updated sensor
+ */
+ public Sensor updateValueFromSensor(Sensor sensor, BigDecimal value) {
+ sensor.setValue(value);
+ final Sensor toReturn = sensorRepository.save(sensor);
+
+ sensorSocketEndpoint.broadcast(sensor, sensorRepository.findUser(sensor.getId()));
+
+ return toReturn;
+ }
+
@PutMapping("/{id}/value")
public Sensor updateValue(
@PathVariable("id") Long sensorId,
@RequestParam("value") BigDecimal value,
final Principal principal)
throws NotFoundException {
-
- final Sensor sensor =
+ return updateValueFromSensor(
sensorRepository
.findByIdAndUsername(sensorId, principal.getName())
- .orElseThrow(NotFoundException::new);
- sensor.setValue(value);
- final Sensor toReturn = sensorRepository.save(sensor);
-
- System.out.println("sensor: " + sensor);
-
- sensorSocketEndpoint.broadcast(sensor, sensorRepository.findUser(sensorId));
-
- return toReturn;
+ .orElseThrow(NotFoundException::new),
+ value);
}
@DeleteMapping("/{id}")
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
index 6dd634a..525ceb3 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java
@@ -13,11 +13,11 @@ import javax.validation.constraints.NotNull;
@Entity
public class Sensor extends InputDevice {
- private static final Map TYPICAL_VALUES =
+ public static final Map TYPICAL_VALUES =
Map.of(
- SensorType.TEMPERATURE, 17,
- SensorType.HUMIDITY, 40,
- SensorType.LIGHT, 1000);
+ SensorType.TEMPERATURE, new BigDecimal(17.0),
+ SensorType.HUMIDITY, new BigDecimal(40.0),
+ SensorType.LIGHT, new BigDecimal(1000));
/** Type of sensor, i.e. of the thing the sensor measures. */
public enum SensorType {
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/SensorUpdateTasks.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/SensorUpdateTasks.java
new file mode 100644
index 0000000..b1614aa
--- /dev/null
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/SensorUpdateTasks.java
@@ -0,0 +1,62 @@
+package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled;
+
+import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.MotionSensorController;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.SensorController;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository;
+import java.math.BigDecimal;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.StreamSupport;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/** Generates fake sensor (and motion sensor) updates as required by milestone one */
+@Component
+public class SensorUpdateTasks {
+
+ @Autowired private SensorRepository sensorRepository;
+
+ @Autowired private MotionSensorRepository motionSensorRepository;
+
+ @Autowired private SensorController sensorController;
+
+ @Autowired private MotionSensorController motionSensorController;
+
+ /** Generates fake sensor updates every two seconds with a +/- 1.25% error */
+ @Scheduled(fixedRate = 2000)
+ public void sensorFakeUpdate() {
+ StreamSupport.stream(sensorRepository.findAll().spliterator(), true)
+ .forEach(
+ sensor ->
+ sensorController.updateValueFromSensor(
+ sensor,
+ Sensor.TYPICAL_VALUES
+ .get(sensor.getSensor())
+ .multiply(
+ new BigDecimal(
+ 0.9875 + Math.random() / 40))));
+ }
+
+ /**
+ * Generate fake motion detections in all motion detectors every 20 seconds for 2 seconds at
+ * most
+ */
+ @Scheduled(fixedDelay = 20000)
+ public void motionSensorFakeUpdate() {
+ StreamSupport.stream(motionSensorRepository.findAll().spliterator(), true)
+ .forEach(
+ sensor -> {
+ motionSensorController.updateDetectionFromMotionSensor(sensor, true);
+ CompletableFuture.delayedExecutor(
+ (long) (Math.random() * 2000), TimeUnit.MILLISECONDS)
+ .execute(
+ () ->
+ motionSensorController
+ .updateDetectionFromMotionSensor(
+ sensor, false));
+ });
+ }
+}
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
index e3d97ea..89415aa 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/AuthenticationMessageListener.java
@@ -44,8 +44,6 @@ public class AuthenticationMessageListener {
return new MessageHandler.Whole<>() {
@Override
public void onMessage(final String message) {
- System.out.println(message);
-
if (message == null) {
acknowledge(false);
return;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
index ee7ff56..bc2f90e 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java
@@ -59,7 +59,6 @@ public class SensorSocketEndpoint extends Endpoint {
*/
public long broadcast(Object message, User u) {
final Collection sessions = authorizedClients.get(u);
- System.out.println(authorizedClients + " " + sessions + " " + u);
return sessions.stream()
.parallel()
.filter(didThrow(s -> s.getBasicRemote().sendText(gson.toJson(message))))
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
index 3f24d4c..99d363b 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java
@@ -22,7 +22,6 @@ public final class Utils {
return (t) -> {
try {
consumer.apply(t);
- System.out.println("successful");
return true;
} catch (Throwable e) {
System.err.println(e.getMessage());
From 24fa574c63e16402c21d5d3ed9e28f41d74e3c89 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Thu, 12 Mar 2020 16:57:50 +0100
Subject: [PATCH 19/21] Added email confirmation test
---
build.gradle | 1 +
.../models/ConfirmationTokenRepository.java | 2 +
.../smarthut/AuthenticationTests.java | 36 ++++++++-------
.../sanmarinoes/smarthut/SmartHutTest.java | 44 +++++++++++++++++++
src/test/resources/application.properties | 2 +-
5 files changed, 69 insertions(+), 16 deletions(-)
diff --git a/build.gradle b/build.gradle
index 5140ea7..303f5e7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -32,6 +32,7 @@ dependencies {
compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
compile 'org.springframework.boot:spring-boot-configuration-processor'
+ testCompile 'org.springframework.boot:spring-boot-starter-webflux'
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-json'
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenRepository.java
index 9bf3791..40c6a17 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenRepository.java
@@ -6,6 +6,8 @@ import org.springframework.data.repository.CrudRepository;
public interface ConfirmationTokenRepository extends CrudRepository {
ConfirmationToken findByConfirmationToken(String confirmationToken);
+ ConfirmationToken findByUser(User user);
+
@Transactional
void deleteByUserAndResetPassword(User user, boolean resetPassword);
}
diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/AuthenticationTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/AuthenticationTests.java
index 60761cd..d13104f 100644
--- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/AuthenticationTests.java
+++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/AuthenticationTests.java
@@ -8,6 +8,8 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.OkResponse;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserRegistrationRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateRegistrationException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.UnauthorizedException;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ConfirmationTokenRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.Map;
@@ -25,6 +27,10 @@ public class AuthenticationTests extends SmartHutTest {
@Autowired private TestRestTemplate restTemplate;
+ @Autowired private UserRepository userRepository;
+
+ @Autowired private ConfirmationTokenRepository tokenRepository;
+
private UserRegistrationRequest getDisabledUser() {
final UserRegistrationRequest disabledUser = new UserRegistrationRequest();
disabledUser.setName("Disabled User");
@@ -34,15 +40,6 @@ public class AuthenticationTests extends SmartHutTest {
return disabledUser;
}
- private static final UserRegistrationRequest enabledUser = new UserRegistrationRequest();
-
- static {
- enabledUser.setName("Enabled User");
- enabledUser.setEmail("enabled@example.com");
- enabledUser.setUsername("enabled");
- enabledUser.setPassword("password");
- }
-
@Override
protected void setUp() {
final ResponseEntity res =
@@ -50,12 +47,7 @@ public class AuthenticationTests extends SmartHutTest {
this.url("/register"), getDisabledUser(), OkResponse.class);
assertThat(res.getStatusCode().equals(HttpStatus.OK));
- final ResponseEntity res2 =
- this.restTemplate.postForEntity(
- this.url("/register"), enabledUser, OkResponse.class);
- assertThat(res2.getStatusCode().equals(HttpStatus.OK));
-
- // TODO: email confirmation for enabledUser
+ registerTestUser(restTemplate, userRepository, tokenRepository);
}
@Test
@@ -230,4 +222,18 @@ public class AuthenticationTests extends SmartHutTest {
assertThat(res.getBody() != null);
assertThat(res.getBody().isUserDisabled());
}
+
+ @Test
+ public void loginShouldReturnTokenWithEnabledUser() {
+ final JWTRequest request = new JWTRequest();
+ request.setUsernameOrEmail("enabled");
+ request.setPassword("password");
+
+ final ResponseEntity res =
+ this.restTemplate.postForEntity(url("/auth/login"), request, JWTResponse.class);
+ assertThat(res.getStatusCode().equals(HttpStatus.OK));
+ assertThat(res.getBody() != null);
+ assertThat(res.getBody().getToken() != null);
+ assertThat(!res.getBody().getToken().isEmpty());
+ }
}
diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmartHutTest.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmartHutTest.java
index 5c6e097..f2b737a 100644
--- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmartHutTest.java
+++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/SmartHutTest.java
@@ -1,6 +1,18 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.OkResponse;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserRegistrationRequest;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ConfirmationToken;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ConfirmationTokenRepository;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
+import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
import org.junit.jupiter.api.BeforeEach;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.reactive.function.client.WebClient;
public abstract class SmartHutTest {
private boolean setupDone = false;
@@ -15,6 +27,38 @@ public abstract class SmartHutTest {
protected void setUp() {}
+ protected static final UserRegistrationRequest enabledUser = new UserRegistrationRequest();
+
+ static {
+ enabledUser.setName("Enabled User");
+ enabledUser.setEmail("enabled@example.com");
+ enabledUser.setUsername("enabled");
+ enabledUser.setPassword("password");
+ }
+
+ protected void registerTestUser(
+ final TestRestTemplate restTemplate,
+ final UserRepository userRepository,
+ final ConfirmationTokenRepository tokenRepository) {
+ final ResponseEntity res2 =
+ restTemplate.postForEntity(this.url("/register"), enabledUser, OkResponse.class);
+ assertThat(res2.getStatusCode().equals(HttpStatus.OK));
+
+ final User persistedEnabledUser = userRepository.findByUsername("enabled");
+ final ConfirmationToken token = tokenRepository.findByUser(persistedEnabledUser);
+
+ final ResponseEntity res3 =
+ WebClient.create(getBaseURL())
+ .get()
+ .uri("/register/confirm-account?token=" + token.getConfirmationToken())
+ .retrieve()
+ .toBodilessEntity()
+ .block();
+
+ assertThat(res3.getStatusCode().is2xxSuccessful());
+ assertThat(userRepository.findByUsername("enabled").getEnabled());
+ }
+
@BeforeEach
void setUpHack() {
if (!setupDone) {
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index ce6fe39..673d02a 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -28,7 +28,7 @@ server.port = 2000
email.registrationSubject=Complete your SmartHut.sm registration
email.registration=To confirm your registration, please click here:
-email.registrationPath=http://localhost:8080/register/confirm-account?token=
+email.registrationPath=http://localhost:2000/register/confirm-account?token=
email.resetpasswordSubject=SmartHut.sm password reset
email.resetpassword=To reset your password, please click here:
From 9c60475e92d2f8c17f4003d06f98870ab229e7bd Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Sun, 15 Mar 2020 17:05:52 +0100
Subject: [PATCH 20/21] Added GET /device route
---
.../smarthut/controller/DeviceController.java | 12 ++++++++----
.../smarthut/models/DeviceRepository.java | 9 +++++++++
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
index fa3242d..2d8dd99 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java
@@ -6,13 +6,12 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RoomRepository;
+import java.security.Principal;
+import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@@ -22,6 +21,11 @@ public class DeviceController {
@Autowired private DeviceRepository deviceRepository;
@Autowired private RoomRepository roomRepository;
+ @GetMapping
+ public List getAll(final Principal user) {
+ return deviceRepository.findAllByUsername(user.getName());
+ }
+
@PutMapping
public Device update(@Valid @RequestBody DeviceSaveRequest deviceSaveRequest)
throws NotFoundException, BadDataException {
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
index b90639b..f844882 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java
@@ -23,6 +23,15 @@ public interface DeviceRepository extends CrudRepository findByIdAndUsername(Long id, String username);
+ /**
+ * Finds all devices belonging to a user
+ *
+ * @param username the User's username
+ * @return all devices of that user
+ */
+ @Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE u.username = ?1")
+ List findAllByUsername(String username);
+
/**
* Find the user associated with a device through a room
*
From 23edc90b815cb896bf8adadd8674557e09d0fa80 Mon Sep 17 00:00:00 2001
From: Claudio Maggioni
Date: Mon, 16 Mar 2020 14:53:07 +0100
Subject: [PATCH 21/21] Fixed @tommi27 uniqueness frenzy for rooms
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
I have now discovered the Schadenfreude in using git-blame. To quote an
old commit message from high school:
[Trascrizione domande fisica e correzione di GRAVISSIMI bug presenti nel
codici di Maggioni](https://gitlab.com/staccastacca/scuolatest/-/commit/dd0933def0262ce1ca2f2b006d4f7a364fb17272)
```
La trascrizione dei test è stata fatta in modo certosino, simile a
quello dei monaci emanuensi.
I GRAVISSIMI buggg (3 g perchè fa faigo) potevano rendere il sito
incomprensibile
```
---
.gitlab-ci.yml | 2 ++
.../usi/inf/sa4/sanmarinoes/smarthut/models/Device.java | 8 ++------
.../ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java | 2 +-
3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fc62202..2250a03 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,6 +11,8 @@ stages:
smarthut_deploy:
stage: deploy
image: docker:latest
+ tags:
+ - dind
services:
- docker:dind
variables:
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
index c564914..6d0333d 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java
@@ -49,17 +49,13 @@ public abstract class Device {
* The name for the category of this particular device (e.g 'dimmer'). Not stored in the
* database but set thanks to constructors
*/
- @ApiModelProperty(hidden = true)
- @Transient
- private final String kind;
+ @Transient private final String kind;
/**
* The way this device behaves in the automation flow. Not stored in the database but set thanks
* to constructors
*/
- @ApiModelProperty(hidden = true)
- @Transient
- private final FlowType flowType;
+ @Transient private final FlowType flowType;
public long getId() {
return id;
diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
index 68c3fc0..a30e4f8 100644
--- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
+++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java
@@ -139,7 +139,7 @@ public class Room {
* inserting from a REST call.
*/
@NotNull
- @Column(name = "user_id", nullable = false, unique = true)
+ @Column(name = "user_id", nullable = false)
private Long userId;
/** The user given name of this room (e.g. 'Master bedroom') */