Added EventProcessor and methods to handle MessageStatus changes
additionally cleaned up whole project, fixed some Javadoc errors and added a few database and connection options. Sorry for the huge commit, there was almost no time inbetween where a commit would have been possible, as to solve every problem, a new problem arose. However, as of now, f/message_handling should be ready to be merged into develop, besides that it could not be tested yet.
This commit is contained in:
		| @@ -11,7 +11,7 @@ import com.jenkov.nioserver.ISocketIdListener; | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>ConnectionManager.java</strong><br> | ||||
|  * Created: <strong>03.01.2020</strong><br> | ||||
|  *  | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy Server Standalone v0.1-alpha | ||||
|  */ | ||||
| @@ -20,14 +20,14 @@ 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<Long> 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<Long, Long> sockets = new HashMap<>(); | ||||
| @@ -53,14 +53,14 @@ public class ConnectionManager implements ISocketIdListener { | ||||
|  | ||||
| 	/** | ||||
| 	 * Associates a socket ID with a user ID. | ||||
| 	 *  | ||||
| 	 * @param socketId the socket ID | ||||
| 	 * | ||||
| 	 * @param userId   the user ID | ||||
| 	 * @param socketId the socket ID | ||||
| 	 * @since Envoy Server Standalone v0.1-alpha | ||||
| 	 */ | ||||
| 	public void registerUser(long socketId, long userId) { | ||||
| 		sockets.put(socketId, userId); | ||||
| 		pendingSockets.remove(socketId); | ||||
| 	public void registerUser(long userId, long socketId) { | ||||
| 		sockets.put(userId, socketId); | ||||
| 		pendingSockets.remove(userId); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -1,32 +0,0 @@ | ||||
| package envoy.server; | ||||
|  | ||||
| import envoy.data.Message; | ||||
| import envoy.server.net.ObjectWriteProxy; | ||||
|  | ||||
| /** | ||||
|  * This {@link ObjectProcessor} handles incoming {@link Message}s.<br> | ||||
|  * <br> | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>MessageProcessor.java</strong><br> | ||||
|  * Created: <strong>30.12.2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy Server Standalone v0.1-alpha | ||||
|  */ | ||||
| public class MessageProcessor implements ObjectProcessor<Message> { | ||||
|  | ||||
| 	@Override | ||||
| 	public Class<Message> getInputClass() { return Message.class; } | ||||
|  | ||||
| 	@Override | ||||
| 	public void process(Message message, long socketId, ObjectWriteProxy writeProxy) { | ||||
|  | ||||
| 		// TODO: Send message to recipient if online | ||||
| 		ConnectionManager connectionManager = ConnectionManager.getInstance(); | ||||
| 		if (connectionManager.isOnline(message.getRecipientId())) { | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		// TODO: Add message to database | ||||
| 	} | ||||
| } | ||||
| @@ -25,9 +25,10 @@ public interface ObjectProcessor<T> { | ||||
| 	Class<T> getInputClass(); | ||||
|  | ||||
| 	/** | ||||
| 	 * @param input    the request object | ||||
| 	 * @param socketId the ID of the socket from which the object was received | ||||
| 	 * @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 | ||||
| 	 */ | ||||
| 	void process(T input, long socketId, ObjectWriteProxy writeProxy) throws IOException; | ||||
|   | ||||
| @@ -8,6 +8,9 @@ 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.<br> | ||||
| @@ -32,6 +35,7 @@ public class Startup { | ||||
| 		Set<ObjectProcessor<?>> 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(); | ||||
|   | ||||
| @@ -12,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 | ||||
| @@ -32,16 +33,15 @@ import envoy.data.MessageBuilder; | ||||
| 	{ @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? | ||||
| 	), @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 long id; | ||||
|  | ||||
| 	@ManyToOne | ||||
| 	private User sender; | ||||
| @@ -50,13 +50,13 @@ public class Message { | ||||
| 	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; | ||||
| @@ -76,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 | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -33,16 +33,42 @@ 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; | ||||
|  | ||||
| 	@ElementCollection | ||||
| 	private List<User>					contacts; | ||||
| 	private List<User> 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} | ||||
|   | ||||
| @@ -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. | ||||
| 	 * | ||||
|   | ||||
| @@ -41,17 +41,13 @@ 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) -> { | ||||
| 					try { | ||||
| 						p.process(p.getInputClass().cast(obj), message.socketId, new ObjectWriteProxy(writeProxy)); | ||||
| 					} catch (IOException e) { | ||||
| 						e.printStackTrace(); | ||||
| 					} | ||||
| 				}); | ||||
| 			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(); | ||||
| 				} | ||||
| 			}); | ||||
| 		} catch (IOException | ClassNotFoundException e) { | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
|   | ||||
| @@ -8,6 +8,8 @@ import com.jenkov.nioserver.WriteProxy; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
|  * This class defines methods to send an object to a client.<br> | ||||
|  * <br> | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>ObjectWriteProxy.java</strong><br> | ||||
|  * Created: <strong>04.01.2020</strong><br> | ||||
| @@ -19,8 +21,20 @@ 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(); | ||||
|   | ||||
							
								
								
									
										77
									
								
								src/main/java/envoy/server/processors/EventProcessor.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/main/java/envoy/server/processors/EventProcessor.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>EventProcessor.java</strong><br> | ||||
|  * Created: <strong>10 Jan 2020</strong><br> | ||||
|  * | ||||
|  * @author Leon Hofmeister | ||||
|  * @since Envoy Server Standalone v0.1-alpha | ||||
|  */ | ||||
| public class EventProcessor implements ObjectProcessor<Event<?>> { | ||||
|  | ||||
| 	private Event<?> event; | ||||
|  | ||||
| 	/** | ||||
| 	 * Creates an instance of @link{EventProcessor}. | ||||
| 	 * | ||||
| 	 * @since Envoy Server Standalone v0.1-alpha | ||||
| 	 */ | ||||
| 	public EventProcessor() {} | ||||
|  | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	@Override | ||||
| 	public Class<Event<?>> getInputClass() { return (Class<Event<?>>) 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); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -1,11 +1,18 @@ | ||||
| package envoy.server; | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
| @@ -42,5 +49,13 @@ public class LoginCredentialProcessor implements ObjectProcessor<LoginCredential | ||||
| 		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<Message> 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); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/main/java/envoy/server/processors/MessageProcessor.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/main/java/envoy/server/processors/MessageProcessor.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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.<br> | ||||
|  * <br> | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>MessageProcessor.java</strong><br> | ||||
|  * Created: <strong>30.12.2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy Server Standalone v0.1-alpha | ||||
|  */ | ||||
| public class MessageProcessor implements ObjectProcessor<Message> { | ||||
|  | ||||
| 	@Override | ||||
| 	public Class<Message> 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)); | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 delvh
					delvh