From 26fc4374cada868961e94fa7f5f13663b98802de Mon Sep 17 00:00:00 2001 From: kske Date: Mon, 6 Jan 2020 14:58:28 +0200 Subject: [PATCH] Added writing capabilities to ObjectProcessor, completed db integration At this moment the client is not able to receive to objects sent consecutively. This will be worked on in a future commit and should be fixed before merging this branch into develop. --- pom.xml | 5 +++ .../server/LoginCredentialProcessor.java | 21 ++++++++++-- .../java/envoy/server/MessageProcessor.java | 6 ++-- .../java/envoy/server/ObjectProcessor.java | 11 +++--- src/main/java/envoy/server/data/Message.java | 20 +++++++++-- src/main/java/envoy/server/data/User.java | 6 +++- .../server/net/ObjectMessageProcessor.java | 32 ++++++----------- .../envoy/server/net/ObjectWriteProxy.java | 34 +++++++++++++++++++ src/main/resources/META-INF/persistence.xml | 29 ++++++++++++++++ 9 files changed, 128 insertions(+), 36 deletions(-) create mode 100644 src/main/java/envoy/server/net/ObjectWriteProxy.java create mode 100644 src/main/resources/META-INF/persistence.xml diff --git a/pom.xml b/pom.xml index 5b81ded..48a6be0 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,11 @@ hibernate-core 5.4.10.Final + + org.postgresql + postgresql + 42.2.9 + diff --git a/src/main/java/envoy/server/LoginCredentialProcessor.java b/src/main/java/envoy/server/LoginCredentialProcessor.java index 0a84edf..89261cf 100644 --- a/src/main/java/envoy/server/LoginCredentialProcessor.java +++ b/src/main/java/envoy/server/LoginCredentialProcessor.java @@ -1,7 +1,12 @@ package envoy.server; +import java.io.IOException; +import java.util.ArrayList; + +import envoy.data.Contacts; import envoy.data.LoginCredentials; import envoy.data.User; +import envoy.server.net.ObjectWriteProxy; /** * This {@link ObjectProcessor} handles {@link LoginCredentials}.
@@ -13,7 +18,7 @@ import envoy.data.User; * @author Kai S. K. Engelbart * @since Envoy Server Standalone v0.1-alpha */ -public class LoginCredentialProcessor implements ObjectProcessor { +public class LoginCredentialProcessor implements ObjectProcessor { // TODO: Acquire user IDs from database private static long currentUserId = 1; @@ -22,10 +27,20 @@ public class LoginCredentialProcessor implements ObjectProcessor getInputClass() { return LoginCredentials.class; } @Override - public User process(LoginCredentials input, long socketId) { + public void process(LoginCredentials input, long socketId, ObjectWriteProxy writeProxy) throws IOException { System.out.println(String.format("Received login credentials %s from socket ID %d", input, socketId)); + + // Create user User user = new User(currentUserId++, input.getName()); ConnectionManager.getInstance().registerUser(socketId, user.getId()); - return user; + + // Create contacts + Contacts contacts = new Contacts(user.getId(), new ArrayList<>()); + + // Complete handshake + System.out.println("Sending user..."); + writeProxy.write(socketId, user); + System.out.println("Sending contacts..."); + writeProxy.write(socketId, contacts); } } diff --git a/src/main/java/envoy/server/MessageProcessor.java b/src/main/java/envoy/server/MessageProcessor.java index 8d80e53..3e2f139 100644 --- a/src/main/java/envoy/server/MessageProcessor.java +++ b/src/main/java/envoy/server/MessageProcessor.java @@ -1,6 +1,7 @@ package envoy.server; import envoy.data.Message; +import envoy.server.net.ObjectWriteProxy; /** * This {@link ObjectProcessor} handles incoming {@link Message}s.
@@ -12,13 +13,13 @@ import envoy.data.Message; * @author Kai S. K. Engelbart * @since Envoy Server Standalone v0.1-alpha */ -public class MessageProcessor implements ObjectProcessor { +public class MessageProcessor implements ObjectProcessor { @Override public Class getInputClass() { return Message.class; } @Override - public Void process(Message message, long socketId) { + public void process(Message message, long socketId, ObjectWriteProxy writeProxy) { // TODO: Send message to recipient if online ConnectionManager connectionManager = ConnectionManager.getInstance(); @@ -27,6 +28,5 @@ public class MessageProcessor implements ObjectProcessor { } // TODO: Add message to database - return null; } } diff --git a/src/main/java/envoy/server/ObjectProcessor.java b/src/main/java/envoy/server/ObjectProcessor.java index 07c0480..0221fc0 100644 --- a/src/main/java/envoy/server/ObjectProcessor.java +++ b/src/main/java/envoy/server/ObjectProcessor.java @@ -1,5 +1,9 @@ package envoy.server; +import java.io.IOException; + +import envoy.server.net.ObjectWriteProxy; + /** * This interface defines methods for processing objects of a specific * type incoming from a client.
@@ -10,13 +14,12 @@ package envoy.server; * * @author Kai S. K. Engelbart * @param type of the request object - * @param type of the response object * @since Envoy Server Standalone v0.1-alpha */ -public interface ObjectProcessor { +public interface ObjectProcessor { /** - * @return the Class of the request object + * @return the class of the request object * @since Envoy Server Standalone v0.1-alpha */ Class getInputClass(); @@ -27,5 +30,5 @@ public interface ObjectProcessor { * @return the response object * @since Envoy Server Standalone v0.1-alpha */ - U process(T input, long socketId); + void process(T input, long socketId, ObjectWriteProxy writeProxy) throws IOException; } \ No newline at end of file diff --git a/src/main/java/envoy/server/data/Message.java b/src/main/java/envoy/server/data/Message.java index 19e25a6..af7f612 100644 --- a/src/main/java/envoy/server/data/Message.java +++ b/src/main/java/envoy/server/data/Message.java @@ -4,6 +4,7 @@ import java.util.Date; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; @@ -28,8 +29,12 @@ import envoy.data.MessageBuilder; @Entity @Table(name = "messages") @NamedQueries( - { @NamedQuery(query = "SELECT m FROM Message m WHERE m.recipient =:recipient AND m.state = 1", name = "getUnreadMessages"), @NamedQuery( - query = "SELECT m FROM Message m WHERE m.sender =:sender AND m.state = :state", + { @NamedQuery( + query = "SELECT m FROM Message m WHERE m.recipient =:recipient AND m.status = envoy.data.Message$MessageStatus.SENT", + name = "getUnreadMessages" + ), + @NamedQuery( + query = "SELECT m FROM Message m WHERE m.sender =:sender AND m.status = :status", name = "find read messages"//TODO do we need this namedQuery? ), @NamedQuery(query = "SELECT m FROM Message m WHERE m.id = :messageId", name = "get message") }//TODO do we need this namedQuery? ) @@ -37,13 +42,22 @@ public class Message { @Id private long id; - private User sender, recipient; + + @ManyToOne + private User sender; + + @ManyToOne + private User recipient; + @Temporal(TemporalType.TIMESTAMP) private Date creationDate; + @Temporal(TemporalType.TIMESTAMP) private Date receivedDate; + @Temporal(TemporalType.TIMESTAMP) private Date readDate; + private envoy.data.Message.MessageStatus status; private String text; private byte[] attachment; diff --git a/src/main/java/envoy/server/data/User.java b/src/main/java/envoy/server/data/User.java index e0de15f..40e25c7 100644 --- a/src/main/java/envoy/server/data/User.java +++ b/src/main/java/envoy/server/data/User.java @@ -3,6 +3,7 @@ package envoy.server.data; import java.util.Date; import java.util.List; +import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -27,7 +28,7 @@ import javax.persistence.TemporalType; */ @Entity @Table(name = "users") -@NamedQuery(query = "SELECT u FROM DBUser u WHERE u.id = :id", name = "getUserById") +@NamedQuery(query = "SELECT u FROM User u WHERE u.id = :id", name = "getUserById") public class User { @Id @@ -35,9 +36,12 @@ public class User { private long id; private String name; private byte[] passwordHash; + @Temporal(TemporalType.TIMESTAMP) private Date lastSeen; private envoy.data.User.UserStatus status; + + @ElementCollection private List contacts; /** diff --git a/src/main/java/envoy/server/net/ObjectMessageProcessor.java b/src/main/java/envoy/server/net/ObjectMessageProcessor.java index 1bf707f..47dae57 100644 --- a/src/main/java/envoy/server/net/ObjectMessageProcessor.java +++ b/src/main/java/envoy/server/net/ObjectMessageProcessor.java @@ -1,10 +1,8 @@ package envoy.server.net; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.Set; import com.jenkov.nioserver.IMessageProcessor; @@ -25,7 +23,7 @@ import envoy.server.ObjectProcessor; */ public class ObjectMessageProcessor implements IMessageProcessor { - private final Set> processors; + private final Set> processors; /** * The constructor to set the {@link ObjectProcessor}s. @@ -33,9 +31,7 @@ public class ObjectMessageProcessor implements IMessageProcessor { * @param processors the {@link ObjectProcessor} to set * @since Envoy Server Standalone v0.1-alpha */ - public ObjectMessageProcessor(Set> processors) { - this.processors = processors; - } + public ObjectMessageProcessor(Set> processors) { this.processors = processors; } @SuppressWarnings("unchecked") @Override @@ -45,25 +41,17 @@ public class ObjectMessageProcessor implements IMessageProcessor { System.out.println("Read object: " + obj.toString()); // Process object - processors.stream().filter(p -> p.getInputClass().isInstance(obj)).forEach((@SuppressWarnings("rawtypes") ObjectProcessor p) -> { - Object responseObj = p.process(p.getInputClass().cast(obj), message.socketId); - if (responseObj != null) { - // Create message targeted at the client - Message response = writeProxy.getMessage(); - response.socketId = message.socketId; - - // Serialize object to byte array - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ObjectOutputStream oout = new ObjectOutputStream(baos)) { - oout.writeObject(responseObj); + processors.stream() + .filter(p -> p.getInputClass().isInstance(obj)) + .forEach((@SuppressWarnings( + "rawtypes" + ) ObjectProcessor p) -> { + try { + p.process(p.getInputClass().cast(obj), message.socketId, new ObjectWriteProxy(writeProxy)); } catch (IOException e) { e.printStackTrace(); } - byte[] objBytes = baos.toByteArray(); - response.writeToMessage(objBytes); - writeProxy.enqueue(response); - } - }); + }); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } diff --git a/src/main/java/envoy/server/net/ObjectWriteProxy.java b/src/main/java/envoy/server/net/ObjectWriteProxy.java new file mode 100644 index 0000000..b1dc337 --- /dev/null +++ b/src/main/java/envoy/server/net/ObjectWriteProxy.java @@ -0,0 +1,34 @@ +package envoy.server.net; + +import java.io.IOException; + +import com.jenkov.nioserver.Message; +import com.jenkov.nioserver.WriteProxy; + +import envoy.util.SerializationUtils; + +/** + * Project: envoy-server-standalone
+ * File: ObjectWriteProxy.java
+ * Created: 04.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy Server Standalone v0.1-alpha + */ +public class ObjectWriteProxy { + + private final WriteProxy writeProxy; + + public ObjectWriteProxy(WriteProxy writeProxy) { this.writeProxy = writeProxy; } + + public void write(long recipientSocketId, Object obj) throws IOException { + // Create message targeted at the client + Message response = writeProxy.getMessage(); + response.socketId = recipientSocketId; + + // Serialize object to byte array + byte[] objBytes = SerializationUtils.writeToByteArray(obj); + response.writeToMessage(objBytes); + writeProxy.enqueue(response); + } +} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..4d937c9 --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file