Implement skeleton for MailboxServer
This commit is contained in:
parent
29ce5d7875
commit
2b0b33baea
@ -2,6 +2,8 @@ package dslab;
|
|||||||
|
|
||||||
import dslab.exception.MalformedInputException;
|
import dslab.exception.MalformedInputException;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class Email {
|
public class Email {
|
||||||
private String username;
|
private String username;
|
||||||
private String domain;
|
private String domain;
|
||||||
@ -43,4 +45,18 @@ public class Email {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return username + '@' + domain;
|
return username + '@' + domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Email email = (Email) o;
|
||||||
|
return Objects.equals(getUsername(), email.getUsername()) &&
|
||||||
|
Objects.equals(getDomain(), email.getDomain());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getUsername(), getDomain());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/main/java/dslab/mailbox/DMAPConnection.java
Normal file
4
src/main/java/dslab/mailbox/DMAPConnection.java
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package dslab.mailbox;
|
||||||
|
|
||||||
|
public class DMAPConnection {
|
||||||
|
}
|
||||||
12
src/main/java/dslab/mailbox/DMAPListener.java
Normal file
12
src/main/java/dslab/mailbox/DMAPListener.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package dslab.mailbox;
|
||||||
|
|
||||||
|
import dslab.Message;
|
||||||
|
import dslab.transfer.ClientConnection;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class DMAPListener {
|
||||||
|
}
|
||||||
142
src/main/java/dslab/mailbox/DMTPConnection.java
Normal file
142
src/main/java/dslab/mailbox/DMTPConnection.java
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package dslab.mailbox;
|
||||||
|
|
||||||
|
import dslab.Email;
|
||||||
|
import dslab.Message;
|
||||||
|
import dslab.exception.MalformedInputException;
|
||||||
|
import dslab.exception.UnknownRecipientException;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class DMTPConnection implements Runnable {
|
||||||
|
Logger logger = Logger.getLogger(DMTPConnection.class.getName());
|
||||||
|
private final Socket socket;
|
||||||
|
private PrintWriter out;
|
||||||
|
private BufferedReader in;
|
||||||
|
|
||||||
|
private Message msg = new Message();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Email, LinkedList<Message>> messageStorage;
|
||||||
|
|
||||||
|
public DMTPConnection(Socket connection, ConcurrentHashMap<Email, LinkedList<Message>> messageStorage) {
|
||||||
|
this.socket = connection;
|
||||||
|
this.messageStorage = messageStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.finer("Preparing for DMTP communication in " + this.toString());
|
||||||
|
try {
|
||||||
|
this.out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
|
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
out.println("ok DMTP");
|
||||||
|
|
||||||
|
String userInput;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!("begin".equals(in.readLine()))) {
|
||||||
|
out.println("error protocol error");
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
// Thrown if socket has already been closed by shutdown() method
|
||||||
|
logger.finer("Received interrupt. Exiting " + this.toString());
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
out.println("ok");
|
||||||
|
|
||||||
|
while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) {
|
||||||
|
if ("quit".equals(userInput)) {
|
||||||
|
out.println("ok bye");
|
||||||
|
shutdown();
|
||||||
|
} else if ("send".equals(userInput)) {
|
||||||
|
try {
|
||||||
|
storeMessage();
|
||||||
|
out.println("ok");
|
||||||
|
} catch (UnknownRecipientException e) {
|
||||||
|
out.println(e.getMessage());
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
} else if ("to".equals(userInput.split("\\s+")[0])) {
|
||||||
|
msg.setTo(new ArrayList<>());
|
||||||
|
String[] emailAddresses = userInput.split("\\s+")[1].split(",");
|
||||||
|
int count = 0;
|
||||||
|
try {
|
||||||
|
for (String emailAddress : emailAddresses) {
|
||||||
|
msg.addTo(new Email(emailAddress));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
out.println("ok " + count);
|
||||||
|
} catch (MalformedInputException mie) {
|
||||||
|
out.println(mie.getMessage());
|
||||||
|
}
|
||||||
|
} else if ("from".equals(userInput.split("\\s+")[0])) {
|
||||||
|
try {
|
||||||
|
Email from = new Email(userInput.split("\\s+")[1]);
|
||||||
|
this.msg.setFrom(from);
|
||||||
|
out.println("ok");
|
||||||
|
} catch (MalformedInputException mie) {
|
||||||
|
out.println(mie.getMessage());
|
||||||
|
}
|
||||||
|
} else if ("subject".equals(userInput.split("\\s+")[0])) {
|
||||||
|
String subject = "";
|
||||||
|
if (userInput.split("\\s+").length > 1)
|
||||||
|
subject = userInput.split("\\s+", 2)[1];
|
||||||
|
logger.info("Setting subject to: " + subject);
|
||||||
|
msg.setSubject(subject);
|
||||||
|
out.println("ok");
|
||||||
|
} else if ("data".equals(userInput.split("\\s+")[0])) {
|
||||||
|
String data = userInput.split("\\s+", 2)[1];
|
||||||
|
logger.info("Setting data to: " + data);
|
||||||
|
msg.setData(data);
|
||||||
|
out.println("ok");
|
||||||
|
} 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void storeMessage() throws UnknownRecipientException {
|
||||||
|
String errorUnknownRecipient = "";
|
||||||
|
for (Email recipient : this.msg.getTo()) {
|
||||||
|
if (this.messageStorage.containsKey(recipient)) {
|
||||||
|
this.messageStorage.get(recipient).add(this.msg);
|
||||||
|
} else {
|
||||||
|
if (errorUnknownRecipient.isBlank())
|
||||||
|
errorUnknownRecipient = "error unknown recipient " + recipient.getUsername();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errorUnknownRecipient.isBlank())
|
||||||
|
throw new UnknownRecipientException(errorUnknownRecipient);
|
||||||
|
this.msg = new Message();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/main/java/dslab/mailbox/DMTPListener.java
Normal file
71
src/main/java/dslab/mailbox/DMTPListener.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package dslab.mailbox;
|
||||||
|
|
||||||
|
import dslab.Email;
|
||||||
|
import dslab.Message;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class DMTPListener extends Thread {
|
||||||
|
private final ServerSocket serverSocket;
|
||||||
|
private final Logger logger = Logger.getLogger(DMTPListener.class.getName());
|
||||||
|
private final ArrayList<DMTPConnection> clients = new ArrayList<>();
|
||||||
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
|
||||||
|
|
||||||
|
public DMTPListener(ServerSocket serverSocket, ConcurrentHashMap<Email, LinkedList<Message>> storage) {
|
||||||
|
this.serverSocket = serverSocket;
|
||||||
|
this.storage = storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
DMTPConnection dmtpConnection = new DMTPConnection(s, storage);
|
||||||
|
clients.add(dmtpConnection);
|
||||||
|
executorService.submit(dmtpConnection);
|
||||||
|
} 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 DMTPHandler " + this.toString());
|
||||||
|
for (DMTPConnection 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,21 +4,28 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import at.ac.tuwien.dsg.orvell.Shell;
|
import at.ac.tuwien.dsg.orvell.Shell;
|
||||||
import at.ac.tuwien.dsg.orvell.StopShellException;
|
import at.ac.tuwien.dsg.orvell.StopShellException;
|
||||||
import at.ac.tuwien.dsg.orvell.annotation.Command;
|
import at.ac.tuwien.dsg.orvell.annotation.Command;
|
||||||
import dslab.ComponentFactory;
|
import dslab.ComponentFactory;
|
||||||
|
import dslab.Email;
|
||||||
|
import dslab.Message;
|
||||||
import dslab.util.Config;
|
import dslab.util.Config;
|
||||||
|
|
||||||
public class MailboxServer implements IMailboxServer, Runnable {
|
public class MailboxServer implements IMailboxServer, Runnable {
|
||||||
private static final Logger logger = Logger.getLogger(MailboxServer.class.getName());
|
private static final Logger logger = Logger.getLogger(MailboxServer.class.getName());
|
||||||
|
private final String domain;
|
||||||
private ServerSocket dmtpServerSocket;
|
private ServerSocket dmtpServerSocket;
|
||||||
private ServerSocket dmapServerSocket;
|
private ServerSocket dmapServerSocket;
|
||||||
private final Shell shell;
|
private final Shell shell;
|
||||||
private final Integer dmtpServerPort;
|
private final Integer dmtpServerPort;
|
||||||
private final Integer dmapServerPort;
|
private final Integer dmapServerPort;
|
||||||
|
private final ConcurrentHashMap<Email, LinkedList<Message>> messageStorage = new ConcurrentHashMap<>();
|
||||||
|
private final ConcurrentHashMap<String, String> userStorage = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new server instance.
|
* Creates a new server instance.
|
||||||
@ -29,7 +36,19 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
* @param out the output stream to write console output to
|
* @param out the output stream to write console output to
|
||||||
*/
|
*/
|
||||||
public MailboxServer(String componentId, Config config, InputStream in, PrintStream out) {
|
public MailboxServer(String componentId, Config config, InputStream in, PrintStream out) {
|
||||||
// TODO initialize email and user storage (concurrent hashmap?)
|
this.domain = config.getString("domain");
|
||||||
|
Config userConfig = new Config(config.getString("users.config"));
|
||||||
|
|
||||||
|
// Load users from config into userStorage for authentication
|
||||||
|
for (String key : userConfig.listKeys()) {
|
||||||
|
userStorage.put(key, userConfig.getString(key));
|
||||||
|
}
|
||||||
|
// Load Email Addresses into messageStorage
|
||||||
|
for (String key : userStorage.keySet()) {
|
||||||
|
Email current = new Email(key, domain);
|
||||||
|
messageStorage.put(current, new LinkedList<>());
|
||||||
|
}
|
||||||
|
|
||||||
this.shell = new Shell(in, out);
|
this.shell = new Shell(in, out);
|
||||||
this.shell.register(this);
|
this.shell.register(this);
|
||||||
this.shell.setPrompt("Mailboxserver> ");
|
this.shell.setPrompt("Mailboxserver> ");
|
||||||
@ -39,7 +58,7 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.info("Creating DMTP serverSocket for TransferServer + " + this.toString());
|
logger.info("Creating DMTP and DMAP serverSockets for MailboxServer + " + this.toString());
|
||||||
try {
|
try {
|
||||||
this.dmtpServerSocket = new ServerSocket(dmtpServerPort);
|
this.dmtpServerSocket = new ServerSocket(dmtpServerPort);
|
||||||
this.dmapServerSocket = new ServerSocket(dmapServerPort);
|
this.dmapServerSocket = new ServerSocket(dmapServerPort);
|
||||||
@ -48,14 +67,16 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
// TODO spawn listener for transfer servers
|
// TODO spawn listener for transfer servers (DMTPListener)
|
||||||
// TODO spawn listener for user clients
|
// TODO spawn listener for user clients (DMAPListener)
|
||||||
this.shell.run();
|
this.shell.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
// TODO shutdown DMTPListener
|
||||||
|
// TODO shutdown DMAPListener
|
||||||
try {
|
try {
|
||||||
if (dmtpServerSocket != null)
|
if (dmtpServerSocket != null)
|
||||||
dmtpServerSocket.close();
|
dmtpServerSocket.close();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user