diff --git a/.classpath b/.classpath
index d2c0172..88d37ef 100644
--- a/.classpath
+++ b/.classpath
@@ -24,18 +24,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
index 8660235..04cfa2c 100644
--- a/.settings/org.eclipse.core.resources.prefs
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -1,8 +1,6 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
-encoding//src/main/xjb=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
-encoding//target/generated-sources/jaxb=UTF-8
encoding/=UTF-8
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
index 08f1a01..a6896ac 100644
--- a/.settings/org.eclipse.wst.common.component
+++ b/.settings/org.eclipse.wst.common.component
@@ -1,13 +1,15 @@
-
+
+
-
+
+
-
-
-
-
+
+
+
+
diff --git a/pom.xml b/pom.xml
index cf6ff6e..6e20167 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
informatik-ag-ngl
envoy-common
- 0.0.1-SNAPSHOT
+ 0.2-alpha
Envoy Common
https://github.com/informatik-ag-ngl/envoy-common
@@ -16,44 +16,7 @@
1.8
-
-
- org.codehaus.mojo
- jaxb2-maven-plugin
- 2.5.0
-
-
-
envoy-common
-
-
- src/main/resources
-
-
- src/main/xjb
-
-
-
-
- org.codehaus.mojo
- jaxb2-maven-plugin
- 2.5.0
-
-
- xjc
-
- xjc
-
-
-
-
- envoy.schema
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/java/envoy/data/LoginCredentials.java b/src/main/java/envoy/data/LoginCredentials.java
new file mode 100644
index 0000000..86b166c
--- /dev/null
+++ b/src/main/java/envoy/data/LoginCredentials.java
@@ -0,0 +1,72 @@
+package envoy.data;
+
+import java.io.Serializable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Formatter;
+
+/**
+ * Project: envoy-common
+ * File: LoginCredentials.java
+ * Created: 29.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Common v0.2-alpha
+ */
+public class LoginCredentials implements Serializable {
+
+ private final String name;
+ private final byte[] passwordHash;
+
+ private static final long serialVersionUID = -7395245059059523314L;
+
+ /**
+ * Creates an in stance of {@link LoginCredentials}.
+ *
+ * @param name the name of the user
+ * @param password the password of the user (will be converted to a hash)
+ * @throws NoSuchAlgorithmException
+ */
+ public LoginCredentials(String name, char[] password) throws NoSuchAlgorithmException {
+ this.name = name;
+ passwordHash = getSha256(toByteArray(password));
+ }
+
+ @Override
+ public String toString() {
+ Formatter form = new Formatter();
+ form.format("LoginCredentials[name=%s,passwordHash=", name);
+ for (int i = 0; i < passwordHash.length; i++)
+ form.format("%02x", passwordHash[i]);
+ form.format("]");
+ String str = form.toString();
+ form.close();
+ return str;
+ }
+
+ private byte[] toByteArray(char[] chars) {
+ byte[] bytes = new byte[chars.length * 2];
+ for (int i = 0; i < chars.length; ++i) {
+ bytes[i * 2] = (byte) (chars[i] >> 8);
+ bytes[i * 2 + 1] = (byte) (chars[i]);
+ }
+ return bytes;
+ }
+
+ private byte[] getSha256(byte[] input) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ return md.digest(input);
+ }
+
+ /**
+ * @return the name of the user performing the login
+ * @since Envoy Common v0.2-alpha
+ */
+ public String getName() { return name; }
+
+ /**
+ * @return the password hash of the user performing the login
+ * @since Envoy Common v0.2-alpha
+ */
+ public byte[] getPasswordHash() { return passwordHash; }
+}
\ No newline at end of file
diff --git a/src/main/java/envoy/data/Message.java b/src/main/java/envoy/data/Message.java
new file mode 100644
index 0000000..555c751
--- /dev/null
+++ b/src/main/java/envoy/data/Message.java
@@ -0,0 +1,97 @@
+package envoy.data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Represents a unique message with a unique, numeric ID. Further metadata
+ * includes the sender and recipient {@link User}s, as well as the creation
+ * date and the current {@link MessageStatus}.
+ *
+ * Project: envoy-common
+ * File: Message.java
+ * Created: 28.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Common v0.2-alpha
+ */
+public abstract class Message implements Serializable {
+
+ private final long id;
+ private final User sender, recipient;
+ private final Date date;
+
+ private MessageStatus status;
+
+ private static final long serialVersionUID = -4393477412979594435L;
+
+ /**
+ * Initializes a {@link Message} from the client's perspective. The current date
+ * is used as the message date and the status is set to
+ * {@link MessageStatus#WAITING}.
+ *
+ * @param id unique ID
+ * @param sender the user who sends the message
+ * @param recipient the user who receives the message
+ * @since Envoy Common v0.2-alpha
+ */
+ public Message(long id, User sender, User recipient) {
+ this.id = id;
+ this.sender = sender;
+ this.recipient = recipient;
+ date = new Date();
+ status = MessageStatus.WAITING;
+ }
+
+ /**
+ * @return the ID of this message
+ * @since Envoy Common v0.2-alpha
+ */
+ public long getId() { return id; }
+
+ /**
+ * @return the sender of this message
+ * @since Envoy Common v0.2-alpha
+ */
+ public User getSender() { return sender; }
+
+ /**
+ * @return the recipient of this message
+ * @since Envoy Common v0.2-alpha
+ */
+ public User getRecipient() { return recipient; }
+
+ /**
+ * @return the date at which this message was created
+ * @since Envoy Common v0.2-alpha
+ */
+ public Date getDate() { return date; }
+
+ /**
+ * @return the current status of this message
+ * @since Envoy Common v0.2-alpha
+ */
+ public MessageStatus getStatus() { return status; }
+
+ /**
+ * Changes the current {@link MessageStatus} to the next logical status.
+ *
+ * The underlying order is as follows:
+ *
+ * - {@link MessageStatus#WAITING}
+ *
- {@link MessageStatus#SENT}
+ *
- {@link MessageStatus#RECEIVED}
+ *
- {@link MessageStatus#READ}
+ *
+ *
+ * @since Envoy Common v0.2-alpha
+ */
+ public void nextStatus() {
+ if (status == MessageStatus.READ) throw new IllegalStateException("Message status READ is already reached");
+ status = MessageStatus.values()[status.ordinal() + 1];
+ }
+
+ public static enum MessageStatus {
+ WAITING, SENT, RECEIVED, READ
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/envoy/data/TextMessage.java b/src/main/java/envoy/data/TextMessage.java
new file mode 100644
index 0000000..cbee210
--- /dev/null
+++ b/src/main/java/envoy/data/TextMessage.java
@@ -0,0 +1,54 @@
+package envoy.data;
+
+import java.text.SimpleDateFormat;
+
+/**
+ * Represents a {@link Message} with content that is comprised of text.
+ *
+ * Project: envoy-common
+ * File: TextMessage.java
+ * Created: 28.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Common v0.2-alpha
+ */
+public class TextMessage extends Message {
+
+ private final String content;
+
+ private static final long serialVersionUID = 1538164720632899917L;
+
+ /**
+ * Initializes a {@link TextMessage} from the client's perspective. The current
+ * date
+ * is used as the message date and the status is set to
+ * {@link envoy.data.Message.MessageStatus#WAITING}.
+ *
+ * @param id unique ID
+ * @param sender the user who sends the message
+ * @param recipient the user who receives the message
+ * @param content the content of the message
+ * @since Envoy Common v0.2-alpha
+ */
+ public TextMessage(long id, User sender, User recipient, String content) {
+ super(id, sender, recipient);
+ this.content = content;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("TextMessage[id=%d,sender=%s,recipient=%s,date=%s,status=%s,content=%s]",
+ getId(),
+ getSender(),
+ getRecipient(),
+ new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(getDate()),
+ getStatus(),
+ content);
+ }
+
+ /**
+ * @return the content of this {@link TextMessage}
+ * @since Envoy Common v0.2-alpha
+ */
+ public String getContent() { return content; }
+}
\ No newline at end of file
diff --git a/src/main/java/envoy/data/User.java b/src/main/java/envoy/data/User.java
new file mode 100644
index 0000000..afca690
--- /dev/null
+++ b/src/main/java/envoy/data/User.java
@@ -0,0 +1,71 @@
+package envoy.data;
+
+import java.io.Serializable;
+
+/**
+ * Represents a unique user with a unique, numeric ID, a name and a current
+ * {@link UserStatus}.
+ *
+ * Project: envoy-common
+ * File: User.java
+ * Created: 28.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Common v0.2-alpha
+ */
+public class User implements Serializable {
+
+ private final long id;
+ private final String name;
+
+ private UserStatus status;
+
+ private static final long serialVersionUID = 3530947374856708236L;
+
+ /**
+ * Initializes a {@link User}. The {@link UserStatus} is set to
+ * {@link UserStatus#OFFLINE}.
+ *
+ * @param id unique ID
+ * @param name user name
+ * @since Envoy Client v0.2-alpha
+ */
+ public User(long id, String name) {
+ this.id = id;
+ this.name = name;
+ status = UserStatus.OFFLINE;
+ }
+
+ @Override
+ public String toString() { return String.format("User[id=%d,name=%s,status=%s]", id, name, status); }
+
+ /**
+ * @return the ID of this {@link User}
+ * @since Envoy Client v0.2-alpha
+ */
+ public long getId() { return id; }
+
+ /**
+ * @return the name of this {@link User}
+ * @since Envoy Client v0.2-alpha
+ */
+ public String getName() { return name; }
+
+ /**
+ * @return the current status of this user
+ * @since Envoy Client v0.2-alpha
+ */
+ public UserStatus getStatus() { return status; }
+
+ /**
+ * Sets the current status of this user
+ *
+ * @param status the status to set
+ * @since Envoy Client v0.2-alpha
+ */
+ public void setStatus(UserStatus status) { this.status = status; }
+
+ public static enum UserStatus {
+ ONLINE, AWAY, BUSY, OFFLINE;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/envoy/event/Event.java b/src/main/java/envoy/event/Event.java
new file mode 100644
index 0000000..f17b95b
--- /dev/null
+++ b/src/main/java/envoy/event/Event.java
@@ -0,0 +1,19 @@
+package envoy.event;
+
+/**
+ * Project: envoy-common
+ * File: Event.java
+ * Created: 04.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @param the type of the Event
+ * @since Envoy v0.2-alpha
+ */
+public interface Event {
+
+ /**
+ * @return the data associated with this event
+ */
+ T get();
+}
+
diff --git a/src/main/java/envoy/event/EventBus.java b/src/main/java/envoy/event/EventBus.java
new file mode 100644
index 0000000..f2e5c9f
--- /dev/null
+++ b/src/main/java/envoy/event/EventBus.java
@@ -0,0 +1,81 @@
+package envoy.event;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class handles events by allowing {@link EventHandler} object to register
+ * themselves and then be notified about certain events dispatched by the event
+ * bus.
+ *
+ * The event bus is a singleton and can be used across the entire application to
+ * guarantee the propagation of events.
+ *
+ * Project: envoy-common
+ * File: EventBus.java
+ * Created: 04.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy v0.2-alpha
+ */
+public class EventBus {
+
+ /**
+ * Contains all {@link EventHandler} instances registered at this
+ * {@link EventBus} as values mapped to by their supported {@link Event}
+ * classes.
+ */
+ private Map>, List> handlers = new HashMap<>();
+
+ /**
+ * The singleton instance of this {@link EventBus} that is used across the
+ * entire application.
+ */
+ private static EventBus eventBus = new EventBus();
+
+ /**
+ * This constructor is not accessible from outside this class because a
+ * singleton instance of it is provided by the {@link EventBus#getInstance()}
+ * method.
+ */
+ private EventBus() {}
+
+ /**
+ * @return the singleton instance of the {@link EventBus}
+ * @since Envoy v0.2-alpha
+ */
+ public static EventBus getInstance() { return eventBus; }
+
+ /**
+ * Registers an {@link EventHandler} to be notified when a
+ * {@link Event} of a certain type is dispatched.
+ *
+ * @param eventClass the class which the {@link EventHandler} is subscribed to
+ * @param handler the {@link EventHandler} to register
+ * @since Envoy v0.2-alpha
+ */
+ public void register(Class extends Event>> eventClass, EventHandler handler) {
+ if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>());
+ handlers.get(eventClass).add(handler);
+ }
+
+ /**
+ * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it.
+ *
+ * @param event the {@link Event} to dispatch
+ * @since Envoy v0.2-alpha
+ */
+ public void dispatch(Event> event) {
+ handlers.keySet().stream().filter(event.getClass()::isAssignableFrom).map(handlers::get).flatMap(List::stream).forEach(h -> h.handle(event));
+ }
+
+ /**
+ * @return a map of all {@link EventHandler} instances currently registered at
+ * this {@link EventBus} with the {@link Event} classes they are
+ * subscribed to as keys
+ * @since Envoy v0.2-alpha
+ */
+ public Map>, List> getHandlers() { return handlers; }
+}
diff --git a/src/main/java/envoy/event/EventHandler.java b/src/main/java/envoy/event/EventHandler.java
new file mode 100644
index 0000000..f842476
--- /dev/null
+++ b/src/main/java/envoy/event/EventHandler.java
@@ -0,0 +1,18 @@
+package envoy.event;
+
+/**
+ * Project: envoy-common
+ * File: EventHandler.java
+ * Created: 04.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ */
+public interface EventHandler {
+
+ /**
+ * Consumes an event dispatched by the event bus.
+ *
+ * @param event The event dispatched by the event bus, only of supported type
+ */
+ void handle(Event> event);
+}
diff --git a/src/main/java/envoy/event/MessageEvent.java b/src/main/java/envoy/event/MessageEvent.java
new file mode 100644
index 0000000..33a7607
--- /dev/null
+++ b/src/main/java/envoy/event/MessageEvent.java
@@ -0,0 +1,27 @@
+package envoy.event;
+
+import envoy.data.Message;
+
+/**
+ * Project: envoy-common
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ *
+ * @author Kai S. K. Engelbart
+ */
+public class MessageEvent implements Event {
+
+ protected final Message message;
+
+ /**
+ * Initializes a {@link MessageEvent} conveying information about a
+ * {@link Message} object.
+ *
+ * @param message the {@link Message} object to attach to this event
+ * @since Envoy v0.2-alpha
+ */
+ public MessageEvent(Message message) { this.message = message; }
+
+ @Override
+ public Message get() { return message; }
+}
diff --git a/src/main/java/envoy/schema/MessageState.java b/src/main/java/envoy/schema/MessageState.java
deleted file mode 100644
index 0f174c6..0000000
--- a/src/main/java/envoy/schema/MessageState.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package envoy.schema;
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Project: envoy-common
- * File: MessageState.java
- * Created: 11 Oct 2019
- *
- * @author Kai S. K. Engelbart
- */
-@XmlType(name = "")
-@XmlEnum
-public enum MessageState {
-
- Waiting, Sent, Received, Read;
-
- public String value() { return name(); }
-
- public static MessageState fromValue(String v) { return valueOf(v); }
-}
diff --git a/src/main/java/envoy/schema/UserStatus.java b/src/main/java/envoy/schema/UserStatus.java
deleted file mode 100644
index f87d576..0000000
--- a/src/main/java/envoy/schema/UserStatus.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package envoy.schema;
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Project: envoy-common
- * File: UserStatus.java
- * Created: 27 Oct 2019
- *
- * @author Maximilian Käfer
- */
-@XmlType(name = "")
-@XmlEnum
-public enum UserStatus {
-
- Online, DoNotDisturb, AFK, Offline;
-
- public String value() { return name(); }
-
- public static UserStatus fromValue(String v) { return valueOf(v); }
-}
diff --git a/src/main/java/envoy/util/SerializationUtils.java b/src/main/java/envoy/util/SerializationUtils.java
new file mode 100644
index 0000000..dfd166b
--- /dev/null
+++ b/src/main/java/envoy/util/SerializationUtils.java
@@ -0,0 +1,94 @@
+package envoy.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+import envoy.exception.EnvoyException;
+
+/**
+ * Project: envoy-client
+ * File: SerializationUtils.java
+ * Created: 23.12.2019
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy Common v0.2-alpha
+ */
+public class SerializationUtils {
+
+ private SerializationUtils() {}
+
+ /**
+ * Deserializes an arbitrary {@link Serializable} object from a file.
+ *
+ * @param the type of the object to deserialize
+ * @param file the file deserialize from
+ * @param serializedClass the class of the object to deserialize
+ * @return the deserialized object
+ * @throws EnvoyException if an error occurred during deserialization
+ * @since Envoy Common v0.2-alpha
+ */
+ public static T read(File file, Class serializedClass) throws IOException, ClassNotFoundException {
+ if (file == null) throw new NullPointerException("File is null");
+ return read(new FileInputStream(file), serializedClass);
+ }
+
+ public static T read(InputStream in, Class serializedClass) throws IOException, ClassNotFoundException {
+ try (ObjectInputStream oin = new ObjectInputStream(in)) {
+ return serializedClass.cast(oin.readObject());
+ }
+ }
+
+ /**
+ * Serializes an arbitrary object to a file.
+ *
+ * @param file the file to serialize to
+ * @param obj the object to serialize
+ * @throws IOException if an error occurred during serialization
+ * @since Envoy Common v0.2-alpha
+ */
+ public static void write(File file, Object obj) throws IOException {
+ if (file == null) throw new NullPointerException("File is null");
+ if (obj == null) throw new NullPointerException("Object to serialize is null");
+ if (!file.exists()) {
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ }
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
+ out.writeObject(obj);
+ }
+ }
+
+ /**
+ * Serializes an object and writes it into an output stream preceded by 4 bytes
+ * containing the number of serialized bytes.
+ *
+ * @param obj the object to serialize
+ * @param out the output stream to serialize to
+ * @throws IOException if an error occurred during serialization
+ */
+ public static void writeBytesWithLength(Object obj, OutputStream out) throws IOException {
+ // Serialize object to byte array
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ObjectOutputStream oout = new ObjectOutputStream(baos)) {
+ oout.writeObject(obj);
+ }
+ byte[] objBytes = baos.toByteArray();
+
+ // Get length of byte array in bytes
+ byte[] objLen = intToBytes(objBytes.length);
+
+ // Write length and byte array
+ out.write(objLen);
+ out.write(objBytes);
+ }
+
+ private static byte[] intToBytes(int n) { return new byte[] { (byte) (n >>> 24), (byte) (n >>> 16), (byte) (n >>> 8), (byte) n }; }
+}
\ No newline at end of file
diff --git a/src/main/resources/sync_schema.xsd b/src/main/resources/sync_schema.xsd
deleted file mode 100644
index 7b20b87..0000000
--- a/src/main/resources/sync_schema.xsd
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/xjb/bindings.xml b/src/main/xjb/bindings.xml
deleted file mode 100644
index 4dc2c23..0000000
--- a/src/main/xjb/bindings.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file