From ac26e6874630f9d32e58cfd8ee85ccad69b31de3 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 1 Apr 2020 18:09:07 +0200 Subject: [PATCH] deleted Contacts object, added contacts as part of Contact class additionally: * updated serialization method to not recurse endlessly * refactored type of contacts from List to Set --- .classpath | 57 ++++++++------- pom.xml | 1 + src/main/java/envoy/data/Contact.java | 26 +++++-- src/main/java/envoy/data/Contacts.java | 36 --------- src/main/java/envoy/data/Group.java | 57 +++++++-------- src/main/java/envoy/data/MessageBuilder.java | 47 +++++++++--- src/main/java/envoy/data/User.java | 73 ++++++++++++++++--- .../java/envoy/event/GroupCreationEvent.java | 24 +++++- .../java/envoy/event/GroupResizeEvent.java | 2 +- src/test/java/envoy/data/UserTest.java | 35 +++++++++ 10 files changed, 229 insertions(+), 129 deletions(-) delete mode 100644 src/main/java/envoy/data/Contacts.java create mode 100644 src/test/java/envoy/data/UserTest.java diff --git a/.classpath b/.classpath index 3603647..e716709 100644 --- a/.classpath +++ b/.classpath @@ -1,28 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 0add6eb..98d18f7 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ src/main/resources + src/test/java diff --git a/src/main/java/envoy/data/Contact.java b/src/main/java/envoy/data/Contact.java index 53992c6..b3b2d03 100644 --- a/src/main/java/envoy/data/Contact.java +++ b/src/main/java/envoy/data/Contact.java @@ -2,6 +2,7 @@ package envoy.data; import java.io.Serializable; import java.util.Objects; +import java.util.Set; /** * This class is the superclass for both {@link User} and {@link Group}.
@@ -16,21 +17,24 @@ import java.util.Objects; */ public abstract class Contact implements Serializable { - private final long id; - private String name; + private final long id; + private final transient Set contacts; + private String name; private static final long serialVersionUID = 0L; /** * Creates a new instance of a {@link Contact}. * - * @param id the ID of this contact - * @param name the name of this contact + * @param id the ID of this contact + * @param name the name of this contact + * @param contacts the {@link Contacts} of this {@link Contact} * @since Envoy Common v0.1-beta */ - public Contact(long id, String name) { - this.id = id; - this.name = name; + public Contact(long id, String name, Set contacts) { + this.id = id; + this.name = name; + this.contacts = contacts; } /** @@ -55,7 +59,7 @@ public abstract class Contact implements Serializable { * {@inheritDoc} */ @Override - public String toString() { return String.format("Contact[id=%d,name=%s]", id, name); } + public String toString() { return String.format("Contact[id=%d,name=%s, contacts=%s]", id, name, contacts); } /** * {@inheritDoc} @@ -72,4 +76,10 @@ public abstract class Contact implements Serializable { if (!(obj instanceof Contact)) return false; return id == ((Contact) obj).id; } + + /** + * @return the contacts of this {@link Contact} + * @since Envoy Common v0.1-beta + */ + public Set getContacts() { return contacts; } } diff --git a/src/main/java/envoy/data/Contacts.java b/src/main/java/envoy/data/Contacts.java deleted file mode 100644 index 71eac52..0000000 --- a/src/main/java/envoy/data/Contacts.java +++ /dev/null @@ -1,36 +0,0 @@ -package envoy.data; - -import java.io.Serializable; -import java.util.List; - -/** - * Project: envoy-common
- * File: Contacts.java
- * Created: 02.01.2020
- * - * @author Kai S. K. Engelbart - * @since Envoy Common v0.2-alpha - */ -public class Contacts implements Serializable { - - private final List contacts; - - private static final long serialVersionUID = 0L; - - /** - * Creates an instance of {@link Contacts}. - * - * @param contacts the contact list - * @since Envoy Common v0.2-alpha - */ - public Contacts(List contacts) { this.contacts = contacts; } - - @Override - public String toString() { return String.format("Contacts[%s]", contacts); } - - /** - * @return a list of users messages can be sent to - * @since Envoy Common v0.2-alpha - */ - public List getContacts() { return contacts; } -} diff --git a/src/main/java/envoy/data/Group.java b/src/main/java/envoy/data/Group.java index 077ff40..bec17be 100644 --- a/src/main/java/envoy/data/Group.java +++ b/src/main/java/envoy/data/Group.java @@ -1,8 +1,9 @@ package envoy.data; -import java.util.ArrayList; -import java.util.List; -import java.util.StringJoiner; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashSet; +import java.util.Set; /** * Project: envoy-common
@@ -12,50 +13,44 @@ import java.util.StringJoiner; * @author Leon Hofmeister * @since Envoy Common v0.1-beta */ -public class Group extends Contact { - - // TODO add admins - private final List memberIDs; +public final class Group extends Contact { private static final long serialVersionUID = 0L; /** - * Creates a new instance of a {@link Group}. + * Creates a new instance of a {@link Group} without any members. * * @param id the ID of this group * @param name the name of this group * @since Envoy Common v0.1-beta */ - public Group(long id, String name) { this(id, name, new ArrayList<>()); } + public Group(long id, String name) { this(id, name, new HashSet()); } /** - * Creates a new instance of a {@link Group}. + * Creates an instance of a {@link Group}. * - * @param id the ID of this group - * @param name the name of this group - * @param memberIDs the IDs of all members that should be preinitialized + * @param id the ID of this group + * @param name the name of this group + * @param members all members that should be preinitialized * @since Envoy Common v0.1-beta */ - public Group(long id, String name, List memberIDs) { - super(id, name); - this.memberIDs = memberIDs; + public Group(long id, String name, Set members) { super(id, name, members); } + + private void readObject(ObjectInputStream inputStream) throws Exception { + inputStream.defaultReadObject(); + var contacts = Contact.class.getDeclaredField("contacts"); + contacts.setAccessible(true); + contacts.set(this, inputStream.readObject()); } - /** - * @return the IDs of all members of this group - * @since Envoy Common v0.1-beta - */ - public List getMemberIDs() { return memberIDs; } + private void writeObject(ObjectOutputStream outputStream) throws Exception { + outputStream.defaultWriteObject(); + getContacts().forEach(user -> user.serializeContacts(false)); + outputStream.writeObject(getContacts()); - /** - * {@inheritDoc} - */ + } + + @SuppressWarnings("unchecked") @Override - public String toString() { - var joiner = new StringJoiner(",", "Group[id=", "]"); - joiner.add("id=" + getID()); - joiner.add("name=" + getName()); - joiner.add("members=" + getMemberIDs().size()); - return joiner.toString(); - } + public Set getContacts() { return (Set) super.getContacts(); } } diff --git a/src/main/java/envoy/data/MessageBuilder.java b/src/main/java/envoy/data/MessageBuilder.java index 79325fa..87c6bf9 100644 --- a/src/main/java/envoy/data/MessageBuilder.java +++ b/src/main/java/envoy/data/MessageBuilder.java @@ -2,6 +2,7 @@ package envoy.data; import java.util.Date; import java.util.HashMap; +import java.util.Map; import envoy.data.Message.MessageStatus; @@ -102,6 +103,35 @@ public class MessageBuilder { return new Message(id, senderID, recipientID, creationDate, text, attachment, status, forwarded); } + /** + * Creates an instance of {@link GroupMessage} with the previously supplied + * values.
+ * Sets all member statuses to {@link MessageStatus#WAITING}.
+ * If a mandatory value is not set, a default value will be used + * instead:
+ *
+ * + * + * + * + * + * + * + * + * + *
{@code date}{@code new Date()}
{@code text}{@code ""}
+ * + * @param group the {@link Group} that is used to fill the map of member + * statuses + * @return a new instance of {@link GroupMessage} + * @since Envoy Common v0.2-alpha + */ + public GroupMessage buildGroupMessage(Group group) { + var memberStatuses = new HashMap(); + group.getContacts().forEach(user -> memberStatuses.put(user.getID(), MessageStatus.WAITING)); + return buildGroupMessage(group, memberStatuses); + } + /** * Creates an instance of {@link GroupMessage} with the previously supplied * values. If a mandatory value is not set, a default value will be used @@ -116,22 +146,17 @@ public class MessageBuilder { * {@code text} * {@code ""} * - * - * {@code status} - * {@code MessageStatus.WAITING} - * * * - * @param group the {@link Group} that is used to fill the map of member - * statuses + * @param group the {@link Group} that is used to fill the map of + * member statuses + * @param memberStatuses the map of all current statuses * @return a new instance of {@link GroupMessage} - * @since Envoy Common v0.2-alpha + * @since Envoy Common v0.1-beta */ - public GroupMessage buildGroupMessage(Group group) { - if (group == null) throw new NullPointerException(); + public GroupMessage buildGroupMessage(Group group, Map memberStatuses) { + if (group == null || memberStatuses == null) throw new NullPointerException(); supplyDefaults(); - var memberStatuses = new HashMap(); - group.getMemberIDs().forEach(id -> memberStatuses.put(id, MessageStatus.WAITING)); return new GroupMessage(id, senderID, recipientID, creationDate, text, attachment, status, forwarded, memberStatuses); } diff --git a/src/main/java/envoy/data/User.java b/src/main/java/envoy/data/User.java index d282e29..ca64d0d 100644 --- a/src/main/java/envoy/data/User.java +++ b/src/main/java/envoy/data/User.java @@ -1,5 +1,11 @@ package envoy.data; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + /** * Represents a unique user with a unique, numeric ID, a name and a current * {@link UserStatus}.
@@ -11,7 +17,16 @@ package envoy.data; * @author Kai S. K. Engelbart * @since Envoy Common v0.2-alpha */ -public class User extends Contact { +public final class User extends Contact { + + private UserStatus status; + + /** + * Used to serialize contact list to a maximum depth of one + */ + private transient boolean serializeContacts = true; + + private static final long serialVersionUID = 1L; /** * This enumeration defines all possible statuses a user can have. @@ -42,38 +57,50 @@ public class User extends Contact { OFFLINE; } - private UserStatus status; - - private static final long serialVersionUID = 1L; - /** * Initializes a {@link User}.
* The {@link UserStatus} is set to {@link UserStatus#ONLINE}. + * No contacts are initialized. * * @param id unique ID * @param name user name * @since Envoy Common v0.2-alpha */ public User(long id, String name) { - super(id, name); + super(id, name, new HashSet<>()); + status = UserStatus.ONLINE; + } + + /** + * Initializes a {@link User}.
+ * The {@link UserStatus} is set to {@link UserStatus#ONLINE}. + * + * @param id unique ID + * @param name user name + * @param contacts the contacts of this user + * @since Envoy Common v0.2-alpha + */ + public User(long id, String name, Set contacts) { + super(id, name, contacts); status = UserStatus.ONLINE; } /** * Initializes a {@link User}. * - * @param id unique ID - * @param name user name - * @param status the status of the user + * @param id unique ID + * @param name user name + * @param status the status of this user + * @param contacts the contacts of this user * @since Envoy Common v0.2-alpha */ - public User(long id, String name, UserStatus status) { - super(id, name); + public User(long id, String name, UserStatus status, Set contacts) { + super(id, name, contacts); this.status = status; } @Override - public String toString() { return String.format("User[id=%d,name=%s,status=%s]", getID(), getName(), status); } + public String toString() { return String.format("User[id=%d,name=%s,status=%s,contacts=%s]", getID(), getName(), status, getContacts()); } /** * @return the current status of this user @@ -86,4 +113,26 @@ public class User extends Contact { * @since Envoy Common v0.2-alpha */ public void setStatus(UserStatus status) { this.status = status; } + + private void readObject(ObjectInputStream inputStream) throws Exception { + inputStream.defaultReadObject(); + var contacts = Contact.class.getDeclaredField("contacts"); + contacts.setAccessible(true); + contacts.set(this, inputStream.readObject()); + } + + private void writeObject(ObjectOutputStream outputStream) throws Exception { + outputStream.defaultWriteObject(); + if (serializeContacts) { + getContacts().stream().filter(User.class::isInstance).map(User.class::cast).forEach(user -> user.serializeContacts = false); + outputStream.writeObject(getContacts()); + } else outputStream.writeObject(new ArrayList<>()); + } + + /** + * @param serializeContacts whether the contacts of this {@link User} should be + * serialized + * @since Envoy Common v0.1-beta + */ + public void serializeContacts(boolean serializeContacts) { this.serializeContacts = serializeContacts; } } diff --git a/src/main/java/envoy/event/GroupCreationEvent.java b/src/main/java/envoy/event/GroupCreationEvent.java index 5b6d365..88c405d 100644 --- a/src/main/java/envoy/event/GroupCreationEvent.java +++ b/src/main/java/envoy/event/GroupCreationEvent.java @@ -1,5 +1,10 @@ package envoy.event; +import java.util.HashSet; +import java.util.Set; + +import envoy.data.User; + /** * This event creates a group with the given name.
*
@@ -12,11 +17,26 @@ package envoy.event; */ public class GroupCreationEvent extends Event { + private final Set initialMemberIDs; + private static final long serialVersionUID = 0L; /** - * @param value the name of this group at creation time + * @param value the name of this group at creation time + * @param initialMemberIDs the IDs of all {@link User}s that should be group + * members from the beginning on (excluding the creator + * of this group) * @since Envoy Common v0.1-beta */ - public GroupCreationEvent(String value) { super(value); } + public GroupCreationEvent(String value, Set initialMemberIDs) { + super(value); + this.initialMemberIDs = (initialMemberIDs != null) ? initialMemberIDs : new HashSet<>(); + } + + /** + * @return the IDs of all {@link User}s that are members from the beginning + * (excluding the creator of this group) + * @since Envoy Common v0.1-beta + */ + public Set getInitialMemberIDs() { return initialMemberIDs; } } diff --git a/src/main/java/envoy/event/GroupResizeEvent.java b/src/main/java/envoy/event/GroupResizeEvent.java index 24f4ac8..5f6791e 100644 --- a/src/main/java/envoy/event/GroupResizeEvent.java +++ b/src/main/java/envoy/event/GroupResizeEvent.java @@ -36,7 +36,7 @@ public class GroupResizeEvent extends Event { */ public GroupResizeEvent(User user, Group group, ElementOperation operation) { super(user.getID()); - if (group.getMemberIDs().contains(user.getID())) { + if (group.getContacts().contains(user)) { if (operation.equals(ElementOperation.ADD)) throw new IllegalStateException( "Cannot add " + user + " to group " + group.getID() + " because he is already a member of this group"); } else if (operation.equals(ElementOperation.REMOVE)) diff --git a/src/test/java/envoy/data/UserTest.java b/src/test/java/envoy/data/UserTest.java new file mode 100644 index 0000000..b04134d --- /dev/null +++ b/src/test/java/envoy/data/UserTest.java @@ -0,0 +1,35 @@ +package envoy.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import envoy.data.User.UserStatus; +import envoy.util.SerializationUtils; + +/** + * Project: envoy-common
+ * File: UserTest.java
+ * Created: 31 Mar 2020
+ * + * @author Leon Hofmeister + * @since Envoy Common v0.1-beta + */ +class UserTest { + + @Test + void test() throws IOException, ClassNotFoundException { + User user2 = new User(2, "kai"); + User user3 = new User(3, "ai"); + User user4 = new User(4, "ki", Set.of(user2, user3)); + User user5 = new User(5, "ka", Set.of(user2, user3, user4)); + User user = new User(1, "maxi", UserStatus.AWAY, Set.of(user2, user3, user4, user5)); + var serializedUser = SerializationUtils.writeToByteArray(user); + var deserializedUser = SerializationUtils.read(serializedUser, User.class); + assertEquals(user.getContacts(), deserializedUser.getContacts()); + } + +}