com.cws.esolutions.core.utils.NetworkUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.cws.esolutions.core.utils.NetworkUtils.java

Source

/*
 * Copyright (c) 2009 - 2017 CaspersBox Web Services
 * 
 * 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 com.cws.esolutions.core.utils;

/*
 * Project: eSolutionsCore
 * Package: com.cws.esolutions.core.utils
 * File: NetworkUtils.java
 *
 * History
 * ----------------------------------------------------------------------------
 * cws-khuntly @ Jan 4, 2013 3:36:54 PM
 *     Created.
 */
import java.net.URL;
import java.net.URI;
import java.util.List;
import java.net.Socket;
import org.slf4j.Logger;
import java.util.Arrays;
import org.xbill.DNS.Name;
import org.xbill.DNS.Type;
import java.util.Hashtable;
import java.util.ArrayList;
import java.io.PrintWriter;
import java.io.IOException;
import org.xbill.DNS.Lookup;
import com.jcraft.jsch.JSch;
import java.net.InetAddress;
import org.xbill.DNS.Record;
import java.io.BufferedReader;
import java.security.Security;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.Session;
import java.io.FileInputStream;
import org.slf4j.LoggerFactory;
import org.apache.http.HttpHost;
import java.io.FileOutputStream;
import java.net.SocketException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.ConnectException;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelExec;
import java.net.URISyntaxException;
import org.xbill.DNS.SimpleResolver;
import java.util.concurrent.TimeUnit;
import java.net.UnknownHostException;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import org.apache.http.auth.AuthScope;
import org.apache.commons.io.FileUtils;
import org.xbill.DNS.TextParseException;
import org.apache.http.auth.NTCredentials;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;

import com.cws.esolutions.core.CoreServiceBean;
import com.cws.esolutions.core.CoreServiceConstants;
import com.cws.esolutions.core.config.xml.FTPConfig;
import com.cws.esolutions.core.config.xml.SSHConfig;
import com.cws.esolutions.core.config.xml.HTTPConfig;
import com.cws.esolutions.core.config.xml.ProxyConfig;
import com.cws.esolutions.security.SecurityServiceBean;
import com.cws.esolutions.security.utils.PasswordUtils;
import com.cws.esolutions.core.utils.exception.UtilityException;

/**
 * Interface for the Application Data DAO layer. Allows access
 * into the asset management database to obtain, modify and remove
 * application information.
 *
 * @author cws-khuntly
 * @version 1.0
 */
public final class NetworkUtils {
    private static final String CRLF = "\r\n";
    private static final String TERMINATE_TELNET = "^]";
    private static final String PROXY_AUTH_TYPE_NTLM = "NTLM";
    private static final String PROXY_AUTH_TYPE_BASIC = "basic";
    private static final String CNAME = NetworkUtils.class.getName();
    private static final CoreServiceBean appBean = CoreServiceBean.getInstance();
    private static final SecurityServiceBean secBean = SecurityServiceBean.getInstance();

    private static final Logger DEBUGGER = LoggerFactory.getLogger(CoreServiceConstants.DEBUGGER);
    private static final boolean DEBUG = DEBUGGER.isDebugEnabled();
    private static final Logger ERROR_RECORDER = LoggerFactory.getLogger(CoreServiceConstants.ERROR_LOGGER + CNAME);

