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 01f453c..6b13ca9 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerDimRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; @@ -21,7 +20,6 @@ public class ButtonDimmerController private DeviceService deviceService; private ButtonDimmerRepository buttonDimmerRepository; - private DimmableRepository dimmableRepository; @Autowired protected ButtonDimmerController( @@ -31,12 +29,14 @@ public class ButtonDimmerController super(inputRepository, outputRepository, DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR); this.deviceService = deviceService; this.buttonDimmerRepository = inputRepository; - this.dimmableRepository = outputRepository; } @PostMapping public ButtonDimmer create( - @Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) { + @Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(bd.getRoomId(), principal.getName()); + ButtonDimmer newBD = new ButtonDimmer(); newBD.setName(bd.getName()); newBD.setRoomId(bd.getRoomId()); @@ -62,7 +62,7 @@ public class ButtonDimmerController break; } - dimmableRepository.saveAll(buttonDimmer.getOutputs()); + deviceService.saveAllAsOwner(buttonDimmer.getOutputs(), principal.getName(), false); return buttonDimmer.getOutputs(); } 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 3e1872a..6644135 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - 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; @@ -31,7 +30,9 @@ public class CurtainsController { @PostMapping public Curtains create( - @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) { + @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(curtain.getRoomId(), principal.getName()); return save(new Curtains(), curtain, principal); } 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 3c80b39..60a4726 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - 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; @@ -58,6 +57,7 @@ public class DimmableLightController extends GuestEnabledController output; + private final List outputs; - private Connection(I input, List output) { + private Connection(I input, List outputs) { this.input = input; - this.output = output; + this.outputs = outputs; } } + @Autowired private DeviceService deviceService; + private DeviceRepository inputRepository; private DeviceRepository outputReposiory; @@ -56,17 +59,17 @@ public abstract class InputDeviceConnectionController< this.connector = connector; } - private Connection checkConnectionIDs(Long inputId, List outputs) + private Connection checkConnectionIDs(Long inputId, List outputs, String username) throws NotFoundException { final I input = inputRepository - .findById(inputId) + .findByIdAndUsername(inputId, username) .orElseThrow(() -> new NotFoundException("input device")); final List outputDevices = new ArrayList<>(); for (final Long outputId : outputs) { outputDevices.add( outputReposiory - .findById(outputId) + .findByIdAndUsername(outputId, username) .orElseThrow(() -> new NotFoundException("output device"))); } return new Connection(input, outputDevices); @@ -76,19 +79,19 @@ public abstract class InputDeviceConnectionController< * Implements the output device connection creation (add) route * * @param inputId input device id - * @param outputId output device id list + * @param outputs output device id list * @return the list of output devices attached to the input device of id inputId * @throws NotFoundException if inputId or outputId are not valid */ - protected Set addOutput(Long inputId, List outputId) - throws NotFoundException { - final Connection pair = checkConnectionIDs(inputId, outputId); + protected Set addOutput( + Long inputId, List outputs, String username) throws NotFoundException { + final Connection pair = checkConnectionIDs(inputId, outputs, username); - for (final O o : pair.output) { + for (final O o : pair.outputs) { connector.connect(pair.input, o, true); } - outputReposiory.saveAll(pair.output); + deviceService.saveAllAsOwner(pair.outputs, username, false); return pair.input.getOutputs(); } @@ -96,33 +99,37 @@ public abstract class InputDeviceConnectionController< * Implements the output device connection destruction (remove) route * * @param inputId input device id - * @param outputId output device id list + * @param outputs output device id list * @return the list of output devices attached to the input device of id inputId * @throws NotFoundException if inputId or outputId are not valid */ - protected Set removeOutput(Long inputId, List outputId) - throws NotFoundException { - final Connection pair = checkConnectionIDs(inputId, outputId); + protected Set removeOutput( + Long inputId, List outputs, String username) throws NotFoundException { + final Connection pair = checkConnectionIDs(inputId, outputs, username); - for (final O o : pair.output) { + for (final O o : pair.outputs) { connector.connect(pair.input, o, false); } - outputReposiory.saveAll(pair.output); + deviceService.saveAllAsOwner(pair.outputs, username, false); return pair.input.getOutputs(); } @PostMapping("/{id}/lights") public List addLight( - @PathVariable("id") long inputId, @RequestBody List lightId) + @PathVariable("id") long inputId, + @RequestBody List lightId, + final Principal principal) throws NotFoundException { - return toList(addOutput(inputId, lightId)); + return toList(addOutput(inputId, lightId, principal.getName())); } @DeleteMapping("/{id}/lights") public List removeLight( - @PathVariable("id") long inputId, @RequestBody List lightId) + @PathVariable("id") long inputId, + @RequestBody List lightId, + final Principal principal) throws NotFoundException { - return toList(removeOutput(inputId, lightId)); + return toList(removeOutput(inputId, lightId, principal.getName())); } } 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 8efaf45..9b30535 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerDimRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; @@ -20,19 +19,19 @@ public class KnobDimmerController extends InputDeviceConnectionController dimmableRepository; @Autowired protected KnobDimmerController( KnobDimmerRepository inputRepository, DimmableRepository outputRepository) { super(inputRepository, outputRepository, Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR); this.knobDimmerRepository = inputRepository; - this.dimmableRepository = outputRepository; } @PostMapping public KnobDimmer create( - @Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) { + @Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(kd.getRoomId(), principal.getName()); KnobDimmer newKD = new KnobDimmer(); newKD.setName(kd.getName()); newKD.setRoomId(kd.getRoomId()); @@ -50,7 +49,7 @@ public class KnobDimmerController extends InputDeviceConnectionController public RegularLight create( @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) throws NotFoundException { + deviceService.throwIfRoomNotOwned(rl.getRoomId(), principal.getName()); return save(new RegularLight(), rl, principal.getName(), null); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 136446a..c4540c5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -49,7 +49,11 @@ public class RoomController { final Principal principal) throws NotFoundException { - List rooms = toList(roomRepository.findAll()); + List rooms = + toList( + hostId != null + ? roomRepository.findByUserId(hostId) + : roomRepository.findByUsername(principal.getName())); return fetchOwnerOrGuest(rooms, hostId, principal); } @@ -60,10 +64,6 @@ public class RoomController { @RequestParam(value = "hostId", required = false) Long hostId) throws NotFoundException { Room room = roomRepository.findById(id).orElseThrow(NotFoundException::new); - /* Very ugly way of avoiding code duplication. If this method call throws no exception, - * we can return the room safely. I pass null as I do not return a list in this case. - * Refer to fetchOwnerOrGuest for further information. - */ fetchOwnerOrGuest(null, hostId, principal); return room; } @@ -115,11 +115,16 @@ public class RoomController { } @DeleteMapping("/{id}") - public void deleteById(@PathVariable("id") long id) { + public void deleteById(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { switchRepository.deleteAllByRoomId(id); knobDimmerRepository.deleteAllByRoomId(id); buttonDimmerRepository.deleteAllByRoomId(id); - roomRepository.deleteById(id); + final Room r = + roomRepository + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + roomRepository.delete(r); } /** 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 f5dd1a2..0cddba2 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 ch.usi.inf.sa4.sanmarinoes.smarthut.service.SceneService; import java.security.Principal; -import java.util.ArrayList; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -26,20 +26,20 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/scene") public class SceneController { - @Autowired private SceneRepository sceneService; + @Autowired private SceneRepository sceneRepository; + @Autowired private SceneService sceneService; @Autowired private UserRepository userService; @Autowired private StateRepository> stateService; - @Autowired private DeviceRepository deviceRepository; @GetMapping public List findAll(Principal principal) { - return toList(sceneService.findByUsername(principal.getName())); + return toList(sceneRepository.findByUsername(principal.getName())); } @GetMapping("/{id}") public @ResponseBody Scene findById(@PathVariable("id") long id, Principal principal) throws NotFoundException { - return sceneService + return sceneRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); } @@ -55,29 +55,20 @@ public class SceneController { newScene.setUserId(userId); newScene.setName(s.getName()); - newScene.setGuestAccessEnabled(s.isGuestAccessEnabled()); - return sceneService.save(newScene); + return sceneRepository.save(newScene); } @PostMapping("/{id}/apply") public @ResponseBody List apply(@PathVariable("id") long id, final Principal principal) throws NotFoundException { final Scene newScene = - sceneService + sceneRepository .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; + return sceneService.apply(newScene); } @PutMapping("/{id}") @@ -85,7 +76,7 @@ public class SceneController { @PathVariable("id") long id, @RequestBody SceneSaveRequest s, final Principal principal) throws NotFoundException { final Scene newScene = - sceneService + sceneRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); @@ -95,13 +86,13 @@ public class SceneController { newScene.setGuestAccessEnabled(s.isGuestAccessEnabled()); - return sceneService.save(newScene); + return sceneRepository.save(newScene); } @DeleteMapping("/{id}") public void deleteById(@PathVariable("id") long id) { stateService.deleteAllBySceneId(id); - sceneService.deleteById(id); + sceneRepository.deleteById(id); } /** 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 c03c430..c063ebf 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - 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; @@ -24,10 +23,11 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/securityCamera") public class SecurityCameraController { - @Autowired DeviceService deviceService; - @Autowired SecurityCameraRepository securityCameraService; + @Autowired private DeviceService deviceService; + @Autowired private SecurityCameraRepository securityCameraService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; + @Autowired private RoomRepository roomRepository; private SecurityCamera save( SecurityCamera newSC, SwitchableSaveRequest sc, final Principal principal) { @@ -40,7 +40,9 @@ public class SecurityCameraController { @PostMapping public SecurityCamera create( - @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) { + @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(sc.getRoomId(), principal.getName()); return save(new SecurityCamera(), sc, principal); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java index 5c14f07..41b9af0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; @@ -29,7 +28,10 @@ public class SensorController { @Autowired private SensorService sensorService; @PostMapping - public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) { + public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(s.getRoomId(), principal.getName()); + Sensor newSensor = new Sensor(); newSensor.setSensor(s.getSensor()); newSensor.setName(s.getName()); 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 32fb300..468cd5d 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - 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; @@ -32,8 +31,9 @@ public class SmartPlugController { } @PostMapping - public SmartPlug create( - @Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) { + public SmartPlug create(@Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) + throws NotFoundException { + deviceService.throwIfRoomNotOwned(sp.getRoomId(), principal.getName()); return save(new SmartPlug(), sp, principal); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java index eecd86e..0847c87 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java @@ -1,13 +1,12 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; - import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchOperationRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService; import java.security.Principal; -import java.util.*; +import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; @@ -36,12 +35,12 @@ public class SwitchController extends InputDeviceConnectionController operate( + public List operate( @Valid @RequestBody final SwitchOperationRequest sr, final Principal principal) throws NotFoundException { final Switch s = @@ -70,9 +69,8 @@ public class SwitchController extends InputDeviceConnectionController> triggers = new HashSet<>(); + + @OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE) + @GsonExclude + private Set scenes = new HashSet<>(); + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Set> getStates() { + return triggers; + } + + public Set getScenes() { + return scenes; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java new file mode 100644 index 0000000..b8b2ac2 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/AutomationRepository.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import org.springframework.data.repository.CrudRepository; + +public interface AutomationRepository extends CrudRepository {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java new file mode 100644 index 0000000..f52e5ca --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTrigger.java @@ -0,0 +1,31 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +public class BooleanTrigger extends Trigger { + + @Column(name = "switchable_on") + private boolean on; + + public boolean isOn() { + return on; + } + + public void setOn(boolean on) { + this.on = on; + } + + public boolean check(boolean on) { + return this.on == on; + } + + @Override + public boolean triggered() { + return getDevice().readTriggerState() == isOn(); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java new file mode 100644 index 0000000..932f4c8 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerRepository.java @@ -0,0 +1,4 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface BooleanTriggerRepository + extends TriggerRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java new file mode 100644 index 0000000..6ff219f --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface BooleanTriggerable { + boolean readTriggerState(); +} 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 dfc852d..a84e705 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 @@ -36,6 +36,11 @@ public abstract class Device { @SocketGsonExclude private Room room; + @OneToMany(mappedBy = "device", orphanRemoval = true) + @GsonExclude + // @SocketGsonExclude + private Set> triggers = new HashSet<>(); + /** * The room this device belongs in, as a foreign key id. To use when updating and inserting from * a REST call. diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmable.java index a3ae206..ab49dd0 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 @@ -9,7 +9,7 @@ import javax.validation.constraints.NotNull; @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -public class Dimmable extends Switchable { +public class Dimmable extends Switchable implements RangeTriggerable { public static final Connector KNOB_DIMMER_DIMMABLE_CONNECTOR = Connector.basic(KnobDimmer::getOutputs, Dimmable::getDimmers); @@ -85,4 +85,9 @@ public class Dimmable extends Switchable { newState.setIntensity(getIntensity()); return newState; } + + @Override + public double readTriggerState() { + return intensity; + } } 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 7ef0808..9b3d627 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Dimmer.java @@ -1,7 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; - import java.util.HashSet; import java.util.Set; import javax.persistence.*; @@ -19,8 +18,7 @@ public abstract class Dimmer extends InputDevice { @JoinTable( name = "dimmer_dimmable", joinColumns = @JoinColumn(name = "dimmer_id"), - inverseJoinColumns = @JoinColumn(name = "dimmable_id") - ) + inverseJoinColumns = @JoinColumn(name = "dimmable_id")) private Set dimmables = new HashSet<>(); /** diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java index 87b527d..89273f8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/KnobDimmer.java @@ -8,10 +8,9 @@ import javax.persistence.Entity; * value, like a knob) */ @Entity -public class KnobDimmer extends Dimmer { +public class KnobDimmer extends Dimmer implements RangeTriggerable { - @Column - Integer intensity = 0; + @Column private int intensity = 0; public KnobDimmer() { super("knobDimmer"); @@ -28,4 +27,9 @@ public class KnobDimmer extends Dimmer { dl.setIntensity(intensity); } } + + @Override + public double readTriggerState() { + return intensity; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java index 6c5baf7..4998922 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/MotionSensor.java @@ -5,7 +5,7 @@ import javax.persistence.Entity; /** Represents a motion sensor device */ @Entity -public class MotionSensor extends InputDevice { +public class MotionSensor extends InputDevice implements BooleanTriggerable { @Column(nullable = false) private boolean detected; @@ -21,4 +21,9 @@ public class MotionSensor extends InputDevice { public MotionSensor() { super("motionSensor"); } + + @Override + public boolean readTriggerState() { + return detected; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java new file mode 100644 index 0000000..73c86eb --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTrigger.java @@ -0,0 +1,68 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import com.google.gson.annotations.SerializedName; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.validation.constraints.NotNull; + +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +public class RangeTrigger extends Trigger { + + @Override + public boolean triggered() { + double value = getDevice().readTriggerState(); + switch (operator) { + case EQUAL: + return value == range; + case LESS: + return value < range; + case GREATER: + return value > range; + case GREATER_EQUAL: + return value >= range; + case LESS_EQUAL: + return value <= range; + } + throw new IllegalStateException(); + } + + enum Operator { + @SerializedName("EQUAL") + EQUAL, + @SerializedName("LESS") + LESS, + @SerializedName("GREATER") + GREATER, + @SerializedName("LESS_EQUAL") + LESS_EQUAL, + @SerializedName("GREATER_EQUAL") + GREATER_EQUAL + } + + @NotNull + @Column(nullable = false) + private Operator operator; + + @NotNull + @Column(nullable = false) + private double range; + + public Operator getOperator() { + return operator; + } + + public void setOperator(Operator operator) { + this.operator = operator; + } + + public double getRange() { + return range; + } + + public void setRange(Float range) { + this.range = range; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java new file mode 100644 index 0000000..084a70f --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerRepository.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface RangeTriggerRepository extends TriggerRepository> {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java new file mode 100644 index 0000000..489a763 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface RangeTriggerable { + double readTriggerState(); +} 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..2d06c59 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 BooleanTriggerable { /** Whether the light is on or not */ @Column(name = "light_on", nullable = false) @@ -27,4 +27,9 @@ public class RegularLight extends Switchable { public void setOn(boolean on) { this.on = on; } + + @Override + public boolean readTriggerState() { + return on; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RoomRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RoomRepository.java index b02413d..7c27baa 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RoomRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RoomRepository.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,10 @@ public interface RoomRepository 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); + + @Query("SELECT r FROM Room r JOIN r.user u WHERE u.id = ?1") + List findByUserId(Long hostId); } 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 8c18e3c..f35d54d 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 @@ -25,15 +25,15 @@ public class Scene { @GsonExclude private User user; - @OneToMany(mappedBy = "scene", orphanRemoval = true) - @GsonExclude - private Set> states = new HashSet<>(); - @NotNull @Column(name = "user_id", nullable = false) @GsonExclude private Long userId; + @OneToMany(mappedBy = "scene", orphanRemoval = true) + @GsonExclude + private Set> states = new HashSet<>(); + /** The user given name of this room (e.g. 'Master bedroom') */ @NotNull @Column(nullable = false) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java new file mode 100644 index 0000000..0652e5e --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriority.java @@ -0,0 +1,88 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PreRemove; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Entity +public class ScenePriority { + + @ManyToOne + @JoinColumn(name = "automation_id", updatable = false, insertable = false) + @GsonExclude + private Automation automation; + + @Column(name = "automation_id", nullable = false) + @NotNull + private Long automationId; + + @NotNull + @Min(0) + @Column(nullable = false) + private Integer priority; + + @ManyToOne + @JoinColumn(name = "scene_id", updatable = false, insertable = false) + @GsonExclude + private Scene scene; + + @Id + @Column(name = "scene_id", nullable = false, updatable = false, unique = true) + @NotNull + private Long sceneId; + + public Integer getPriority() { + return priority; + } + + public void setPriority(Integer priority) { + this.priority = priority; + } + + public Automation getAutomation() { + return automation; + } + + public void setAutomation(Automation automation) { + this.automation = automation; + } + + public Long getAutomationId() { + return automationId; + } + + public void setAutomationId(Long automationId) { + this.automationId = automationId; + } + + 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; + } + + @PreRemove + public void preRemove() { + this.setAutomation(null); + this.setAutomationId(null); + + this.setScene(null); + this.setSceneId(null); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java new file mode 100644 index 0000000..2dc81c4 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ScenePriorityRepository.java @@ -0,0 +1,5 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import org.springframework.data.repository.CrudRepository; + +public interface ScenePriorityRepository extends CrudRepository {} 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..3d4cef9 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 BooleanTriggerable { public SecurityCamera() { super("securityCamera"); @@ -33,4 +33,9 @@ public class SecurityCamera extends Switchable { public void setOn(boolean on) { this.on = on; } + + @Override + public boolean readTriggerState() { + return on; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java index 6b5e6b9..2fb5442 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Sensor.java @@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull; /** A sensor input device that measures a quantity in a continuous scale (e.g. temperature) */ @Entity -public class Sensor extends InputDevice { +public class Sensor extends InputDevice implements RangeTriggerable { public static final Map TYPICAL_VALUES = Map.of( @@ -19,6 +19,11 @@ public class Sensor extends InputDevice { SensorType.HUMIDITY, new BigDecimal(40.0), SensorType.LIGHT, new BigDecimal(1000)); + @Override + public double readTriggerState() { + return value.doubleValue(); + } + /** Type of sensor, i.e. of the thing the sensor measures. */ public enum SensorType { /** A sensor that measures temperature in degrees celsius */ 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 546c746..77f6c3d 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 @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -import com.google.common.base.Objects; import java.math.BigDecimal; import javax.persistence.Column; @@ -9,7 +8,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 BooleanTriggerable { /** The average consumption of an active plug when on in Watt */ public static final Double AVERAGE_CONSUMPTION_KW = 200.0; @@ -46,4 +45,9 @@ public class SmartPlug extends Switchable { public SmartPlug() { super("smartPlug"); } + + @Override + public boolean readTriggerState() { + return on; + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java index e78bf9f..0768d6b 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Switch.java @@ -1,22 +1,20 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; - import java.util.HashSet; import java.util.Set; import javax.persistence.*; /** A switch input device */ @Entity -public class Switch extends InputDevice { +public class Switch extends InputDevice implements BooleanTriggerable { @ManyToMany(cascade = CascadeType.DETACH) @GsonExclude @JoinTable( name = "switch_switchable", joinColumns = @JoinColumn(name = "switch_id"), - inverseJoinColumns = @JoinColumn(name = "switchable_id") - ) + inverseJoinColumns = @JoinColumn(name = "switchable_id")) private Set switchables = new HashSet<>(); /** The state of this switch */ @@ -57,4 +55,9 @@ public class Switch extends InputDevice { public Set getOutputs() { return switchables; } + + @Override + public boolean readTriggerState() { + return on; + } } 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 7c54d54..2dd3772 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 @@ -1,15 +1,19 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import com.google.gson.annotations.SerializedName; import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.OneToMany; import javax.persistence.Transient; import javax.validation.constraints.NotNull; /** A thermostat capable of controlling cooling and heating. */ @Entity -public class Thermostat extends Switchable { +public class Thermostat extends Switchable implements BooleanTriggerable { @Override public boolean isOn() { @@ -24,6 +28,7 @@ public class Thermostat extends Switchable { /** * Computes the new thermostat state, for when the thermostat is on; + * * @return true if the state changed, false if not; */ public boolean computeState() { @@ -49,6 +54,11 @@ public class Thermostat extends Switchable { return true; } + @Override + public boolean readTriggerState() { + return mode != Mode.OFF; + } + public enum Mode { @SerializedName("OFF") OFF, @@ -75,6 +85,10 @@ public class Thermostat extends Switchable { @Column private boolean useExternalSensors = false; + @OneToMany(mappedBy = "scene", orphanRemoval = true) + @GsonExclude + private Set> triggers = new HashSet<>(); + /** Creates a thermostat with a temperature sensor and its initial OFF state */ public Thermostat() { super("thermostat"); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java new file mode 100644 index 0000000..1ef68f0 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -0,0 +1,99 @@ +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.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PreRemove; +import javax.validation.constraints.NotNull; + +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +public abstract class Trigger { + + public abstract boolean triggered(); + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", updatable = false, nullable = false, unique = true) + @ApiModelProperty(hidden = true) + private long id; + + @ManyToOne(targetEntity = OutputDevice.class) + @JoinColumn(name = "device_id", updatable = false, insertable = false) + @GsonExclude + private D device; + + /** + * The device this trigger belongs to, 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 = "automation_id", updatable = false, insertable = false) + @GsonExclude + private Automation automation; + + @Column(name = "automation_id", nullable = false) + @NotNull + private Long automationId; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public D getDevice() { + return device; + } + + public void setDevice(D device) { + this.device = device; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public Automation getAutomation() { + return automation; + } + + public void setAutomation(Automation automation) { + this.automation = automation; + } + + public Long getAutomationId() { + return automationId; + } + + public void setAutomationId(Long automationId) { + this.automationId = automationId; + } + + @PreRemove + public void removeDeviceAndScene() { + this.setDevice(null); + this.setDeviceId(null); + + this.setAutomation(null); + this.setAutomationId(null); + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java new file mode 100644 index 0000000..a506ce6 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/TriggerRepository.java @@ -0,0 +1,10 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.util.List; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +public interface TriggerRepository> extends CrudRepository { + + List findAllByDeviceId(@Param("deviceId") long deviceId); +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java index 01fd897..d1569d6 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/UserRepository.java @@ -1,10 +1,17 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.util.*; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository { User findByUsername(String username); + @Query("SELECT u FROM #{#entityName} u JOIN FETCH u.guests WHERE u.username = ?1") + User findByUsernameFetchGuests(String username); + + @Query("SELECT u FROM #{#entityName} u JOIN FETCH u.guests WHERE u.id = ?1") + User findByIdFetchGuests(Long id); + User findByEmailIgnoreCase(String email); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java index 4fe293c..e701166 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java @@ -1,7 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled; -import ch.usi.inf.sa4.sanmarinoes.smarthut.controller.MotionSensorController; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.MotionSensorService; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; @@ -30,7 +30,7 @@ public class UpdateTasks { @Autowired private ThermostatService thermostatService; - @Autowired private MotionSensorController motionSensorController; + @Autowired private MotionSensorService motionSensorService; @Autowired private SensorSocketEndpoint sensorSocketEndpoint; @@ -55,14 +55,18 @@ public class UpdateTasks { StreamSupport.stream(motionSensorRepository.findAll().spliterator(), true) .forEach( sensor -> { - motionSensorController.updateDetectionFromMotionSensor(sensor, true); + final User owner = motionSensorRepository.findUser(sensor.getId()); + motionSensorService.updateDetectionFromMotionSensor( + sensor, true, owner.getUsername()); CompletableFuture.delayedExecutor( (long) (Math.random() * 2000), TimeUnit.MILLISECONDS) .execute( () -> - motionSensorController + motionSensorService .updateDetectionFromMotionSensor( - sensor, false)); + sensor, + false, + owner.getUsername())); }); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index f95cb21..f043b05 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -5,6 +5,8 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; @@ -12,14 +14,44 @@ import org.springframework.stereotype.Component; @Component public class DeviceService { - // FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF) @Autowired private DeviceRepository deviceRepository; + @Autowired private AutomationRepository automationRepository; + @Autowired private SceneRepository sceneRepository; + @Autowired private SceneService sceneService; + @Autowired private TriggerRepository> triggerRepository; @Autowired private RoomRepository roomRepository; @Autowired private UserRepository userRepository; @Autowired private SensorSocketEndpoint endpoint; @Autowired private ThermostatService thermostatService; + public void throwIfRoomNotOwned(Long roomId, String username) throws NotFoundException { + roomRepository.findByIdAndUsername(roomId, username).orElseThrow(NotFoundException::new); + } + + public void triggerTriggers(Device device) { + + final long deviceId = device.getId(); + + List> triggers = triggerRepository.findAllByDeviceId(deviceId); + + triggers.stream() + .filter(Trigger::triggered) + .map(Trigger::getAutomationId) + .map(t -> automationRepository.findById(t).orElseThrow(IllegalStateException::new)) + .distinct() + .map(Automation::getScenes) + .flatMap(Collection::stream) + .distinct() + .sorted(Comparator.comparing(ScenePriority::getPriority)) + .map( + t -> + sceneRepository + .findById(t.getSceneId()) + .orElseThrow(IllegalStateException::new)) + .forEach(sceneService::apply); + } + public List findAll(Long hostId, String username) throws NotFoundException { return findAll(null, hostId, username); } @@ -72,10 +104,9 @@ public class DeviceService { public T saveAsGuest(T device, String guestUsername, Long hostId) throws NotFoundException { - device = deviceRepository.save(device); - final User currentUser = userRepository.findByUsername(guestUsername); - final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); + final User host = userRepository.findByIdFetchGuests(hostId); + if (host == null) throw new NotFoundException(); final Set guests = Set.copyOf(host.getGuests()); // We're telling the host that a guest has modified a device. Therefore, fromGuest becomes @@ -100,10 +131,8 @@ public class DeviceService { return device; } - public T saveAsOwner(T device, String username) { - device = deviceRepository.save(device); - - final User user = userRepository.findByUsername(username); + private void propagateUpdateAsOwner(Device device, String username) { + final User user = userRepository.findByUsernameFetchGuests(username); final Set guests = user.getGuests(); // make sure we're broadcasting from host device.setFromHost(true); @@ -112,10 +141,35 @@ public class DeviceService { // broadcast to endpoint the object device, with receiving user set to guest endpoint.queueDeviceUpdate(device, guest); } + } + + public List saveAllAsOwner( + Iterable devices, String username, boolean fromScene) { + devices = deviceRepository.saveAll(devices); + devices.forEach((d) -> propagateUpdateAsOwner(d, username)); + + if (!fromScene) { + devices.forEach(this::triggerTriggers); + } + + return toList(devices); + } + + public T saveAsOwner(T device, String username, boolean fromScene) { + device = deviceRepository.save(device); + propagateUpdateAsOwner(device, username); + + if (!fromScene) { + triggerTriggers(device); + } return device; } + public T saveAsOwner(T device, String username) { + return saveAsOwner(device, username, false); + } + public void delete(Long id, String username) throws NotFoundException { Device device = deviceRepository @@ -123,7 +177,7 @@ public class DeviceService { .orElseThrow(NotFoundException::new); deviceRepository.delete(device); - final User user = userRepository.findByUsername(username); + final User user = userRepository.findByUsernameFetchGuests(username); final Set guests = user.getGuests(); device.setFromHost(true); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java new file mode 100644 index 0000000..01a7401 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/MotionSensorService.java @@ -0,0 +1,33 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensor; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class MotionSensorService { + + @Autowired private SensorSocketEndpoint sensorSocketEndpoint; + @Autowired private DeviceService deviceService; + @Autowired private MotionSensorRepository motionSensorRepository; + + /** + * Updates detection status of given motion sensor and propagates update throgh socket + * + * @param sensor the motion sensor to update + * @param detected the new detection status + * @return the updated motion sensor + */ + public MotionSensor updateDetectionFromMotionSensor( + MotionSensor sensor, boolean detected, String username) { + sensor.setDetected(detected); + final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username); + + sensorSocketEndpoint.queueDeviceUpdate( + sensor, motionSensorRepository.findUser(sensor.getId())); + + return toReturn; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java new file mode 100644 index 0000000..826d896 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SceneService.java @@ -0,0 +1,28 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Scene; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SceneService { + + @Autowired private DeviceRepository deviceRepository; + + public List apply(Scene newScene) { + final List updated = new ArrayList<>(); + + for (final State s : newScene.getStates()) { + s.apply(); + updated.add(s.getDevice()); + } + deviceRepository.saveAll(updated); + + return updated; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java index f3072cd..0e4fbbd 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java @@ -12,6 +12,8 @@ public class SensorService { @Autowired private SensorRepository sensorRepository; + @Autowired private DeviceService deviceService; + @Autowired private ThermostatService thermostatService; @Autowired private SensorSocketEndpoint endpoint; @@ -38,10 +40,10 @@ public class SensorService { */ public Sensor updateValueFromSensor(Sensor sensor, BigDecimal value) { sensor.setValue(value); - final Sensor toReturn = sensorRepository.save(sensor); - + sensor = + deviceService.saveAsOwner( + sensor, sensorRepository.findUser(sensor.getId()).getUsername()); endpoint.queueDeviceUpdate(sensor, sensorRepository.findUser(sensor.getId())); - - return toReturn; + return sensor; } } 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 2352cf9..e214e39 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 @@ -16,6 +16,8 @@ public class ThermostatService { @Autowired private SensorSocketEndpoint endpoint; + @Autowired private DeviceService deviceService; + @Autowired private ThermostatRepository thermostatRepository; private void randomJitter(Thermostat thermostat) { @@ -28,7 +30,8 @@ public class ThermostatService { private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) { thermostat.setInternalSensorTemperature(value); - thermostatRepository.save(thermostat); + deviceService.saveAsOwner( + thermostat, thermostatRepository.findUser(thermostat.getId()).getUsername()); } public void fakeUpdateAll() { @@ -51,7 +54,7 @@ public class ThermostatService { boolean shouldUpdate = this.computeState(t); if (shouldUpdate) { - thermostatRepository.save(t); + deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername()); endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId())); } }