org.tellervo.desktop.wsi.WSIServerDetails.java Source code

Java tutorial

Introduction

Here is the source code for org.tellervo.desktop.wsi.WSIServerDetails.java

Source

/*******************************************************************************
 * Copyright (C) 2010 Lucas Madar and Peter Brewer
 * 
 * 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, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Lucas Madar
 *     Peter Brewer
 ******************************************************************************/
package org.tellervo.desktop.wsi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.NetworkInterface;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;

import javax.net.ssl.SSLPeerUnverifiedException;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellervo.desktop.core.App;
import org.tellervo.desktop.prefs.Prefs.PrefKey;
import org.tellervo.desktop.versioning.Build;
import org.tellervo.desktop.versioning.VersionUtil;
import org.tellervo.desktop.wsi.util.WSCookieStoreHandler;

/**
 * Class for polling the Tellervo WS to check the server is valid and to check
 * version information.
 * 
 * @author pwb48
 *
 */
public class WSIServerDetails {

    /**
     * Status of Tellervo Webservice Server
     * @author pwb48
     *
     */
    public enum WSIServerStatus {
        NO_CONNECTION, MALFORMED_URL, URL_NOT_RESPONDING, URL_NOT_TELLERVO_WS, NOT_CHECKED, TOO_OLD, STATUS_ERROR, VALID, SSL_CERTIFICATE_PROBLEM;

    }

    private static final Logger log = LoggerFactory.getLogger(WSIServerDetails.class);
    private Integer majorversion = null;
    private Integer minorversion = null;
    private String revision = "";
    private WSIServerStatus status = WSIServerStatus.NOT_CHECKED;
    private String errMessage = "";
    private Boolean isNetworkConnected = false;

    public WSIServerDetails() {
        pingServer();
    }

