Merge branch 'data-model-feature' into 'dev'

Data model feature

See merge request sa4-2020/the-sanmarinoes/backend!4
This commit is contained in:
Claudio Maggioni 2020-02-24 16:53:00 +01:00
commit d9348bb6da
34 changed files with 568 additions and 19 deletions

20
.idea/jarRepositories.xml Normal file
View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_12" project-jdk-name="12.0.1" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="12" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

12
backend.iml Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -13,8 +13,14 @@ repositories {
} }
dependencies { dependencies {
compile 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.postgresql:postgresql'
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-json'
}
implementation 'com.google.code.gson:gson'
testImplementation('org.springframework.boot:spring-boot-starter-test') { testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
} }

View file

@ -1,5 +1,6 @@
#Thu Feb 20 21:04:58 CET 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip

View file

@ -1,15 +0,0 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class HelloWorld {
@RequestMapping("/")
String home() {
return "Hello World!";
}
}

View file

@ -5,7 +5,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @SpringBootApplication
public class SmarthutApplication { public class SmarthutApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(SmarthutApplication.class, args); SpringApplication.run(SmarthutApplication.class, args);
} }

View file

@ -0,0 +1,24 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import java.util.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@Controller
public class WelcomeController {
@GetMapping("/")
List<Device> testDevices() {
return Arrays.asList(
new KnobDimmer(),
new RegularLight(),
new MotionSensor(),
new Sensor(),
new SmartPlug(),
new Switch());
}
}

View file

