configuration.ClientConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for configuration.ClientConfiguration.java

Source

package configuration;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;

import misc.Coder;
import misc.FileHandler;
import misc.JSONPrettyPrintWriter;

import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;

/*
 * Copyright (c) 2012-2013 Fabian Foerg
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

/**
 * Allows to parse and store client configuration files.
 * 
 * @author Fabian Foerg
 */
public final class ClientConfiguration {
    public static final String KEY_ROOT_PATH = "root_path";
    public static final String KEY_USER = "user";
    public static final String KEY_PASSWORD = "password";
    public static final String KEY_SERVER_HOST = "server_host";
    public static final String KEY_SERVER_PORT = "server_port";
    public static final String KEY_SERVER_CERT = "server_cert";
    public static final String KEY_SERVER_CERT_PASSWORD = "server_cert_password";
    public static final String KEY_SYNC_PATH = "sync_path";
    public static final String KEY_DIFF = "diff";
    public static final String KEY_DIFF_THRESHOLD = "diff_threshold";
    public static final String KEY_SYNC_INTERVAL = "sync_interval";
    public static final String KEY_LOG_FILE = "log_file";
    public static final String KEY_LOG_ERROR_FILE = "log_error_file";

    /**
     * The pattern for user names on the server.
     */
    private static final Pattern USER_NAME_PATTERN = Pattern.compile("[a-z]{1}[a-z0-9]{0,9}");

    /**
     * The pattern for password on the server.
     */
    private static final Pattern PASSWORD_PATTERN = Pattern.compile(".{6,32}");

    private final String rootPath;
    private final String user;
    private final String password;
    private final String serverHost;
    private final long serverPort;
    private final String serverCert;
    private final String serverCertPassword;
    private final String syncPath;
    private final boolean diff;
    private final double diffThreshold;
    private final long syncInterval;
    private final String logFile;
    private final String logErrorFile;

    /**
     * Creates a new client configuration.
     * 
     * @param rootPath
     *            the path to the client root directory which contains the files
     *            to synchronize.
     * @param user
     *            the user name used for authenticating the client towards the
     *            server.
     * @param password
     *            the password used for authenticating the client towards the
     *            server.
     * @param serverHost
     *            the host name of the server.
     * @param serverPort
     *            the server port.
     * @param serverCert
     *            the path to the key store which contains the server
     *            certificate.
     * @param serverCertPassword
     *            the password for accessing the key store which contains the
     *            server certificate.
     * @param syncPath
     *            the path to the file copies and information necessary for
     *            syncing.
     * @param diff
     *            <code>true</code>, if diffs should be made. Otherwise,
     *            complete files are transmitted.
     * @param diffThreshold
     *            consider the fraction of the size of the diff and the original
     *            file size. If this fraction is greater or equal to the
     *            threshold, then the original files is transmitted completely.
     * @param syncInterval
     *            the time interval in seconds after which to synchronize all
     *            local directories periodically.
     * @param logFile
     *            the path to the log file.
     * @param logErrorFile
     *            the path to the error log file.
     */
    public ClientConfiguration(String rootPath, String user, String password, String serverHost, long serverPort,
            String serverCert, String serverCertPassword, String syncPath, boolean diff, double diffThreshold,
            long syncInterval, String logFile, String logErrorFile) {
        if ((rootPath == null) || !Files.isDirectory(Paths.get(rootPath))) {
            throw new IllegalArgumentException("rootPath must be valid!");
        }
        if (!isValidUserName(user)) {
            throw new IllegalArgumentException("user must be valid!");
        }
        if (!isValidPassword(password)) {
            throw new IllegalArgumentException("password must be valid!");
        }
        if ((serverHost == null) || serverHost.isEmpty()) {
            throw new IllegalArgumentException("serverHost must be valid!");
        }
        if ((serverPort < 1) || (serverPort > 65535)) {
            throw new IllegalArgumentException("serverPort must be valid!");
        }
        if ((serverCert == null) || !Files.exists(Paths.get(serverCert))) {
            throw new IllegalArgumentException("serverCert must be valid!");
        }
        if ((serverCertPassword == null) || serverCertPassword.isEmpty()) {
            throw new IllegalArgumentException("serverCertPassword must be valid!");
        }
        if (syncPath == null) {
            throw new IllegalArgumentException("syncPath must be valid!");
        }
        if ((diffThreshold < 0.0)) {
            throw new IllegalArgumentException("diffThreshold must be at least zero!");
        }
        if (syncInterval < 0) {
            throw new IllegalArgumentException("syncInterval must be at least zero!");
        }
        if (logFile == null) {
            throw new IllegalArgumentException("logFile may not be null!");
        }
        if (logErrorFile == null) {
            throw new IllegalArgumentException("logErrorFile may not be null!");
        }

        this.rootPath = rootPath;
        this.user = user;
        this.password = password;
        this.serverHost = serverHost;
        this.serverPort = serverPort;
        this.serverCert = serverCert;
        this.serverCertPassword = serverCertPassword;
        this.syncPath = syncPath;
        this.diff = diff;
        this.diffThreshold = diffThreshold;
        this.syncInterval = syncInterval;
        this.logFile = logFile;
        this.logErrorFile = logErrorFile;

        if (!Files.isDirectory(Paths.get(syncPath))) {
            FileHandler.makeParentDirs(Paths.get(syncPath, "arbitrary"));
        }
    }

