Skip to content
This repository has been archived by the owner on Apr 6, 2021. It is now read-only.

Release 0.0.4.release #43

Merged
merged 8 commits into from
Nov 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
<packaging>pom</packaging>
<name>${project.groupId}:${project.artifactId}</name>

Expand Down
2 changes: 1 addition & 1 deletion server-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package ar.edu.itba.iot.carne_iot.server.models;

import ar.edu.itba.iot.carne_iot.server.error_handling.errros.IllegalStateError;
import ar.edu.itba.iot.carne_iot.server.error_handling.errros.ValidationError;
import ar.edu.itba.iot.carne_iot.server.error_handling.helpers.ValidationExceptionThrower;
import ar.edu.itba.iot.carne_iot.server.error_handling.helpers.ValidationHelper;
import ar.edu.itba.iot.carne_iot.server.exceptions.CustomIllegalStateException;
import ar.edu.itba.iot.carne_iot.server.exceptions.ValidationException;
import ar.edu.itba.iot.carne_iot.server.models.constants.ValidationConstants;
import ar.edu.itba.iot.carne_iot.server.models.constants.ValidationErrorConstants;

import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.LinkedList;
Expand Down Expand Up @@ -41,13 +42,6 @@ public class Device implements ValidationExceptionThrower {
@Column(name = "last_temperature_update")
private Instant lastTemperatureUpdate;

/**
* The actual state of this device.
*/
@Column(name = "state", length = 64)
@Enumerated(EnumType.STRING)
private State state;


/* package */ Device() {
// For Hibernate
Expand All @@ -62,7 +56,6 @@ public Device(long id) {
this.id = id;
this.temperature = null;
this.lastTemperatureUpdate = null;
this.state = State.IDLE;
}

/**
Expand All @@ -87,52 +80,19 @@ public Instant getLastTemperatureUpdate() {
return lastTemperatureUpdate;
}

/**
* @return The actual state of this device.
*/
public State getState() {
return state;
}

/**
* Sets the actual temperature measured by this device.
*
* @param temperature The actual temperature measured by this device.
* @throws ValidationException If the temperature is not valid.
*/
public void setTemperature(BigDecimal temperature) throws ValidationException {
if (this.state != State.ACTIVE) {
throw new CustomIllegalStateException(CHANGE_TEMPERATURE_IN_NOT_ACTIVE_STATE);
}
validateTemperature(temperature);

this.temperature = temperature;
this.lastTemperatureUpdate = Instant.now();
}

/**
* Changes this device state to active.
*/
public void startCooking() {
this.state = State.ACTIVE;
}

/**
* Changes this device state to idle.
*/
public void stopCooking() {
this.state = State.IDLE;
}


/**
* Enum listing all possible states for a {@link Device}.
*/
public enum State {
IDLE,
ACTIVE,
}


// ====================
// Validators
Expand Down Expand Up @@ -163,8 +123,4 @@ private void validateTemperature(BigDecimal temperature) throws ValidationExcept

/* package */ static final int PRECISION = 5;
/* package */ static final int SCALE = 2;

private static final IllegalStateError CHANGE_TEMPERATURE_IN_NOT_ACTIVE_STATE =
new IllegalStateError("Device must be active to set the temperature",
Device.class.getSimpleName());
}
2 changes: 1 addition & 1 deletion server-persistence-interfaces/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-persistence-interfaces</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion server-persistence/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-persistence</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion server-services-interfaces/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-services-interfaces</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,12 @@ public interface DeviceService {
String pair(long ownerId, long deviceId);

/**
* Makes a {@link Device} start cooking (i.e change its state to {@link Device.State#ACTIVE}).
* This is an idempotent operation.
* Performs pairing of {@link ar.edu.itba.iot.carne_iot.server.models.Device}s, using a system {@link User}.
*
* @param deviceId The id of the {@link Device} that will start cooking.
*/
void startCooking(long deviceId);

/**
* Makes a {@link Device} stop cooking (i.e change its state to {@link Device.State#IDLE}).
* This is an idempotent operation.
*
* @param deviceId The id of the {@link Device} that will stop cooking.
* @param deviceId The id of the {@link ar.edu.itba.iot.carne_iot.server.models.Device} to be paired.
* @return The token generated by the pairing process.
*/
void stopCooking(long deviceId);
String pair(long deviceId);

/**
* Updates the temperature of a given {@link Device}.
Expand Down
2 changes: 1 addition & 1 deletion server-services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-services</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
import ar.edu.itba.iot.carne_iot.server.exceptions.UniqueViolationException;
import ar.edu.itba.iot.carne_iot.server.models.Device;
import ar.edu.itba.iot.carne_iot.server.models.DeviceRegistration;
import ar.edu.itba.iot.carne_iot.server.models.Session;
import ar.edu.itba.iot.carne_iot.server.models.User;
import ar.edu.itba.iot.carne_iot.server.persistence.daos.DeviceDao;
import ar.edu.itba.iot.carne_iot.server.persistence.daos.DeviceRegistrationDao;
import ar.edu.itba.iot.carne_iot.server.persistence.daos.SessionDao;
import ar.edu.itba.iot.carne_iot.server.persistence.daos.UserDao;
import ar.edu.itba.iot.carne_iot.server.persistence.query_helpers.DeviceQueryHelper;
import ar.edu.itba.iot.carne_iot.server.persistence.query_helpers.DeviceRegistrationQueryHelper;
Expand All @@ -27,8 +25,8 @@
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
Expand All @@ -41,9 +39,11 @@
public class DeviceServiceImpl implements DeviceService, UniqueViolationExceptionThrower {

/**
* Amount of tries to perform the pairing process.
* A system {@link User} to be used to create device tokens.
*/
private static final int MAX_TRIES = 10;
private static final User deviceUser = new User("device",
LocalDate.of(1900, 1, 1),
"username", "email@email.com", "hashed");

/**
* DAO for managing {@link User}s data.
Expand Down Expand Up @@ -75,24 +75,18 @@ public class DeviceServiceImpl implements DeviceService, UniqueViolationExceptio
*/
private final JwtTokenGenerator jwtTokenGenerator;

/**
* DAO for retrieving {@link Session}s data.
*/
private final SessionDao sessionDao;


@Autowired
public DeviceServiceImpl(UserDao userDao, DeviceDao deviceDao, DeviceRegistrationDao deviceRegistrationDao,
DeviceQueryHelper deviceQueryHelper,
DeviceRegistrationQueryHelper deviceRegistrationQueryHelper,
JwtTokenGenerator jwtTokenGenerator, SessionDao sessionDao) {
JwtTokenGenerator jwtTokenGenerator) {
this.userDao = userDao;
this.deviceDao = deviceDao;
this.deviceRegistrationDao = deviceRegistrationDao;
this.deviceQueryHelper = deviceQueryHelper;
this.deviceRegistrationQueryHelper = deviceRegistrationQueryHelper;
this.jwtTokenGenerator = jwtTokenGenerator;
this.sessionDao = sessionDao;
}


Expand Down Expand Up @@ -209,7 +203,6 @@ public void unregisterDevice(long deviceId) {
}

@Override
@Transactional
@PreAuthorize("@devicePermissionProvider.isOwnerOrAdmin(#deviceId)")
public String pair(long ownerId, long deviceId) {
final User user = userDao.findById(ownerId).orElseThrow(NoSuchEntityException::new);
Expand All @@ -220,39 +213,14 @@ public String pair(long ownerId, long deviceId) {
throw new CustomIllegalStateException(OPERATION_OVER_UNREGISTERED_DEVICE);
}

// Try to create the token...
boolean validToken = false;
int tries = 0;
JwtTokenGenerator.TokenAndSessionContainer container = null;
while (!validToken && tries < MAX_TRIES) {
container = jwtTokenGenerator.generateDeviceToken(user, device);
validToken = !sessionDao.existsByOwnerAndJti(user, container.getJti());
tries++;
}
if (tries >= MAX_TRIES) {
throw new RuntimeException("Could not create a session after " + MAX_TRIES + "tries");
}

// Store token in order to pass the
Objects.requireNonNull(container, "The container was not initialized correctly");
final Session session = new Session(user, container.getJti()); // Actually not a session, but whatever
sessionDao.save(session);

return container.getToken();
return jwtTokenGenerator.generateDeviceToken(user, device).getToken();
}

@Override
@Transactional
@PreAuthorize("@devicePermissionProvider.isOwnerOrAdmin(#deviceId)")
public void startCooking(long deviceId) {
performChangeOfState(deviceId, Device::startCooking);
}

@Override
@Transactional
@PreAuthorize("@devicePermissionProvider.isOwnerOrAdmin(#deviceId)")
public void stopCooking(long deviceId) {
performChangeOfState(deviceId, Device::stopCooking);
@PreAuthorize("@adminPermissionProvider.isAdmin()")
public String pair(long deviceId) {
final Device device = deviceDao.findById(deviceId).orElseThrow(NoSuchEntityException::new);
return jwtTokenGenerator.generateDeviceToken(deviceUser, device).getToken();
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion server-webapp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>ar.edu.itba.iot.carne-iot</groupId>
<artifactId>server</artifactId>
<version>0.0.3.RELEASE</version>
<version>0.0.4.RELEASE</version>
</parent>

<artifactId>server-webapp</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ public class DeviceDto implements Resoursable {
@JsonSerialize(using = Java8InstantSerializer.class)
private Instant lastTemperatureUpdate;

@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Device.State state;


public DeviceDto() {
// For Jersey
Expand All @@ -46,7 +43,6 @@ public DeviceDto() {
this.id = device.getId();
this.temperature = device.getTemperature();
this.lastTemperatureUpdate = device.getLastTemperatureUpdate();
this.state = device.getState();
}

public Long getId() {
Expand All @@ -60,8 +56,4 @@ public BigDecimal getTemperature() {
public Instant getLastTemperatureUpdate() {
return lastTemperatureUpdate;
}

public Device.State getState() {
return state;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,34 +136,6 @@ public Response unregisterDevice(@PathParam("id") @Base64url final Long id) {
// Device state changers
// ======================================

@PUT
@Path("/{id : .+}/cooking")
public Response startCooking(@PathParam("id") @Base64url final Long id) {
if (id == null) {
throw new IllegalParamValueException(Collections.singletonList("id"));
}

LOGGER.debug("Device with id {} started cooking", id);

deviceService.startCooking(id);

return Response.noContent().build();
}

@DELETE
@Path("/{id : .+}/cooking")
public Response stopCooking(@PathParam("id") @Base64url final Long id) {
if (id == null) {
throw new IllegalParamValueException(Collections.singletonList("id"));
}

LOGGER.debug("Device with id {} stopped cooking", id);

deviceService.stopCooking(id);

return Response.noContent().build();
}

@PUT
@Path("/{id : .+}/temperature")
@Consumes(MediaType.APPLICATION_JSON)
Expand All @@ -182,4 +154,22 @@ public Response updateTemperature(@PathParam("id") @Base64url final Long id, Str

return Response.noContent().build();
}

@POST
@Path("/{deviceId : .+}/pair")
public Response pairDevice(@PathParam("deviceId") @Base64url final Long deviceId) {

LOGGER.debug("Trying to pair device with id {}", deviceId);

// Create a JWT for the paired device
final String token = deviceService.pair(deviceId);

LOGGER.debug("Device {} successfully paired", deviceId);

// TODO: if token can be invalidated, add an "invalidation" url

return Response.noContent()
.header("X-Device-Token", token)
.build();
}
}
Loading