/** * Copyright (c) 2008-2016, XebiaLabs B.V., All rights reserved. * * * Overthere is licensed under the terms of the GPLv2 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most XebiaLabs Libraries. * There are special exceptions to the terms and conditions of the GPLv2 as it is applied to * this software, see the FLOSS License Exception * <http://github.com/xebialabs/overthere/blob/master/LICENSE>. * * 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; version 2 * of the License. * * 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., 51 Franklin St, Fifth * Floor, Boston, MA 02110-1301 USA */ package com.xebialabs.overthere; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Represents options to use when creating a {@link OverthereConnection connection}. */ public class ConnectionOptions { private static final Set<String> filteredKeys = new HashSet<>(); public static String registerFilteredKey(String key) { filteredKeys.add(key); return key; } /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#protocol">the online documentation</a> */ public static final String PROTOCOL = "protocol"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#os">the online documentation</a> */ public static final String OPERATING_SYSTEM = "os"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#tmp">the online documentation</a> */ public static final String TEMPORARY_DIRECTORY_PATH = "tmp"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#tmpDeleteOnDisconnect">the online documentation</a> */ public static final String TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT = "tmpDeleteOnDisconnect"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#tmpDeleteOnDisconnect">the online documentation</a> */ public static final boolean TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT_DEFAULT = true; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#tmpFileCreationRetries">the online documentation</a> */ public static final String TEMPORARY_FILE_CREATION_RETRIES = "tmpFileCreationRetries"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#tmpFileCreationRetries">the online documentation</a> */ public static final int TEMPORARY_FILE_CREATION_RETRIES_DEFAULT = 100; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#connectionTimeoutMillis">the online documentation</a> */ public static final String CONNECTION_TIMEOUT_MILLIS = "connectionTimeoutMillis"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#connectionTimeoutMillis">the online documentation</a> */ public static final int CONNECTION_TIMEOUT_MILLIS_DEFAULT = 120000; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#socketTimeoutMillis">the online documentation</a> */ public static final String SOCKET_TIMEOUT_MILLIS = "socketTimeoutMillis"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#socketTimeoutMillis">the online documentation</a> */ public static final int SOCKET_TIMEOUT_MILLIS_DEFAULT = 0; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#address">the online documentation</a> */ public static final String ADDRESS = "address"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#port">the online documentation</a> */ public static final String PORT = "port"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#username">the online documentation</a> */ public static final String USERNAME = "username"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#password">the online documentation</a> */ public static final String PASSWORD = registerFilteredKey("password"); /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#jumpstation">the online documentation</a> */ public static final String JUMPSTATION = "jumpstation"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForUnix">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_UNIX = "fileCopyCommandForUnix"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForUnix">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_UNIX_DEFAULT = "cp -p {0} {1}"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForUnix">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_UNIX = "directoryCopyCommandForUnix"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForUnix">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_UNIX_DEFAULT = "cd {1} ; tar -cf - -C {0} . | tar xpf -"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForWindows">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_WINDOWS = "fileCopyCommandForWindows"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForWindows">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_WINDOWS_DEFAULT = "copy {0} {1} /y"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForWindows">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_WINDOWS = "directoryCopyCommandForWindows"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForWindows">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_WINDOWS_DEFAULT = "xcopy {0} {1} /i /y /s /e /h /q"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForZos">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_ZOS = "fileCopyCommandForZos"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#fileCopyCommandForZos">the online documentation</a> */ public static final String FILE_COPY_COMMAND_FOR_ZOS_DEFAULT = "cp -p {0} {1}"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForZos">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_ZOS = "directoryCopyCommandForZos"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#directoryCopyCommandForZos">the online documentation</a> */ public static final String DIRECTORY_COPY_COMMAND_FOR_ZOS_DEFAULT = "tar cC {0} . | tar xmC {1}"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#remoteCopyBufferSize">the online documentation</a> */ public static final String REMOTE_COPY_BUFFER_SIZE = "remoteCopyBufferSize"; /** * See <a href="https://github.com/xebialabs/overthere/blob/master/README.md#remoteCopyBufferSize">the online documentation</a> */ public static final int REMOTE_COPY_BUFFER_SIZE_DEFAULT = 64 * 1024; // 64 KB private final Map<String, Object> options; /** * Creates an empty options object. */ public ConnectionOptions() { options = new HashMap<String, Object>(); } /** * Creates a copy of an existing options object. */ public ConnectionOptions(ConnectionOptions options) { this(); this.options.putAll(options.options); } /** * Sets a connection option. * * @param key the key of the connection option. * @param value the value of the connection option. */ public void set(String key, Object value) { options.put(key, value); } /** * Retrieves the value of a required connection option. * * @param <T> the type of the connection option. * @param key the key of the connection option. * @return the value of the connection option. * @throws IllegalArgumentException if no value was supplied for the connection option */ @SuppressWarnings("unchecked") public <T> T get(String key) throws IllegalArgumentException { T value = (T) options.get(key); if (value == null) { throw new IllegalArgumentException("No value specified for required connection option " + key); } return value; } /** * Retrieves the value of an optional connection option. * * @param <T> the type of the connection option. * @param key the key of the connection option. * @return the value of the connection option or <code>null</code> if that option was not specified. */ @SuppressWarnings("unchecked") public <T> T getOptional(String key) { return (T) options.get(key); } /** * Retrieves the value of a connection option or a default value if that option has not been set. * * @param <T> the type of the connection option. * @param key the key of the connection option. * @param defaultValue the default value to use of the connection options has not been set. * @return the value of the connection option or the default value if that option was not specified. */ @SuppressWarnings("unchecked") public <T> T get(String key, T defaultValue) { if (options.containsKey(key)) { return (T) options.get(key); } else { return defaultValue; } } public boolean getBoolean(String key) { Object o = options.get(key); if (o == null) { throw new IllegalArgumentException("No value specified for required connection option " + key); } else if (o instanceof Boolean) { return (Boolean) o; } else if (o instanceof String) { return Boolean.valueOf((String) o); } else { throw new IllegalArgumentException("Value specified for required connection option " + key + " is neither a Boolean nor a String"); } } public boolean getBoolean(String key, boolean defaultValue) { Object o = options.get(key); if (o == null) { return defaultValue; } else if (o instanceof Boolean) { return (Boolean) o; } else if (o instanceof String) { return Boolean.valueOf((String) o); } else { throw new IllegalArgumentException("Value specified for connection option " + key + " is neither a Boolean nor a String"); } } public int getInteger(String key) { Object o = options.get(key); if (o == null) { throw new IllegalArgumentException("No value specified for required connection option " + key); } else if (o instanceof Integer) { return (Integer) o; } else if (o instanceof String) { return Integer.parseInt((String) o); } else { throw new IllegalArgumentException("Value specified for required connection option " + key + " is neither an Integer nor a String"); } } public int getInteger(String key, int defaultValue) { Object o = options.get(key); if (o == null) { return defaultValue; } else if (o instanceof Integer) { return (Integer) o; } else if (o instanceof String) { return Integer.parseInt((String) o); } else { throw new IllegalArgumentException("Value specified for connection option " + key + " is neither an Integer nor a String"); } } @SuppressWarnings("unchecked") public <T extends Enum<T>> T getEnum(String key, Class<T> enumClazz) { T o = getEnum(key, enumClazz, null); if (o == null) { throw new IllegalArgumentException("No value specified for required connection option " + key); } else { return o; } } @SuppressWarnings("unchecked") public <T extends Enum<T>> T getOptionalEnum(String key, Class<T> enumClazz) { return getEnum(key, enumClazz, null); } @SuppressWarnings("unchecked") public <T extends Enum<T>> T getEnum(String key, Class<T> enumClazz, T defaultValue) { Object o = options.get(key); if (o == null) { return defaultValue; } else if (o.getClass().equals(enumClazz)) { return (T) o; } else if (o instanceof String) { return Enum.valueOf(enumClazz, (String) o); } else { throw new IllegalArgumentException("Value specified for connection option " + key + " is neither an instanceof of " + enumClazz.getName() + " nor a String"); } } /** * Returns whether a connection option is set. * * @param key the key of the connection option. * @return true iff the connection option is set, false otherwise. */ public boolean containsKey(String key) { return options.containsKey(key); } /** * Returns the keys of all connection options set. * * @return a {@link Set} containing the keys. */ public Set<String> keys() { return options.keySet(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConnectionOptions that = (ConnectionOptions) o; return options.equals(that.options); } @Override public int hashCode() { return options.hashCode(); } @Override public String toString() { return print(this, ""); } private static String print(ConnectionOptions options, String indent) { StringBuilder b = new StringBuilder(); b.append("ConnectionOptions[\n"); for (Map.Entry<String, Object> e : options.options.entrySet()) { b.append(indent).append("\t").append(e.getKey()).append(" --> "); Object value = e.getValue(); if (value instanceof ConnectionOptions) { b.append(print((ConnectionOptions) value, indent + "\t")); } else { b.append(filteredKeys.contains(e.getKey()) ? "********" : value); } b.append("\n"); } b.append(indent).append("]"); return b.toString(); } }