    /**
     * Ping the server to update status
     * 
     * @return
     */
    public boolean pingServer() {
        // First make sure we have a network connection
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface nic = interfaces.nextElement();
                if (nic.isLoopback())
                    continue;

                if (nic.isUp()) {
                    log.debug("Network adapter '" + nic.getDisplayName() + "' is up");
                    isNetworkConnected = true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (!isNetworkConnected) {
            status = WSIServerStatus.NO_CONNECTION;
            errMessage = "You do not appear to have a network connection.\nPlease check you network and try again.";
            return false;
        }

        URI url = null;
        BufferedReader dis = null;
        DefaultHttpClient client = new DefaultHttpClient();

        try {

            String path = App.prefs.getPref(PrefKey.WEBSERVICE_URL, "invalid-url!");

            url = new URI(path.trim());

            // Check we're accessing HTTP or HTTPS connection
            if (url.getScheme() == null
                    || ((!url.getScheme().equals("http")) && !url.getScheme().equals("https"))) {
                errMessage = "The webservice URL is invalid.  It should begin http or https";
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            }

            // load cookies
            client.setCookieStore(WSCookieStoreHandler.getCookieStore().toCookieStore());

            if (App.prefs.getBooleanPref(PrefKey.WEBSERVICE_USE_STRICT_SECURITY, false)) {
                // Using strict security so don't allow self signed certificates for SSL
            } else {
                // Not using strict security so allow self signed certificates for SSL
                if (url.getScheme().equals("https"))
                    WebJaxbAccessor.setSelfSignableHTTPSScheme(client);
            }

            HttpGet req = new HttpGet(url);

            HttpParams httpParameters = new BasicHttpParams();
            int timeoutConnection = 3000;
            HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
            // Set the default socket timeout (SO_TIMEOUT) 
            // in milliseconds which is the timeout for waiting for data.
            int timeoutSocket = 5000;
            HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
            client.setParams(httpParameters);

            HttpResponse response = client.execute(req);

            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream responseIS = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(responseIS));
                String s = "";
                while ((s = reader.readLine()) != null) {
                    if (s.contains("<webserviceVersion>")) {
                        String[] strparts = s.split("<[/]*webserviceVersion>");
                        if (strparts.length > 0)
                            parserThisServerVersion(strparts[1]);

                        status = WSIServerStatus.VALID;
                        return true;
                    } else if (s.startsWith("<b>Parse error</b>:")) {
                        status = WSIServerStatus.STATUS_ERROR;
                        errMessage = s.replace("<b>", "").replace("</b>", "").replace("<br />", "");
                        return false;
                    }
                }
            } else if (response.getStatusLine().getStatusCode() == 403) {
                String serverType = "";
                try {
                    serverType = "(" + response.getHeaders("Server")[0].getValue() + ")";
                } catch (Exception e) {
                }

                errMessage = "The webserver " + serverType
                        + " reports you do not have permission to access this URL.\n"
                        + "This is a problem with the server setup, not your Tellervo username/password.\n"
                        + "Contact your systems administrator for help.";
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            } else if (response.getStatusLine().getStatusCode() == 404) {
                errMessage = "Server reports that there is no webservice at this URL.\nPlease check and try again.";
                log.debug(errMessage);
                status = WSIServerStatus.URL_NOT_TELLERVO_WS;
                return false;
            } else if (response.getStatusLine().getStatusCode() == 407) {
                errMessage = "Proxy authentication is required to access this server.\nCheck your proxy server settings and try again.";
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            } else if (response.getStatusLine().getStatusCode() >= 500) {
                errMessage = "Internal server error (code " + response.getStatusLine().getStatusCode()
                        + ").\nContact your systems administrator";
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            } else if (response.getStatusLine().getStatusCode() >= 300
                    && response.getStatusLine().getStatusCode() < 400) {
                errMessage = "Server reports that your request has been redirected to a different URL.\nCheck your URL and try again.";
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            } else {
                errMessage = "The server is returning an error:\nCode: " + response.getStatusLine().getStatusCode()
                        + "\n" + response.getStatusLine().getReasonPhrase();
                log.debug(errMessage);
                status = WSIServerStatus.STATUS_ERROR;
                return false;
            }

        } catch (ClientProtocolException e) {
            errMessage = "There was as problem with the HTTP protocol.\nPlease contact the Tellervo developers.";
            log.debug(errMessage);
            status = WSIServerStatus.STATUS_ERROR;
            return false;
        } catch (SSLPeerUnverifiedException sslex) {
            errMessage = "You have strict security policy enabled but the server you are connecting to does not have a valid SSL certificate.";
            log.debug(errMessage);
            status = WSIServerStatus.SSL_CERTIFICATE_PROBLEM;
            return false;
        } catch (IOException e) {

            if (url.toString().startsWith("http://10.")) {
                // Provide extra help to those failing to access a local server address
                errMessage = "There is no response from the server at this URL. Are you sure this is the correct address?\n\nPlease note that the URL you have specified is a local network address. You will need to be on the same network as the server to gain access.";
            } else if (e.getMessage().contains("hostname in certificate didn't match")) {
                errMessage = "The security certificate for this server is for a different domain.  This could be an indication of a 'man-in-the-middle' attack.";
            } else {
                errMessage = "There is no response from the server at this URL.\nAre you sure this is the correct address and that\nthe server is turned on and configured correctly?";
            }
            log.debug(errMessage);
            log.debug("IOException " + e.getLocalizedMessage());
            status = WSIServerStatus.URL_NOT_RESPONDING;
            return false;
        } catch (URISyntaxException e) {
            errMessage = "The web service URL you entered was malformed.\nPlease check for typos and try again.";
            log.debug(errMessage);
            status = WSIServerStatus.MALFORMED_URL;
            return false;
        } catch (IllegalStateException e) {
            errMessage = "This communications protocol is not supported.\nPlease contact your systems administrator.";
            log.debug(errMessage);
            status = WSIServerStatus.MALFORMED_URL;
            return false;
        } catch (Exception e) {
            errMessage = "The URL you specified exists, but does not appear to be a Tellervo webservice.\nPlease check and try again.";
            log.debug(errMessage);
            status = WSIServerStatus.URL_NOT_TELLERVO_WS;
            return false;
        } finally {
            try {
                if (dis != null) {
                    dis.close();
                }
            } catch (IOException e) {
            }
        }