@ -0,0 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/**
* Represents a dimmer that can only instruct an increase or decrease of intensity (i.e. like a
* dimmer with a '+' and a '-' button)
*/
@Entity
public class ButtonDimmer extends Dimmer {
public ButtonDimmer() {
super("button-dimmer");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface ButtonDimmerRepository extends CrudRepository<ButtonDimmer, Long> {}

View file

@ -0,0 +1,71 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.*;
/** Generic abstraction for a smart home device */
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Device {
/** Ways a device can behave in the automation flow. For now only input/output */
public enum FlowType {
INPUT,
OUTPUT
}
/** Device identifier */
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private long id;
/** The room this device belongs in */
@ManyToOne
@JoinColumn(name = "room_id")
private Room room;
/** The name of the device as assigned by the user (e.g. 'Master bedroom light') */
@Column private String name;
/**
* The name for the category of this particular device (e.g 'dimmer'). Not stored in the
* database (thanks to 'transient') but set thanks to constructors
*/
private final transient String kind;
/**
* The way this device behaves in the automation flow. Not stored in the database (thanks to
* 'transient') but set thanks to constructors
*/
private final transient FlowType flowType;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Device(String kind, FlowType flowType) {
this.kind = kind;
this.flowType = flowType;
this.name = kind + " " + this.id;
}
}

View file

@ -0,0 +1,27 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Column;
import javax.persistence.Entity;
/** Represent a dimmable light */
@Entity
public class DimmableLight extends Light {
public DimmableLight() {
super("light");
}
/** The light intensity value. Goes from 0 (off) to 100 (on) */
@Column private int intensity = 0;
public int getIntensity() {
return intensity;
}
public void setIntensity(int intensity) throws IllegalArgumentException {
if (intensity < 0 || intensity > 100) {
throw new IllegalArgumentException("The intensity level can't go below 0 or above 100");
}
this.intensity = intensity;
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface DimmableLightRepository extends CrudRepository<DimmableLight, Long> {}

View file

@ -0,0 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
/** Represents a generic dimmer input device */
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Dimmer extends InputDevice {
public Dimmer(String kind) {
super(kind);
}
}

View file

@ -0,0 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/**
* A generic abstraction for an input device, i.e. something that captures input either from the
* environment (sensor) or the user (switch / dimmer).
*/
@Entity
public abstract class InputDevice extends Device {
public InputDevice(String kind) {
super(kind, FlowType.INPUT);
}
}

View file

@ -0,0 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/**
* Represents a dimmer able to set absolute intensity values (i.e. knowing the absolute intensity
* value, like a knob)
*/
@Entity
public class KnobDimmer extends Dimmer {
public KnobDimmer() {
super("knob-dimmer");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface KnobDimmerRepository extends CrudRepository<KnobDimmer, Long> {}

View file

@ -0,0 +1,29 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
/** Represents a generic light */
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Light extends OutputDevice {
/** Whether the light is on or not */
@Column(name = "light_on")
boolean on;
protected Light(String kind) {
super(kind);
this.on = false;
}
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
}

View file

@ -0,0 +1,11 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/** Represents a motion sensor device */
@Entity
public class MotionSensor extends InputDevice {
public MotionSensor() {
super("motion-sensor");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface MotionSensorRepository extends CrudRepository<MotionSensor, Long> {}

View file

@ -0,0 +1,17 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
/**
* Represents a generic output device, i.e. something that causes some behaviour (light, smartPlugs,
* ...).
*/
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class OutputDevice extends Device {
public OutputDevice(String kind) {
super(kind, FlowType.OUTPUT);
}
}

View file

@ -0,0 +1,11 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/** Represents a standard non-dimmable light */
@Entity
public class RegularLight extends Light {
public RegularLight() {
super("regular-light");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface RegularLightRepository extends CrudRepository<RegularLight, Long> {}

View file

@ -0,0 +1,69 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.Set;
import javax.persistence.*;
/** Represents a room in the house owned by the user */
@Entity
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
/** User that owns the house this room is in */
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
/** The user given name of this room (e.g. 'Master bedroom') */
@Column private String name;
/** Collectiion of devices present in this room */
@OneToMany(mappedBy = "room")
private Set<Device> devices;
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 String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Device> getDevices() {
return devices;
}
@Override
public String toString() {
return "Room{"
+ "id="
+ id
+ ", user="
+ user
+ ", name='"
+ name
+ '\''
+ ", devices="
+ devices
+ '}';
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface RoomRepository extends CrudRepository<Room, User> {}

View file

@ -0,0 +1,32 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
/** A sensor input device that measures a quantity in a continuous scale (e.g. temperature) */
@Entity
public class Sensor extends InputDevice {
/** Type of sensor, i.e. of the thing the sensor measures. */
enum SensorType {
/** A sensor that measures temperature in degrees celsius */
TEMPERATURE,
/** A sensor that measures relative humidity in percentage points */
HUMIDITY,
/** A sensor that measures light in degrees */
LIGHT
}
/** The type of this sensor */
@Column
@Enumerated(value = EnumType.STRING)
private SensorType sensor;
public Sensor() {
super("sensor");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface SensorRepository extends CrudRepository<Sensor, Long> {}

View file

@ -0,0 +1,25 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Column;
import javax.persistence.Entity;
/** A smart plug that can be turned either on or off */
@Entity
public class SmartPlug extends OutputDevice {
/** Whether the smart plug is on */
@Column(name = "smart_plug_on")
private boolean on;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
public SmartPlug() {
super("smart-plug");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface SmartPlugRepository extends CrudRepository<SmartPlug, Long> {}

View file

@ -0,0 +1,11 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import javax.persistence.Entity;
/** A switch input device TODO: define switch behaviour (push button vs on/off state) */
@Entity
public class Switch extends InputDevice {
public Switch() {
super("switch");
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface SwitchRepository extends CrudRepository<Switch, Long> {}

View file

@ -0,0 +1,82 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.Set;
import javax.persistence.*;
/** A user of the Smarthut application */
@Entity(name = "smarthutuser")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
/** The full name of the user */
@Column private String name;
/** A properly salted way to store the password TODO: define the implementation of salt */
@Column private String hashedPassword;
/** The user's email TODO: validate email in setters */
@Column private String email;
/** All rooms in the user's house */
@OneToMany(mappedBy = "user")
private Set<Room> rooms;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
public Set<Room> getRooms() {
return rooms;
}
@Override
public String toString() {
return "User{"
+ "id="
+ id
+ ", name='"
+ name
+ '\''
+ ", hashedPassword='"
+ hashedPassword
+ '\''
+ ", email='"
+ email
+ '\''
+ ", rooms="
+ rooms
+ '}';
}
}

View file

@ -0,0 +1,5 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {}

View file

@ -1 +1,12 @@
spring.http.converters.preferred-json-mapper=gson
spring.datasource.url=jdbc:postgresql://localhost:5432/smarthut
spring.datasource.username=postgres
spring.datasource.password=
# Hibernate properties
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.properties.hibernate.format_sql=true
,