diff --git a/pom.xml b/pom.xml
index 6de0e12..3f21938 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,19 @@
spring-boot-starter-websocket
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+
+
+ org.postgresql
+ postgresql
+
+
org.projectlombok
lombok
diff --git a/src/main/java/de/ph87/tools/session/AbstractSession.java b/src/main/java/de/ph87/tools/session/AbstractSession.java
index 1d981bd..9f61da9 100644
--- a/src/main/java/de/ph87/tools/session/AbstractSession.java
+++ b/src/main/java/de/ph87/tools/session/AbstractSession.java
@@ -2,10 +2,8 @@ package de.ph87.tools.session;
import de.ph87.tools.user.User;
import de.ph87.tools.web.IWebSocketMessage;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.Setter;
-import lombok.ToString;
+import jakarta.persistence.*;
+import lombok.*;
import java.time.ZonedDateTime;
import java.util.HashSet;
@@ -13,36 +11,47 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
+@Entity
@Getter
@ToString
+@NoArgsConstructor
public abstract class AbstractSession implements IWebSocketMessage {
+ @Id
@NonNull
- public final String uuid = UUID.randomUUID().toString();
+ @Column(nullable = false)
+ private String uuid = UUID.randomUUID().toString();
@NonNull
- public final User owner;
+ @ManyToOne(optional = false)
+ private User owner;
@NonNull
- public final ZonedDateTime created = ZonedDateTime.now();
+ @Column(nullable = false)
+ private ZonedDateTime created = ZonedDateTime.now();
@NonNull
+ @ManyToMany
@ToString.Exclude
- private final Set users = new HashSet<>();
+ private Set users = new HashSet<>();
@Setter
@NonNull
- public String title = "Spiel ohne Namen";
+ @Column(nullable = false)
+ private String title = "Spiel ohne Namen";
@Setter
@NonNull
@ToString.Exclude
+ @Column(nullable = false)
private String password = UUID.randomUUID().toString().substring(0, 4);
@Setter
+ @Column(nullable = false)
private boolean initial = true;
@NonNull
+ @Column(nullable = false)
private ZonedDateTime lastAccess = created;
protected AbstractSession(@NonNull final User user) {
@@ -50,16 +59,12 @@ public abstract class AbstractSession implements IWebSocketMessage {
}
public void join(@NonNull final User user) {
- synchronized (uuid) {
- users.add(user);
- touch();
- }
+ users.add(user);
+ touch();
}
public void leave(@NonNull final User user) {
- synchronized (uuid) {
- users.remove(user);
- }
+ users.remove(user);
}
private void touch() {
@@ -71,4 +76,21 @@ public abstract class AbstractSession implements IWebSocketMessage {
return List.of("Number", uuid);
}
+ public boolean isOwnedBy(@NonNull final User user) {
+ return owner.equals(user);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof final AbstractSession session)) {
+ return false;
+ }
+ return session.uuid.equals(this.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
}
diff --git a/src/main/java/de/ph87/tools/session/AbstractSessionController.java b/src/main/java/de/ph87/tools/session/AbstractSessionController.java
index ad94565..05a1aed 100644
--- a/src/main/java/de/ph87/tools/session/AbstractSessionController.java
+++ b/src/main/java/de/ph87/tools/session/AbstractSessionController.java
@@ -40,9 +40,7 @@ public abstract class AbstractSessionController
@Scheduled(timeUnit = TimeUnit.MINUTES, initialDelay = 5, fixedRate = 5)
public void cleanUp() {
final ZonedDateTime deadline = ZonedDateTime.now().minusDays(30);
- synchronized (sessions) {
- sessions.stream().filter(session -> session.getLastAccess().isBefore(deadline)).forEach(this::delete);
- }
+ sessions.stream().filter(session -> session.getLastAccess().isBefore(deadline)).forEach(this::delete);
}
private void delete(@NonNull final SESSION session) {
@@ -63,9 +61,7 @@ public abstract class AbstractSessionController
final SESSION session = create(user);
log.info("Session CREATED: {}", session);
- synchronized (sessions) {
- sessions.add(session);
- }
+ sessions.add(session);
return join(session, user);
}
@@ -110,7 +106,7 @@ public abstract class AbstractSessionController
public AbstractSessionDto changeTitle(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @RequestBody final SessionChangeTitleInbound inbound) {
final User user = userService.getByPrivateUuidOrThrow(userUuid);
final SESSION session = getUserSession(user, inbound.uuid);
- if (session.owner != user) {
+ if (session.isOwnedBy(user)) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
session.setTitle(inbound.title);
@@ -122,7 +118,7 @@ public abstract class AbstractSessionController
public AbstractSessionDto changePassword(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @RequestBody final SessionChangePasswordInbound inbound) {
final User user = userService.getByPrivateUuidOrThrow(userUuid);
final SESSION session = getUserSession(user, inbound.uuid);
- if (session.owner != user) {
+ if (session.isOwnedBy(user)) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
session.setPassword(inbound.password);
@@ -147,14 +143,12 @@ public abstract class AbstractSessionController
@NonNull
private Optional findUserSession(@NonNull final User user, @NonNull final String sessionUuid) {
- return user.getSessions().stream().filter(s -> s.uuid.equals(sessionUuid)).filter(sessionClazz::isInstance).map(sessionClazz::cast).findFirst();
+ return user.getSessions().stream().filter(s -> s.getUuid().equals(sessionUuid)).filter(sessionClazz::isInstance).map(sessionClazz::cast).findFirst();
}
@NonNull
private SESSION getSessionByUuid(@NonNull final String uuid) {
- synchronized (sessions) {
- return sessions.stream().filter(u -> u.getUuid().equals(uuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
- }
+ return sessions.stream().filter(u -> u.getUuid().equals(uuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
}
@NonNull
diff --git a/src/main/java/de/ph87/tools/session/AbstractSessionDto.java b/src/main/java/de/ph87/tools/session/AbstractSessionDto.java
index 5881d4a..dd8344e 100644
--- a/src/main/java/de/ph87/tools/session/AbstractSessionDto.java
+++ b/src/main/java/de/ph87/tools/session/AbstractSessionDto.java
@@ -40,11 +40,11 @@ public abstract class AbstractSessionDto {
protected AbstractSessionDto(@NonNull final AbstractSession session, @NonNull final String type) {
this.type = type;
- this.uuid = session.uuid;
- this.title = session.title;
- this.created = session.created;
+ this.uuid = session.getUuid();
+ this.title = session.getTitle();
+ this.created = session.getCreated();
this.password = session.getPassword();
- this.owner = new UserPublicDto(session.owner);
+ this.owner = new UserPublicDto(session.getOwner());
this.users = session.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet());
this.initial = session.isInitial();
}
diff --git a/src/main/java/de/ph87/tools/user/User.java b/src/main/java/de/ph87/tools/user/User.java
index 9c10bd9..e40d804 100644
--- a/src/main/java/de/ph87/tools/user/User.java
+++ b/src/main/java/de/ph87/tools/user/User.java
@@ -1,12 +1,12 @@
package de.ph87.tools.user;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import de.ph87.tools.session.AbstractSession;
import de.ph87.tools.web.IWebSocketMessage;
-import lombok.Getter;
-import lombok.NonNull;
-import lombok.Setter;
-import lombok.ToString;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.ManyToMany;
+import lombok.*;
import java.time.ZonedDateTime;
import java.util.HashSet;
@@ -14,43 +14,49 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
+@Entity
@Getter
@ToString
+@NoArgsConstructor
public class User implements IWebSocketMessage {
+ @Id
@NonNull
- public final String privateUuid = UUID.randomUUID().toString();
+ @Column(nullable = false)
+ private String privateUuid = UUID.randomUUID().toString();
@NonNull
- public final String publicUuid = UUID.randomUUID().toString();
+ @Column(nullable = false)
+ private String publicUuid = UUID.randomUUID().toString();
- public final ZonedDateTime created = ZonedDateTime.now();
+ @NonNull
+ @Column(nullable = false)
+ private ZonedDateTime created = ZonedDateTime.now();
- @JsonIgnore
+ @ManyToMany
@ToString.Exclude
- private final Set sessions = new HashSet<>();
+ private Set sessions = new HashSet<>();
+ @NonNull
+ @Column(nullable = false)
private ZonedDateTime lastAccess = created;
@Setter
@NonNull
- public String name = "unnamed";
+ @Column(nullable = false)
+ private String name = "Neuer Benutzer";
private void touch() {
lastAccess = ZonedDateTime.now();
}
public void join(@NonNull final AbstractSession session) {
- synchronized (privateUuid) {
- sessions.add(session);
- touch();
- }
+ sessions.add(session);
+ touch();
}
public void leave(@NonNull final AbstractSession session) {
- synchronized (sessions) {
- sessions.remove(session);
- }
+ sessions.remove(session);
}
@Override
@@ -58,4 +64,17 @@ public class User implements IWebSocketMessage {
return List.of("User", privateUuid);
}
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof final User user)) {
+ return false;
+ }
+ return user.privateUuid.equals(this.privateUuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return privateUuid.hashCode();
+ }
+
}
diff --git a/src/main/java/de/ph87/tools/user/UserPrivateDto.java b/src/main/java/de/ph87/tools/user/UserPrivateDto.java
index 8a503df..bc47c4b 100644
--- a/src/main/java/de/ph87/tools/user/UserPrivateDto.java
+++ b/src/main/java/de/ph87/tools/user/UserPrivateDto.java
@@ -32,8 +32,8 @@ public class UserPrivateDto {
public UserPrivateDto(@NonNull final User user) {
this.publicUuid = user.getPublicUuid();
this.name = user.getName();
- this.privateUuid = user.privateUuid;
- this.created = user.created;
+ this.privateUuid = user.getPrivateUuid();
+ this.created = user.getCreated();
this.sessions = user.getSessions().stream().map(AbstractSessionDto::toDto).collect(Collectors.toSet());
}
diff --git a/src/main/java/de/ph87/tools/user/UserRepository.java b/src/main/java/de/ph87/tools/user/UserRepository.java
new file mode 100644
index 0000000..4b318b5
--- /dev/null
+++ b/src/main/java/de/ph87/tools/user/UserRepository.java
@@ -0,0 +1,7 @@
+package de.ph87.tools.user;
+
+import org.springframework.data.repository.ListCrudRepository;
+
+public interface UserRepository extends ListCrudRepository {
+
+}
diff --git a/src/main/java/de/ph87/tools/user/UserService.java b/src/main/java/de/ph87/tools/user/UserService.java
index 91a0afb..4bb406d 100644
--- a/src/main/java/de/ph87/tools/user/UserService.java
+++ b/src/main/java/de/ph87/tools/user/UserService.java
@@ -30,11 +30,9 @@ public class UserService {
@NonNull
public User getUserByUuidOrElseCreate(@Nullable final String uuid, @NonNull final HttpServletResponse response) {
- synchronized (users) {
- final User user = Optional.ofNullable(uuid).map(this::findByPrivateUuid).filter(Optional::isPresent).map(Optional::get).orElseGet(this::create);
- writeUserUuidCookie(response, user);
- return user;
- }
+ final User user = Optional.ofNullable(uuid).map(this::findByPrivateUuid).filter(Optional::isPresent).map(Optional::get).orElseGet(this::create);
+ writeUserUuidCookie(response, user);
+ return user;
}
@Nullable
@@ -48,26 +46,20 @@ public class UserService {
}
public void delete(@NonNull final String userUuid, final @NonNull HttpServletResponse response) {
- synchronized (users) {
- final User user = findByPrivateUuid(userUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
- users.remove(user);
- log.info("User DELETED: {}", user);
- }
+ final User user = findByPrivateUuid(userUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
+ users.remove(user);
+ log.info("User DELETED: {}", user);
writeUserUuidCookie(response, null);
}
@NonNull
public User getByPrivateUuidOrThrow(@NonNull final String uuid) {
- synchronized (users) {
- return findByPrivateUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
- }
+ return findByPrivateUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
}
@NonNull
public User getByPublicUuid(@NonNull final String uuid) {
- synchronized (users) {
- return findByPublicUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
- }
+ return findByPublicUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST));
}
@NonNull
@@ -91,7 +83,7 @@ public class UserService {
private static void writeUserUuidCookie(@NonNull final HttpServletResponse response, @Nullable final User user) {
final Cookie cookie = new Cookie(USER_UUID_COOKIE_NAME, "");
if (user != null) {
- cookie.setValue(user.privateUuid);
+ cookie.setValue(user.getPrivateUuid());
}
cookie.setMaxAge(10 * 365 * 24 * 60 * 60);
cookie.setPath("/");