eu.smeny.jpapercut.smtp.MailServer.java Source code

Java tutorial

Introduction

Here is the source code for eu.smeny.jpapercut.smtp.MailServer.java

Source

/*  
 *  MailServer
 *  
 *  [C#]   Papercut  - Copyright  2008-2012 Ken Robertson
 *  [Java] JPapercut - Copyright  2014      Stphane Meny
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  
 */
package eu.smeny.jpapercut.smtp;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MailServer implements Runnable {

    /**
     * Maximum allowed connections before refusing new ones.
     */
    private static final int MAX_ALLOWED_CONNECTIONS = 50;

    /**
     * The socket used to receive incoming connections.
     */
    private ServerSocket socket;
    /**
     * Port used to receive messages. Defaults to SMTP port (25).
     */
    private int port = 25;
    /**
     * Indicates if the server is currently running.
     */
    private volatile boolean running;
    /**
     * Logger used in this class.
     */
    private final Logger logger = LogManager.getLogger(getClass());
    /**
     * Map of connections to this server currently opened.
     */
    private Map<Integer, Connection> connections;

    public MailServer() {
        running = false;
        connections = new HashMap<Integer, Connection>();
    }

    public MailServer(int port) {
        this();
        this.port = port;
    }

    @Override
    public void run() {
        logger.info("Starting server ...");
        openServerSocket();
        // We check that the server socket is opened to continue
        if (!running) {
            logger.error("Impossible to start server, socket is closed");
            stop();
        }
        // Will handle connection only if server is running
        handleConnection();
    }

    private void handleConnection() {
        while (running) {
            try {
                // Starts a new client connection
                Socket client = socket.accept();
                if (connections.size() < MAX_ALLOWED_CONNECTIONS) {
                    acceptConnection(client);
                } else {
                    refuseConnection(client);
                }
            } catch (IOException ioe) {
                logger.error("IO Error while starting connection", ioe);
            }
        }
    }

    private void acceptConnection(Socket client) {
        final int id = connections.size() + 1;
        final Connection connection = new Connection(id, client);
        final Thread thread = new Thread(connection);

        connections.put(Integer.valueOf(id), connection);
        thread.start();
    }

    private void refuseConnection(Socket client) {
        try {
            OutputStream output = client.getOutputStream();
            PrintWriter writer = new PrintWriter(output);
            String hostname = retrieveHostname();
            writer.write("421 " + hostname + " Service not available, too much connections");
            writer.flush();
            client.close();
        } catch (IOException ioe) {
            logger.error("IO Error while refusing connection", ioe);
        }
    }

    private void openServerSocket() {
        try {
            socket = new ServerSocket(port);
            logger.info("Socket opened successfully on port " + port);
            running = true;
        } catch (IOException ioe) {
            logger.error("Error while opening socket on port " + port, ioe);
        }
    }

    public void stop() {
        running = false;
        logger.info("Stoping server ...");
    }

    public static String retrieveHostname() {
        String hostname;
        try {
            hostname = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException uhe) {
            // Tries environment variables
            hostname = System.getenv("COMPUTERNAME");

            if (StringUtils.isEmpty(hostname)) {
                hostname = System.getenv("HOSTNAME");
            }

            if (StringUtils.isEmpty(hostname)) {
                hostname = "localhost";
            }
        }
        return hostname;
    }
}