ws.argo.DemoWebClient.Browser.BrowserController.java Source code

Java tutorial

Introduction

Here is the source code for ws.argo.DemoWebClient.Browser.BrowserController.java

Source

/*
 * Copyright 2015 Jeff Simpson.
 *
 * Licensed under the MIT License, (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://opensource.org/licenses/MIT
 *
 * 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 ws.argo.DemoWebClient.Browser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import ws.argo.plugin.transport.exception.TransportConfigException;
import ws.argo.plugin.transport.exception.TransportException;
import ws.argo.probe.Probe;
import ws.argo.probe.ProbeSender;
import ws.argo.probe.ProbeSenderException;
import ws.argo.probe.ProbeSenderFactory;
import ws.argo.probe.UnsupportedPayloadType;

/**
 * The BrowserController implements all the functions that I couldn't do in
 * javascript. It implements them as REST API calls.
 * 
 * @author Jeff Simpson
 * @since v0.0.1
 */
@Path("controller")
public class BrowserController {

    private static final Logger LOGGER = LogManager.getLogger(BrowserController.class.getName());

    private static final String PROBE_GENERATOR_PROPERTIES_FILE = "argoClient.prop";
    private static final String DEFAULT_PROBE_RESPONSE_URL_PATH = "/AsynchListener/api/responseHandler/probeResponse";
    private static final String DEFAULT_RESPONSES_URL_PATH = "/AsynchListener/api/responseHandler/responses";
    private static final String DEFAULT_CLEAR_CACHE_URL_PATH = "/AsynchListener/api/responseHandler/clearCache";
    private static final String DEFAULT_MULTICAST_GROUP_ADDR = "230.0.0.1";
    private static final Integer DEFAULT_MULTICAST_PORT = 4003;
    private static final String ARGO_HOME_ENV_NAME = "ARGO_HOME";
    private static final String ARGO_HOME_PROPS_PATH = "/config/";

    protected CloseableHttpClient httpClient = null;
    protected static Properties clientProps = null;

    protected static ArrayList<ProbeRespondToAddress> respondToAddresses = new ArrayList<ProbeRespondToAddress>();

    @GET
    @Path("/testService")
    public String testService() {
        return "this is a test service for the controller.  yea.";
    }

    /**
     * Return the ip info of where the web host lives that supports the browser
     * app.
     * 
     * @return the ip addr info
     * @throws UnknownHostException if something goes wrong
     */
    @GET
    @Path("/ipAddrInfo")
    public String getIPAddrInfo() throws UnknownHostException {

        Properties clientProps = getPropeSenderProps();

        StringBuffer buf = new StringBuffer();

        InetAddress localhost = null;
        NetworkInterface ni = null;
        try {
            localhost = InetAddress.getLocalHost();
            LOGGER.debug("Network Interface name not specified.  Using the NI for localhost "
                    + localhost.getHostAddress());
            ni = NetworkInterface.getByInetAddress(localhost);
        } catch (UnknownHostException | SocketException e) {
            LOGGER.error("Error occured dealing with network interface name lookup ", e);

        }

        buf.append("<p>").append("<span style='color: red'> IP Address: </span>")
                .append(localhost.getHostAddress());
        buf.append("<span style='color: red'> Host name: </span>").append(localhost.getCanonicalHostName());
        if (ni == null) {
            buf.append("<span style='color: red'> Network Interface is NULL </span>");
        } else {
            buf.append("<span style='color: red'> Network Interface name: </span>").append(ni.getDisplayName());
        }
        buf.append("</p><p>");
        buf.append("Sending probes to " + respondToAddresses.size() + " addresses -  ");
        for (ProbeRespondToAddress rta : respondToAddresses) {
            buf.append("<span style='color: red'> Probe to: </span>")
                    .append(rta.respondToAddress + ":" + rta.respondToPort);
        }
        buf.append("</p>");

        return buf.toString();
    }

