From 2eeb55ed52479719761456ca44dd611eafbcce32 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 22 Oct 2020 23:58:55 +0200 Subject: [PATCH] Add client side errors in case of data initialization with null values --- .../src/main/java/envoy/data/Attachment.java | 7 +-- common/src/main/java/envoy/data/Contact.java | 4 +- .../main/java/envoy/data/GroupMessage.java | 3 +- .../java/envoy/data/LoginCredentials.java | 9 ++-- common/src/main/java/envoy/data/Message.java | 5 ++- common/src/main/java/envoy/data/User.java | 2 +- common/src/main/java/envoy/event/Event.java | 14 +++++- .../java/envoy/event/GroupCreationResult.java | 2 +- .../main/java/envoy/event/GroupResize.java | 4 +- .../src/main/java/envoy/event/IsTyping.java | 2 +- .../main/java/envoy/event/IssueProposal.java | 6 +-- .../java/envoy/event/MessageStatusChange.java | 3 +- .../envoy/event/PasswordChangeRequest.java | 4 +- .../envoy/event/contact/UserOperation.java | 4 +- .../envoy/server/data/PersistenceManager.java | 44 ++++++++++++------- 15 files changed, 72 insertions(+), 41 deletions(-) diff --git a/common/src/main/java/envoy/data/Attachment.java b/common/src/main/java/envoy/data/Attachment.java index 0be0e1f..fc79d9f 100644 --- a/common/src/main/java/envoy/data/Attachment.java +++ b/common/src/main/java/envoy/data/Attachment.java @@ -1,6 +1,7 @@ package envoy.data; import java.io.Serializable; +import java.util.Objects; /** * This interface should be used for any type supposed to be a {@link Message} attachment (i.e. @@ -63,9 +64,9 @@ public final class Attachment implements Serializable { * @since Envoy Common v0.1-beta */ public Attachment(byte[] data, String name, AttachmentType type) { - this.data = data; - this.name = name; - this.type = type; + this.data = Objects.requireNonNull(data); + this.name = Objects.requireNonNull(name); + this.type = Objects.requireNonNull(type); } /** diff --git a/common/src/main/java/envoy/data/Contact.java b/common/src/main/java/envoy/data/Contact.java index 8e250dc..18e0e4f 100644 --- a/common/src/main/java/envoy/data/Contact.java +++ b/common/src/main/java/envoy/data/Contact.java @@ -29,8 +29,8 @@ public abstract class Contact implements Serializable { */ public Contact(long id, String name, Set contacts) { this.id = id; - this.name = name; - this.contacts = contacts; + this.name = Objects.requireNonNull(name); + this.contacts = contacts == null ? new HashSet<>() : contacts; } /** diff --git a/common/src/main/java/envoy/data/GroupMessage.java b/common/src/main/java/envoy/data/GroupMessage.java index d6a30a9..8f2f28a 100644 --- a/common/src/main/java/envoy/data/GroupMessage.java +++ b/common/src/main/java/envoy/data/GroupMessage.java @@ -38,7 +38,8 @@ public final class GroupMessage extends Message { Map memberStatuses) { super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status, forwarded); - this.memberStatuses = memberStatuses; + this.memberStatuses = + memberStatuses == null ? new HashMap<>() : memberStatuses; } /** diff --git a/common/src/main/java/envoy/data/LoginCredentials.java b/common/src/main/java/envoy/data/LoginCredentials.java index f121005..c0a455a 100644 --- a/common/src/main/java/envoy/data/LoginCredentials.java +++ b/common/src/main/java/envoy/data/LoginCredentials.java @@ -2,6 +2,7 @@ package envoy.data; import java.io.Serializable; import java.time.Instant; +import java.util.Objects; /** * Contains a {@link User}'s login / registration information as well as the client version. @@ -22,12 +23,12 @@ public final class LoginCredentials implements Serializable { private LoginCredentials(String identifier, String password, boolean registration, boolean token, String clientVersion, Instant lastSync) { - this.identifier = identifier; - this.password = password; + this.identifier = Objects.requireNonNull(identifier); + this.password = Objects.requireNonNull(password); this.registration = registration; this.token = token; - this.clientVersion = clientVersion; - this.lastSync = lastSync; + this.clientVersion = Objects.requireNonNull(clientVersion); + this.lastSync = lastSync == null ? Instant.EPOCH : lastSync; } /** diff --git a/common/src/main/java/envoy/data/Message.java b/common/src/main/java/envoy/data/Message.java index b8965a3..78a5ad6 100644 --- a/common/src/main/java/envoy/data/Message.java +++ b/common/src/main/java/envoy/data/Message.java @@ -2,6 +2,7 @@ package envoy.data; import java.io.Serializable; import java.time.Instant; +import java.util.Objects; import dev.kske.eventbus.IEvent; @@ -80,9 +81,9 @@ public class Message implements Serializable, IEvent { this.creationDate = creationDate; this.receivedDate = receivedDate; this.readDate = readDate; - this.text = text; + this.text = text == null ? "" : text; this.attachment = attachment; - this.status = status; + this.status = Objects.requireNonNull(status); this.forwarded = forwarded; } diff --git a/common/src/main/java/envoy/data/User.java b/common/src/main/java/envoy/data/User.java index f0f2a62..6b7c580 100644 --- a/common/src/main/java/envoy/data/User.java +++ b/common/src/main/java/envoy/data/User.java @@ -86,7 +86,7 @@ public final class User extends Contact { */ public User(long id, String name, UserStatus status, Set contacts) { super(id, name, contacts); - this.status = status; + this.status = Objects.requireNonNull(status); } @Override diff --git a/common/src/main/java/envoy/event/Event.java b/common/src/main/java/envoy/event/Event.java index e12b882..5812878 100644 --- a/common/src/main/java/envoy/event/Event.java +++ b/common/src/main/java/envoy/event/Event.java @@ -1,6 +1,7 @@ package envoy.event; import java.io.Serializable; +import java.util.Objects; import dev.kske.eventbus.IEvent; @@ -20,7 +21,16 @@ public abstract class Event implements IEvent, Serializable { private static final long serialVersionUID = 0L; protected Event(T value) { - this.value = value; + this(value, false); + } + + /** + * This constructor is reserved for {@link Valueless} events. No other event should contain null + * values. Only use if really necessary. Using this constructor with {@code true} implies that + * the user has to manually check if the value of the event is null. + */ + protected Event(T value, boolean canBeNull) { + this.value = canBeNull ? value : Objects.requireNonNull(value); } /** @@ -46,7 +56,7 @@ public abstract class Event implements IEvent, Serializable { private static final long serialVersionUID = 0L; protected Valueless() { - super(null); + super(null, true); } @Override diff --git a/common/src/main/java/envoy/event/GroupCreationResult.java b/common/src/main/java/envoy/event/GroupCreationResult.java index c1a002b..2c01b44 100644 --- a/common/src/main/java/envoy/event/GroupCreationResult.java +++ b/common/src/main/java/envoy/event/GroupCreationResult.java @@ -20,7 +20,7 @@ public class GroupCreationResult extends Event { * @since Envoy Common v0.2-beta */ public GroupCreationResult() { - super(null); + super(null, true); } /** diff --git a/common/src/main/java/envoy/event/GroupResize.java b/common/src/main/java/envoy/event/GroupResize.java index 69e0447..3679f14 100644 --- a/common/src/main/java/envoy/event/GroupResize.java +++ b/common/src/main/java/envoy/event/GroupResize.java @@ -2,6 +2,8 @@ package envoy.event; import static envoy.event.ElementOperation.*; +import java.util.Objects; + import envoy.data.*; /** @@ -30,7 +32,7 @@ public final class GroupResize extends Event { */ public GroupResize(User user, Group group, ElementOperation operation) { super(user); - this.operation = operation; + this.operation = Objects.requireNonNull(operation); final var contained = group.getContacts().contains(user); if (contained && operation.equals(ADD)) throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group)); diff --git a/common/src/main/java/envoy/event/IsTyping.java b/common/src/main/java/envoy/event/IsTyping.java index 4c5e93e..4e587b4 100644 --- a/common/src/main/java/envoy/event/IsTyping.java +++ b/common/src/main/java/envoy/event/IsTyping.java @@ -28,7 +28,7 @@ public final class IsTyping extends Event { * @param destinationID the ID of the contact the user wrote to * @since Envoy Common v0.2-beta */ - public IsTyping(Long sourceID, long destinationID) { + public IsTyping(long sourceID, long destinationID) { super(sourceID); this.destinationID = destinationID; } diff --git a/common/src/main/java/envoy/event/IssueProposal.java b/common/src/main/java/envoy/event/IssueProposal.java index d015e88..0b2cc5f 100644 --- a/common/src/main/java/envoy/event/IssueProposal.java +++ b/common/src/main/java/envoy/event/IssueProposal.java @@ -23,7 +23,7 @@ public final class IssueProposal extends Event { */ public IssueProposal(String title, String description, boolean isBug) { super(escape(title)); - this.description = sanitizeDescription(description); + this.description = description == null ? "" : sanitizeDescription(description); bug = isBug; } @@ -37,8 +37,8 @@ public final class IssueProposal extends Event { */ public IssueProposal(String title, String description, String user, boolean isBug) { super(escape(title)); - this.description = - sanitizeDescription(description) + String.format("
Submitted by user %s.", user); + this.description = description == null ? "" + : sanitizeDescription(description) + String.format("
Submitted by user %s.", user); bug = isBug; } diff --git a/common/src/main/java/envoy/event/MessageStatusChange.java b/common/src/main/java/envoy/event/MessageStatusChange.java index 5bdacde..5581f67 100644 --- a/common/src/main/java/envoy/event/MessageStatusChange.java +++ b/common/src/main/java/envoy/event/MessageStatusChange.java @@ -1,6 +1,7 @@ package envoy.event; import java.time.Instant; +import java.util.Objects; import envoy.data.Message; @@ -26,7 +27,7 @@ public class MessageStatusChange extends Event { public MessageStatusChange(long id, Message.MessageStatus status, Instant date) { super(status); this.id = id; - this.date = date; + this.date = Objects.requireNonNull(date); } /** diff --git a/common/src/main/java/envoy/event/PasswordChangeRequest.java b/common/src/main/java/envoy/event/PasswordChangeRequest.java index b1b860c..023c482 100644 --- a/common/src/main/java/envoy/event/PasswordChangeRequest.java +++ b/common/src/main/java/envoy/event/PasswordChangeRequest.java @@ -1,5 +1,7 @@ package envoy.event; +import java.util.Objects; + import envoy.data.Contact; /** @@ -21,7 +23,7 @@ public final class PasswordChangeRequest extends Event { */ public PasswordChangeRequest(String newPassword, String oldPassword, long userID) { super(newPassword); - this.oldPassword = oldPassword; + this.oldPassword = Objects.requireNonNull(oldPassword); id = userID; } diff --git a/common/src/main/java/envoy/event/contact/UserOperation.java b/common/src/main/java/envoy/event/contact/UserOperation.java index bbec1c9..fd4de7f 100644 --- a/common/src/main/java/envoy/event/contact/UserOperation.java +++ b/common/src/main/java/envoy/event/contact/UserOperation.java @@ -1,5 +1,7 @@ package envoy.event.contact; +import java.util.Objects; + import envoy.data.User; import envoy.event.*; @@ -24,7 +26,7 @@ public final class UserOperation extends Event { */ public UserOperation(User contact, ElementOperation operationType) { super(contact); - this.operationType = operationType; + this.operationType = Objects.requireNonNull(operationType); } /** diff --git a/server/src/main/java/envoy/server/data/PersistenceManager.java b/server/src/main/java/envoy/server/data/PersistenceManager.java index ddabe7b..d2e1f22 100755 --- a/server/src/main/java/envoy/server/data/PersistenceManager.java +++ b/server/src/main/java/envoy/server/data/PersistenceManager.java @@ -1,7 +1,7 @@ package envoy.server.data; import java.time.Instant; -import java.util.List; +import java.util.*; import java.util.logging.Level; import javax.persistence.*; @@ -223,6 +223,9 @@ public final class PersistenceManager { * @since Envoy Server Standalone v0.2-beta */ public List getPendingMessages(User user, Instant lastSync) { + if (user == null) + return new ArrayList<>(); + lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH); return entityManager.createNamedQuery(Message.getPending).setParameter("user", user) .setParameter("lastSeen", lastSync).getResultList(); } @@ -236,6 +239,9 @@ public final class PersistenceManager { * @since Envoy Server Standalone v0.2-beta */ public List getPendingGroupMessages(User user, Instant lastSync) { + if (user == null) + return new ArrayList<>(); + lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH); return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg) .setParameter("userId", user.getID()) .setParameter("lastSeen", lastSync) @@ -277,16 +283,18 @@ public final class PersistenceManager { * @since Envoy Server v0.3-beta */ public void addContactBidirectional(Contact contact1, Contact contact2) { + if (!(contact1 == null || contact2 == null)) { - // Add users to each others contact list - contact1.getContacts().add(contact2); - contact2.getContacts().add(contact1); + // Add users to each others contact list + contact1.getContacts().add(contact2); + contact2.getContacts().add(contact1); - // Synchronize changes with the database - transaction(() -> { - entityManager.merge(contact1); - entityManager.merge(contact2); - }); + // Synchronize changes with the database + transaction(() -> { + entityManager.merge(contact1); + entityManager.merge(contact2); + }); + } } /** @@ -308,16 +316,18 @@ public final class PersistenceManager { * @since Envoy Server v0.3-beta */ public void removeContactBidirectional(Contact contact1, Contact contact2) { + if (!(contact1 == null || contact2 == null)) { - // Remove users from each others contact list - contact1.getContacts().remove(contact2); - contact2.getContacts().remove(contact1); + // Remove users from each others contact list + contact1.getContacts().remove(contact2); + contact2.getContacts().remove(contact1); - // Synchronize changes with the database - transaction(() -> { - entityManager.merge(contact1); - entityManager.merge(contact2); - }); + // Synchronize changes with the database + transaction(() -> { + entityManager.merge(contact1); + entityManager.merge(contact2); + }); + } } /**