From 6be999ffcc9bd5882a00c237c7901f9f413566dc Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Wed, 15 Apr 2020 16:21:39 +0200 Subject: [PATCH 01/12] Created models for scenes and states --- .../sanmarinoes/smarthut/models/Device.java | 6 ++ .../smarthut/models/DimmableLightState.java | 27 ++++++ .../sanmarinoes/smarthut/models/Scene.java | 67 +++++++++++++++ .../sanmarinoes/smarthut/models/State.java | 83 +++++++++++++++++++ .../smarthut/models/SwitchableState.java | 22 +++++ 5 files changed, 205 insertions(+) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java 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 295fe37..082d954 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 @@ -3,6 +3,8 @@ 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 java.util.HashSet; +import java.util.Set; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -57,6 +59,10 @@ public abstract class Device { */ @Transient private final FlowType flowType; + @OneToMany(mappedBy = "device", orphanRemoval = true) + @GsonExclude + private Set states = new HashSet<>(); + public long getId() { return id; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java new file mode 100644 index 0000000..6162cb7 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java @@ -0,0 +1,27 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** Represent a dimmable light state */ +@Entity +public class DimmableLightState extends State { + + /** The light intensity value. Goes from 0 (off) to 100 (on) */ + @NotNull + @Column(nullable = false) + @Min(0) + @Max(100) + private Integer intensity = 0; + + 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/models/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java new file mode 100644 index 0000000..d006430 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -0,0 +1,67 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import io.swagger.annotations.ApiModelProperty; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +/** + * Represent a collection of state changes to devices even in different rooms but belonging to the + * same user + */ +@Entity +public class Scene { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @ManyToOne + @JoinColumn(name = "user_id", updatable = false, insertable = false) + @GsonExclude + private User user; + + @OneToMany(mappedBy = "scene", orphanRemoval = true) + @GsonExclude + private Set states = new HashSet<>(); + + @NotNull + @Column(name = "user_id", nullable = false) + private Long userId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Set getStates() { + return states; + } + + public void setStates(Set states) { + this.states = states; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java new file mode 100644 index 0000000..25e9e31 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java @@ -0,0 +1,83 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import io.swagger.annotations.ApiModelProperty; +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +/** + * Represents instructions on how to change the state of a particular device. Many states (plus + * other properties) form a Scene + */ +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +public abstract class State { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @ManyToOne + @JoinColumn(name = "device_id", updatable = false, insertable = false) + @GsonExclude + private Device device; + + /** + * The device this state belongs in, as a foreign key id. To use when updating and inserting + * from a REST call. + */ + @Column(name = "device_id", nullable = false) + @NotNull + private Long deviceId; + + @ManyToOne + @JoinColumn(name = "scene_id", updatable = false, insertable = false) + @GsonExclude + private Scene scene; + + @Column(name = "scene_id", nullable = false) + @NotNull + private Long sceneId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Device getDevice() { + return device; + } + + public void setDevice(Device device) { + this.device = device; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public Scene getScene() { + return scene; + } + + public void setScene(Scene scene) { + this.scene = scene; + } + + public Long getSceneId() { + return sceneId; + } + + public void setSceneId(Long sceneId) { + this.sceneId = sceneId; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java new file mode 100644 index 0000000..95efe8a --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java @@ -0,0 +1,22 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.validation.constraints.NotNull; + +/** A state for RegularLight and SmartPlug */ +@Entity +public class SwitchableState extends State { + + @Column(name = "switchable_on", nullable = false) + @NotNull + private boolean on; + + public boolean isOn() { + return on; + } + + public void setOn(boolean on) { + this.on = on; + } +} From 495c317eb887f086bdfe06154cb08993177cd3ee Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Wed, 15 Apr 2020 23:08:57 +0200 Subject: [PATCH 02/12] Added apply() method on State to change underlying device accordingly --- .../controller/ThermostatController.java | 5 ++--- .../models/AlterableFromDimmableState.java | 13 +++++++++++ .../smarthut/models/AlterableFromState.java | 6 +++++ .../models/AlterableFromSwitchableState.java | 13 +++++++++++ .../sanmarinoes/smarthut/models/Curtains.java | 12 +++++++++- .../smarthut/models/DimmableLight.java | 12 +++++++++- ...ableLightState.java => DimmableState.java} | 14 ++++++------ .../smarthut/models/IDimmable.java | 10 +++++++++ .../smarthut/models/ISwtichable.java | 20 +++++++++++++++++ .../smarthut/models/RegularLight.java | 2 +- .../smarthut/models/SecurityCamera.java | 2 +- .../smarthut/models/SmartPlug.java | 2 +- .../sanmarinoes/smarthut/models/State.java | 19 +++++++++++----- .../smarthut/models/Switchable.java | 16 +------------- .../smarthut/models/SwitchableState.java | 4 ++-- .../smarthut/models/Thermostat.java | 22 ++++++++++++------- .../smarthut/models/ThermostatState.java | 16 ++++++++++++++ .../smarthut/service/ThermostatService.java | 14 ++++++------ 18 files changed, 150 insertions(+), 52 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java rename src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/{DimmableLightState.java => DimmableState.java} (55%) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 57e1ca9..00899c8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -5,7 +5,6 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import java.security.Principal; -import java.util.*; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -42,10 +41,10 @@ public class ThermostatController { newT.setUseExternalSensors(t.isUseExternalSensors()); if (t.isTurnOn()) { - newT.setState(Thermostat.ThermostatState.IDLE); + newT.setMode(Thermostat.Mode.IDLE); thermostatService.computeState(newT); } else { - newT.setState(Thermostat.ThermostatState.OFF); + newT.setMode(Thermostat.Mode.OFF); } newT = thermostatRepository.save(newT); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java new file mode 100644 index 0000000..64b7039 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java @@ -0,0 +1,13 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +/** + * An IDimmable Device whose state can be set by a DimmableState of the corresponding type + * @param the type of the class that extends this interface (just for type bounds, does not mean actually anything) + */ +public interface AlterableFromDimmableState> + extends IDimmable, AlterableFromState> { + default void readStateAndSet(State state) { + final DimmableState hack = (DimmableState) state; + setDimAmount(hack.getDimAmount()); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java new file mode 100644 index 0000000..235017c --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java @@ -0,0 +1,6 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +/** An OutputDevice whose state can be set by a State of corresponding device type */ +public interface AlterableFromState> { + void readStateAndSet(T state); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java new file mode 100644 index 0000000..a4f2d29 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java @@ -0,0 +1,13 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +/** + * An ISwitchable Device whose state can be set by a SwitchableState of the corresponding type + * @param the type of the class that extends this interface (just for type bounds, does not mean actually anything) + */ +public interface AlterableFromSwitchableState> + extends ISwtichable, AlterableFromState> { + default void readStateAndSet(State state) { + final SwitchableState hack = (SwitchableState) state; + setOn(hack.isOn()); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java index cfc3c2f..00fa464 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java @@ -7,7 +7,7 @@ import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; @Entity -public class Curtains extends OutputDevice { +public class Curtains extends OutputDevice implements IDimmable, AlterableFromDimmableState { /** * it represents how much the curtains are opened, 0 is completely closed 100 is completely open @@ -38,4 +38,14 @@ public class Curtains extends OutputDevice { this.openedAmount = newOpening; } } + + @Override + public Integer getDimAmount() { + return getOpenedAmount(); + } + + @Override + public void setDimAmount(Integer intensity) { + setOpenedAmount(intensity); + } } 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 6b537c6..300ec6e 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 Switchable { +public class DimmableLight extends Switchable implements IDimmable, AlterableFromDimmableState { public static final Connector BUTTON_DIMMER_DIMMABLE_LIGHT_CONNECTOR = @@ -86,4 +86,14 @@ public class DimmableLight extends Switchable { super.setSwitchId(switchId); this.dimmerId = null; } + + @Override + public Integer getDimAmount() { + return getIntensity(); + } + + @Override + public void setDimAmount(Integer intensity) { + setIntensity(intensity); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java similarity index 55% rename from src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java rename to src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java index 6162cb7..d04c089 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableLightState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java @@ -6,22 +6,22 @@ import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -/** Represent a dimmable light state */ +/** Represent a state for an IDimmable device */ @Entity -public class DimmableLightState extends State { +public class DimmableState>> extends State { /** The light intensity value. Goes from 0 (off) to 100 (on) */ @NotNull @Column(nullable = false) @Min(0) @Max(100) - private Integer intensity = 0; + private Integer dimAmount = 0; - public Integer getIntensity() { - return intensity; + public Integer getDimAmount() { + return dimAmount; } - public void setIntensity(Integer intensity) { - this.intensity = intensity; + public void setDimAmount(Integer dimAmount) { + this.dimAmount = dimAmount; } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java new file mode 100644 index 0000000..3ee8a77 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java @@ -0,0 +1,10 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +/** + * Although not totally enforced in code, it represents an OutputDevice that can be set a state (here "dimAmount") + * that ranges from 0 to 100 + */ +public interface IDimmable { + Integer getDimAmount(); + void setDimAmount(Integer intensity); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java new file mode 100644 index 0000000..fda22fa --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java @@ -0,0 +1,20 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +/** Interface equivalent of Switchable. Altough not totally enforced in code, it represents an OutputDevice that can be + * turned on or off + */ +public interface ISwtichable { + /** + * 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); +} 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 2dcff1b..5d8cb3f 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 Switchable { +public class RegularLight extends Switchable implements AlterableFromSwitchableState { /** 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/SecurityCamera.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java index 7ddde5d..be0f559 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java @@ -5,7 +5,7 @@ import javax.persistence.Entity; import javax.validation.constraints.NotNull; @Entity -public class SecurityCamera extends Switchable { +public class SecurityCamera extends Switchable implements AlterableFromSwitchableState { public SecurityCamera() { super("securityCamera"); 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 9b07e69..9f138d9 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 @@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull; /** A smart plug that can be turned either on or off */ @Entity -public class SmartPlug extends Switchable { +public class SmartPlug extends Switchable implements AlterableFromSwitchableState { /** The average consumption of an active plug when on in Watt */ public static final Double AVERAGE_CONSUMPTION_KW = 200.0; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java index 25e9e31..8e58f76 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java @@ -2,6 +2,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import io.swagger.annotations.ApiModelProperty; +import org.hibernate.annotations.Type; + import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -11,7 +13,7 @@ import javax.validation.constraints.NotNull; */ @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -public abstract class State { +public abstract class State>> { @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -19,10 +21,10 @@ public abstract class State { @ApiModelProperty(hidden = true) private long id; - @ManyToOne + @ManyToOne(targetEntity = OutputDevice.class) @JoinColumn(name = "device_id", updatable = false, insertable = false) @GsonExclude - private Device device; + private D device; /** * The device this state belongs in, as a foreign key id. To use when updating and inserting @@ -41,6 +43,13 @@ public abstract class State { @NotNull private Long sceneId; + /** + * Sets the state of the connected device to the state represented by this object. + */ + public void apply() { + device.readStateAndSet(this); + } + public long getId() { return id; } @@ -49,11 +58,11 @@ public abstract class State { this.id = id; } - public Device getDevice() { + public D getDevice() { return device; } - public void setDevice(Device device) { + public void setDevice(D device) { this.device = device; } 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 5ba0702..898c6a4 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 @@ -6,7 +6,7 @@ import javax.persistence.*; /** A device that can be turned either on or off */ @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -public abstract class Switchable extends OutputDevice { +public abstract class Switchable extends OutputDevice implements ISwtichable { public static final Connector SWITCH_SWITCHABLE_CONNECTOR = Connector.basic(Switch::getOutputs, Switchable::setSwitchId); @@ -23,20 +23,6 @@ public abstract class Switchable extends OutputDevice { super(kind); } - /** - * Returns whether the device is on (true) or not (false) - * - * @return whether the device is on (true) or not (false) - */ - public abstract boolean isOn(); - - /** - * Sets the on status of the device - * - * @param on the new on status: true for on, false for off - */ - public abstract void setOn(boolean on); - public Long getSwitchId() { return switchId; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java index 95efe8a..9260801 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java @@ -4,9 +4,9 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.validation.constraints.NotNull; -/** A state for RegularLight and SmartPlug */ +/** Represents a state for a Switchable device */ @Entity -public class SwitchableState extends State { +public class SwitchableState>> extends State { @Column(name = "switchable_on", nullable = false) @NotNull diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index 8524b8f..61081f5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -9,9 +9,15 @@ import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ @Entity -public class Thermostat extends OutputDevice { +public class Thermostat extends OutputDevice implements AlterableFromState> { - public enum ThermostatState { + @Override + public void readStateAndSet(State state) { + final ThermostatState hack = (ThermostatState) state; + setMode(hack.getMode()); + } + + public enum Mode { @SerializedName("OFF") OFF, @SerializedName("IDLE") @@ -31,7 +37,7 @@ public class Thermostat extends OutputDevice { Sensor.TYPICAL_VALUES.get(Sensor.SensorType.TEMPERATURE); /** State of this thermostat */ - @Column @NotNull private ThermostatState state; + @Column @NotNull private Thermostat.Mode mode; @Transient private BigDecimal measuredTemperature; @@ -40,15 +46,15 @@ public class Thermostat extends OutputDevice { /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { super("thermostat"); - this.state = ThermostatState.OFF; + this.mode = Mode.OFF; } - public void setState(ThermostatState state) { - this.state = state; + public void setMode(Mode state) { + this.mode = state; } - public ThermostatState getState() { - return this.state; + public Mode getMode() { + return this.mode; } public BigDecimal getTargetTemperature() { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java new file mode 100644 index 0000000..f80c34d --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java @@ -0,0 +1,16 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Entity; + +@Entity +public class ThermostatState extends State { + private Thermostat.Mode mode; + + public Thermostat.Mode getMode() { + return mode; + } + + public void setMode(Thermostat.Mode mode) { + this.mode = mode; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java index fca88ee..fcd5378 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -43,7 +43,7 @@ public class ThermostatService { } public boolean computeState(Thermostat t) { - if (t.getState() == Thermostat.ThermostatState.OFF) { + if (t.getMode() == Thermostat.Mode.OFF) { return false; } @@ -53,14 +53,14 @@ public class ThermostatService { BigDecimal delta = target.subtract(measured); if (delta.abs().doubleValue() < 0.25) { - if (t.getState() == Thermostat.ThermostatState.IDLE) return false; - t.setState(Thermostat.ThermostatState.IDLE); + if (t.getMode() == Thermostat.Mode.IDLE) return false; + t.setMode(Thermostat.Mode.IDLE); } else if (delta.signum() > 0) { - if (t.getState() == Thermostat.ThermostatState.HEATING) return false; - t.setState(Thermostat.ThermostatState.HEATING); + if (t.getMode() == Thermostat.Mode.HEATING) return false; + t.setMode(Thermostat.Mode.HEATING); } else { - if (t.getState() == Thermostat.ThermostatState.COOLING) return false; - t.setState(Thermostat.ThermostatState.COOLING); + if (t.getMode() == Thermostat.Mode.COOLING) return false; + t.setMode(Thermostat.Mode.COOLING); } return true; From e3aa44435e9d1786a121b5f095583da610508f36 Mon Sep 17 00:00:00 2001 From: omenem Date: Fri, 17 Apr 2020 17:03:21 +0200 Subject: [PATCH 03/12] Scene Controller, saveRequest and Repository --- .../smarthut/controller/SceneController.java | 92 +++++++++++++++++++ .../smarthut/dto/SceneSaveRequest.java | 24 +++++ .../sanmarinoes/smarthut/models/Scene.java | 19 +++- .../smarthut/models/SceneRepository.java | 18 ++++ .../smarthut/models/StateRepository.java | 14 +++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java new file mode 100644 index 0000000..0cbf2d7 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -0,0 +1,92 @@ +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.SceneSaveRequest; +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.Scene; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; +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.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@EnableAutoConfiguration +@RequestMapping("/scene") +public class SceneController { + + @Autowired SceneRepository sceneService; + @Autowired UserRepository userService; + @Autowired StateRepository stateService; + + @GetMapping + public List findAll() { + return toList(sceneService.findAll()); + } + + @GetMapping("/{id}") + public @ResponseBody Scene findById(@PathVariable("id") long id) throws NotFoundException { + return sceneService.findById(id).orElseThrow(NotFoundException::new); + } + + @PostMapping + public @ResponseBody Scene create( + @Valid @RequestBody SceneSaveRequest s, final Principal principal) { + + final String username = principal.getName(); + final Long userId = userService.findByUsername(username).getId(); + + final Scene newScene = new Scene(); + + newScene.setUserId(userId); + newScene.setName(s.getName()); + + return sceneService.save(newScene); + } + + @PutMapping("/{id}") + public @ResponseBody Scene update( + @PathVariable("id") long id, @RequestBody SceneSaveRequest s, final Principal principal) + throws NotFoundException { + final Scene newScene = + sceneService + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + + if (s.getName() != null) { + newScene.setName(s.getName()); + } + + return sceneService.save(newScene); + } + + @DeleteMapping("/{id}") + public void deleteById(@PathVariable("id") long id) { + stateService.deleteAllBySceneId(id); + sceneService.deleteById(id); + } + + /** + * Returns a List of all Devices that are associated to a given scene (identified by its + * id). + */ + @GetMapping(path = "/{sceneId}/devices") + public List getDevices(@PathVariable("sceneId") long sceneId) { + Iterable states = stateService.findBySceneId(sceneId); + return toList(states); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java new file mode 100644 index 0000000..ea3c6bd --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java @@ -0,0 +1,24 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + +import com.sun.istack.NotNull; + +public class SceneSaveRequest { + + /** Room identifier */ + private long id; + + /** The user given name of this room (e.g. 'Master bedroom') */ + @NotNull private String name; + + public long getId() { + return id; + } + + 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/models/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java index d006430..3d026b7 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -27,12 +27,25 @@ public class Scene { @OneToMany(mappedBy = "scene", orphanRemoval = true) @GsonExclude - private Set states = new HashSet<>(); + private Set> states = new HashSet<>(); @NotNull @Column(name = "user_id", nullable = false) private Long userId; + /** The user given name of this room (e.g. 'Master bedroom') */ + @NotNull + @Column(nullable = false) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public long getId() { return id; } @@ -49,11 +62,11 @@ public class Scene { this.user = user; } - public Set getStates() { + public Set> getStates() { return states; } - public void setStates(Set states) { + public void setStates(Set> states) { this.states = states; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java new file mode 100644 index 0000000..513ed9c --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java @@ -0,0 +1,18 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.util.Optional; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; + +public interface SceneRepository extends CrudRepository { + + /** + * Finds a room by their id and a username + * + * @param id the scene id + * @param username a User's username + * @return an optional scene, empty if none found + */ + @Query("SELECT r FROM Room r JOIN r.user u WHERE r.id = ?1 AND u.username = ?2") + Optional findByIdAndUsername(Long id, String username); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java new file mode 100644 index 0000000..4cf31f9 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java @@ -0,0 +1,14 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.util.List; +import javax.transaction.Transactional; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +public interface StateRepository extends CrudRepository { + + @Transactional + void deleteAllBySceneId(long roomId); + + List findBySceneId(@Param("sceneId") long sceneId); +} From 80088c0dc351d36b0b76951734c4d1427a167a22 Mon Sep 17 00:00:00 2001 From: omenem Date: Fri, 17 Apr 2020 18:13:46 +0200 Subject: [PATCH 04/12] State controller, saveRequest and Repository --- .../controller/SwitchableStateController.java | 64 ++++++++++++++++++ .../controller/ThermostatStateController.java | 67 +++++++++++++++++++ .../dto/SwitchableStateSaveRequest.java | 43 ++++++++++++ .../dto/ThermostatStateSaveRequest.java | 44 ++++++++++++ .../sanmarinoes/smarthut/models/State.java | 15 +++-- .../models/SwitchableStateRepository.java | 3 + .../models/ThermostatStateRepository.java | 3 + 7 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java new file mode 100644 index 0000000..e7e056b --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java @@ -0,0 +1,64 @@ +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.SwitchableStateSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableState; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableStateRepository; +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.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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("/switchableState") +public class SwitchableStateController { + + @Autowired private SwitchableStateRepository switchableStateService; + + @GetMapping + public List findAll() { + return toList(switchableStateService.findAll()); + } + + @GetMapping("/{id}") + public SwitchableState findById(@PathVariable("id") long id) throws NotFoundException { + return switchableStateService.findById(id).orElseThrow(NotFoundException::new); + } + + private SwitchableState save(SwitchableState initial, SwitchableStateSaveRequest ss) { + initial.setDeviceId(ss.getDeviceId()); + initial.setSceneId(ss.getSceneId()); + initial.setOn(ss.isOn()); + + return switchableStateService.save(initial); + } + + @PostMapping + public SwitchableState create(@Valid @RequestBody SwitchableStateSaveRequest dl) { + return save(new SwitchableState(), dl); + } + + @PutMapping + public SwitchableState update(@Valid @RequestBody SwitchableStateSaveRequest ss) + throws NotFoundException { + return save( + switchableStateService.findById(ss.getId()).orElseThrow(NotFoundException::new), + ss); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") long id) { + switchableStateService.deleteById(id); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java new file mode 100644 index 0000000..cbc0a91 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java @@ -0,0 +1,67 @@ +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.ThermostatStateSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatState; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatStateRepository; +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.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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; + +public class ThermostatStateController { + + @RestController + @EnableAutoConfiguration + @RequestMapping("/thermostatState") + public class SwitchableStateController { + + @Autowired private ThermostatStateRepository thermostatStateService; + + @GetMapping + public List findAll() { + return toList(thermostatStateService.findAll()); + } + + @GetMapping("/{id}") + public ThermostatState findById(@PathVariable("id") long id) throws NotFoundException { + return thermostatStateService.findById(id).orElseThrow(NotFoundException::new); + } + + private ThermostatState save(ThermostatState initial, ThermostatStateSaveRequest ts) { + initial.setDeviceId(ts.getDeviceId()); + initial.setSceneId(ts.getSceneId()); + initial.setMode(ts.getMode()); + + return thermostatStateService.save(initial); + } + + @PostMapping + public ThermostatState create(@Valid @RequestBody ThermostatStateSaveRequest dl) { + return save(new ThermostatState(), dl); + } + + @PutMapping + public ThermostatState update(@Valid @RequestBody ThermostatStateSaveRequest ts) + throws NotFoundException { + return save( + thermostatStateService.findById(ts.getId()).orElseThrow(NotFoundException::new), + ts); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") long id) { + thermostatStateService.deleteById(id); + } + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java new file mode 100644 index 0000000..a22d7b0 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java @@ -0,0 +1,43 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + +import javax.validation.constraints.NotNull; + +public class SwitchableStateSaveRequest { + + /** Device id (used only for update requests) */ + private Long id; + + @NotNull private Long deviceId; + + @NotNull private Long sceneId; + + @NotNull private boolean on; + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public Long getSceneId() { + return sceneId; + } + + public void setSceneId(Long sceneId) { + this.sceneId = sceneId; + } + + public boolean isOn() { + return on; + } + + public void setOn(boolean on) { + this.on = on; + } + + public Long getId() { + return id; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java new file mode 100644 index 0000000..2a7912b --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java @@ -0,0 +1,44 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; +import javax.validation.constraints.NotNull; + +public class ThermostatStateSaveRequest { + + /** Device id (used only for update requests) */ + private Long id; + + @NotNull private Long deviceId; + + @NotNull private Long sceneId; + + private Thermostat.Mode mode; + + public Thermostat.Mode getMode() { + return mode; + } + + public void setMode(Thermostat.Mode mode) { + this.mode = mode; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public Long getSceneId() { + return sceneId; + } + + public void setSceneId(Long sceneId) { + this.sceneId = sceneId; + } + + public Long getId() { + return id; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java index 8e58f76..d0b139f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java @@ -2,8 +2,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import io.swagger.annotations.ApiModelProperty; -import org.hibernate.annotations.Type; - import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -43,9 +41,7 @@ public abstract class State @NotNull private Long sceneId; - /** - * Sets the state of the connected device to the state represented by this object. - */ + /** Sets the state of the connected device to the state represented by this object. */ public void apply() { device.readStateAndSet(this); } @@ -89,4 +85,13 @@ public abstract class State public void setSceneId(Long sceneId) { this.sceneId = sceneId; } + + @PreRemove + public void removeDeviceAndScene() { + this.setScene(null); + this.setSceneId(null); + + this.setDevice(null); + this.setDeviceId(null); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java new file mode 100644 index 0000000..5c9850b --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface SwitchableStateRepository extends StateRepository {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java new file mode 100644 index 0000000..2496a5d --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface ThermostatStateRepository extends StateRepository {} From 3cedaf5f50ac8224a87e52873dd8537692c5cfa4 Mon Sep 17 00:00:00 2001 From: omenem Date: Fri, 17 Apr 2020 18:28:42 +0200 Subject: [PATCH 05/12] Fix --- .../controller/ThermostatStateController.java | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java index cbc0a91..4f83c29 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java @@ -19,49 +19,46 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +@RestController +@EnableAutoConfiguration +@RequestMapping("/thermostatState") public class ThermostatStateController { - @RestController - @EnableAutoConfiguration - @RequestMapping("/thermostatState") - public class SwitchableStateController { + @Autowired private ThermostatStateRepository thermostatStateService; - @Autowired private ThermostatStateRepository thermostatStateService; + @GetMapping + public List findAll() { + return toList(thermostatStateService.findAll()); + } - @GetMapping - public List findAll() { - return toList(thermostatStateService.findAll()); - } + @GetMapping("/{id}") + public ThermostatState findById(@PathVariable("id") long id) throws NotFoundException { + return thermostatStateService.findById(id).orElseThrow(NotFoundException::new); + } - @GetMapping("/{id}") - public ThermostatState findById(@PathVariable("id") long id) throws NotFoundException { - return thermostatStateService.findById(id).orElseThrow(NotFoundException::new); - } + private ThermostatState save(ThermostatState initial, ThermostatStateSaveRequest ts) { + initial.setDeviceId(ts.getDeviceId()); + initial.setSceneId(ts.getSceneId()); + initial.setMode(ts.getMode()); - private ThermostatState save(ThermostatState initial, ThermostatStateSaveRequest ts) { - initial.setDeviceId(ts.getDeviceId()); - initial.setSceneId(ts.getSceneId()); - initial.setMode(ts.getMode()); + return thermostatStateService.save(initial); + } - return thermostatStateService.save(initial); - } + @PostMapping + public ThermostatState create(@Valid @RequestBody ThermostatStateSaveRequest dl) { + return save(new ThermostatState(), dl); + } - @PostMapping - public ThermostatState create(@Valid @RequestBody ThermostatStateSaveRequest dl) { - return save(new ThermostatState(), dl); - } + @PutMapping + public ThermostatState update(@Valid @RequestBody ThermostatStateSaveRequest ts) + throws NotFoundException { + return save( + thermostatStateService.findById(ts.getId()).orElseThrow(NotFoundException::new), + ts); + } - @PutMapping - public ThermostatState update(@Valid @RequestBody ThermostatStateSaveRequest ts) - throws NotFoundException { - return save( - thermostatStateService.findById(ts.getId()).orElseThrow(NotFoundException::new), - ts); - } - - @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - thermostatStateService.deleteById(id); - } + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") long id) { + thermostatStateService.deleteById(id); } } From fefd073534e4d9e2499bdfeddd7ccfc26d128fdc Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 17 Apr 2020 19:09:32 +0200 Subject: [PATCH 06/12] Converted thermostat to dimmable state and fixed errors on generics --- .../smarthut/controller/SceneController.java | 13 ++-- .../controller/SwitchableStateController.java | 12 ++-- .../controller/ThermostatStateController.java | 64 ------------------- .../models/DimmableStateRepository.java | 3 + .../smarthut/models/StateRepository.java | 2 +- .../models/SwitchableStateRepository.java | 2 +- .../smarthut/models/Thermostat.java | 40 ++++++++++-- .../smarthut/models/ThermostatState.java | 16 ----- .../models/ThermostatStateRepository.java | 3 - .../smarthut/service/ThermostatService.java | 21 +----- 10 files changed, 53 insertions(+), 123 deletions(-) delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableStateRepository.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index 0cbf2d7..c2c82eb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -4,11 +4,8 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SceneSaveRequest; 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.Scene; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; + import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -31,7 +28,7 @@ public class SceneController { @Autowired SceneRepository sceneService; @Autowired UserRepository userService; - @Autowired StateRepository stateService; + @Autowired StateRepository> stateService; @GetMapping public List findAll() { @@ -85,8 +82,8 @@ public class SceneController { * id). */ @GetMapping(path = "/{sceneId}/devices") - public List getDevices(@PathVariable("sceneId") long sceneId) { - Iterable states = stateService.findBySceneId(sceneId); + public List> getDevices(@PathVariable("sceneId") long sceneId) { + Iterable> states = stateService.findBySceneId(sceneId); return toList(states); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java index e7e056b..65786e8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java @@ -27,16 +27,16 @@ public class SwitchableStateController { @Autowired private SwitchableStateRepository switchableStateService; @GetMapping - public List findAll() { + public List> findAll() { return toList(switchableStateService.findAll()); } @GetMapping("/{id}") - public SwitchableState findById(@PathVariable("id") long id) throws NotFoundException { + public SwitchableState findById(@PathVariable("id") long id) throws NotFoundException { return switchableStateService.findById(id).orElseThrow(NotFoundException::new); } - private SwitchableState save(SwitchableState initial, SwitchableStateSaveRequest ss) { + private SwitchableState save(SwitchableState initial, SwitchableStateSaveRequest ss) { initial.setDeviceId(ss.getDeviceId()); initial.setSceneId(ss.getSceneId()); initial.setOn(ss.isOn()); @@ -45,12 +45,12 @@ public class SwitchableStateController { } @PostMapping - public SwitchableState create(@Valid @RequestBody SwitchableStateSaveRequest dl) { - return save(new SwitchableState(), dl); + public SwitchableState create(@Valid @RequestBody SwitchableStateSaveRequest dl) { + return save(new SwitchableState<>(), dl); } @PutMapping - public SwitchableState update(@Valid @RequestBody SwitchableStateSaveRequest ss) + public SwitchableState update(@Valid @RequestBody SwitchableStateSaveRequest ss) throws NotFoundException { return save( switchableStateService.findById(ss.getId()).orElseThrow(NotFoundException::new), diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java deleted file mode 100644 index 4f83c29..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatStateController.java +++ /dev/null @@ -1,64 +0,0 @@ -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.ThermostatStateSaveRequest; -import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatState; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatStateRepository; -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.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -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("/thermostatState") -public class ThermostatStateController { - - @Autowired private ThermostatStateRepository thermostatStateService; - - @GetMapping - public List findAll() { - return toList(thermostatStateService.findAll()); - } - - @GetMapping("/{id}") - public ThermostatState findById(@PathVariable("id") long id) throws NotFoundException { - return thermostatStateService.findById(id).orElseThrow(NotFoundException::new); - } - - private ThermostatState save(ThermostatState initial, ThermostatStateSaveRequest ts) { - initial.setDeviceId(ts.getDeviceId()); - initial.setSceneId(ts.getSceneId()); - initial.setMode(ts.getMode()); - - return thermostatStateService.save(initial); - } - - @PostMapping - public ThermostatState create(@Valid @RequestBody ThermostatStateSaveRequest dl) { - return save(new ThermostatState(), dl); - } - - @PutMapping - public ThermostatState update(@Valid @RequestBody ThermostatStateSaveRequest ts) - throws NotFoundException { - return save( - thermostatStateService.findById(ts.getId()).orElseThrow(NotFoundException::new), - ts); - } - - @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - thermostatStateService.deleteById(id); - } -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableStateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableStateRepository.java new file mode 100644 index 0000000..00edb96 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableStateRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface DimmableStateRepository extends StateRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java index 4cf31f9..eda0824 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java @@ -5,7 +5,7 @@ import javax.transaction.Transactional; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; -public interface StateRepository extends CrudRepository { +public interface StateRepository> extends CrudRepository { @Transactional void deleteAllBySceneId(long roomId); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java index 5c9850b..933ac6c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableStateRepository.java @@ -1,3 +1,3 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -public interface SwitchableStateRepository extends StateRepository {} +public interface SwitchableStateRepository extends StateRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java index 61081f5..ee18054 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Thermostat.java @@ -9,12 +9,44 @@ import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ @Entity -public class Thermostat extends OutputDevice implements AlterableFromState> { +public class Thermostat extends Switchable implements AlterableFromSwitchableState { @Override - public void readStateAndSet(State state) { - final ThermostatState hack = (ThermostatState) state; - setMode(hack.getMode()); + public boolean isOn() { + return mode != Mode.OFF; + } + + @Override + public void setOn(boolean on) { + mode = on ? Mode.IDLE : Mode.OFF; + computeState(); + } + + /** + * Computes the new thermostat state, for when the thermostat is on; + * @return true if the state changed, false if not; + */ + public boolean computeState() { + if (mode == Thermostat.Mode.OFF) { + return false; + } + + BigDecimal measured = this.getMeasuredTemperature(); + BigDecimal target = this.getTargetTemperature(); + BigDecimal delta = target.subtract(measured); + + if (delta.abs().doubleValue() < 0.25) { + if (this.getMode() == Thermostat.Mode.IDLE) return false; + this.setMode(Thermostat.Mode.IDLE); + } else if (delta.signum() > 0) { + if (this.getMode() == Thermostat.Mode.HEATING) return false; + this.setMode(Thermostat.Mode.HEATING); + } else { + if (this.getMode() == Thermostat.Mode.COOLING) return false; + this.setMode(Thermostat.Mode.COOLING); + } + + return true; } public enum Mode { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java deleted file mode 100644 index f80c34d..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatState.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -import javax.persistence.Entity; - -@Entity -public class ThermostatState extends State { - private Thermostat.Mode mode; - - public Thermostat.Mode getMode() { - return mode; - } - - public void setMode(Thermostat.Mode mode) { - this.mode = mode; - } -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java deleted file mode 100644 index 2496a5d..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ThermostatStateRepository.java +++ /dev/null @@ -1,3 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -public interface ThermostatStateRepository extends StateRepository {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java index fcd5378..2352cf9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -43,27 +43,8 @@ public class ThermostatService { } public boolean computeState(Thermostat t) { - if (t.getMode() == Thermostat.Mode.OFF) { - return false; - } - populateMeasuredTemperature(t); - BigDecimal measured = t.getMeasuredTemperature(); - BigDecimal target = t.getTargetTemperature(); - BigDecimal delta = target.subtract(measured); - - if (delta.abs().doubleValue() < 0.25) { - if (t.getMode() == Thermostat.Mode.IDLE) return false; - t.setMode(Thermostat.Mode.IDLE); - } else if (delta.signum() > 0) { - if (t.getMode() == Thermostat.Mode.HEATING) return false; - t.setMode(Thermostat.Mode.HEATING); - } else { - if (t.getMode() == Thermostat.Mode.COOLING) return false; - t.setMode(Thermostat.Mode.COOLING); - } - - return true; + return t.computeState(); } private void updateState(Thermostat t) { From 2bfff689b385fbd9a3a0e0696443256e21170f39 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 17 Apr 2020 20:20:12 +0200 Subject: [PATCH 07/12] Simplified Models for States --- .../controller/ButtonDimmerController.java | 8 ++++---- .../controller/KnobDimmerController.java | 8 ++++---- .../models/AlterableFromDimmableState.java | 13 ------------ .../smarthut/models/AlterableFromState.java | 6 ------ .../models/AlterableFromSwitchableState.java | 13 ------------ .../sanmarinoes/smarthut/models/Curtains.java | 2 +- .../sanmarinoes/smarthut/models/Dimmable.java | 16 +++++---------- .../smarthut/models/DimmableLight.java | 2 +- .../smarthut/models/DimmableState.java | 11 +++++++--- .../sanmarinoes/smarthut/models/Dimmer.java | 6 +++--- .../smarthut/models/IDimmable.java | 10 ---------- .../smarthut/models/ISwtichable.java | 20 ------------------- .../smarthut/models/RegularLight.java | 2 +- .../smarthut/models/SecurityCamera.java | 2 +- .../smarthut/models/SmartPlug.java | 2 +- .../sanmarinoes/smarthut/models/State.java | 6 ++---- .../smarthut/models/Switchable.java | 6 +++++- .../smarthut/models/SwitchableState.java | 7 ++++++- .../smarthut/models/Thermostat.java | 2 +- 19 files changed, 43 insertions(+), 99 deletions(-) delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.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 62da223..1870abc 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 @@ -18,13 +18,13 @@ import org.springframework.web.bind.annotation.*; @EnableAutoConfiguration @RequestMapping("/buttonDimmer") public class ButtonDimmerController - extends InputDeviceConnectionController> { + extends InputDeviceConnectionController { private ButtonDimmerRepository buttonDimmerRepository; - private DimmableRepository> dimmableRepository; + private DimmableRepository dimmableRepository; @Autowired protected ButtonDimmerController( - ButtonDimmerRepository inputRepository, DimmableRepository> outputRepository) { + ButtonDimmerRepository inputRepository, DimmableRepository outputRepository) { super( inputRepository, outputRepository, @@ -53,7 +53,7 @@ public class ButtonDimmerController } @PutMapping("/dim") - public Set> dim( + public Set dim( @Valid @RequestBody final ButtonDimmerDimRequest bd, final Principal principal) throws NotFoundException { final ButtonDimmer buttonDimmer = 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 29adf09..adf75ea 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 @@ -18,14 +18,14 @@ import org.springframework.web.bind.annotation.*; @EnableAutoConfiguration @RequestMapping("/knobDimmer") public class KnobDimmerController - extends InputDeviceConnectionController> { + extends InputDeviceConnectionController { @Autowired private KnobDimmerRepository knobDimmerRepository; - @Autowired private DimmableRepository> dimmableRepository; + @Autowired private DimmableRepository dimmableRepository; @Autowired protected KnobDimmerController( - KnobDimmerRepository inputRepository, DimmableRepository> outputRepository) { + KnobDimmerRepository inputRepository, DimmableRepository outputRepository) { super( inputRepository, outputRepository, @@ -54,7 +54,7 @@ public class KnobDimmerController } @PutMapping("/dimTo") - public Set> dimTo( + public Set dimTo( @Valid @RequestBody final KnobDimmerDimRequest bd, final Principal principal) throws NotFoundException { final KnobDimmer dimmer = diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java deleted file mode 100644 index 64b7039..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromDimmableState.java +++ /dev/null @@ -1,13 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -/** - * An IDimmable Device whose state can be set by a DimmableState of the corresponding type - * @param the type of the class that extends this interface (just for type bounds, does not mean actually anything) - */ -public interface AlterableFromDimmableState> - extends IDimmable, AlterableFromState> { - default void readStateAndSet(State state) { - final DimmableState hack = (DimmableState) state; - setDimAmount(hack.getDimAmount()); - } -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java deleted file mode 100644 index 235017c..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromState.java +++ /dev/null @@ -1,6 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -/** An OutputDevice whose state can be set by a State of corresponding device type */ -public interface AlterableFromState> { - void readStateAndSet(T state); -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java deleted file mode 100644 index a4f2d29..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AlterableFromSwitchableState.java +++ /dev/null @@ -1,13 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -/** - * An ISwitchable Device whose state can be set by a SwitchableState of the corresponding type - * @param the type of the class that extends this interface (just for type bounds, does not mean actually anything) - */ -public interface AlterableFromSwitchableState> - extends ISwtichable, AlterableFromState> { - default void readStateAndSet(State state) { - final SwitchableState hack = (SwitchableState) state; - setOn(hack.isOn()); - } -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java index b08e59a..d9e8d98 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Curtains.java @@ -7,7 +7,7 @@ import javax.persistence.Entity; * 0 is completely closed 100 is completely open */ @Entity -public class Curtains extends Dimmable { +public class Curtains extends Dimmable { public Curtains() { super("curtains"); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java index ee31d28..8a4da95 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java @@ -10,13 +10,13 @@ import java.util.Set; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -public class Dimmable> extends Switchable implements IDimmable, AlterableFromDimmableState { +public class Dimmable extends Switchable { - public static final Connector> + public static final Connector KNOB_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(KnobDimmer::getOutputs, Dimmable::getDimmers); - public static final Connector> + public static final Connector BUTTON_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(ButtonDimmer::getOutputs, Dimmable::getDimmers); @@ -76,13 +76,7 @@ public class Dimmable> extends Switchable implements IDimm return this.dimmers; } - @Override - public Integer getDimAmount() { - return getIntensity(); - } - - @Override - public void setDimAmount(Integer intensity) { - setIntensity(intensity); + public void readStateAndSet(DimmableState state) { + setIntensity(state.getIntensity()); } } 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 127b9a4..89806a7 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 @@ -4,7 +4,7 @@ import javax.persistence.*; /** Represent a dimmable light */ @Entity -public class DimmableLight extends Dimmable { +public class DimmableLight extends Dimmable { public DimmableLight() { super("dimmableLight"); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java index d04c089..1f548f8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java @@ -8,7 +8,7 @@ import javax.validation.constraints.NotNull; /** Represent a state for an IDimmable device */ @Entity -public class DimmableState>> extends State { +public class DimmableState extends State { /** The light intensity value. Goes from 0 (off) to 100 (on) */ @NotNull @@ -17,11 +17,16 @@ public class DimmableState> @Max(100) private Integer dimAmount = 0; - public Integer getDimAmount() { + public Integer getIntensity() { return dimAmount; } - public void setDimAmount(Integer dimAmount) { + public void setIntensity(Integer dimAmount) { this.dimAmount = dimAmount; } + + @Override + public void apply() { + getDevice().readStateAndSet(this); + } } 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 0480534..7ef0808 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 @@ -21,7 +21,7 @@ public abstract class Dimmer extends InputDevice { joinColumns = @JoinColumn(name = "dimmer_id"), inverseJoinColumns = @JoinColumn(name = "dimmable_id") ) - private Set> dimmables = new HashSet<>(); + private Set dimmables = new HashSet<>(); /** * Get the lights connected to this dimmer @@ -29,12 +29,12 @@ public abstract class Dimmer extends InputDevice { * @return duh */ @Override - public Set> getOutputs() { + public Set getOutputs() { return this.dimmables; } /** Add a light to be controller by this dimmer */ - public void addDimmable(Dimmable dimmable) { + public void addDimmable(Dimmable dimmable) { dimmables.add(dimmable); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java deleted file mode 100644 index 3ee8a77..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/IDimmable.java +++ /dev/null @@ -1,10 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -/** - * Although not totally enforced in code, it represents an OutputDevice that can be set a state (here "dimAmount") - * that ranges from 0 to 100 - */ -public interface IDimmable { - Integer getDimAmount(); - void setDimAmount(Integer intensity); -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java deleted file mode 100644 index fda22fa..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ISwtichable.java +++ /dev/null @@ -1,20 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -/** Interface equivalent of Switchable. Altough not totally enforced in code, it represents an OutputDevice that can be - * turned on or off - */ -public interface ISwtichable { - /** - * 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); -} 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 5d8cb3f..2dcff1b 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 Switchable implements AlterableFromSwitchableState { +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/SecurityCamera.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java index be0f559..7ddde5d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SecurityCamera.java @@ -5,7 +5,7 @@ import javax.persistence.Entity; import javax.validation.constraints.NotNull; @Entity -public class SecurityCamera extends Switchable implements AlterableFromSwitchableState { +public class SecurityCamera extends Switchable { public SecurityCamera() { super("securityCamera"); 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 0abc2e2..546c746 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 @@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull; /** A smart plug that can be turned either on or off */ @Entity -public class SmartPlug extends Switchable implements AlterableFromSwitchableState { +public class SmartPlug extends Switchable { /** The average consumption of an active plug when on in Watt */ public static final Double AVERAGE_CONSUMPTION_KW = 200.0; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java index d0b139f..e8e1555 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java @@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull; */ @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -public abstract class State>> { +public abstract class State { @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -42,9 +42,7 @@ public abstract class State private Long sceneId; /** Sets the state of the connected device to the state represented by this object. */ - public void apply() { - device.readStateAndSet(this); - } + public abstract void apply(); public long getId() { return id; 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 16b6f84..318ae98 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 @@ -8,7 +8,7 @@ import java.util.Set; /** A device that can be turned either on or off */ @Entity @Inheritance(strategy = InheritanceType.JOINED) -public abstract class Switchable extends OutputDevice implements ISwtichable { +public abstract class Switchable extends OutputDevice { public static final Connector SWITCH_SWITCHABLE_CONNECTOR = Connector.basic(Switch::getOutputs, Switchable::getSwitches); @@ -38,4 +38,8 @@ public abstract class Switchable extends OutputDevice implements ISwtichable { public Set getSwitches() { return inputs; } + + public void readStateAndSet(SwitchableState state) { + setOn(state.isOn()); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java index 9260801..8e6a5fa 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java @@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull; /** Represents a state for a Switchable device */ @Entity -public class SwitchableState>> extends State { +public class SwitchableState extends State { @Column(name = "switchable_on", nullable = false) @NotNull @@ -19,4 +19,9 @@ public class SwitchableState { +public class Thermostat extends Switchable { @Override public boolean isOn() { From 57a6e22e2a487cba5beb6ceb0af38966ae9692f7 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 17 Apr 2020 20:54:09 +0200 Subject: [PATCH 08/12] Corrections on Scene controllers and method cloneState on all OutputDevices --- .../smarthut/config/SpringFoxConfig.java | 3 ++ .../controller/DimmableStateController.java | 33 ++++++++++++++ .../smarthut/controller/SceneController.java | 35 ++++++++++++--- .../controller/SwitchableStateController.java | 40 +++-------------- .../dto/DimmableStateSaveRequest.java | 28 ++++++++++++ .../dto/SwitchableStateSaveRequest.java | 22 +--------- .../dto/ThermostatStateSaveRequest.java | 44 ------------------- .../sanmarinoes/smarthut/models/Dimmable.java | 18 +++++--- .../smarthut/models/OutputDevice.java | 2 + .../smarthut/models/SceneRepository.java | 4 ++ .../smarthut/models/Switchable.java | 11 ++++- 11 files changed, 129 insertions(+), 111 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableStateController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableStateSaveRequest.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.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 193c18b..2f45d22 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 @@ -75,6 +75,9 @@ public class SpringFoxConfig { .or(PathSelectors.regex("/securityCamera.*")::apply) .or(PathSelectors.regex("/sensor.*")::apply) .or(PathSelectors.regex("/smartPlug.*")::apply) + .or(PathSelectors.regex("/scene.*")::apply) + .or(PathSelectors.regex("/switchableState.*")::apply) + .or(PathSelectors.regex("/dimmableState.*")::apply) .or(PathSelectors.regex("/switch.*")::apply) .or(PathSelectors.regex("/motionSensor.*")::apply) .or(PathSelectors.regex("/curtains.*")::apply) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableStateController.java new file mode 100644 index 0000000..d866d78 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableStateController.java @@ -0,0 +1,33 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableStateSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableStateRepository; +import javax.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.web.bind.annotation.*; + +@RestController +@EnableAutoConfiguration +@RequestMapping("/dimmableState") +public class DimmableStateController { + + @Autowired private DimmableStateRepository dimmableStateRepository; + + @PutMapping + public DimmableState update(@Valid @RequestBody DimmableStateSaveRequest ss) + throws NotFoundException { + final DimmableState initial = + dimmableStateRepository.findById(ss.getId()).orElseThrow(NotFoundException::new); + initial.setIntensity(ss.getIntensity()); + dimmableStateRepository.save(initial); + return initial; + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") long id) { + dimmableStateRepository.deleteById(id); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index c2c82eb..2b4c9c1 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -5,8 +5,8 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SceneSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; - import java.security.Principal; +import java.util.ArrayList; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -29,15 +29,19 @@ public class SceneController { @Autowired SceneRepository sceneService; @Autowired UserRepository userService; @Autowired StateRepository> stateService; + @Autowired DeviceRepository deviceRepository; @GetMapping - public List findAll() { - return toList(sceneService.findAll()); + public List findAll(Principal principal) { + return toList(sceneService.findByUsername(principal.getName())); } @GetMapping("/{id}") - public @ResponseBody Scene findById(@PathVariable("id") long id) throws NotFoundException { - return sceneService.findById(id).orElseThrow(NotFoundException::new); + public @ResponseBody Scene findById(@PathVariable("id") long id, Principal principal) + throws NotFoundException { + return sceneService + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); } @PostMapping @@ -55,6 +59,25 @@ public class SceneController { return sceneService.save(newScene); } + @PostMapping("/{id}/apply") + public @ResponseBody List apply(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + final Scene newScene = + sceneService + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + + final List updated = new ArrayList<>(); + + for (final State s : newScene.getStates()) { + s.apply(); + updated.add(s.getDevice()); + } + deviceRepository.saveAll(updated); + + return updated; + } + @PutMapping("/{id}") public @ResponseBody Scene update( @PathVariable("id") long id, @RequestBody SceneSaveRequest s, final Principal principal) @@ -81,7 +104,7 @@ public class SceneController { * Returns a List of all Devices that are associated to a given scene (identified by its * id). */ - @GetMapping(path = "/{sceneId}/devices") + @GetMapping(path = "/{sceneId}/states") public List> getDevices(@PathVariable("sceneId") long sceneId) { Iterable> states = stateService.findBySceneId(sceneId); return toList(states); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java index 65786e8..ed6f30c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchableStateController.java @@ -1,19 +1,14 @@ 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.SwitchableStateSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableState; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableStateRepository; -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.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -24,41 +19,20 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/switchableState") public class SwitchableStateController { - @Autowired private SwitchableStateRepository switchableStateService; - - @GetMapping - public List> findAll() { - return toList(switchableStateService.findAll()); - } - - @GetMapping("/{id}") - public SwitchableState findById(@PathVariable("id") long id) throws NotFoundException { - return switchableStateService.findById(id).orElseThrow(NotFoundException::new); - } - - private SwitchableState save(SwitchableState initial, SwitchableStateSaveRequest ss) { - initial.setDeviceId(ss.getDeviceId()); - initial.setSceneId(ss.getSceneId()); - initial.setOn(ss.isOn()); - - return switchableStateService.save(initial); - } - - @PostMapping - public SwitchableState create(@Valid @RequestBody SwitchableStateSaveRequest dl) { - return save(new SwitchableState<>(), dl); - } + @Autowired private SwitchableStateRepository switchableStateRepository; @PutMapping public SwitchableState update(@Valid @RequestBody SwitchableStateSaveRequest ss) throws NotFoundException { - return save( - switchableStateService.findById(ss.getId()).orElseThrow(NotFoundException::new), - ss); + final SwitchableState initial = + switchableStateRepository.findById(ss.getId()).orElseThrow(NotFoundException::new); + initial.setOn(ss.isOn()); + switchableStateRepository.save(initial); + return initial; } @DeleteMapping("/{id}") public void delete(@PathVariable("id") long id) { - switchableStateService.deleteById(id); + switchableStateRepository.deleteById(id); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableStateSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableStateSaveRequest.java new file mode 100644 index 0000000..ebf99eb --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/DimmableStateSaveRequest.java @@ -0,0 +1,28 @@ +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 DimmableStateSaveRequest { + + /** Device id (used only for update requests) */ + @NotNull private Long id; + + @NotNull + @Min(0) + @Max(100) + private Integer intensity = 0; + + public Integer getIntensity() { + return intensity; + } + + public void setIntensity(Integer intensity) { + this.intensity = intensity; + } + + public Long getId() { + return id; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java index a22d7b0..ab03f27 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SwitchableStateSaveRequest.java @@ -5,30 +5,10 @@ import javax.validation.constraints.NotNull; public class SwitchableStateSaveRequest { /** Device id (used only for update requests) */ - private Long id; - - @NotNull private Long deviceId; - - @NotNull private Long sceneId; + @NotNull private Long id; @NotNull private boolean on; - public Long getDeviceId() { - return deviceId; - } - - public void setDeviceId(Long deviceId) { - this.deviceId = deviceId; - } - - public Long getSceneId() { - return sceneId; - } - - public void setSceneId(Long sceneId) { - this.sceneId = sceneId; - } - public boolean isOn() { return on; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java deleted file mode 100644 index 2a7912b..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/ThermostatStateSaveRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; - -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Thermostat; -import javax.validation.constraints.NotNull; - -public class ThermostatStateSaveRequest { - - /** Device id (used only for update requests) */ - private Long id; - - @NotNull private Long deviceId; - - @NotNull private Long sceneId; - - private Thermostat.Mode mode; - - public Thermostat.Mode getMode() { - return mode; - } - - public void setMode(Thermostat.Mode mode) { - this.mode = mode; - } - - public Long getDeviceId() { - return deviceId; - } - - public void setDeviceId(Long deviceId) { - this.deviceId = deviceId; - } - - public Long getSceneId() { - return sceneId; - } - - public void setSceneId(Long sceneId) { - this.sceneId = sceneId; - } - - public Long getId() { - return id; - } -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java index 8a4da95..4bfd828 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java @@ -1,23 +1,20 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; - +import java.util.Set; import javax.persistence.*; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -import java.util.Set; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public class Dimmable extends Switchable { - public static final Connector - KNOB_DIMMER_DIMMABLE_CONNECTOR = + public static final Connector KNOB_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(KnobDimmer::getOutputs, Dimmable::getDimmers); - public static final Connector - BUTTON_DIMMER_DIMMABLE_CONNECTOR = + public static final Connector BUTTON_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(ButtonDimmer::getOutputs, Dimmable::getDimmers); protected Dimmable(String kind) { @@ -79,4 +76,13 @@ public class Dimmable extends Switchable { public void readStateAndSet(DimmableState state) { setIntensity(state.getIntensity()); } + + @Override + public DimmableState cloneState() { + final DimmableState newState = new DimmableState<>(); + newState.setDeviceId(getId()); + newState.setDevice(this); + newState.setIntensity(getIntensity()); + return newState; + } } 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 56e68c5..69e24ca 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 @@ -12,4 +12,6 @@ public abstract class OutputDevice extends Device { public OutputDevice(String kind) { super(kind, FlowType.OUTPUT); } + + public abstract State cloneState(); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java index 513ed9c..de08a53 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SceneRepository.java @@ -1,5 +1,6 @@ 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; @@ -15,4 +16,7 @@ public interface SceneRepository extends CrudRepository { */ @Query("SELECT r FROM Room r JOIN r.user u WHERE r.id = ?1 AND u.username = ?2") Optional findByIdAndUsername(Long id, String username); + + @Query("SELECT r FROM Room r JOIN r.user u WHERE u.username = ?1") + List findByUsername(String username); } 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 318ae98..e68e75c 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,9 +1,9 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; -import javax.persistence.*; import java.util.HashSet; import java.util.Set; +import javax.persistence.*; /** A device that can be turned either on or off */ @Entity @@ -42,4 +42,13 @@ public abstract class Switchable extends OutputDevice { public void readStateAndSet(SwitchableState state) { setOn(state.isOn()); } + + @Override + public State cloneState() { + final SwitchableState newState = new SwitchableState<>(); + newState.setDeviceId(getId()); + newState.setDevice(this); + newState.setOn(isOn()); + return newState; + } } From 4aa4d687386e676718efff68e19c0d08e48b4e6f Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 17 Apr 2020 21:05:17 +0200 Subject: [PATCH 09/12] Fix on thermostat --- .../smarthut/controller/ThermostatController.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 00899c8..886e14a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -39,13 +39,7 @@ public class ThermostatController { newT.setName(t.getName()); newT.setRoomId(t.getRoomId()); newT.setUseExternalSensors(t.isUseExternalSensors()); - - if (t.isTurnOn()) { - newT.setMode(Thermostat.Mode.IDLE); - thermostatService.computeState(newT); - } else { - newT.setMode(Thermostat.Mode.OFF); - } + newT.setOn(t.isTurnOn()); newT = thermostatRepository.save(newT); thermostatService.populateMeasuredTemperature(newT); From f565a3be6e25b5ab671a2f8b174847184cb7f595 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 17 Apr 2020 21:12:33 +0200 Subject: [PATCH 10/12] Added documentation to Device.cloneState() --- .../inf/sa4/sanmarinoes/smarthut/models/OutputDevice.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 69e24ca..ba1813e 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 @@ -13,5 +13,11 @@ public abstract class OutputDevice extends Device { super(kind, FlowType.OUTPUT); } + /** + * Creates a State object initialized to point at this device and with values copied from + * this device's state + * + * @return a new State object + */ public abstract State cloneState(); } From e79ab46cb8efb367937133584bcc7c71d8168281 Mon Sep 17 00:00:00 2001 From: omenem Date: Sat, 18 Apr 2020 10:54:53 +0200 Subject: [PATCH 11/12] added sceneBinding method in cotrollers of output devices --- .../controller/CurtainsController.java | 24 ++++++++++++++++++ .../controller/DimmableLightController.java | 25 +++++++++++++++++++ .../controller/RegularLightController.java | 25 +++++++++++++++++++ .../controller/SecurityCameraController.java | 24 ++++++++++++++++++ .../controller/SmartPlugController.java | 19 ++++++++++++++ .../controller/ThermostatController.java | 20 +++++++++++++++ 6 files changed, 137 insertions(+) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java index 54541cf..3ad0974 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java @@ -6,6 +6,11 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Curtains; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.CurtainsRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Dimmable; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import java.security.Principal; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -17,6 +22,8 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/curtains") public class CurtainsController { @Autowired private CurtainsRepository curtainsService; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; @GetMapping public List findAll() { @@ -53,4 +60,21 @@ public class CurtainsController { public void delete(@PathVariable("id") long id) { curtainsService.deleteById(id); } + + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + + Curtains c = + curtainsService + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + DimmableState s = c.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(s); + } } 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 ee33933..367dca3 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 @@ -4,8 +4,12 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Dimmable; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLight; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLightRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -19,6 +23,8 @@ import org.springframework.web.bind.annotation.*; public class DimmableLightController { @Autowired private DimmableLightRepository dimmableLightService; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; @GetMapping public List findAll() { @@ -58,4 +64,23 @@ public class DimmableLightController { public void delete(@PathVariable("id") long id) { dimmableLightService.deleteById(id); } + + // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} + // however it is not necessary to specify the query in the mapping + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + + DimmableLight d = + dimmableLightService + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + State s = d.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(s); + } } 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 cdb3e9d..cc0a5ee 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 @@ -4,8 +4,12 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.OutputDevice; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RegularLight; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RegularLightRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -18,6 +22,7 @@ import org.springframework.web.bind.annotation.PostMapping; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -26,6 +31,8 @@ import org.springframework.web.bind.annotation.RestController; public class RegularLightController { @Autowired private RegularLightRepository regularLightService; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; @GetMapping public List findAll() { @@ -65,4 +72,22 @@ public class RegularLightController { public void delete(@PathVariable("id") long id) { regularLightService.deleteById(id); } + + // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} + // however it is not necessary to specify the query in the mapping + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + RegularLight d = + regularLightService + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + State s = d.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(s); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java index dcaafc4..bd5bd23 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java @@ -4,8 +4,12 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.OutputDevice; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SecurityCamera; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SecurityCameraRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -18,6 +22,7 @@ import org.springframework.web.bind.annotation.PostMapping; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -26,6 +31,8 @@ import org.springframework.web.bind.annotation.RestController; public class SecurityCameraController { @Autowired SecurityCameraRepository securityCameraService; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; @GetMapping public List findAll() { @@ -65,4 +72,21 @@ public class SecurityCameraController { public void delete(@PathVariable("id") long id) { securityCameraService.deleteById(id); } + + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + + SecurityCamera d = + securityCameraService + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + State s = d.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(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 45c33ff..1a165d8 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 @@ -18,6 +18,8 @@ import org.springframework.web.bind.annotation.*; public class SmartPlugController { @Autowired private SmartPlugRepository smartPlugRepository; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; @GetMapping public List findAll() { @@ -69,4 +71,21 @@ public class SmartPlugController { public void deleteById(@PathVariable("id") long id) { smartPlugRepository.deleteById(id); } + + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + + SmartPlug d = + smartPlugRepository + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + State s = d.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(s); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 886e14a..8a3137c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -20,6 +20,9 @@ public class ThermostatController { @Autowired private ThermostatService thermostatService; + @Autowired private SceneRepository sceneRepository; + @Autowired private StateRepository stateRepository; + @GetMapping public List findAll(Principal user) { return thermostatService.findAll(user.getName()); @@ -65,4 +68,21 @@ public class ThermostatController { public void deleteById(@PathVariable("id") long id) { thermostatRepository.deleteById(id); } + + @PostMapping("/{id}/state") + public void sceneBinding( + @PathVariable("id") long deviceId, + @RequestParam long sceneId, + final Principal principal) + throws NotFoundException { + + Thermostat d = + thermostatRepository + .findByIdAndUsername(deviceId, principal.getName()) + .orElseThrow(NotFoundException::new); + State s = d.cloneState(); + sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); + s.setSceneId(sceneId); + stateRepository.save(s); + } } From 61ff797ea19eeb0e8d061a3709a2e7e616fde561 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Sat, 18 Apr 2020 12:38:52 +0200 Subject: [PATCH 12/12] Fixes to Scene implementation --- build.gradle | 8 + .../smarthut/config/GsonConfig.java | 8 + .../config/RuntimeTypeAdapterFactory.java | 315 ++++++++++++++++++ .../controller/CurtainsController.java | 20 +- .../controller/DimmableLightController.java | 20 +- .../controller/RegularLightController.java | 20 +- .../controller/SecurityCameraController.java | 20 +- .../controller/SmartPlugController.java | 13 +- .../controller/ThermostatController.java | 13 +- .../error/DuplicateStateException.java | 12 + .../sanmarinoes/smarthut/models/Dimmable.java | 2 +- .../smarthut/models/DimmableState.java | 14 +- .../sa4/sanmarinoes/smarthut/models/Room.java | 1 + .../sanmarinoes/smarthut/models/Scene.java | 1 + .../sanmarinoes/smarthut/models/State.java | 1 + .../smarthut/models/StateRepository.java | 2 + .../smarthut/models/Switchable.java | 2 +- .../smarthut/models/SwitchableState.java | 4 +- 18 files changed, 408 insertions(+), 68 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateStateException.java diff --git a/build.gradle b/build.gradle index 3116923..c55c8c1 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() + } dependencies { compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final' @@ -39,6 +40,13 @@ dependencies { // Fixes https://stackoverflow.com/a/60455550 testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.11' } + +gradle.projectsEvaluated { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + } +} + test { useJUnitPlatform() } \ No newline at end of file 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 69c4fc9..67b25dc 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 @@ -1,5 +1,8 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.config; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableState; import com.google.gson.*; import java.lang.reflect.Type; import org.springframework.context.annotation.Bean; @@ -24,6 +27,11 @@ public class GsonConfig { final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter()); builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy()); + RuntimeTypeAdapterFactory runtimeTypeAdapterFactory = + RuntimeTypeAdapterFactory.of(State.class, "kind") + .registerSubtype(SwitchableState.class, "switchableState") + .registerSubtype(DimmableState.class, "dimmableState"); + builder.registerTypeAdapterFactory(runtimeTypeAdapterFactory); return builder.create(); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..e4a9107 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java @@ -0,0 +1,315 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.config; + +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Adapts values whose runtime type may differ from their declaration type. This is necessary when a + * field's type is not the same type that GSON should create when deserializing that field. For + * example, consider these types: + * + *
{@code
+ * abstract class Shape {
+ *   int x;
+ *   int y;
+ * }
+ * class Circle extends Shape {
+ *   int radius;
+ * }
+ * class Rectangle extends Shape {
+ *   int width;
+ *   int height;
+ * }
+ * class Diamond extends Shape {
+ *   int width;
+ *   int height;
+ * }
+ * class Drawing {
+ *   Shape bottomShape;
+ *   Shape topShape;
+ * }
+ * }
+ * + *

Without additional type information, the serialized JSON is ambiguous. Is the bottom shape in + * this drawing a rectangle or a diamond? + * + *

{@code
+ * {
+ *   "bottomShape": {
+ *     "width": 10,
+ *     "height": 5,
+ *     "x": 0,
+ *     "y": 0
+ *   },
+ *   "topShape": {
+ *     "radius": 2,
+ *     "x": 4,
+ *     "y": 1
+ *   }
+ * }
+ * }
+ * + * This class addresses this problem by adding type information to the serialized JSON and honoring + * that type information when the JSON is deserialized: + * + *
{@code
+ * {
+ *   "bottomShape": {
+ *     "type": "Diamond",
+ *     "width": 10,
+ *     "height": 5,
+ *     "x": 0,
+ *     "y": 0
+ *   },
+ *   "topShape": {
+ *     "type": "Circle",
+ *     "radius": 2,
+ *     "x": 4,
+ *     "y": 1
+ *   }
+ * }
+ * }
+ * + * Both the type field name ({@code "type"}) and the type labels ({@code "Rectangle"}) are + * configurable. + * + *

Registering Types

+ * + * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field name to the + * {@link #of} factory method. If you don't supply an explicit type field name, {@code "type"} will + * be used. + * + *
{@code
+ * RuntimeTypeAdapterFactory shapeAdapterFactory
+ *     = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * + * Next register all of your subtypes. Every subtype must be explicitly registered. This protects + * your application from injection attacks. If you don't supply an explicit type label, the type's + * simple name will be used. + * + *
{@code
+ * shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ * shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ * shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * + * Finally, register the type adapter factory in your application's GSON builder: + * + *
{@code
+ * Gson gson = new GsonBuilder()
+ *     .registerTypeAdapterFactory(shapeAdapterFactory)
+ *     .create();
+ * }
+ * + * Like {@code GsonBuilder}, this API supports chaining: + * + *
{@code
+ * RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *     .registerSubtype(Rectangle.class)
+ *     .registerSubtype(Circle.class)
+ *     .registerSubtype(Diamond.class);
+ * }
+ * + *

Serialization and deserialization

+ * + * In order to serialize and deserialize a polymorphic object, you must specify the base type + * explicitly. + * + *
{@code
+ * Diamond diamond = new Diamond();
+ * String json = gson.toJson(diamond, Shape.class);
+ * }
+ * + * And then: + * + *
{@code
+ * Shape shape = gson.fromJson(json, Shape.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory( + Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code typeFieldName} as + * the type field name. Type field names are case sensitive. {@code maintainType} flag decide if + * the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of( + Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code typeFieldName} as + * the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as the type + * field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} have already been + * registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple name}. Labels are + * case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name have already been + * registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate = + new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate = + new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = + gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException( + "cannot deserialize " + + baseType + + " because it does not define a field named " + + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException( + "cannot deserialize " + + baseType + + " subtype named " + + label + + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException( + "cannot serialize " + + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException( + "cannot serialize " + + srcType.getName() + + " because it already defines a field named " + + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java index 3ad0974..5eb00be 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java @@ -3,13 +3,9 @@ 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.DimmableSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Curtains; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.CurtainsRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Dimmable; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -23,7 +19,7 @@ import org.springframework.web.bind.annotation.*; public class CurtainsController { @Autowired private CurtainsRepository curtainsService; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll() { @@ -62,19 +58,21 @@ public class CurtainsController { } @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { Curtains c = curtainsService .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - DimmableState s = c.cloneState(); + State s = c.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(s); } } 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 367dca3..cb7cc00 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 @@ -3,13 +3,9 @@ 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.DimmableSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Dimmable; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLight; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableLightRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -24,7 +20,7 @@ public class DimmableLightController { @Autowired private DimmableLightRepository dimmableLightService; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll() { @@ -68,19 +64,21 @@ public class DimmableLightController { // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} // however it is not necessary to specify the query in the mapping @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { DimmableLight d = dimmableLightService .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - State s = d.cloneState(); + State s = d.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(s); } } 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 cc0a5ee..ac0fd47 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 @@ -3,13 +3,9 @@ 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.SwitchableSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.OutputDevice; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RegularLight; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RegularLightRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -32,7 +28,7 @@ public class RegularLightController { @Autowired private RegularLightRepository regularLightService; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll() { @@ -76,18 +72,20 @@ public class RegularLightController { // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} // however it is not necessary to specify the query in the mapping @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { RegularLight d = regularLightService .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - State s = d.cloneState(); + State s = d.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(s); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java index bd5bd23..d7fdc8e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java @@ -3,13 +3,9 @@ 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.SwitchableSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.OutputDevice; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SecurityCamera; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SecurityCameraRepository; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.StateRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -32,7 +28,7 @@ public class SecurityCameraController { @Autowired SecurityCameraRepository securityCameraService; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll() { @@ -74,19 +70,21 @@ public class SecurityCameraController { } @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { SecurityCamera d = securityCameraService .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - State s = d.cloneState(); + State s = d.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(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 1a165d8..d90c9ac 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 @@ -3,6 +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.SwitchableSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; @@ -19,7 +20,7 @@ public class SmartPlugController { @Autowired private SmartPlugRepository smartPlugRepository; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll() { @@ -73,19 +74,21 @@ public class SmartPlugController { } @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { SmartPlug d = smartPlugRepository .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - State s = d.cloneState(); + State s = d.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(s); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java index 8a3137c..ee566ed 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ThermostatController.java @@ -1,6 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ThermostatSaveRequest; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; @@ -21,7 +22,7 @@ public class ThermostatController { @Autowired private ThermostatService thermostatService; @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository stateRepository; + @Autowired private StateRepository> stateRepository; @GetMapping public List findAll(Principal user) { @@ -70,19 +71,21 @@ public class ThermostatController { } @PostMapping("/{id}/state") - public void sceneBinding( + public State sceneBinding( @PathVariable("id") long deviceId, @RequestParam long sceneId, final Principal principal) - throws NotFoundException { + throws NotFoundException, DuplicateStateException { Thermostat d = thermostatRepository .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); - State s = d.cloneState(); + State s = d.cloneState(); sceneRepository.findById(sceneId).orElseThrow(NotFoundException::new); s.setSceneId(sceneId); - stateRepository.save(s); + if (stateRepository.countByDeviceIdAndSceneId(deviceId, sceneId) > 0) + throw new DuplicateStateException(); + return stateRepository.save(s); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateStateException.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateStateException.java new file mode 100644 index 0000000..4e9f3d5 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/error/DuplicateStateException.java @@ -0,0 +1,12 @@ +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 DuplicateStateException extends Exception { + public DuplicateStateException() { + super( + "Cannot create state since it has already been created for this scene and this device"); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java index 4bfd828..a3ae206 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java @@ -78,7 +78,7 @@ public class Dimmable extends Switchable { } @Override - public DimmableState cloneState() { + public State cloneState() { final DimmableState newState = new DimmableState<>(); newState.setDeviceId(getId()); newState.setDevice(this); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java index 1f548f8..7c0b8d2 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DimmableState.java @@ -1,28 +1,24 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -import javax.persistence.Column; import javax.persistence.Entity; import javax.validation.constraints.Max; import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; /** Represent a state for an IDimmable device */ @Entity public class DimmableState extends State { /** The light intensity value. Goes from 0 (off) to 100 (on) */ - @NotNull - @Column(nullable = false) @Min(0) @Max(100) - private Integer dimAmount = 0; + private int intensity = 0; - public Integer getIntensity() { - return dimAmount; + public int getIntensity() { + return intensity; } - public void setIntensity(Integer dimAmount) { - this.dimAmount = dimAmount; + public void setIntensity(int dimAmount) { + this.intensity = dimAmount; } @Override 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 34f3824..4f0f592 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 @@ -145,6 +145,7 @@ public class Room { */ @NotNull @Column(name = "user_id", nullable = false) + @GsonExclude 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/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java index 3d026b7..e762087 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -31,6 +31,7 @@ public class Scene { @NotNull @Column(name = "user_id", nullable = false) + @GsonExclude 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/State.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java index e8e1555..01398b8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/State.java @@ -10,6 +10,7 @@ import javax.validation.constraints.NotNull; * other properties) form a Scene */ @Entity +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"device_id", "scene_id"})}) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class State { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java index eda0824..d2d1278 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/StateRepository.java @@ -11,4 +11,6 @@ public interface StateRepository> extends CrudRepository findBySceneId(@Param("sceneId") long sceneId); + + Integer countByDeviceIdAndSceneId(long deviceId, long sceneId); } 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 e68e75c..7fbc64a 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 @@ -44,7 +44,7 @@ public abstract class Switchable extends OutputDevice { } @Override - public State cloneState() { + public State cloneState() { final SwitchableState newState = new SwitchableState<>(); newState.setDeviceId(getId()); newState.setDevice(this); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java index 8e6a5fa..67b3118 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/SwitchableState.java @@ -2,14 +2,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import javax.persistence.Column; import javax.persistence.Entity; -import javax.validation.constraints.NotNull; /** Represents a state for a Switchable device */ @Entity public class SwitchableState extends State { - @Column(name = "switchable_on", nullable = false) - @NotNull + @Column(name = "switchable_on") private boolean on; public boolean isOn() {