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:
		
							
								
								
									
										5
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -33,6 +33,11 @@ | |||||||
| 			<artifactId>hibernate-core</artifactId> | 			<artifactId>hibernate-core</artifactId> | ||||||
| 			<version>5.4.10.Final</version> | 			<version>5.4.10.Final</version> | ||||||
| 		</dependency> | 		</dependency> | ||||||
|  | 		<dependency> | ||||||
|  | 			<groupId>org.postgresql</groupId> | ||||||
|  | 			<artifactId>postgresql</artifactId> | ||||||
|  | 			<version>42.2.9</version> | ||||||
|  | 		</dependency> | ||||||
| 	</dependencies> | 	</dependencies> | ||||||
|  |  | ||||||
| 	<build> | 	<build> | ||||||
|   | |||||||
| @@ -1,7 +1,12 @@ | |||||||
| package envoy.server; | package envoy.server; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.ArrayList; | ||||||
|  |  | ||||||
|  | import envoy.data.Contacts; | ||||||
| import envoy.data.LoginCredentials; | import envoy.data.LoginCredentials; | ||||||
| import envoy.data.User; | import envoy.data.User; | ||||||
|  | import envoy.server.net.ObjectWriteProxy; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This {@link ObjectProcessor} handles {@link LoginCredentials}.<br> |  * This {@link ObjectProcessor} handles {@link LoginCredentials}.<br> | ||||||
| @@ -13,7 +18,7 @@ import envoy.data.User; | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy Server Standalone v0.1-alpha |  * @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 | 	// TODO: Acquire user IDs from database | ||||||
| 	private static long currentUserId = 1; | 	private static long currentUserId = 1; | ||||||
| @@ -22,10 +27,20 @@ public class LoginCredentialProcessor implements ObjectProcessor<LoginCredential | |||||||
| 	public Class<LoginCredentials> getInputClass() { return LoginCredentials.class; } | 	public Class<LoginCredentials> getInputClass() { return LoginCredentials.class; } | ||||||
|  |  | ||||||
| 	@Override | 	@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)); | 		System.out.println(String.format("Received login credentials %s from socket ID %d", input, socketId)); | ||||||
|  |  | ||||||
|  | 		// Create user | ||||||
| 		User user = new User(currentUserId++, input.getName()); | 		User user = new User(currentUserId++, input.getName()); | ||||||
| 		ConnectionManager.getInstance().registerUser(socketId, user.getId()); | 		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); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package envoy.server; | package envoy.server; | ||||||
|  |  | ||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
|  | import envoy.server.net.ObjectWriteProxy; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This {@link ObjectProcessor} handles incoming {@link Message}s.<br> |  * This {@link ObjectProcessor} handles incoming {@link Message}s.<br> | ||||||
| @@ -12,13 +13,13 @@ import envoy.data.Message; | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy Server Standalone v0.1-alpha |  * @since Envoy Server Standalone v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class MessageProcessor implements ObjectProcessor<Message, Void> { | public class MessageProcessor implements ObjectProcessor<Message> { | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Class<Message> getInputClass() { return Message.class; } | 	public Class<Message> getInputClass() { return Message.class; } | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Void process(Message message, long socketId) { | 	public void process(Message message, long socketId, ObjectWriteProxy writeProxy) { | ||||||
|  |  | ||||||
| 		// TODO: Send message to recipient if online | 		// TODO: Send message to recipient if online | ||||||
| 		ConnectionManager connectionManager = ConnectionManager.getInstance(); | 		ConnectionManager connectionManager = ConnectionManager.getInstance(); | ||||||
| @@ -27,6 +28,5 @@ public class MessageProcessor implements ObjectProcessor<Message, Void> { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// TODO: Add message to database | 		// TODO: Add message to database | ||||||
| 		return null; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| package envoy.server; | package envoy.server; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  |  | ||||||
|  | import envoy.server.net.ObjectWriteProxy; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This interface defines methods for processing objects of a specific |  * This interface defines methods for processing objects of a specific | ||||||
|  * type incoming from a client.<br> |  * type incoming from a client.<br> | ||||||
| @@ -10,13 +14,12 @@ package envoy.server; | |||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @param <T> type of the request object |  * @param <T> type of the request object | ||||||
|  * @param <U> type of the response object |  | ||||||
|  * @since Envoy Server Standalone v0.1-alpha |  * @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 | 	 * @since Envoy Server Standalone v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	Class<T> getInputClass(); | 	Class<T> getInputClass(); | ||||||
| @@ -27,5 +30,5 @@ public interface ObjectProcessor<T, U> { | |||||||
| 	 * @return the response object | 	 * @return the response object | ||||||
| 	 * @since Envoy Server Standalone v0.1-alpha | 	 * @since Envoy Server Standalone v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	U process(T input, long socketId); | 	void process(T input, long socketId, ObjectWriteProxy writeProxy) throws IOException; | ||||||
| } | } | ||||||
| @@ -4,6 +4,7 @@ import java.util.Date; | |||||||
|  |  | ||||||
| import javax.persistence.Entity; | import javax.persistence.Entity; | ||||||
| import javax.persistence.Id; | import javax.persistence.Id; | ||||||
|  | import javax.persistence.ManyToOne; | ||||||
| import javax.persistence.NamedQueries; | import javax.persistence.NamedQueries; | ||||||
| import javax.persistence.NamedQuery; | import javax.persistence.NamedQuery; | ||||||
| import javax.persistence.Table; | import javax.persistence.Table; | ||||||
| @@ -28,8 +29,12 @@ import envoy.data.MessageBuilder; | |||||||
| @Entity | @Entity | ||||||
| @Table(name = "messages") | @Table(name = "messages") | ||||||
| @NamedQueries( | @NamedQueries( | ||||||
| 	{ @NamedQuery(query = "SELECT m FROM Message m WHERE m.recipient =:recipient AND m.state = 1", name = "getUnreadMessages"), @NamedQuery( | 	{ @NamedQuery( | ||||||
| 		query = "SELECT m FROM Message m WHERE m.sender =:sender AND m.state = :state", | 		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? | 		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.id = :messageId", name = "get message") }//TODO do we need this namedQuery? | ||||||
| ) | ) | ||||||
| @@ -37,13 +42,22 @@ public class Message { | |||||||
|  |  | ||||||
| 	@Id | 	@Id | ||||||
| 	private long								id; | 	private long								id; | ||||||
| 	private User								sender, recipient; |  | ||||||
|  | 	@ManyToOne | ||||||
|  | 	private User sender; | ||||||
|  |  | ||||||
|  | 	@ManyToOne | ||||||
|  | 	private User recipient; | ||||||
|  |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) | 	@Temporal(TemporalType.TIMESTAMP) | ||||||
| 	private Date								creationDate; | 	private Date								creationDate; | ||||||
|  |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) | 	@Temporal(TemporalType.TIMESTAMP) | ||||||
| 	private Date								receivedDate; | 	private Date								receivedDate; | ||||||
|  |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) | 	@Temporal(TemporalType.TIMESTAMP) | ||||||
| 	private Date								readDate; | 	private Date								readDate; | ||||||
|  |  | ||||||
| 	private envoy.data.Message.MessageStatus	status; | 	private envoy.data.Message.MessageStatus	status; | ||||||
| 	private String								text; | 	private String								text; | ||||||
| 	private byte[]								attachment; | 	private byte[]								attachment; | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package envoy.server.data; | |||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
|  | import javax.persistence.ElementCollection; | ||||||
| import javax.persistence.Entity; | import javax.persistence.Entity; | ||||||
| import javax.persistence.GeneratedValue; | import javax.persistence.GeneratedValue; | ||||||
| import javax.persistence.GenerationType; | import javax.persistence.GenerationType; | ||||||
| @@ -27,7 +28,7 @@ import javax.persistence.TemporalType; | |||||||
|  */ |  */ | ||||||
| @Entity | @Entity | ||||||
| @Table(name = "users") | @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 { | public class User { | ||||||
|  |  | ||||||
| 	@Id | 	@Id | ||||||
| @@ -35,9 +36,12 @@ public class User { | |||||||
| 	private long						id; | 	private long						id; | ||||||
| 	private String						name; | 	private String						name; | ||||||
| 	private byte[]						passwordHash; | 	private byte[]						passwordHash; | ||||||
|  |  | ||||||
| 	@Temporal(TemporalType.TIMESTAMP) | 	@Temporal(TemporalType.TIMESTAMP) | ||||||
| 	private Date						lastSeen; | 	private Date						lastSeen; | ||||||
| 	private envoy.data.User.UserStatus	status; | 	private envoy.data.User.UserStatus	status; | ||||||
|  |  | ||||||
|  | 	@ElementCollection | ||||||
| 	private List<User>					contacts; | 	private List<User>					contacts; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -1,10 +1,8 @@ | |||||||
| package envoy.server.net; | package envoy.server.net; | ||||||
|  |  | ||||||
| import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||||
| import java.io.ByteArrayOutputStream; |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.ObjectInputStream; | import java.io.ObjectInputStream; | ||||||
| import java.io.ObjectOutputStream; |  | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  |  | ||||||
| import com.jenkov.nioserver.IMessageProcessor; | import com.jenkov.nioserver.IMessageProcessor; | ||||||
| @@ -25,7 +23,7 @@ import envoy.server.ObjectProcessor; | |||||||
|  */ |  */ | ||||||
| public class ObjectMessageProcessor implements IMessageProcessor { | public class ObjectMessageProcessor implements IMessageProcessor { | ||||||
|  |  | ||||||
| 	private final Set<ObjectProcessor<?, ?>>	processors; | 	private final Set<ObjectProcessor<?>> processors; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * The constructor to set the {@link ObjectProcessor}s. | 	 * The constructor to set the {@link ObjectProcessor}s. | ||||||
| @@ -33,9 +31,7 @@ public class ObjectMessageProcessor implements IMessageProcessor { | |||||||
| 	 * @param processors the {@link ObjectProcessor} to set | 	 * @param processors the {@link ObjectProcessor} to set | ||||||
| 	 * @since Envoy Server Standalone v0.1-alpha | 	 * @since Envoy Server Standalone v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public ObjectMessageProcessor(Set<ObjectProcessor<?, ?>> processors) { | 	public ObjectMessageProcessor(Set<ObjectProcessor<?>> processors) { this.processors = processors; } | ||||||
| 		this.processors			= processors; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@SuppressWarnings("unchecked") | 	@SuppressWarnings("unchecked") | ||||||
| 	@Override | 	@Override | ||||||
| @@ -45,25 +41,17 @@ public class ObjectMessageProcessor implements IMessageProcessor { | |||||||
| 			System.out.println("Read object: " + obj.toString()); | 			System.out.println("Read object: " + obj.toString()); | ||||||
|  |  | ||||||
| 			// Process object | 			// Process object | ||||||
| 			processors.stream().filter(p -> p.getInputClass().isInstance(obj)).forEach((@SuppressWarnings("rawtypes") ObjectProcessor p) -> { | 			processors.stream() | ||||||
| 				Object responseObj = p.process(p.getInputClass().cast(obj), message.socketId); | 				.filter(p -> p.getInputClass().isInstance(obj)) | ||||||
| 				if (responseObj != null) { | 				.forEach((@SuppressWarnings( | ||||||
| 					// Create message targeted at the client | 					"rawtypes" | ||||||
| 					Message response = writeProxy.getMessage(); | 				) ObjectProcessor p) -> { | ||||||
| 					response.socketId = message.socketId; | 					try { | ||||||
|  | 						p.process(p.getInputClass().cast(obj), message.socketId, new ObjectWriteProxy(writeProxy)); | ||||||
| 					// Serialize object to byte array |  | ||||||
| 					ByteArrayOutputStream baos = new ByteArrayOutputStream(); |  | ||||||
| 					try (ObjectOutputStream oout = new ObjectOutputStream(baos)) { |  | ||||||
| 						oout.writeObject(responseObj); |  | ||||||
| 					} catch (IOException e) { | 					} catch (IOException e) { | ||||||
| 						e.printStackTrace(); | 						e.printStackTrace(); | ||||||
| 					} | 					} | ||||||
| 					byte[] objBytes = baos.toByteArray(); | 				}); | ||||||
| 					response.writeToMessage(objBytes); |  | ||||||
| 					writeProxy.enqueue(response); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		} catch (IOException | ClassNotFoundException e) { | 		} catch (IOException | ClassNotFoundException e) { | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 		} | 		} | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								src/main/java/envoy/server/net/ObjectWriteProxy.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/main/java/envoy/server/net/ObjectWriteProxy.java
									
									
									
									
									
										Normal 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); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/main/resources/META-INF/persistence.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/main/resources/META-INF/persistence.xml
									
									
									
									
									
										Normal 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> | ||||||
		Reference in New Issue
	
	Block a user