    /**
     * Returns the root path which contains the files to synchronize.
     * 
     * @return the root path with the files to synchronize.
     */
    public String getRootPath() {
        return rootPath;
    }

    /**
     * Returns the user name used to authenticate towards the server.
     * 
     * @return the user name used to authenticate towards the server.
     */
    public String getUser() {
        return user;
    }

    public static boolean isValidUserName(String user) {
        // white list check
        return (user != null) && USER_NAME_PATTERN.matcher(user).matches();
    }

    public static boolean isValidPassword(String password) {
        // white list check
        return (password != null) && PASSWORD_PATTERN.matcher(password).matches();
    }

    /**
     * Returns the password to authenticate towards the server.
     * 
     * @return the password to authenticate towards the server.
     */
    public String getPassword() {
        return password;
    }

    /**
     * Returns the server's host name.
     * 
     * @return the server's host name.
     */
    public String getServerHost() {
        return serverHost;
    }

    /**
     * Returns the server's port.
     * 
     * @return the server's port.
     */
    public long getServerPort() {
        return serverPort;
    }

    /**
     * Returns the path to the key store which contains the server certificate.
     * 
     * @return the path to the key store which contains the server certificate.
     */
    public String getServerCert() {
        return serverCert;
    }

    /**
     * Returns the password used to access the key store with the server
     * certificate.
     * 
     * @return the password used to access the key store with the server
     *         certificate.
     */
    public String getServerCertPassword() {
        return serverCertPassword;
    }

    /**
     * Returns the synchronization path holding file copies and information
     * required for synchronization.
     * 
     * @return the synchronization path.
     */
    public String getSyncPath() {
        return syncPath;
    }

    /**
     * Returns whether diffs are used or files are transmitted completely each
     * time.
     * 
     * @return <code>true</code> if diffs are used. <code>false</code>,
     *         otherwise.
     */
    public boolean isDiff() {
        return diff;
    }

    /**
     * Returns the threshold which determines when complete files are
     * transmitted instead of diffs.
     * 
     * @return the threshold which determines when complete files are
     *         transmitted instead of diffs.
     */
    public double getDiffThreshold() {
        return diffThreshold;
    }

    /**
     * Returns the time interval in seconds after which to synchronize all local
     * directories periodically.
     * 
     * @return the time interval in seconds after which to synchronize all local
     *         directories periodically.
     */
    public long getSyncInterval() {
        return syncInterval;
    }

    /**
     * Returns the path to the log file.
     * 
     * @return the path to the log file.
     */
    public String getLogFile() {
        return logFile;
    }

    /**
     * Returns the path to the error log file.
     * 
     * @return the path to the error log file.
     */
    public String getLogErrorFile() {
        return logErrorFile;
    }