    /**
     * Creates an SSH connection to a target host and then executes an SCP
     * request to send or receive a file to or from the target. This is fully
     * key-based, as a result, a keyfile is required for the connection to
     * successfully authenticate.
     * 
     * NOTE: The key file provided MUST be an OpenSSH key. If its not, it must
     * be converted using ssh-keygen:
     * If no passphrase exists on the key: ssh-keygen -i -f /path/to/file
     * If a passphrase exists:
     * Remove the passphrase first: ssh-keygen-g3 -e /path/to/file
     *  - provide passphrase
     * Type 'yes'
     * Type 'no'
     * Type 'yes'
     * Hit enter twice without entering a new passphrase
     * Convert the keyfile: ssh-keygen -i -f /path/to/file > /path/to/new-file
     * Re-encrypt the file: ssh-keygen -p -f /path/to/new-file
     *
     * @param sourceFile - The full path to the source file to transfer
     * @param targetFile - The full path (including file name) of the desired target file
     * @param targetHost - The target server to perform the transfer to
     * @param isUpload - <code>true</code> is the transfer is an upload, <code>false</code> if it
     *            is a download 
     * @throws UtilityException - If an error occurs processing SSH keys or file transfer operations
     */
    public static final synchronized void executeSftpTransfer(final String sourceFile, final String targetFile,
            final String targetHost, final boolean isUpload) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeSftpTransfer(final String sourceFile, final String targetFile, final String targetHost, final boolean isUpload) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("Value: {}", sourceFile);
            DEBUGGER.debug("Value: {}", targetFile);
            DEBUGGER.debug("Value: {}", targetHost);
            DEBUGGER.debug("Value: {}", isUpload);
        }

        Session session = null;
        Channel channel = null;

        final SSHConfig sshConfig = appBean.getConfigData().getSshConfig();

        if (DEBUG) {
            DEBUGGER.debug("SSHConfig sshConfig: {}", sshConfig);
        }

        try {
            Hashtable<String, String> sshProperties = new Hashtable<String, String>();
            sshProperties.put("StrictHostKeyChecking", "no");

            if (DEBUG) {
                DEBUGGER.debug("Hashtable<String, String> sshProperties: {}", sshProperties);
            }

            JSch jsch = new JSch();
            JSch.setConfig(sshProperties);

            if (DEBUG) {
                DEBUGGER.debug("JSch jsch: {}", jsch);
            }

            session = jsch
                    .getSession((StringUtils.isNotEmpty(sshConfig.getSshAccount())) ? sshConfig.getSshAccount()
                            : System.getProperty("user.name"), targetHost, 22);

            if (DEBUG) {
                DEBUGGER.debug("Session session: {}", session);
            }

            if (StringUtils.isNotEmpty(sshConfig.getSshKey())) {
                if (!(FileUtils.getFile(sshConfig.getSshKey()).canRead())) {
                    throw new UtilityException("Provided keyfile cannot be accessed.");
                }

                switch (sshConfig.getSshPassword().length()) {
                case 0:
                    jsch.addIdentity(FileUtils.getFile(sshConfig.getSshKey()).toString());

                    break;
                default:
                    jsch.addIdentity(FileUtils.getFile(sshConfig.getSshKey()).toString(),
                            PasswordUtils.decryptText(sshConfig.getSshPassword(), sshConfig.getSshSalt(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getIterations(),
                                    secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                    appBean.getConfigData().getSystemConfig().getEncoding()));

                    break;
                }
            } else {
                session.setPassword(PasswordUtils.decryptText(sshConfig.getSshPassword(), sshConfig.getSshSalt(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                        secBean.getConfigData().getSecurityConfig().getIterations(),
                        secBean.getConfigData().getSecurityConfig().getKeyBits(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                        appBean.getConfigData().getSystemConfig().getEncoding()));
            }

            session.connect((int) TimeUnit.SECONDS.toMillis(appBean.getConfigData().getSshConfig().getTimeout()));

            if (!(session.isConnected())) {
                throw new UtilityException("Failed to connect to the target host");
            }

            channel = session.openChannel("sftp");
            channel.connect();

            if (DEBUG) {
                DEBUGGER.debug("Channel channel: {}", channel);
            }

            ChannelSftp sftpChannel = (ChannelSftp) channel;

            if (DEBUG) {
                DEBUGGER.debug("ChannelSftp sftpChannel: {}", sftpChannel);
            }

            if (isUpload) {

                sftpChannel.put(sourceFile, targetFile, ChannelSftp.OVERWRITE);

                int returnCode = sftpChannel.getExitStatus();

                if (DEBUG) {
                    DEBUGGER.debug("int returnCode: {}", returnCode);
                }
            } else {
                FileOutputStream outStream = new FileOutputStream(FileUtils.getFile(targetFile));

                if (DEBUG) {
                    DEBUGGER.debug("BufferedInputStream outStream: {}", outStream);
                }

                sftpChannel.get(sourceFile, outStream);

                int returnCode = sftpChannel.getExitStatus();

                if (DEBUG) {
                    DEBUGGER.debug("int returnCode: {}", returnCode);
                }

                outStream.flush();
                outStream.close();
            }

            channel.disconnect();
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } catch (SftpException sx) {
            throw new UtilityException(sx.getMessage(), sx);
        } catch (JSchException jx) {
            throw new UtilityException(jx.getMessage(), jx);
        } finally {
            if ((channel != null) && (channel.isConnected())) {
                channel.disconnect();
            }

            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }
    }

    /**
     * Creates an SSH connection to a target host and then executes an SCP
     * request to send or receive a file to or from the target. This is fully
     * key-based, as a result, a keyfile is required for the connection to
     * successfully authenticate.
     * 
     * NOTE: The key file provided MUST be an OpenSSH key. If its not, it must
     * be converted using ssh-keygen:
     * If no passphrase exists on the key: ssh-keygen -i -f /path/to/file
     * If a passphrase exists:
     * Remove the passphrase first: ssh-keygen-g3 -e /path/to/file
     *  - provide passphrase
     * Type 'yes'
     * Type 'no'
     * Type 'yes'
     * Hit enter twice without entering a new passphrase
     * Convert the keyfile: ssh-keygen -i -f /path/to/file &gt; /path/to/new-file
     * Re-encrypt the file: ssh-keygen -p -f /path/to/new-file
     *
     * @param targetHost - The target server to perform the transfer to
     * @param commandList - The list of commands to execute on the remote host.
     * @return <code>StringBuilder</code> containing the response information from the provided commandList
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized StringBuilder executeSshConnection(final String targetHost,
            final String commandList) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeSshConnection(final String targetHost, final String commandList) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("Value: {}", targetHost);
            DEBUGGER.debug("Value: {}", commandList);
        }

        Session session = null;
        Channel channel = null;
        StringBuilder sBuilder = null;

        final SSHConfig sshConfig = appBean.getConfigData().getSshConfig();

        if (DEBUG) {
            DEBUGGER.debug("SSHConfig: {}", sshConfig);
        }

        try {
            Hashtable<String, String> sshProperties = new Hashtable<String, String>();
            sshProperties.put("StrictHostKeyChecking", "yes");

            if (DEBUG) {
                DEBUGGER.debug("Hashtable<String, String> sshProperties: {}", sshProperties);
            }

            JSch jsch = new JSch();
            JSch.setConfig(sshProperties);

            if (DEBUG) {
                DEBUGGER.debug("JSch: {}", jsch);
            }

            session = jsch
                    .getSession((StringUtils.isNotEmpty(sshConfig.getSshAccount())) ? sshConfig.getSshAccount()
                            : System.getProperty("user.name"), targetHost, 22);

            if (DEBUG) {
                DEBUGGER.debug("Session: {}", session);
            }

            if (StringUtils.isNotEmpty(sshConfig.getSshKey())) {
                if (!(FileUtils.getFile(sshConfig.getSshKey()).canRead())) {
                    throw new UtilityException("Provided keyfile cannot be accessed.");
                }

                switch (sshConfig.getSshPassword().length()) {
                case 0:
                    jsch.addIdentity(FileUtils.getFile(sshConfig.getSshKey()).toString());

                    break;
                default:
                    jsch.addIdentity(FileUtils.getFile(sshConfig.getSshKey()).toString(),
                            PasswordUtils.decryptText(sshConfig.getSshPassword(), sshConfig.getSshSalt(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getIterations(),
                                    secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                    secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                    appBean.getConfigData().getSystemConfig().getEncoding()));

                    break;
                }
            } else {
                session.setPassword(PasswordUtils.decryptText(sshConfig.getSshPassword(), sshConfig.getSshSalt(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                        secBean.getConfigData().getSecurityConfig().getIterations(),
                        secBean.getConfigData().getSecurityConfig().getKeyBits(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                        secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                        appBean.getConfigData().getSystemConfig().getEncoding()));
            }

            session.connect((int) TimeUnit.SECONDS.toMillis(appBean.getConfigData().getSshConfig().getTimeout()));

            if (!(session.isConnected())) {
                throw new UtilityException("Failed to connect to the target host");
            }

            if (StringUtils.isNotEmpty(commandList)) {
                for (String cmd : StringUtils.split(commandList, ",")) {
                    if (DEBUG) {
                        DEBUGGER.debug("cmd: {}", cmd);
                    }

                    channel = session.openChannel("exec");
                    ((ChannelExec) channel).setCommand(cmd.trim());
                    ((ChannelExec) channel).setErrStream(System.err);
                    channel.setInputStream(null);

                    if (DEBUG) {
                        DEBUGGER.debug("ChannelExec: {}", channel);
                    }

                    channel.connect(
                            (int) TimeUnit.SECONDS.toMillis(appBean.getConfigData().getSshConfig().getTimeout()));

                    if (!(channel.isConnected())) {
                        throw new UtilityException("Failed to open a channel connection to the target host");
                    }

                    String line = null;
                    BufferedReader bReader = new BufferedReader(new InputStreamReader(channel.getInputStream()));

                    if (DEBUG) {
                        DEBUGGER.debug("BufferedReader: {}", bReader);
                    }

                    sBuilder = new StringBuilder();

                    while ((line = bReader.readLine()) != null) {
                        if (DEBUG) {
                            DEBUGGER.debug("Data: {}", line);
                        }

                        sBuilder.append(line + CoreServiceConstants.LINE_BREAK);
                    }

                    if (DEBUG) {
                        DEBUGGER.debug("StringBuilder: {}", sBuilder.toString());
                    }

                    bReader.close();

                    channel.disconnect();
                }
            }
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } catch (JSchException jx) {
            throw new UtilityException(jx.getMessage(), jx);
        } finally {
            if ((channel != null) && (channel.isConnected())) {
                channel.disconnect();
            }

            if ((session != null) && (session.isConnected())) {
                session.disconnect();
            }
        }

        return sBuilder;
    }

    /**
     * Creates a connection to a target host and then executes an FTP
     * request to send or receive a file to or from the target. This is fully
     * key-based, as a result, a keyfile is required for the connection to
     * successfully authenticate.
     * 
     * @param sourceFile - The full path to the source file to transfer
     * @param targetFile - The full path (including file name) of the desired target file
     * @param targetHost - The target server to perform the transfer to
     * @param isUpload - <code>true</code> is the transfer is an upload, <code>false</code> if it
     *            is a download 
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized void executeFtpConnection(final String sourceFile, final String targetFile,
            final String targetHost, final boolean isUpload) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeFtpConnection(final String sourceFile, final String targetFile, final String targetHost, final boolean isUpload) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("Value: {}", sourceFile);
            DEBUGGER.debug("Value: {}", targetFile);
            DEBUGGER.debug("Value: {}", targetHost);
            DEBUGGER.debug("Value: {}", isUpload);
        }

        final FTPClient client = new FTPClient();
        final FTPConfig ftpConfig = appBean.getConfigData().getFtpConfig();

        if (DEBUG) {
            DEBUGGER.debug("FTPClient: {}", client);
            DEBUGGER.debug("FTPConfig: {}", ftpConfig);
        }

        try {
            client.connect(targetHost);

            if (DEBUG) {
                DEBUGGER.debug("FTPClient: {}", client);
            }

            if (!(client.isConnected())) {
                throw new IOException("Failed to authenticate to remote host with the provided information");
            }

            boolean isAuthenticated = false;

            if (StringUtils.isNotBlank(ftpConfig.getFtpAccount())) {
                isAuthenticated = client.login(
                        (StringUtils.isNotEmpty(ftpConfig.getFtpAccount())) ? ftpConfig.getFtpAccount()
                                : System.getProperty("user.name"),
                        PasswordUtils.decryptText(ftpConfig.getFtpPassword(), ftpConfig.getFtpSalt(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                appBean.getConfigData().getSystemConfig().getEncoding()));
            } else {
                isAuthenticated = client.login(ftpConfig.getFtpAccount(), null);
            }

            if (DEBUG) {
                DEBUGGER.debug("isAuthenticated: {}", isAuthenticated);
            }

            if (!(isAuthenticated)) {
                throw new IOException("Failed to connect to FTP server: " + targetHost);
            }

            client.enterLocalPassiveMode();

            if (!(FileUtils.getFile(sourceFile).exists())) {
                throw new IOException("File " + sourceFile + " does not exist. Skipping");
            }

            if (isUpload) {
                client.storeFile(targetFile, new FileInputStream(FileUtils.getFile(sourceFile)));
            } else {
                client.retrieveFile(sourceFile, new FileOutputStream(targetFile));
            }

            if (DEBUG) {
                DEBUGGER.debug("Reply: {}", client.getReplyCode());
                DEBUGGER.debug("Reply: {}", client.getReplyString());
            }
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } finally {
            try {
                if (client.isConnected()) {
                    client.completePendingCommand();
                    client.disconnect();
                }
            } catch (IOException iox) {
                ERROR_RECORDER.error(iox.getMessage(), iox);
            }
        }
    }

    /**
     * Creates an telnet connection to a target host and port number. Silently
     * succeeds if no issues are encountered, if so, exceptions are logged and
     * re-thrown back to the requestor.
     *
     * If an exception is thrown during the <code>socket.close()</code> operation,
     * it is logged but NOT re-thrown. It's not re-thrown because it does not indicate
     * a connection failure (indeed, it means the connection succeeded) but it is
     * logged because continued failures to close the socket could result in target
     * system instability.
     * 
     * @param hostName - The target host to make the connection to
     * @param portNumber - The port number to attempt the connection on
     * @param timeout - The timeout for the connection
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized void executeTelnetRequest(final String hostName, final int portNumber,
            final int timeout) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeTelnetRequest(final String hostName, final int portNumber, final int timeout) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug(hostName);
            DEBUGGER.debug("portNumber: {}", portNumber);
            DEBUGGER.debug("timeout: {}", timeout);
        }

        Socket socket = null;

        try {
            synchronized (new Object()) {
                if (InetAddress.getByName(hostName) == null) {
                    throw new UnknownHostException("No host was found in DNS for the given name: " + hostName);
                }

                InetSocketAddress socketAddress = new InetSocketAddress(hostName, portNumber);

                socket = new Socket();
                socket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(timeout));
                socket.setSoLinger(false, 0);
                socket.setKeepAlive(false);
                socket.connect(socketAddress, (int) TimeUnit.SECONDS.toMillis(timeout));

                if (!(socket.isConnected())) {
                    throw new ConnectException("Failed to connect to host " + hostName + " on port " + portNumber);
                }

                PrintWriter pWriter = new PrintWriter(socket.getOutputStream(), true);

                pWriter.println(NetworkUtils.TERMINATE_TELNET + NetworkUtils.CRLF);

                pWriter.flush();
                pWriter.close();
            }
        } catch (ConnectException cx) {
            throw new UtilityException(cx.getMessage(), cx);
        } catch (UnknownHostException ux) {
            throw new UtilityException(ux.getMessage(), ux);
        } catch (SocketException sx) {
            throw new UtilityException(sx.getMessage(), sx);
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } finally {
            try {
                if ((socket != null) && (!(socket.isClosed()))) {
                    socket.close();
                }
            } catch (IOException iox) {
                // log it - this could cause problems later on
                ERROR_RECORDER.error(iox.getMessage(), iox);
            }
        }
    }

    /**
     * Creates an HTTP connection to a provided website and returns the data back
     * to the requestor.
     *
     * @param hostName - The fully qualified URL for the host desired. MUST be
     *     prefixed with http/https:// as necessary
     * @param methodType - GET or POST, depending on what is necessary
     * @return A object containing the response data
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized Object executeHttpConnection(final URL hostName, final String methodType)
            throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeHttpConnection(final URL hostName, final String methodType) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("Value: {}", hostName);
            DEBUGGER.debug("Value: {}", methodType);
        }

        RequestConfig requestConfig = null;
        CloseableHttpClient httpClient = null;
        CredentialsProvider credsProvider = null;
        CloseableHttpResponse httpResponse = null;

        final HttpClientParams httpParams = new HttpClientParams();
        final HTTPConfig httpConfig = appBean.getConfigData().getHttpConfig();
        final ProxyConfig proxyConfig = appBean.getConfigData().getProxyConfig();

        if (DEBUG) {
            DEBUGGER.debug("HttpClient: {}", httpClient);
            DEBUGGER.debug("HttpClientParams: {}", httpParams);
            DEBUGGER.debug("HTTPConfig: {}", httpConfig);
            DEBUGGER.debug("ProxyConfig: {}", proxyConfig);
        }
        try {
            final URI requestURI = new URIBuilder().setScheme(hostName.getProtocol()).setHost(hostName.getHost())
                    .setPort(hostName.getPort()).build();

            if (StringUtils.isNotEmpty(httpConfig.getTrustStoreFile())) {
                System.setProperty("javax.net.ssl.trustStoreType",
                        (StringUtils.isNotEmpty(httpConfig.getTrustStoreType()) ? httpConfig.getTrustStoreType()
                                : "jks"));
                System.setProperty("javax.net.ssl.trustStore", httpConfig.getTrustStoreFile());
                System.setProperty("javax.net.ssl.trustStorePassword",
                        PasswordUtils.decryptText(httpConfig.getTrustStorePass(), httpConfig.getTrustStoreSalt(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                appBean.getConfigData().getSystemConfig().getEncoding()));
            }

            if (StringUtils.isNotEmpty(httpConfig.getKeyStoreFile())) {
                System.setProperty("javax.net.ssl.keyStoreType",
                        (StringUtils.isNotEmpty(httpConfig.getKeyStoreType()) ? httpConfig.getKeyStoreType()
                                : "jks"));
                System.setProperty("javax.net.ssl.keyStore", httpConfig.getKeyStoreFile());
                System.setProperty("javax.net.ssl.keyStorePassword",
                        PasswordUtils.decryptText(httpConfig.getKeyStorePass(), httpConfig.getKeyStoreSalt(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getIterations(),
                                secBean.getConfigData().getSecurityConfig().getKeyBits(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                                secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                                appBean.getConfigData().getSystemConfig().getEncoding()));
            }

            if (proxyConfig.isProxyServiceRequired()) {
                if (DEBUG) {
                    DEBUGGER.debug("ProxyConfig: {}", proxyConfig);
                }

                if (StringUtils.isEmpty(proxyConfig.getProxyServerName())) {
                    throw new UtilityException(
                            "Configuration states proxy usage is required, but no proxy is configured.");
                }

                if (proxyConfig.isProxyAuthRequired()) {
                    List<String> authList = new ArrayList<String>();
                    authList.add(AuthPolicy.BASIC);
                    authList.add(AuthPolicy.DIGEST);
                    authList.add(AuthPolicy.NTLM);

                    if (DEBUG) {
                        DEBUGGER.debug("authList: {}", authList);
                    }

                    requestConfig = RequestConfig.custom()
                            .setConnectionRequestTimeout(
                                    (int) TimeUnit.SECONDS.toMillis(httpConfig.getConnTimeout()))
                            .setConnectTimeout((int) TimeUnit.SECONDS.toMillis(httpConfig.getConnTimeout()))
                            .setContentCompressionEnabled(Boolean.TRUE)
                            .setProxy(new HttpHost(proxyConfig.getProxyServerName(),
                                    proxyConfig.getProxyServerPort()))
                            .setProxyPreferredAuthSchemes(authList).build();

                    if (DEBUG) {
                        DEBUGGER.debug("requestConfig: {}", requestConfig);
                    }

                    String proxyPwd = PasswordUtils.decryptText(proxyConfig.getProxyPassword(),
                            proxyConfig.getProxyPwdSalt(),
                            secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                            secBean.getConfigData().getSecurityConfig().getIterations(),
                            secBean.getConfigData().getSecurityConfig().getKeyBits(),
                            secBean.getConfigData().getSecurityConfig().getEncryptionAlgorithm(),
                            secBean.getConfigData().getSecurityConfig().getEncryptionInstance(),
                            appBean.getConfigData().getSystemConfig().getEncoding());

                    if (DEBUG) {
                        DEBUGGER.debug("proxyPwd: {}", proxyPwd);
                    }

                    if (StringUtils.equals(NetworkUtils.PROXY_AUTH_TYPE_BASIC, proxyConfig.getProxyAuthType())) {
                        credsProvider = new SystemDefaultCredentialsProvider();
                        credsProvider.setCredentials(
                                new AuthScope(proxyConfig.getProxyServerName(), proxyConfig.getProxyServerPort()),
                                new UsernamePasswordCredentials(proxyConfig.getProxyUserId(), proxyPwd));
                    } else if (StringUtils.equals(NetworkUtils.PROXY_AUTH_TYPE_NTLM,
                            proxyConfig.getProxyAuthType())) {
                        credsProvider = new SystemDefaultCredentialsProvider();
                        credsProvider.setCredentials(
                                new AuthScope(proxyConfig.getProxyServerName(), proxyConfig.getProxyServerPort()),
                                new NTCredentials(proxyConfig.getProxyUserId(), proxyPwd,
                                        InetAddress.getLocalHost().getHostName(),
                                        proxyConfig.getProxyAuthDomain()));
                    }

                    if (DEBUG) {
                        DEBUGGER.debug("httpClient: {}", httpClient);
                    }
                }
            }

            synchronized (new Object()) {
                httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();

                if (StringUtils.equalsIgnoreCase(methodType, "POST")) {
                    HttpPost httpMethod = new HttpPost(requestURI);
                    httpMethod.setConfig(requestConfig);

                    httpResponse = httpClient.execute(httpMethod);
                } else {
                    HttpGet httpMethod = new HttpGet(requestURI);
                    httpMethod.setConfig(requestConfig);

                    httpResponse = httpClient.execute(httpMethod);
                }

                int responseCode = httpResponse.getStatusLine().getStatusCode();

                if (DEBUG) {
                    DEBUGGER.debug("responseCode: {}", responseCode);
                }

                if (responseCode != 200) {
                    ERROR_RECORDER.error("HTTP Response Code received NOT 200: " + responseCode);

                    throw new UtilityException("HTTP Response Code received NOT 200: " + responseCode);
                }

                return httpResponse.getEntity().toString();
            }
        } catch (ConnectException cx) {
            throw new UtilityException(cx.getMessage(), cx);
        } catch (UnknownHostException ux) {
            throw new UtilityException(ux.getMessage(), ux);
        } catch (SocketException sx) {
            throw new UtilityException(sx.getMessage(), sx);
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } catch (URISyntaxException usx) {
            throw new UtilityException(usx.getMessage(), usx);
        } finally {
            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (IOException iox) {
                } // dont do anything with it
            }
        }
    }

    /**
     * Creates an telnet connection to a target host and port number. Silently
     * succeeds if no issues are encountered, if so, exceptions are logged and
     * re-thrown back to the requestor.
     *
     * If an exception is thrown during the <code>socket.close()</code> operation,
     * it is logged but NOT re-thrown. It's not re-thrown because it does not indicate
     * a connection failure (indeed, it means the connection succeeded) but it is
     * logged because continued failures to close the socket could result in target
     * system instability.
     * 
     * @param hostName - The target host to make the connection to
     * @param portNumber - The port number to attempt the connection on
     * @param timeout - How long to wait for a connection to establish or a response from the target
     * @param object - The serializable object to send to the target
     * @return <code>Object</code> as output from the request
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized Object executeTcpRequest(final String hostName, final int portNumber,
            final int timeout, final Object object) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeTcpRequest(final String hostName, final int portNumber, final int timeout, final Object object) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug(hostName);
            DEBUGGER.debug("portNumber: {}", portNumber);
            DEBUGGER.debug("timeout: {}", timeout);
            DEBUGGER.debug("object: {}", object);
        }

        Socket socket = null;
        Object resObject = null;

        try {
            synchronized (new Object()) {
                if (StringUtils.isEmpty(InetAddress.getByName(hostName).toString())) {
                    throw new UnknownHostException("No host was found in DNS for the given name: " + hostName);
                }

                InetSocketAddress socketAddress = new InetSocketAddress(hostName, portNumber);

                socket = new Socket();
                socket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(timeout));
                socket.setSoLinger(false, 0);
                socket.setKeepAlive(false);
                socket.connect(socketAddress, (int) TimeUnit.SECONDS.toMillis(timeout));

                if (!(socket.isConnected())) {
                    throw new ConnectException("Failed to connect to host " + hostName + " on port " + portNumber);
                }

                ObjectOutputStream objectOut = new ObjectOutputStream(socket.getOutputStream());

                if (DEBUG) {
                    DEBUGGER.debug("ObjectOutputStream: {}", objectOut);
                }

                objectOut.writeObject(object);

                resObject = new ObjectInputStream(socket.getInputStream()).readObject();

                if (DEBUG) {
                    DEBUGGER.debug("resObject: {}", resObject);
                }

                PrintWriter pWriter = new PrintWriter(socket.getOutputStream(), true);

                pWriter.println(NetworkUtils.TERMINATE_TELNET + NetworkUtils.CRLF);

                pWriter.flush();
                pWriter.close();
            }
        } catch (ConnectException cx) {
            throw new UtilityException(cx.getMessage(), cx);
        } catch (UnknownHostException ux) {
            throw new UtilityException(ux.getMessage(), ux);
        } catch (SocketException sx) {
            throw new UtilityException(sx.getMessage(), sx);
        } catch (IOException iox) {
            throw new UtilityException(iox.getMessage(), iox);
        } catch (ClassNotFoundException cnfx) {
            throw new UtilityException(cnfx.getMessage(), cnfx);
        } finally {
            try {
                if ((socket != null) && (!(socket.isClosed()))) {
                    socket.close();
                }
            } catch (IOException iox) {
                // log it - this could cause problems later on
                ERROR_RECORDER.error(iox.getMessage(), iox);
            }
        }

        return resObject;
    }

    /**
     * Performs a DNS lookup of a given name and type against a provided server
     * (or if no server is provided, the default system resolver).
     *
     * If an error occurs during the lookup, a <code>UtilityException</code> is
     * thrown containing the error response text.
     * 
     * @param resolverHost - The target host to use for resolution. Can be null, if not provided the
     * the default system resolver is used.
     * @param recordName - The DNS hostname/IP address to lookup.
     * @param recordType - The type of record to look up.
     * @param searchList - A search list to utilize if a short name is provided.
     * @return An ArrayList as output from the request
     * @throws UtilityException {@link com.cws.esolutions.core.utils.exception.UtilityException} if an error occurs processing
     */
    public static final synchronized List<List<String>> executeDNSLookup(final String resolverHost,
            final String recordName, final String recordType, final String[] searchList) throws UtilityException {
        final String methodName = NetworkUtils.CNAME
                + "#executeDNSLookup(final String resolverHost, final String recordName, final String recordType, final String[] searchList) throws UtilityException";

        if (DEBUG) {
            DEBUGGER.debug(methodName);
            DEBUGGER.debug("String: {}", resolverHost);
            DEBUGGER.debug("String: {}", recordName);
            DEBUGGER.debug("String: {}", recordType);
            DEBUGGER.debug("String: {}", (Object) searchList);
        }

        Lookup lookup = null;
        String responseName = null;
        String responseType = null;
        Record[] recordList = null;
        String responseAddress = null;
        SimpleResolver resolver = null;
        List<String> lookupData = null;
        List<List<String>> response = null;

        final String currentTimeout = Security.getProperty("networkaddress.cache.ttl");

        if (DEBUG) {
            DEBUGGER.debug("currentTimeout: {}", currentTimeout);
        }

        try {
            // no authorization required for service lookup
            Name name = Name.fromString(recordName);
            lookup = new Lookup(name, Type.value(recordType));

            if (DEBUG) {
                DEBUGGER.debug("Name: {}", name);
                DEBUGGER.debug("Lookup: {}", lookup);
            }

            if (StringUtils.isNotEmpty(resolverHost)) {
                resolver = new SimpleResolver(resolverHost);

                if (DEBUG) {
                    DEBUGGER.debug("SimpleResolver: {}", resolver);
                }
            } else {
                resolver = new SimpleResolver();

                if (DEBUG) {
                    DEBUGGER.debug("SimpleResolver: {}", resolver);
                }
            }

            lookup.setResolver(resolver);
            lookup.setCache(null);

            if (searchList != null) {
                lookup.setSearchPath(searchList);
            }

            if (DEBUG) {
                DEBUGGER.debug("Lookup: {}", lookup);
            }

            recordList = lookup.run();

            if (DEBUG) {
                if (recordList != null) {
                    for (Record dRecord : recordList) {
                        DEBUGGER.debug("Record: {}", dRecord);
                    }
                }
            }

            if (lookup.getResult() != Lookup.SUCCESSFUL) {
                throw new UtilityException("An error occurred during the lookup. The response obtained is: "
                        + lookup.getErrorString());
            }

            response = new ArrayList<List<String>>();

            if ((recordList == null) || (recordList.length == 0)) {
                throw new UtilityException("No results were found for the provided information.");
            }

            switch (recordList.length) {
            case 1:
                Record sRecord = recordList[0];

                if (DEBUG) {
                    DEBUGGER.debug("Record: {}", sRecord);
                }

                responseAddress = sRecord.rdataToString();
                responseName = sRecord.getName().toString();
                responseType = Type.string(sRecord.getType());

                lookupData = new ArrayList<String>(Arrays.asList(responseAddress, responseName, responseType));
                if (DEBUG) {
                    DEBUGGER.debug("responseAddress: {}", responseAddress);
                    DEBUGGER.debug("responseName: {}", responseName);
                    DEBUGGER.debug("responseType: {}", responseType);
                }

                response.add(lookupData);

                break;
            default:
                for (Record mRecord : recordList) {
                    if (DEBUG) {
                        DEBUGGER.debug("Record: {}", mRecord);
                    }

                    responseAddress = mRecord.rdataToString();
                    responseName = mRecord.getName().toString();
                    responseType = Type.string(mRecord.getType());

                    lookupData = new ArrayList<String>(Arrays.asList(responseAddress, responseName, responseType));
                    if (DEBUG) {
                        DEBUGGER.debug("responseAddress: {}", responseAddress);
                        DEBUGGER.debug("responseName: {}", responseName);
                        DEBUGGER.debug("responseType: {}", responseType);
                    }

                    response.add(lookupData);

                    if (DEBUG) {
                        DEBUGGER.debug("response: {}", response);
                    }
                }

                break;
            }

            if (DEBUG) {
                DEBUGGER.debug("response: {}", response);
            }
        } catch (TextParseException tpx) {
            ERROR_RECORDER.error(tpx.getMessage(), tpx);

            throw new UtilityException(tpx.getMessage(), tpx);
        } catch (UnknownHostException uhx) {
            ERROR_RECORDER.error(uhx.getMessage(), uhx);

            throw new UtilityException(uhx.getMessage(), uhx);
        } finally {
            // reset java dns timeout
            try {
                Security.setProperty("networkaddress.cache.ttl", currentTimeout);
            } catch (NullPointerException npx) {
            }
        }

        return response;
    }
}