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.
This commit is contained in:
Kai S. K. Engelbart 2020-01-06 14:58:28 +02:00
parent 19ed6ca0fa
commit 242593472e
9 changed files with 128 additions and 36 deletions

View File

@ -33,6 +33,11 @@
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.9</version>
</dependency>
</dependencies>
<build>

View File

@ -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}.<br>
@ -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<LoginCredentials, User> {
public class LoginCredentialProcessor implements ObjectProcessor<LoginCredentials> {
// TODO: Acquire user IDs from database
private static long currentUserId = 1;
@ -22,10 +27,20 @@ public class LoginCredentialProcessor implements ObjectProcessor<LoginCredential
public Class<LoginCredentials> 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);
}
}

View File

@ -1,6 +1,7 @@
package envoy.server;
import envoy.data.Message;
import envoy.server.net.ObjectWriteProxy;
/**
* This {@link ObjectProcessor} handles incoming {@link Message}s.<br>
@ -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<Message, Void> {
public class MessageProcessor implements ObjectProcessor<Message> {
@Override
public Class<Message> 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<Message, Void> {
}
// TODO: Add message to database
return null;
}
}

View File

@ -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.<br>
@ -10,13 +14,12 @@ package envoy.server;
*
* @author Kai S. K. Engelbart
* @param <T> type of the request object
* @param <U> type of the response object
* @since Envoy Server Standalone v0.1-alpha
*/
public interface ObjectProcessor<T, U> {
public interface ObjectProcessor<T> {
/**
* @return the Class of the request object
* @return the class of the request object
* @since Envoy Server Standalone v0.1-alpha
*/
Class<T> getInputClass();
@ -27,5 +30,5 @@ public interface ObjectProcessor<T, U> {
* @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;
}

View File

@ -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;

View File

@ -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<User> contacts;
/**

View File

@ -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<ObjectProcessor<?, ?>> processors;
private final Set<ObjectProcessor<?>> 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<ObjectProcessor<?, ?>> processors) {
this.processors = processors;
}
public ObjectMessageProcessor(Set<ObjectProcessor<?>> 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();
}

View File

@ -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: <strong>envoy-server-standalone</strong><br>
* File: <strong>ObjectWriteProxy.java</strong><br>
* Created: <strong>04.01.2020</strong><br>
*
* @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);
}
}

View File

@ -0,0 +1,29 @@
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="envoy"
transaction-type="RESOURCE_LOCAL">
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.postgresql.Driver" /> <!-- DB Driver -->
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost/envoy" /> <!-- BD Mane -->
<property name="javax.persistence.jdbc.user" value="envoy" /> <!-- DB User -->
<property name="javax.persistence.jdbc.password"
value="envoy" /> <!-- DB Password -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQL95Dialect" /> <!-- DB Dialect -->
<property name="hibernate.hbm2ddl.auto" value="update" /> <!-- create / create-drop / update -->
<property name="hibernate.show_sql" value="true" /> <!-- Show SQL in console -->
<property name="hibernate.format_sql" value="true" /> <!-- Show SQL formatted -->
</properties>
</persistence-unit>
</persistence>