/*
 * Autopsy Forensic Browser
 *
 * Copyright 2015 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> org
 *
 * 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 org.sleuthkit.autopsy.events;

import java.net.URI;
import java.net.URISyntaxException;
import javax.annotation.concurrent.Immutable;
import javax.jms.Connection;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnectionFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.util.MissingResourceException;
import org.openide.util.NbBundle;

/**
 * Connection info for a Java Message Service (JMS) provider. Thread-safe.
 */
@Immutable
public final class MessageServiceConnectionInfo {

    private static final String MESSAGE_SERVICE_URI = "tcp://%s:%s?wireFormat.maxInactivityDuration=0";
    private static final String CONNECTION_TIMED_OUT = "connection timed out";
    private static final String CONNECTION_REFUSED = "connection refused";
    private static final String PASSWORD_OR_USERNAME_BAD = "user name [";
    private static final int IS_REACHABLE_TIMEOUT_MS = 1000;
    private final String userName;
    private final String password;
    private final String host;
    private final int port;

    /**
     * Constructs an object containing connection info for a Java Message
     * Service (JMS) provider.
     *
     * @param host     The host to use for a message service connection. May be
     *                 a host name or an IP address.
     * @param port     The port number to use for a message service connection.
     * @param userName The user name to use for a message service connection.
     * @param password The password to use for a message service connection.
     *
     */
    public MessageServiceConnectionInfo(String host, int port, String userName, String password) {
        this.host = host;
        this.port = port;
        this.userName = userName;
        this.password = password;
    }

    /**
     * Gets the user name to use for a message service connection.
     *
     * @return The user name as a string.
     */
    public String getUserName() {
        return userName;
    }

    /**
     * Gets the password to use for a message service connection.
     *
     * @return The password as a string.
     */
    public String getPassword() {
        return password;
    }

    /**
     * Gets the host to use for a message service connection. May be a host name
     * or an IP address.
     *
     * @return The host as a string.
     */
    public String getHost() {
        return host;
    }

    /**
     * Gets the port number to use for a message service connection.
     *
     * @return The port as an int.
     */
    public int getPort() {
        return port;
    }

    /**
     * Gets the TCP URI to use for a message service connection.
     *
     * @return The URI.
     *
     * @throws URISyntaxException if the connection info is not for a valid TCP
     *                            URI.
     */
    URI getURI() throws URISyntaxException {
        return new URI(String.format(MESSAGE_SERVICE_URI, getHost(), Integer.toString(getPort())));
    }

    /**
     * Verifies connection to messaging service. Throws if we cannot communicate
     * with messaging service.
     *
     * When issues occur, it attempts to diagnose them by looking at the
     * exception messages, returning the appropriate user-facing text for the
     * exception received. This method expects the Exceptions messages to be in
     * English and compares against English text.
     *
     * @throws org.sleuthkit.autopsy.events.MessageServiceException
     */
    public void tryConnect() throws MessageServiceException {
        if (host == null || host.isEmpty()) {
            throw new MessageServiceException(NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.MissingHostname")); //NON-NLS
        } else if (userName == null || userName.isEmpty()) {
            throw new MessageServiceException(NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.MissingUsername")); //NON-NLS
        } else if (password == null || password.isEmpty()) {
            throw new MessageServiceException(NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.MissingPassword")); //NON-NLS
        }
        try {
            ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(getUserName(), getPassword(), getURI());
            Connection connection = connectionFactory.createConnection(getUserName(), getPassword());
            connection.start();
            connection.close();
        } catch (URISyntaxException ex) {
            // The hostname or port seems bad
            throw new MessageServiceException(NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.HostnameOrPort")); //NON-NLS
        } catch (JMSException ex) {
            String result;
            Throwable cause = ex.getCause();
            if (cause != null) {
                // there is more information from another exception
                String msg = cause.getMessage();
                if (msg.startsWith(CONNECTION_TIMED_OUT)) {
                    // The hostname or IP address seems bad
                    result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.Hostname"); //NON-NLS
                } else if (msg.toLowerCase().startsWith(CONNECTION_REFUSED)) {
                    // The port seems bad
                    result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.Port"); //NON-NLS
                } else if (msg.toLowerCase().startsWith(PASSWORD_OR_USERNAME_BAD)) {
                    // The username or password seems bad
                    result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.UsernameAndPassword"); //NON-NLS
                } else {
                    // Could be either hostname or port number
                    result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.HostnameOrPort"); //NON-NLS
                }
            } else {
                // there is no more information from another exception
                try {
                    if (InetAddress.getByName(getHost()).isReachable(IS_REACHABLE_TIMEOUT_MS)) {
                        // if we can reach the host, then it's probably a port problem
                        result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.Port"); //NON-NLS
                    } else {
                        result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.Hostname"); //NON-NLS
                    }
                } catch (IOException | MissingResourceException any) {
                    // it may be anything
                    result = NbBundle.getMessage(MessageServiceConnectionInfo.class, "MessageServiceConnectionInfo.ConnectionCheck.Everything"); //NON-NLS
                }
            }
            throw new MessageServiceException(result);
        }
    }
}

@@ -2137,32 +2137,80 @@
 ice connection.%0A
+     *                 May be the empty string.%0A
      * @param pa
@@ -2261,32 +2261,80 @@
 vice connection.
+ May%0A     *                 be the empty string.
 %0A     *%0A     */%0A
@@ -2674,32 +2674,46 @@
 ame as a string.
+ May be empty.
 %0A     */%0A    pub
@@ -2844,32 +2844,32 @@
 nection.%0A     *%0A
-
      * @return T
@@ -2884,32 +2884,46 @@
 ord as a string.
+ May be empty.
 %0A     */%0A    pub
@@ -4577,30 +4577,8 @@
 null
- %7C%7C userName.isEmpty()
 ) %7B%0A
@@ -4778,30 +4778,8 @@
 null
- %7C%7C password.isEmpty()
 ) %7B%0A

Make username and pwd optional in events.MessageServiceConnectionInfo