        status = WSIServerStatus.URL_NOT_TELLERVO_WS;

        return false;

    }

    /**
     * Get the status of the Tellervo server
     * @return
     */
    public WSIServerStatus getWSIServerStatus() {
        return status;
    }

    private void parserThisServerVersion(String str) throws Exception {
        String[] versionparts = VersionUtil.parseVersionStr(str);

        try {
            if (versionparts.length >= 1) {
                majorversion = Integer.parseInt(versionparts[0]);
            }
            if (versionparts.length >= 2) {
                minorversion = Integer.parseInt(versionparts[1]);
            }
            if (versionparts.length >= 3) {
                revision = versionparts[2];
            }
        } catch (NumberFormatException e) {
            throw new Exception("Server version is invalid");
        }

        isServerValid();

    }

    /**
     * Get the Tellervo server version as a full string
     * 
     * @return
     */
    public String getWSIVersion() {
        String str = "";

        if (!majorversion.equals("")) {
            str += majorversion;
        }
        if (!minorversion.equals("")) {
            str += "." + minorversion;
        }
        if (!revision.equals("")) {
            str += "." + revision;
        }

        return str;

    }

    /**
     * Is the server a valid Tellervo WS?
     * 
     * @return
     */
    public Boolean isServerValid() {
        return isServerValid(Build.earliestServerVersionSupported);
    }

    public Boolean isServerValid(String earliestServerVersionSupported) {
        log.debug("Checking if server is valid...");

        if (status == WSIServerStatus.VALID) {
            try {
                String[] earliestServerVersion = VersionUtil.parseVersionStr(earliestServerVersionSupported);
                Integer earliestMajor = null;
                Integer earliestMinor = null;
                String earliestRevision = null;

                if (earliestServerVersion.length >= 1) {
                    earliestMajor = Integer.parseInt(earliestServerVersion[0]);
                }
                if (earliestServerVersion.length >= 2) {
                    earliestMinor = Integer.parseInt(earliestServerVersion[1]);
                }
                if (earliestServerVersion.length >= 3) {
                    earliestRevision = earliestServerVersion[2];
                }

                log.debug("Earliest server version accepted is : " + earliestMajor + " . " + earliestMinor + " . "
                        + earliestRevision);
                log.debug("Actual server version is            : " + majorversion + " . " + minorversion + " . "
                        + revision);

                Boolean success = VersionUtil.compareVersionNumbers(earliestMajor, earliestMinor, earliestRevision,
                        majorversion, minorversion, revision);

                if (success) {
                    log.debug("Server is valid");
                    return true;
                }

                setTooOldErrorMessage();

            } catch (Exception e) {
                errMessage = "Supported server versions not specified correctly in code";
                log.debug(errMessage);
                return false;
            }

        }

        log.debug("Server is NOT valid");
        log.debug("Server status is " + status.toString());
        return false;

    }

    private void setTooOldErrorMessage() {
        log.debug("Server too old!");
        errMessage = "The version of the Tellervo server (" + getWSIVersion() + ") that\n"
                + "you are trying to connect to is too old for this client.\n" + "The server needs to be version "
                + Build.earliestServerVersionSupported + " or later.";
        log.debug(errMessage);
        status = WSIServerStatus.TOO_OLD;
    }

    public String getErrorMessage() {
        return errMessage;
    }

    /**
     * Get the major version number for the server
     * 
     * @return
     */
    public Integer getMajorVersion() {
        return majorversion;
    }

    /**
     * Get the minor version number for the server
     * 
     * @return
     */
    public Integer getMinorVersion() {
        return minorversion;
    }

    /**
     * Get the revision number for the server
     * @return
     */
    public String getRevision() {
        return revision;
    }
}