diff --git a/.classpath b/.classpath
index 2a83b68..b468bc4 100644
--- a/.classpath
+++ b/.classpath
@@ -6,11 +6,6 @@
-
-
-
-
-
@@ -18,12 +13,6 @@
-
-
-
-
-
-
@@ -35,5 +24,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
index 45a395e..fdd0c87 100644
--- a/.project
+++ b/.project
@@ -5,11 +5,21 @@
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
org.eclipse.jdt.core.javabuilder
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
org.eclipse.m2e.core.maven2Builder
@@ -19,5 +29,6 @@
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
+ org.eclipse.wst.common.project.facet.core.nature
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 2f5cc74..db24ee7 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -1,7 +1,14 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
diff --git a/.settings/org.eclipse.jpt.core.prefs b/.settings/org.eclipse.jpt.core.prefs
new file mode 100644
index 0000000..8aa2bb2
--- /dev/null
+++ b/.settings/org.eclipse.jpt.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+org.eclipse.jpt.core.platform=hibernate2_1
+org.eclipse.jpt.jpa.core.discoverAnnotatedClasses=true
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..7961132
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..90f3be6
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.settings/org.hibernate.eclipse.console.prefs b/.settings/org.hibernate.eclipse.console.prefs
new file mode 100644
index 0000000..a6ccf3c
--- /dev/null
+++ b/.settings/org.hibernate.eclipse.console.prefs
@@ -0,0 +1,3 @@
+default.configuration=envoy-server-standalone
+eclipse.preferences.version=1
+hibernate3.enabled=true
diff --git a/pom.xml b/pom.xml
index 5b81ded..c0ed70b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,22 +17,34 @@
1.8
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
- informatik-ag-ngl
+ com.github.informatik-ag-ngl
envoy-common
- 0.2-alpha
+ develop-SNAPSHOT
- informatik-ag-ngl
+ com.github.informatik-ag-ngl
java-nio-server
- 0.0.1-SNAPSHOT
+ master-SNAPSHOT
org.hibernate
hibernate-core
5.4.10.Final
+
+ org.postgresql
+ postgresql
+ 42.2.9
+
diff --git a/src/main/java/envoy/server/ConnectionManager.java b/src/main/java/envoy/server/ConnectionManager.java
new file mode 100644
index 0000000..0ae8fcc
--- /dev/null
+++ b/src/main/java/envoy/server/ConnectionManager.java
@@ -0,0 +1,79 @@
+package envoy.server;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.jenkov.nioserver.ISocketIdListener;
+
+/**
+ * Project: envoy-server-standalone
+ * File: ConnectionManager.java
+ * Created: 03.01.2020
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+public class ConnectionManager implements ISocketIdListener {
+
+ /**
+ * Contains all socket IDs that have not yet performed a handshake / acquired
+ * their corresponding user ID.
+ *
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ private Set pendingSockets = new HashSet<>();
+
+ /**
+ * Contains all socket IDs that have acquired a user ID as keys to these IDs.
+ *
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ private Map sockets = new HashMap<>();
+
+ private static ConnectionManager connectionManager = new ConnectionManager();
+
+ private ConnectionManager() {}
+
+ /**
+ * @return a singleton instance of this object
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public static ConnectionManager getInstance() { return connectionManager; }
+
+ @Override
+ public void socketCancelled(long socketId) {
+ if (!pendingSockets.remove(socketId))
+ sockets.entrySet().stream().filter(e -> e.getValue() == socketId).forEach(e -> sockets.remove(e.getValue()));
+ }
+
+ @Override
+ public void socketRegistered(long socketId) { pendingSockets.add(socketId); }
+
+ /**
+ * Associates a socket ID with a user ID.
+ *
+ * @param userId the user ID
+ * @param socketId the socket ID
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public void registerUser(long userId, long socketId) {
+ sockets.put(userId, socketId);
+ pendingSockets.remove(userId);
+ }
+
+ /**
+ * @param userId the ID of the user registered at the a socket
+ * @return the ID of the socket
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public long getSocketId(long userId) { return sockets.get(userId); }
+
+ /**
+ * @param userId the ID of the user to check for
+ * @return {@code true} if the user is online
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public boolean isOnline(long userId) { return sockets.containsKey(userId); }
+}
diff --git a/src/main/java/envoy/server/LoginCredentialProcessor.java b/src/main/java/envoy/server/LoginCredentialProcessor.java
deleted file mode 100644
index f208a3e..0000000
--- a/src/main/java/envoy/server/LoginCredentialProcessor.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package envoy.server;
-
-import envoy.data.LoginCredentials;
-import envoy.data.User;
-
-/**
- * This {@link ObjectProcessor} handles {@link LoginCredentials}.
- *
- * Project: envoy-server-standalone
- * File: LoginCredentialProcessor.java
- * Created: 30.12.2019
- *
- * @author Kai S. K. Engelbart
- * @since Envoy Server Standalone v0.1-alpha
- */
-public class LoginCredentialProcessor implements ObjectProcessor {
-
- // TODO: Acquire user IDs from database
- private static long currentUserId = 1;
-
- @Override
- public Class getInputClass() { return LoginCredentials.class; }
-
- @Override
- public User process(LoginCredentials input) {
- System.out.println("Received login credentials " + input);
- return new User(currentUserId++, input.getName());
- }
-}
diff --git a/src/main/java/envoy/server/MessageProcessor.java b/src/main/java/envoy/server/MessageProcessor.java
deleted file mode 100644
index ea52c55..0000000
--- a/src/main/java/envoy/server/MessageProcessor.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package envoy.server;
-
-import envoy.data.Message;
-
-/**
- * This {@link ObjectProcessor} handles incoming {@link Message}s.
- *
- * Project: envoy-server-standalone
- * File: MessageProcessor.java
- * Created: 30.12.2019
- *
- * @author Kai S. K. Engelbart
- * @since Envoy Server Standalone v0.1-alpha
- */
-public class MessageProcessor implements ObjectProcessor {
-
- @Override
- public Class getInputClass() { return Message.class; }
-
- @Override
- public Void process(Message input) { return null; }
-}
diff --git a/src/main/java/envoy/server/ObjectProcessor.java b/src/main/java/envoy/server/ObjectProcessor.java
index 44c07e1..6828598 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,21 +14,22 @@ 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();
/**
- * @param input the request object
- * @return the response object
+ * @param input the request object
+ * @param socketId the ID of the socket from which the object was received
+ * @param writeProxy the object that allows writing to a client
+ * @throws IOException if something went wrong during processing
* @since Envoy Server Standalone v0.1-alpha
*/
- U process(T input);
+ void process(T input, long socketId, ObjectWriteProxy writeProxy) throws IOException;
}
\ No newline at end of file
diff --git a/src/main/java/envoy/server/Startup.java b/src/main/java/envoy/server/Startup.java
index 58a8366..e2edb6a 100644
--- a/src/main/java/envoy/server/Startup.java
+++ b/src/main/java/envoy/server/Startup.java
@@ -6,6 +6,12 @@ import java.util.Set;
import com.jenkov.nioserver.Server;
+import envoy.server.net.ObjectMessageProcessor;
+import envoy.server.net.ObjectMessageReader;
+import envoy.server.processors.EventProcessor;
+import envoy.server.processors.LoginCredentialProcessor;
+import envoy.server.processors.MessageProcessor;
+
/**
* Starts the server.
*
@@ -26,10 +32,13 @@ public class Startup {
* @since Envoy Server Standalone v0.1-alpha
*/
public static void main(String[] args) throws IOException {
- Set> processors = new HashSet<>();
+ Set> processors = new HashSet<>();
processors.add(new LoginCredentialProcessor());
processors.add(new MessageProcessor());
+ processors.add(new EventProcessor());
+ // new PersistenceManager();
Server server = new Server(8080, () -> new ObjectMessageReader(), new ObjectMessageProcessor(processors));
server.start();
+ server.getSocketProcessor().registerSocketIdListener(ConnectionManager.getInstance());
}
}
\ 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..575da6a 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;
@@ -11,6 +12,7 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import envoy.data.MessageBuilder;
+import envoy.server.database.PersistenceManager;
/**
* This class serves as a way to let Hibernate communicate with the server
@@ -28,22 +30,34 @@ 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",
- 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?
+ { @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 = "getMessageById") }
)
public class Message {
@Id
- private long id;
- private User sender, recipient;
+ private long id;
+
+ @ManyToOne
+ private User sender;
+
+ @ManyToOne
+ private User recipient;
+
@Temporal(TemporalType.TIMESTAMP)
- private Date creationDate;
+ private Date creationDate;
+
@Temporal(TemporalType.TIMESTAMP)
- private Date receivedDate;
+ private Date receivedDate;
+
@Temporal(TemporalType.TIMESTAMP)
- private Date readDate;
+ private Date readDate;
+
private envoy.data.Message.MessageStatus status;
private String text;
private byte[] attachment;
@@ -62,9 +76,14 @@ public class Message {
* @since Envoy Server Standalone v0.1-alpha
*/
public Message(envoy.data.Message message) {
- id = message.getId();
- status = message.getStatus();
- text = message.getText();
+ PersistenceManager persMan = PersistenceManager.getPersistenceManager();
+ id = message.getId();
+ status = message.getStatus();
+ text = message.getText();
+ creationDate = message.getCreationDate();
+ sender = persMan.getUserById(message.getSenderId());
+ recipient = persMan.getUserById(message.getRecipientId());
+ // attachment = message.getAttachment().toByteArray();DOES NOT WORK YET
}
/**
diff --git a/src/main/java/envoy/server/data/User.java b/src/main/java/envoy/server/data/User.java
index e0de15f..5f4e28e 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,18 +28,47 @@ 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
@GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
- private String name;
- private byte[] passwordHash;
+ private long id;
+ private String name;
+ private byte[] passwordHash;
+
@Temporal(TemporalType.TIMESTAMP)
private Date lastSeen;
private envoy.data.User.UserStatus status;
- private List contacts;
+
+ @ElementCollection
+ private List contacts;
+
+ /**
+ * Creates an instance of @link{User}.
+ * Solely used for JPA/ Hibernate
+ *
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public User() {}
+
+ /**
+ * Creates an instance of @link{User}.
+ *
+ * @param user the {@link envoy.data.User} to convert
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public User(envoy.data.User user) {
+ id = user.getId();
+ name = user.getName();
+ status = user.getStatus();
+ }
+
+ /**
+ * @return a database {@link User} converted into an {@link envoy.data.User}
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public envoy.data.User toCommonUser() { return new envoy.data.User(this.id, this.name); }
/**
* @return the id of a {link envoy.data.User}
diff --git a/src/main/java/envoy/server/database/PersistenceManager.java b/src/main/java/envoy/server/database/PersistenceManager.java
index e7c2dc8..fb38a9e 100644
--- a/src/main/java/envoy/server/database/PersistenceManager.java
+++ b/src/main/java/envoy/server/database/PersistenceManager.java
@@ -20,6 +20,21 @@ import envoy.server.data.User;
*/
public class PersistenceManager {
+ private static final PersistenceManager persistenceManager = new PersistenceManager();
+
+ /**
+ * Creates the singleton instance of the @link{PersistenceManager}.
+ *
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ private PersistenceManager() {}
+
+ /**
+ * @return the {@link PersistenceManager} singleton
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public static PersistenceManager getPersistenceManager() { return persistenceManager; }
+
private EntityManager entityManager = Persistence.createEntityManagerFactory("envoy").createEntityManager();
/**
@@ -55,7 +70,7 @@ public class PersistenceManager {
public void updateMessage(Message message) { entityManager.unwrap(Session.class).merge(message); }
/**
- * Searches for a user with a specific id.
+ * Searches for a {@link User} with a specific id.
*
* @param id - the id to search for
* @return the user with the specified id
@@ -63,6 +78,17 @@ public class PersistenceManager {
*/
public User getUserById(long id) { return (User) entityManager.createNamedQuery("getUserById").setParameter("id", id).getSingleResult(); }
+ /**
+ * Searches for a {@link Message} with a specific id.
+ *
+ * @param id - the id to search for
+ * @return the message with the specified id
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public Message getMessageById(long id) {
+ return (Message) entityManager.createNamedQuery("getMessageById").setParameter("id", id).getSingleResult();
+ }
+
/**
* Returns all messages received while being offline.
*
diff --git a/src/main/java/envoy/server/ObjectMessageProcessor.java b/src/main/java/envoy/server/net/ObjectMessageProcessor.java
similarity index 60%
rename from src/main/java/envoy/server/ObjectMessageProcessor.java
rename to src/main/java/envoy/server/net/ObjectMessageProcessor.java
index 53e53da..226fb69 100644
--- a/src/main/java/envoy/server/ObjectMessageProcessor.java
+++ b/src/main/java/envoy/server/net/ObjectMessageProcessor.java
@@ -1,16 +1,16 @@
-package envoy.server;
+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;
import com.jenkov.nioserver.Message;
import com.jenkov.nioserver.WriteProxy;
+import envoy.server.ObjectProcessor;
+
/**
* Handles incoming objects.
*
@@ -23,7 +23,7 @@ import com.jenkov.nioserver.WriteProxy;
*/
public class ObjectMessageProcessor implements IMessageProcessor {
- private final Set> processors;
+ private final Set> processors;
/**
* The constructor to set the {@link ObjectProcessor}s.
@@ -31,7 +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
@@ -42,22 +42,10 @@ public class ObjectMessageProcessor implements IMessageProcessor {
// Process object
processors.stream().filter(p -> p.getInputClass().isInstance(obj)).forEach((@SuppressWarnings("rawtypes") ObjectProcessor p) -> {
- Object responseObj = p.process(p.getInputClass().cast(obj));
- 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);
- } catch (IOException e) {
- e.printStackTrace();
- }
- byte[] objBytes = baos.toByteArray();
- response.writeToMessage(objBytes);
- writeProxy.enqueue(response);
+ try {
+ p.process(p.getInputClass().cast(obj), message.socketId, new ObjectWriteProxy(writeProxy));
+ } catch (IOException e) {
+ e.printStackTrace();
}
});
} catch (IOException | ClassNotFoundException e) {
diff --git a/src/main/java/envoy/server/ObjectMessageReader.java b/src/main/java/envoy/server/net/ObjectMessageReader.java
similarity index 75%
rename from src/main/java/envoy/server/ObjectMessageReader.java
rename to src/main/java/envoy/server/net/ObjectMessageReader.java
index f0fa73a..51fa3df 100644
--- a/src/main/java/envoy/server/ObjectMessageReader.java
+++ b/src/main/java/envoy/server/net/ObjectMessageReader.java
@@ -1,14 +1,13 @@
-package envoy.server;
+package envoy.server.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
-import com.jenkov.nioserver.IMessageReader;
-import com.jenkov.nioserver.Message;
-import com.jenkov.nioserver.MessageBuffer;
-import com.jenkov.nioserver.Socket;
+import com.jenkov.nioserver.*;
+
+import envoy.util.SerializationUtils;
/**
* This {@link IMessageReader} decodes serialized Java objects.
@@ -26,11 +25,6 @@ public class ObjectMessageReader implements IMessageReader {
private Message nextMessage;
private MessageBuffer messageBuffer;
- private int fromByteArray(byte[] bytes, int offset) {
- return ((bytes[offset] & 0xFF) << 24) | ((bytes[offset + 1] & 0xFF) << 16) | ((bytes[offset + 2] & 0xFF) << 8)
- | ((bytes[offset + 3] & 0xFF) << 0);
- }
-
@Override
public List getMessages() { return completeMessages; }
@@ -54,7 +48,7 @@ public class ObjectMessageReader implements IMessageReader {
// Get message length
if (nextMessage.length - nextMessage.offset < 4) return;
- int length = fromByteArray(nextMessage.sharedArray, nextMessage.offset) + 4;
+ int length = SerializationUtils.bytesToInt(nextMessage.sharedArray, nextMessage.offset) + 4;
if (nextMessage.length - nextMessage.offset >= length) {
Message message = messageBuffer.getMessage();
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..2ec9223
--- /dev/null
+++ b/src/main/java/envoy/server/net/ObjectWriteProxy.java
@@ -0,0 +1,53 @@
+package envoy.server.net;
+
+import java.io.IOException;
+
+import com.jenkov.nioserver.Message;
+import com.jenkov.nioserver.WriteProxy;
+
+import envoy.util.SerializationUtils;
+
+/**
+ * This class defines methods to send an object to a client.
+ *
+ * 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;
+
+ /**
+ * Creates an instance of @link{ObjectWriteProxy}.
+ *
+ * @param writeProxy the {@link WriteProxy} to write objects to another client
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public ObjectWriteProxy(WriteProxy writeProxy) { this.writeProxy = writeProxy; }
+
+ /**
+ * @param recipientSocketId the socket id of the recipient
+ * @param obj the object to return to the client
+ * @throws IOException if the serialization of the object failed
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ 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);
+
+ // Acquire object length in bytes
+ byte[] objLen = SerializationUtils.intToBytes(objBytes.length);
+
+ response.writeToMessage(objLen);
+ response.writeToMessage(objBytes);
+ writeProxy.enqueue(response);
+ }
+}
diff --git a/src/main/java/envoy/server/processors/EventProcessor.java b/src/main/java/envoy/server/processors/EventProcessor.java
new file mode 100644
index 0000000..58c769f
--- /dev/null
+++ b/src/main/java/envoy/server/processors/EventProcessor.java
@@ -0,0 +1,77 @@
+package envoy.server.processors;
+
+import java.io.IOException;
+
+import envoy.data.Message;
+import envoy.data.Message.MessageStatus;
+import envoy.event.Event;
+import envoy.event.MessageStatusChangeEvent;
+import envoy.exception.EnvoyException;
+import envoy.server.ConnectionManager;
+import envoy.server.ObjectProcessor;
+import envoy.server.database.PersistenceManager;
+import envoy.server.net.ObjectWriteProxy;
+
+/**
+ * Project: envoy-server-standalone
+ * File: EventProcessor.java
+ * Created: 10 Jan 2020
+ *
+ * @author Leon Hofmeister
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+public class EventProcessor implements ObjectProcessor> {
+
+ private Event> event;
+
+ /**
+ * Creates an instance of @link{EventProcessor}.
+ *
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ public EventProcessor() {}
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Class> getInputClass() { return (Class>) event.getClass(); }
+
+ @Override
+ public void process(Event> input, long socketId, ObjectWriteProxy writeProxy) throws IOException {
+ event = input;
+ if (event instanceof MessageStatusChangeEvent) try {
+ applyMessageStatusChange((MessageStatusChangeEvent) event, writeProxy);
+ } catch (EnvoyException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Redirects messageStatus changes to the database and to the recipient of the
+ * {@link Message}.
+ *
+ * @param event the {@link MessageStatusChangeEvent} to adjust
+ * @throws EnvoyException if the {@link Message} has an invalid state
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+ private void applyMessageStatusChange(MessageStatusChangeEvent event, ObjectWriteProxy writeProxy) throws EnvoyException {
+ if (!(event.get() == MessageStatus.READ))// check that no invalid MessageStatuses are sent
+ throw new EnvoyException("Message" + event.getId() + "has an invalid status");
+
+ ConnectionManager conMan = ConnectionManager.getInstance();
+ PersistenceManager perMan = PersistenceManager.getPersistenceManager();
+ envoy.server.data.Message msg = perMan.getMessageById(event.getId());
+
+ msg.setStatus(event.get());
+ msg.setReadDate(event.getDate());
+
+ if (conMan.isOnline(msg.getRecipient().getId())) try {
+ writeProxy.write(conMan.getSocketId(msg.getRecipient().getId()), event);
+ } catch (IOException e) {
+ System.err.println("Recipient online. Failed to send MessageStatusChangedEvent at message" + event.getId());
+ e.printStackTrace();
+ }
+ perMan.updateMessage(msg);
+
+ }
+
+}
diff --git a/src/main/java/envoy/server/processors/LoginCredentialProcessor.java b/src/main/java/envoy/server/processors/LoginCredentialProcessor.java
new file mode 100644
index 0000000..e94ce91
--- /dev/null
+++ b/src/main/java/envoy/server/processors/LoginCredentialProcessor.java
@@ -0,0 +1,61 @@
+package envoy.server.processors;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import envoy.data.Contacts;
+import envoy.data.LoginCredentials;
+import envoy.data.Message.MessageStatus;
+import envoy.data.User;
+import envoy.server.ConnectionManager;
+import envoy.server.ObjectProcessor;
+import envoy.server.data.Message;
+import envoy.server.database.PersistenceManager;
+import envoy.server.net.ObjectWriteProxy;
+
+/**
+ * This {@link ObjectProcessor} handles {@link LoginCredentials}.
+ *
+ * Project: envoy-server-standalone
+ * File: LoginCredentialProcessor.java
+ * Created: 30.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+public class LoginCredentialProcessor implements ObjectProcessor {
+
+ // TODO: Acquire user IDs from database
+ private static long currentUserId = 1;
+
+ @Override
+ public Class getInputClass() { return LoginCredentials.class; }
+
+ @Override
+ 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());
+
+ // 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);
+ System.out.println("Sending unread messages and updating them in the database...");
+ List pendingMessages = PersistenceManager.getPersistenceManager().getUnreadMessages(new envoy.server.data.User(user));
+ pendingMessages.forEach((msg) -> {
+ msg.setReceivedDate(new Date());
+ msg.setStatus(MessageStatus.RECEIVED);
+ PersistenceManager.getPersistenceManager().updateMessage(msg);
+ });
+ writeProxy.write(socketId, pendingMessages);
+ }
+}
diff --git a/src/main/java/envoy/server/processors/MessageProcessor.java b/src/main/java/envoy/server/processors/MessageProcessor.java
new file mode 100644
index 0000000..ce857de
--- /dev/null
+++ b/src/main/java/envoy/server/processors/MessageProcessor.java
@@ -0,0 +1,47 @@
+package envoy.server.processors;
+
+import java.io.IOException;
+import java.util.Date;
+
+import envoy.data.Message;
+import envoy.event.MessageStatusChangeEvent;
+import envoy.server.ConnectionManager;
+import envoy.server.ObjectProcessor;
+import envoy.server.database.PersistenceManager;
+import envoy.server.net.ObjectWriteProxy;
+
+/**
+ * This {@link ObjectProcessor} handles incoming {@link Message}s.
+ *
+ * Project: envoy-server-standalone
+ * File: MessageProcessor.java
+ * Created: 30.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Server Standalone v0.1-alpha
+ */
+public class MessageProcessor implements ObjectProcessor {
+
+ @Override
+ public Class getInputClass() { return Message.class; }
+
+ @Override
+ public void process(Message message, long socketId, ObjectWriteProxy writeProxy) {
+
+ ConnectionManager connectionManager = ConnectionManager.getInstance();
+ message.nextStatus();
+ if (connectionManager.isOnline(message.getRecipientId())) try {// if recipient is online, he receives the message directly
+ writeProxy.write(connectionManager.getSocketId(message.getRecipientId()), message);
+ } catch (IOException e) {
+ System.err.println("Recipient online. Failed to send message" + message.getId());
+ e.printStackTrace();
+ }
+ try {// sender receives confirmation that the server received the message
+ writeProxy.write(connectionManager.getSocketId(message.getSenderId()),
+ new MessageStatusChangeEvent(message.getId(), message.getStatus(), new Date()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ PersistenceManager.getPersistenceManager().addMessage(new envoy.server.data.Message(message));
+ }
+}
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