    /**
     * Actually launch a probe.
     * 
     * @return some confirmation string back to the client
     * @throws IOException if there is some transport issues
     * @throws UnsupportedPayloadType shouldn't happen as we always ask for JSON
     *           here
     * @throws ProbeSenderException if something else goes wrong
     * @throws TransportException if something else goes wrong
     */
    @GET
    @Path("/launchProbe")
    @Produces("application/txt")
    public String launchProbe()
            throws IOException, UnsupportedPayloadType, ProbeSenderException, TransportException {

        Properties clientProps = getPropeSenderProps();

        String multicastGroupAddr = clientProps.getProperty("multicastGroupAddr", DEFAULT_MULTICAST_GROUP_ADDR);
        String multicastPortString = clientProps.getProperty("multicastPort", DEFAULT_MULTICAST_PORT.toString());

        // String listenerIPAddress = clientProps.getProperty("listenerIPAddress");
        // String listenerPort = clientProps.getProperty("listenerPort");
        String listenerURLPath = clientProps.getProperty("listenerProbeResponseURLPath",
                DEFAULT_PROBE_RESPONSE_URL_PATH);

        Integer multicastPort = Integer.parseInt(multicastPortString);

        ProbeSender gen;
        try {
            gen = ProbeSenderFactory.createMulticastProbeSender(multicastGroupAddr, multicastPort);

            // loop over the "respond to addresses" specified in the properties file.
            // TODO: Clean out the commented out code.
            // for (ProbeRespondToAddress rta : respondToAddresses) {
            //
            // Probe probe = new Probe(Probe.JSON);
            // probe.addRespondToURL("http://"+rta.respondToAddress+":"+rta.respondToPort+listenerURLPath);
            // // The following is a "naked" probe - no service contract IDs, etc.
            // // No specified service contract IDs implies "all"
            // // This will evoke responses from all reachable responders except those
            // configured to "noBrowser"
            // gen.sendProbe(probe);
            // }
            Probe probe = new Probe(Probe.JSON);
            for (ProbeRespondToAddress rta : respondToAddresses) {
                probe.addRespondToURL("browser",
                        "http://" + rta.respondToAddress + ":" + rta.respondToPort + listenerURLPath);
            }
            // The following is a "naked" probe - no service contract IDs, etc.
            // No specified service contract IDs implies "all"
            // This will evoke responses from all reachable responders except those
            // configured to "noBrowser"
            gen.sendProbe(probe);
            gen.close();

            return "Launched " + respondToAddresses.size() + " probe(s) successfully on " + multicastGroupAddr + ":"
                    + multicastPort;

        } catch (TransportConfigException e) {
            return "Launched Failed: " + e.getLocalizedMessage();
        }
    }

    /**
     * Returns a list of the responses collected in the listener.
     * 
     * @return list of the responses collected in the listener
     * @throws UnknownHostException if the ProbeSender props throws it
     */
    @GET
    @Path("/responses")
    @Produces("application/json")
    public String getResponses() throws UnknownHostException {
        Properties clientProps = getPropeSenderProps();

        String listenerIPAddress = clientProps.getProperty("listenerIPAddress");
        String listenerPort = clientProps.getProperty("listenerPort");
        String listenerReponsesURLPath = clientProps.getProperty("listenerReponsesURLPath",
                DEFAULT_RESPONSES_URL_PATH);

        String response = restGetCall("http://" + listenerIPAddress + ":" + listenerPort + listenerReponsesURLPath);

        return response;
    }

    /**
     * Clears the active response cache.
     * 
     * @return the response from the listener service
     * @throws UnknownHostException if there is an issue with the listener address
     */
    @GET
    @Path("/clearCache")
    @Produces("application/json")
    public String clearCache() throws UnknownHostException {
        Properties clientProps = getPropeSenderProps();

        String listenerIPAddress = clientProps.getProperty("listenerIPAddress");
        String listenerPort = clientProps.getProperty("listenerPort");
        String listenerClearCacheURLPath = clientProps.getProperty("listenerClearCacheURLPath",
                DEFAULT_CLEAR_CACHE_URL_PATH);

        String response = restGetCall(
                "http://" + listenerIPAddress + ":" + listenerPort + listenerClearCacheURLPath);

        return response;
    }

    @SuppressWarnings("resource")
    private static InputStream getPropertiesFileInputStream() {
        InputStream is = null;

        String ARGO_HOME = System.getenv(ARGO_HOME_ENV_NAME);
        String externPropsFilename = ARGO_HOME + ARGO_HOME_PROPS_PATH + PROBE_GENERATOR_PROPERTIES_FILE;

        File file = new File(externPropsFilename);
        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            LOGGER.warn("External config file " + externPropsFilename + " not found.");
            LOGGER.warn("Using defaults located in classpath embedded in war file.");
            is = BrowserController.class.getClassLoader().getResourceAsStream(PROBE_GENERATOR_PROPERTIES_FILE);
        }

