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 eaace7a..3a714e8 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 @@ -17,13 +17,26 @@ import org.springframework.web.bind.annotation.*; @RestController @EnableAutoConfiguration @RequestMapping("/dimmableLight") -public class DimmableLightController { +public class DimmableLightController extends GuestEnabledController { - @Autowired private UserRepository userRepository; - @Autowired private DimmableLightRepository dimmableLightRepository; - @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository> stateRepository; - @Autowired private DeviceService deviceService; + private DimmableLightRepository dimmableLightRepository; + private SceneRepository sceneRepository; + private StateRepository> stateRepository; + private DeviceService deviceService; + + @Autowired + public DimmableLightController( + UserRepository userRepository, + DimmableLightRepository dimmableLightRepository, + SceneRepository sceneRepository, + StateRepository> stateRepository, + DeviceService deviceService) { + super(userRepository, dimmableLightRepository); + this.dimmableLightRepository = dimmableLightRepository; + this.sceneRepository = sceneRepository; + this.stateRepository = stateRepository; + this.deviceService = deviceService; + } @GetMapping public List findAll() { @@ -60,31 +73,6 @@ public class DimmableLightController { return save(new DimmableLight(), dl, principal.getName(), null); } - private DimmableLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) - throws NotFoundException { - if (hostId == null) { - return dimmableLightRepository - .findByIdAndUsername(id, principal.getName()) - .orElseThrow(NotFoundException::new); - } else { - /* - * Slightly less extremely verbose check through various repositories to control user/guest authorization. - */ - DimmableLight dl = - dimmableLightRepository - .findByIdAndUserId(id, hostId) - .orElseThrow(NotFoundException::new); - User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new); - User guest = userRepository.findByUsername(principal.getName()); - dl.setFromHost(true); - if (!host.getGuests().contains(guest)) { - throw new NotFoundException(); - } else { - return dl; - } - } - } - /* Logic for saving either as owner or guest is handled in method save of this controller */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java new file mode 100644 index 0000000..1aa2e7c --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java @@ -0,0 +1,37 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; + +import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.returnIfGuest; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import java.security.Principal; + +public abstract class GuestEnabledController { + + private UserRepository userRepository; + private DeviceRepository deviceRepository; + + public GuestEnabledController( + final UserRepository userRepository, final DeviceRepository deviceRepository) { + this.userRepository = userRepository; + this.deviceRepository = deviceRepository; + } + + protected T fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) + throws NotFoundException { + if (hostId == null) { + return deviceRepository + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + } else { + /* + * Slightly less extremely verbose check through various repositories to control user/guest authorization. + */ + T device = + deviceRepository + .findByIdAndUserId(id, hostId) + .orElseThrow(NotFoundException::new); + return returnIfGuest(userRepository, device, hostId, principal); + } + } +} 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 b73bff3..308b8ee 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 @@ -25,42 +25,35 @@ import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration @RequestMapping("/regularLight") -public class RegularLightController { +public class RegularLightController extends GuestEnabledController { - @Autowired private UserRepository userRepository; - @Autowired private RegularLightRepository regularLightService; - @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository> stateRepository; - @Autowired private DeviceService deviceService; + private RegularLightRepository regularLightRepository; + private SceneRepository sceneRepository; + private StateRepository> stateRepository; + private DeviceService deviceService; - private RegularLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) - throws NotFoundException { - if (hostId == null) { - return regularLightService.findById(id).orElseThrow(NotFoundException::new); - } else { - RegularLight rl = - regularLightService - .findByIdAndUserId(id, hostId) - .orElseThrow(NotFoundException::new); - User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new); - User guest = userRepository.findByUsername(principal.getName()); - rl.setFromHost(true); - if (!host.getGuests().contains(guest)) { - throw new NotFoundException(); - } else { - return rl; - } - } + @Autowired + public RegularLightController( + UserRepository userRepository, + RegularLightRepository regularLightRepository, + SceneRepository sceneRepository, + StateRepository> stateRepository, + DeviceService deviceService) { + super(userRepository, regularLightRepository); + this.regularLightRepository = regularLightRepository; + this.sceneRepository = sceneRepository; + this.stateRepository = stateRepository; + this.deviceService = deviceService; } @GetMapping public List findAll() { - return toList(regularLightService.findAll()); + return toList(regularLightRepository.findAll()); } @GetMapping("/{id}") public RegularLight findById(@PathVariable("id") long id) throws NotFoundException { - return regularLightService.findById(id).orElseThrow(NotFoundException::new); + return regularLightRepository.findById(id).orElseThrow(NotFoundException::new); } private RegularLight save( @@ -97,10 +90,10 @@ public class RegularLightController { @DeleteMapping("/{id}") public void delete(@PathVariable("id") long id) { - regularLightService.deleteById(id); + regularLightRepository.deleteById(id); } - // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} + // the full url should be: "/regularLight/{id}/state?sceneId={sceneId} // however it is not necessary to specify the query in the mapping @PostMapping("/{id}/state") public State sceneBinding( @@ -109,7 +102,7 @@ public class RegularLightController { final Principal principal) throws NotFoundException, DuplicateStateException { RegularLight d = - regularLightService + regularLightRepository .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); State s = d.cloneState(); 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 03a115f..7de58db 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 @@ -6,6 +6,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.RoomSaveRequest; 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 ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; import java.security.Principal; import java.util.*; import javax.validation.Valid; @@ -37,13 +38,7 @@ public class RoomController { if (hostId == null) { return list; } else { - User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); - User guest = userRepository.findByUsername(principal.getName()); - if (!host.getGuests().contains(guest)) { - throw new NotFoundException(); - } else { - return list; - } + return Utils.returnIfGuest(userRepository, list, hostId, principal); } } 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 4629779..3b681c5 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 @@ -68,6 +68,16 @@ public abstract class Device { @Transient @GsonExclude private boolean fromHost = false; + @Transient @GsonExclude private boolean fromGuest = false; + + public boolean isFromGuest() { + return fromGuest; + } + + public void setFromGuest(boolean fromGuest) { + this.fromGuest = fromGuest; + } + public void setFromHost(boolean fromHost) { this.fromHost = fromHost; } 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 da2614b..4bf6cca 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 @@ -1,13 +1,11 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; -import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; -import java.beans.Transient; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,56 +14,54 @@ import org.springframework.stereotype.Component; public class DeviceService { // FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF) - @Autowired DeviceRepository deviceRepository; - @Autowired UserRepository userRepository; - @Autowired SensorSocketEndpoint endpoint; + @Autowired private DeviceRepository deviceRepository; + @Autowired private UserRepository userRepository; + @Autowired private SensorSocketEndpoint endpoint; - /* - TODO: remember to put a @Transient @GsonIgnore (but not @SocketGsonIgnore) property on device to signal a device update - TODO: coming from DeviceService.saveAsGuest() - */ - public T saveAsGuest( - @Transient @GsonExclude T device, String guestUsername, Long hostId) + 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 Set guests = host.getGuests(); + final Set guests = Set.copyOf(host.getGuests()); - // filter out currentUser from guests as we do not want to broadcast an update to the - // updating user itself - if (guests.contains(currentUser)) { - guests.remove(currentUser); - } - - // broadcasting from not a host + // We're telling the host that a guest has modified a device. Therefore, fromGuest becomes + // true. device.setFromHost(false); - // broadcast device update for host + device.setFromGuest(true); + // broadcast device update to host endpoint.queueDeviceUpdate(device, host); - userRepository.save(host); - endpoint.flushDeviceUpdates(); + + // We're telling all guests that a higher entity has issued a device update. Therefore, + // fromHost becomes true. + device.setFromHost(true); + device.setFromGuest(false); for (final User guest : guests) { + if (guest.equals(currentUser)) { + continue; + } // enqueue all device updates for all other guests endpoint.queueDeviceUpdate(device, guest); - userRepository.save(guest); } // broadcast device updates for all other guests - endpoint.flushDeviceUpdates(); - return deviceRepository.save(device); + return device; } public T saveAsOwner(T device, String username) { + device = deviceRepository.save(device); + final User user = userRepository.findByUsername(username); final Set guests = user.getGuests(); // make sure we're broadcasting from host device.setFromHost(true); + device.setFromGuest(false); for (final User guest : guests) { // broadcast to endpoint the object device, with receiving user set to guest endpoint.queueDeviceUpdate(device, guest); - userRepository.save(guest); } // after queueing the device update for each user, flush them all in a single message // can be moved inside the foreach loop to send a single message for each update enqueued - endpoint.flushDeviceUpdates(); - return deviceRepository.save(device); + return device; } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java index 319a8e3..050afa5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java @@ -1,7 +1,10 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.utils; +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; +import java.security.Principal; import java.util.List; -import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -9,24 +12,19 @@ import java.util.stream.StreamSupport; public final class Utils { private Utils() {} - @FunctionalInterface - public interface ConsumerWithException { - void apply(T input) throws Throwable; + public static U returnIfGuest( + UserRepository userRepository, U toReturn, Long hostId, Principal principal) + throws NotFoundException { + User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); + User guest = userRepository.findByUsername(principal.getName()); + if (!host.getGuests().contains(guest)) { + throw new NotFoundException(); + } else { + return toReturn; + } } public static List toList(Iterable iterable) { return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()); } - - public static Predicate didThrow(ConsumerWithException consumer) { - return (t) -> { - try { - consumer.apply(t); - return true; - } catch (Throwable e) { - System.err.println(e.getMessage()); - return false; - } - }; - } }