    /**
     * Returns a map representation of this object.
     * 
     * @return a map representation of this object.
     */
    public Map<String, Object> toMap() {
        Map<String, Object> thisMap = new LinkedHashMap<>();
        thisMap.put(KEY_ROOT_PATH, rootPath);
        thisMap.put(KEY_USER, user);
        thisMap.put(KEY_PASSWORD, password);
        thisMap.put(KEY_SERVER_HOST, serverHost);
        thisMap.put(KEY_SERVER_PORT, new Long(serverPort));
        thisMap.put(KEY_SERVER_CERT, serverCert);
        thisMap.put(KEY_SERVER_CERT_PASSWORD, serverCertPassword);
        thisMap.put(KEY_SYNC_PATH, syncPath);
        thisMap.put(KEY_DIFF, new Boolean(diff));
        thisMap.put(KEY_DIFF_THRESHOLD, new Double(diffThreshold));
        thisMap.put(KEY_SYNC_INTERVAL, new Long(syncInterval));
        thisMap.put(KEY_LOG_FILE, logFile);
        thisMap.put(KEY_LOG_ERROR_FILE, logErrorFile);

        return thisMap;
    }

    /**
     * Parses the given configuration file.
     * 
     * @param file
     *            the path to the configuration file.
     * @return the parsed configuration.
     * @throws FileNotFoundException
     * @throws IOException
     * @throws ParseException
     */
    public static ClientConfiguration parse(Path file) throws FileNotFoundException, IOException, ParseException {
        if (file == null) {
            throw new NullPointerException("file may not be null!");
        }

        return Parser.parse(file);
    }

    /**
     * Stores this configuration under the given path.
     * 
     * @param file
     *            the path where this configuration is to be stored.
     * @throws IOException
     */
    public void store(Path file) throws IOException {
        if (file == null) {
            throw new NullPointerException("file may not be null!");
        }

        Parser.store(this, file);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        Writer writer = new JSONPrettyPrintWriter();
        try {
            JSONValue.writeJSONString(toMap(), writer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return writer.toString();
    }

    /**
     * Parses and stores client configuration files.
     * 
     * @author Fabian Foerg
     */
    private static class Parser {
        public static ClientConfiguration parse(Path file)
                throws FileNotFoundException, IOException, ParseException {
            if ((file == null) || !Files.isReadable(file)) {
                throw new NullPointerException("file must be readable!");
            }

            BufferedReader in = Files.newBufferedReader(file, Coder.CHARSET);
            StringBuilder sb = new StringBuilder();
            String read = null;
            JSONObject object;
            String rootPath;
            String user;
            String password;
            String serverHost;
            long serverPort;
            String serverCert;
            String serverCertPassword;
            String syncPath;
            boolean diff;
            double diffThreshold;
            long syncInterval;
            String logFile;
            String logErrorFile;

            // load file
            do {
                read = in.readLine();

                if (read != null) {
                    sb.append(read);
                }
            } while (read != null);

            if (in != null) {
                in.close();
            }

            // parse file
            object = (JSONObject) JSONValue.parse(sb.toString());
            rootPath = (String) object.get(KEY_ROOT_PATH);
            user = (String) object.get(KEY_USER);
            password = (String) object.get(KEY_PASSWORD);
            serverHost = (String) object.get(KEY_SERVER_HOST);
            serverPort = (Long) object.get(KEY_SERVER_PORT);
            serverCert = (String) object.get(KEY_SERVER_CERT);
            serverCertPassword = (String) object.get(KEY_SERVER_CERT_PASSWORD);
            syncPath = (String) object.get(KEY_SYNC_PATH);
            diff = (Boolean) object.get(KEY_DIFF);
            diffThreshold = (Double) object.get(KEY_DIFF_THRESHOLD);
            syncInterval = (Long) object.get(KEY_SYNC_INTERVAL);
            logFile = (String) object.get(KEY_LOG_FILE);
            logErrorFile = (String) object.get(KEY_LOG_ERROR_FILE);

            return new ClientConfiguration(rootPath, user, password, serverHost, serverPort, serverCert,
                    serverCertPassword, syncPath, diff, diffThreshold, syncInterval, logFile, logErrorFile);
        }

        /**
         * Stores this configuration under the given path.
         * 
         * @param config
         *            the configuration to store.
         * @param file
         *            the path where this configuration is to be stored.
         * @throws IOException
         */
        public static void store(ClientConfiguration config, Path file) throws IOException {
            if ((file == null) || !Files.isWritable(file)) {
                throw new NullPointerException("file must be writable!");
            }

            BufferedWriter out = Files.newBufferedWriter(file, Coder.CHARSET);

            if (out != null) {
                out.write(config.toString());
                out.close();
            }
        }
    }
}