        return is;
    }

    /*
     * provides the correct host IP address from a string (propIPAddress). This
     * method takes the IP addresses from the properties file and then resolves it
     * to be the correct IP address for the local host to use.
     * 
     * The propIPAddress might be empty. In this case return the correct IP
     * address for the local host and not the loopback address. This makes an
     * assumption that if the user omitted the IP address from the config file,
     * then just use the local host address.
     * 
     * This handles the majority of cases where you don't know the IP address but
     * want simple configuration. It's a good way to default to the local host IP
     * address.
     * 
     * @param propIPAddress the IP address from the properties file
     * 
     * @return the value of the correct string for the local host IP address if
     * the propIPAddress is empty
     */
    private static String getHostIPAddressFromString(String propIPAddress, String niName) {
        String hostIPAddr = propIPAddress;

        if (propIPAddress.equals("")) {
            // If the listenerIPAddress is blank, then try to get the ip address of
            // the interface

            try {
                NetworkInterface ni = null;
                if (niName != null)
                    ni = NetworkInterface.getByName(niName);
                if (ni == null) {
                    LOGGER.info("Network Interface name not specified or incorrect.  Defaulting to localhost");
                    hostIPAddr = InetAddress.getLocalHost().getHostAddress();
                } else {

                    if (!ni.isLoopback()) {

                        Enumeration<InetAddress> ee = ni.getInetAddresses();
                        while (ee.hasMoreElements()) {
                            InetAddress i = (InetAddress) ee.nextElement();
                            if (i instanceof Inet4Address) {
                                hostIPAddr = i.getHostAddress();
                                break; // get the first one an get out of the loop
                            }
                        }
                    }
                }

            } catch (SocketException e) {
                LOGGER.warn("A socket exception occurred.");
            } catch (UnknownHostException e) {
                LOGGER.warn("Error finding Network Interface", e);
            }

        }

        return hostIPAddr;
    }

    private static synchronized Properties getPropeSenderProps() throws UnknownHostException {

        if (clientProps != null)
            return clientProps;

        InputStream in = getPropertiesFileInputStream();

        clientProps = new Properties();

        if (in != null) {
            try {
                clientProps.load(in);
            } catch (IOException e) {
                // Should log the props file issue
                setDefaultProbeSenderProperties(clientProps);
            }

        }

        String niName = clientProps.getProperty("networkInterfaceName");
        if (niName.isEmpty())
            niName = null;

        // Get the listener IP address (for cache related GUI calls) - usually
        // localhost

        String listenerIPAddress = clientProps.getProperty("listenerIPAddress", "");
        if (listenerIPAddress.equals("")) {
            String hostIPAddr = getHostIPAddressFromString(listenerIPAddress, niName);
            clientProps.put("listenerIPAddress", hostIPAddr);
        }

        // handle the list of appHandler information

        boolean continueProcessing = true;
        int number = 1;
        while (continueProcessing) {
            String respondToAddress;
            String respondToPort;

            respondToAddress = clientProps.getProperty("respondToIPAddress." + number, "");
            respondToPort = clientProps.getProperty("respondToPort." + number, "80");

            if (clientProps.containsKey("respondToIPAddress." + number)) {
                String hostIPAddr = getHostIPAddressFromString(respondToAddress, niName);
                ProbeRespondToAddress rta = new ProbeRespondToAddress();
                rta.respondToAddress = hostIPAddr;
                rta.respondToPort = Integer.valueOf(respondToPort);
                respondToAddresses.add(rta);
            } else {
                continueProcessing = false;
            }
            number++;

        }

        return clientProps;
    }

    private static void setDefaultProbeSenderProperties(Properties props) {
        props.put("multicastPort", DEFAULT_MULTICAST_PORT);
        props.put("multicastGroupAddr", DEFAULT_MULTICAST_GROUP_ADDR);
        props.put("listenerIPAddress", "");
        props.put("listenerURLPath", DEFAULT_PROBE_RESPONSE_URL_PATH);
    }

    private String restGetCall(String url) {
        String response = "";

        try {

            HttpGet getRequest = new HttpGet(url);

            CloseableHttpResponse httpResponse = getHttpClient().execute(getRequest);

            try {
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode > 300) {
                    throw new RuntimeException(
                            "Failed : HTTP error code : " + httpResponse.getStatusLine().getStatusCode());
                }

                if (statusCode != 204) {
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader((httpResponse.getEntity().getContent())));

                    StringBuffer buf = new StringBuffer();

                    String output;
                    while ((output = br.readLine()) != null) {
                        buf.append(output);
                    }

                    response = buf.toString();
                }
            } finally {
                httpClient.close();
            }

        } catch (MalformedURLException e) {
            LOGGER.error("nThe respondTo URL was a no good.  respondTo URL is: " + url, e);
        } catch (IOException e) {
            LOGGER.error("An IOException occured: the error message is - ", e);
        } catch (Exception e) {
            LOGGER.error("Some error occured: the error message is - ", e);
        }

        return response;
    }

    CloseableHttpClient getHttpClient() {

        if (httpClient == null) {
            httpClient = HttpClients.createDefault();
        }

        return httpClient;

    }

}