Implement DMAP communication with MailboxServer

This commit is contained in:
Tobias Eidelpes 2020-11-16 12:19:03 +01:00
parent 909c4af4e9
commit fcd00674c2
5 changed files with 265 additions and 5 deletions

View File

@ -9,8 +9,8 @@ import java.util.stream.Collectors;
public class Message { public class Message {
private ArrayList<Email> to = new ArrayList<>(); private ArrayList<Email> to = new ArrayList<>();
private Email from; private Email from;
private String subject; private String subject = "";
private String data; private String data = "";
private Integer id; private Integer id;
public Message() { public Message() {
@ -80,6 +80,10 @@ public class Message {
this.id = id; this.id = id;
} }
public String listMessage() {
return getId() + " " + getFrom() + " " + getSubject();
}
@Override @Override
public String toString() { public String toString() {
return "from " + getFrom().toString() + "\n" + return "from " + getFrom().toString() + "\n" +

View File

@ -0,0 +1,7 @@
package dslab.exception;
public class MessageNotFoundException extends Exception {
public MessageNotFoundException(String errorMessage) {
super(errorMessage);
}
}

View File

@ -1,4 +1,187 @@
package dslab.mailbox; package dslab.mailbox;
public class DMAPConnection { import dslab.Email;
import dslab.Message;
import dslab.exception.MessageNotFoundException;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
public class DMAPConnection implements Runnable {
Logger logger = Logger.getLogger(DMAPConnection.class.getName());
private final Socket socket;
private PrintWriter out;
private BufferedReader in;
private Email currentUser = null;
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
private final ConcurrentHashMap<String, String> userStorage;
public DMAPConnection(Socket connection, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage) {
this.socket = connection;
this.storage = storage;
this.userStorage = userStorage;
}
@Override
public void run() {
logger.finer("Preparing for DMAP communication in " + this.toString());
try {
this.out = new PrintWriter(socket.getOutputStream(), true);
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("ok DMAP");
loginLoop();
out.println("ok");
String userInput;
while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) {
if ("quit".equals(userInput)) {
out.println("ok bye");
shutdown();
} else if ("logout".equals(userInput)) {
out.println("ok");
currentUser = null;
loginLoop();
} else if ("list".equals(userInput)) {
listMessages();
} else if ("delete".equals(userInput.split("\\s+")[0])) {
if (userInput.split("\\s+").length == 2) {
deleteMessage(userInput.split("\\s+")[1]);
} else {
out.println("Please supply a message id to delete!");
}
} else if ("show".equals(userInput.split("\\s+")[0])) {
if (userInput.split("\\s+").length == 2) {
showMessage(userInput.split("\\s+")[1]);
} else {
out.println("Please supply a message id to show!");
}
} else {
out.println("error protocol error");
shutdown();
}
}
} catch (InterruptedIOException ioe) {
logger.info("Received interrupt from parent. Shutting down...");
shutdown();
} catch (IOException e) {
logger.severe("Failed to get IO-Stream");
e.printStackTrace();
shutdown();
} catch (MessageNotFoundException e) {
out.println(e.getMessage());
}
}
private void loginLoop() {
String userInput;
try {
while (!Thread.currentThread().isInterrupted()) {
userInput = in.readLine();
if ("quit".equals(userInput.split("\\s+")[0])) {
out.println("ok bye");
shutdown();
} else if ("login".equals(userInput.split("\\s+")[0])) {
String[] args = userInput.split("\\s+");
if (args.length != 3)
out.println("Please specify a username and password to login!");
if (this.userStorage.containsKey(args[1])) {
// Check if username exists
if (args[2].equals(this.userStorage.get(args[1]))) {
// Check if password matches
for (Email email : this.storage.keySet()) {
if (args[1].equals(email.getUsername())) {
// Set current user if login successful
currentUser = email;
logger.info("User successfully logged in: " + currentUser.toString());
return;
}
}
} else {
out.println("error wrong password");
}
} else {
out.println("error unknown user");
}
} else {
out.println("error not logged in");
}
}
} catch (InterruptedIOException ioe) {
logger.info("Received interrupt from parent. Shutting down...");
shutdown();
} catch (SocketException e) {
logger.finer("Received interrupt. Exiting " + this.toString());
shutdown();
} catch (IOException e) {
logger.severe("Failed to get IO-Stream");
e.printStackTrace();
shutdown();
}
}
private void showMessage(String id) throws MessageNotFoundException {
int i;
try {
i = Integer.parseInt(id);
} catch (NumberFormatException e) {
throw new MessageNotFoundException("error unknown message id");
}
for (Message m : storage.get(currentUser)) {
if (m.getId() == i) {
out.println(m);
return;
}
}
throw new MessageNotFoundException("error unknown message id");
}
private void listMessages() {
if (storage.get(currentUser).isEmpty()) {
out.println("You do not have any messages at the moment!");
return;
}
for (Message m : storage.get(currentUser)) {
out.println(m.listMessage());
}
}
public void deleteMessage (String id) throws MessageNotFoundException {
int i;
try {
i = Integer.parseInt(id);
} catch (NumberFormatException e) {
throw new MessageNotFoundException("error unknown message id");
}
for (Message m : storage.get(currentUser)) {
if (m.getId() == i) {
storage.get(currentUser).remove(m);
return;
}
}
throw new MessageNotFoundException("error unknown message id");
}
public void shutdown() {
logger.info("Shutting down client connection " + this.toString());
try {
if (socket != null)
socket.close();
in.close();
out.close();
} catch (IOException e) {
logger.severe("Error closing socket and/or IO-streams");
e.printStackTrace();
}
Thread.currentThread().interrupt();
}
} }

View File

@ -1,12 +1,76 @@
package dslab.mailbox; package dslab.mailbox;
import dslab.Email;
import dslab.Message; import dslab.Message;
import dslab.transfer.ClientConnection; import dslab.transfer.ClientConnection;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; import java.util.logging.Logger;
public class DMAPListener { public class DMAPListener extends Thread {
private final ServerSocket serverSocket;
private final Logger logger = Logger.getLogger(DMAPListener.class.getName());
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
private final ConcurrentHashMap<String, String> userStorage;
private final ArrayList<DMAPConnection> clients = new ArrayList<>();
private final ExecutorService executorService = Executors.newCachedThreadPool();
public DMAPListener(ServerSocket serverSocket, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage) {
this.serverSocket = serverSocket;
this.storage = storage;
this.userStorage = userStorage;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
logger.finer("Waiting for request on serverSocket " + serverSocket.toString());
try {
Socket s = serverSocket.accept();
logger.fine("Processing incoming socket " + s.toString());
DMAPConnection dmapConnection = new DMAPConnection(s, storage, userStorage);
clients.add(dmapConnection);
executorService.submit(dmapConnection);
} catch (InterruptedIOException | SocketException e) {
logger.finer("Received interrupt. Exiting " + this.toString());
this.shutdown();
} catch (IOException e) {
logger.severe("Error starting serverSocket " + serverSocket.toString());
e.printStackTrace();
this.shutdown();
}
}
}
public void shutdown() {
logger.finer("Shutting down DMAPListener " + this.toString());
for (DMAPConnection client : clients) {
if (client != null)
client.shutdown();
}
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
this.interrupt();
}
} }

View File

@ -75,7 +75,8 @@ public class MailboxServer implements IMailboxServer, Runnable {
} }
this.dmtpListener = new DMTPListener(this.dmtpServerSocket, this.messageStorage); this.dmtpListener = new DMTPListener(this.dmtpServerSocket, this.messageStorage);
this.dmtpListener.start(); this.dmtpListener.start();
// TODO spawn listener for user clients (DMAPListener) this.dmapListener = new DMAPListener(this.dmapServerSocket, this.messageStorage, this.userStorage);
this.dmapListener.start();
this.shell.run(); this.shell.run();
} }
@ -95,6 +96,7 @@ public class MailboxServer implements IMailboxServer, Runnable {
try { try {
if (dmapServerSocket != null) if (dmapServerSocket != null)
dmapServerSocket.close(); dmapServerSocket.close();
this.dmapListener.interrupt();
} catch (IOException e) { } catch (IOException e) {
logger.severe("Error closing DMTP serverSocket " + dmapServerSocket.toString()); logger.severe("Error closing DMTP serverSocket " + dmapServerSocket.toString());
e.printStackTrace(); e.printStackTrace();