diff --git a/src/main/java/envoy/server/Startup.java b/src/main/java/envoy/server/Startup.java index 8ccbe5e..e23bf69 100644 --- a/src/main/java/envoy/server/Startup.java +++ b/src/main/java/envoy/server/Startup.java @@ -38,6 +38,8 @@ public class Startup { processors.add(new MessageStatusChangeProcessor()); processors.add(new UserStatusChangeProcessor()); processors.add(new IdGeneratorRequestProcessor()); + processors.add(new ContactsRequestEventProcessor()); + processors.add(new ContactOperationProcessor()); Server server = new Server(8080, () -> new ObjectMessageReader(), new ObjectMessageProcessor(processors)); initializeCurrentMessageId(); diff --git a/src/main/java/envoy/server/data/User.java b/src/main/java/envoy/server/data/User.java index 7b9cbd7..4cee18e 100644 --- a/src/main/java/envoy/server/data/User.java +++ b/src/main/java/envoy/server/data/User.java @@ -16,14 +16,19 @@ import javax.persistence.*; * Created: 02.01.2020
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy Server Standalone v0.1-alpha */ @Entity @Table(name = "users") @NamedQueries( - { @NamedQuery(query = "SELECT u FROM User u WHERE u.name = :name", name = "getUserByName"), - @NamedQuery(query = "SELECT u.contacts FROM User u WHERE u = :user", name = "getContactsOfUser")// not tested - } + { @NamedQuery(query = "SELECT u FROM User u WHERE u.name = :name", name = "getUserByName"), @NamedQuery( + query = "SELECT u.contacts FROM User u WHERE u = :user", + name = "getContactsOfUser" + ), @NamedQuery( + query = "SELECT u FROM User u WHERE (lower(u.name) LIKE lower(:searchPhrase) AND u <> :context AND NOT :context in elements(u.contacts))", + name = "searchUsers" + ) } ) public class User { @@ -37,7 +42,7 @@ public class User { private Date lastSeen; private envoy.data.User.UserStatus status; - @OneToMany(targetEntity = User.class, cascade = CascadeType.ALL, orphanRemoval = true) + @ManyToMany(targetEntity = User.class, cascade = CascadeType.ALL) private List contacts; /** diff --git a/src/main/java/envoy/server/database/PersistenceManager.java b/src/main/java/envoy/server/database/PersistenceManager.java index 84587e6..8943f52 100644 --- a/src/main/java/envoy/server/database/PersistenceManager.java +++ b/src/main/java/envoy/server/database/PersistenceManager.java @@ -177,12 +177,44 @@ public class PersistenceManager { } /** - * @param user the User whose contacts should be retrieved - * @return the contacts of this User - currently everyone using Envoy + * Searches for users matching a search phrase. Contacts of the attached user + * and the attached user is ignored. + * + * @param searchPhrase the search phrase + * @param userId the ID of the user in whose context the search is + * performed + * @return a list of all users who matched the criteria * @since Envoy Server Standalone v0.1-alpha */ - public List getContacts(User user) { return entityManager.createQuery("FROM User").getResultList(); } - // TODO current solution gets all users, not just contacts. Should be changed to - // entityManager.createNamedQuery("getContactsOfUser").setParameter("user", - // user).getResultList(); + public List searchUsers(String searchPhrase, long userId) { + return entityManager.createNamedQuery("searchUsers") + .setParameter("searchPhrase", searchPhrase + "%") + .setParameter("context", getUserById(userId)) + .getResultList(); + } + + /** + * Adds a user to the contact list of another user and vice versa. + * + * @param userId1 the ID of the first user + * @param userId2 the ID of the second user + * @since Envoy Server Standalone v0.1-alpha + */ + public void addContact(long userId1, long userId2) { + User u1 = getUserById(userId1); + User u2 = getUserById(userId2); + u1.getContacts().add(u2); + u2.getContacts().add(u1); + updateUser(u1); + updateUser(u2); + } + + /** + * @param user the User whose contacts should be retrieved + * @return the contacts of this User + * @since Envoy Server Standalone v0.1-alpha + */ + public List getContacts(User user) { + return entityManager.createNamedQuery("getContactsOfUser").setParameter("user", user).getResultList(); + } } \ No newline at end of file diff --git a/src/main/java/envoy/server/processors/ContactOperationProcessor.java b/src/main/java/envoy/server/processors/ContactOperationProcessor.java new file mode 100644 index 0000000..48ec6d9 --- /dev/null +++ b/src/main/java/envoy/server/processors/ContactOperationProcessor.java @@ -0,0 +1,46 @@ +package envoy.server.processors; + +import java.io.IOException; +import java.util.Arrays; + +import envoy.data.Contacts; +import envoy.event.ContactOperationEvent; +import envoy.server.ConnectionManager; +import envoy.server.ObjectProcessor; +import envoy.server.database.PersistenceManager; +import envoy.server.net.ObjectWriteProxy; + +/** + * Project: envoy-server-standalone
+ * File: ContactOperationProcessor.java
+ * Created: 08.02.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy Server Standalone v0.1-alpha + */ +public class ContactOperationProcessor implements ObjectProcessor { + + private static final ConnectionManager connectionManager = ConnectionManager.getInstance(); + + @Override + public void process(ContactOperationEvent evt, long socketId, ObjectWriteProxy writeProxy) throws IOException { + switch (evt.getOperationType()) { + case ADD: + final long userId = ConnectionManager.getInstance().getUserIdBySocketId(socketId); + final long contactId = evt.get().getId(); + + System.out.printf("Adding user %s to the contact list of user %d.%n", evt.get(), userId); + PersistenceManager.getPersistenceManager().addContact(userId, contactId); + + // Notify the contact if online + if (ConnectionManager.getInstance().isOnline(contactId)) writeProxy.write(connectionManager.getSocketId(contactId), + new Contacts(Arrays.asList(PersistenceManager.getPersistenceManager().getUserById(userId).toCommonUser()))); + break; + default: + System.err.printf("Received %s with an unsupported operation.%n", evt); + } + } + + @Override + public Class getInputClass() { return ContactOperationEvent.class; } +} diff --git a/src/main/java/envoy/server/processors/ContactsRequestEventProcessor.java b/src/main/java/envoy/server/processors/ContactsRequestEventProcessor.java new file mode 100644 index 0000000..e96c16e --- /dev/null +++ b/src/main/java/envoy/server/processors/ContactsRequestEventProcessor.java @@ -0,0 +1,45 @@ +package envoy.server.processors; + +import java.io.IOException; +import java.util.stream.Collectors; + +import envoy.data.Contacts; +import envoy.event.ContactSearchRequest; +import envoy.event.ContactSearchResult; +import envoy.server.ConnectionManager; +import envoy.server.ObjectProcessor; +import envoy.server.data.User; +import envoy.server.database.PersistenceManager; +import envoy.server.net.ObjectWriteProxy; + +/** + * Project: envoy-server-standalone
+ * File: ContactsRequestEventProcessor.java
+ * Created: 08.02.2020
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy Server Standalone v0.1-alpha + */ +public class ContactsRequestEventProcessor implements ObjectProcessor { + + /** + * Writes a {@link Contacts} list to the client containing all {@link User}s + * matching the search phrase contained inside the request. The client and their + * contacts are excluded from the result. + * + * @since Envoy Server Standalone v0.1-alpha + */ + @Override + public void process(ContactSearchRequest request, long socketId, ObjectWriteProxy writeProxy) throws IOException { + writeProxy.write(socketId, + new ContactSearchResult(PersistenceManager.getPersistenceManager() + .searchUsers(request.get(), ConnectionManager.getInstance().getUserIdBySocketId(socketId)) + .stream() + .map(User::toCommonUser) + .collect(Collectors.toList()))); + } + + @Override + public Class getInputClass() { return ContactSearchRequest.class; } +} diff --git a/src/main/java/envoy/server/processors/LoginCredentialProcessor.java b/src/main/java/envoy/server/processors/LoginCredentialProcessor.java index 4a7f2c8..c7475e9 100644 --- a/src/main/java/envoy/server/processors/LoginCredentialProcessor.java +++ b/src/main/java/envoy/server/processors/LoginCredentialProcessor.java @@ -1,9 +1,7 @@ package envoy.server.processors; import java.io.IOException; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; import envoy.data.Contacts; @@ -52,8 +50,7 @@ public class LoginCredentialProcessor implements ObjectProcessor()); } else { user = persistenceManager.getUserByName(credentials.getName()); // TODO: Implement error when user does not exist