org.eclipse.cft.server.core.internal.CloudErrorUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cft.server.core.internal.CloudErrorUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2015 Pivotal Software, Inc. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution. 
 * 
 * The Eclipse Public License is available at 
 * 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * and the Apache License v2.0 is available at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * You may elect to redistribute this code under either of these licenses.
 *  
 *  Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 *     Keith Chong, IBM - Support more general branded server type IDs.   Moved isCloudFoundryServer to CloudServerUtil.
 ********************************************************************************/
package org.eclipse.cft.server.core.internal;

import java.io.IOException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.websocket.DeploymentException;

import org.cloudfoundry.client.lib.CloudFoundryException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestClientException;

/**
 * Utility to detect various types of HTTP errors, like 400 Bad Request errors.
 * 
 */
public class CloudErrorUtil {

    private CloudErrorUtil() {
        // Util class
    }

    /**
     * Parses a error message if and only if the error is due to a request
     * failure because of a connection error. For example, if a request failed
     * due to 401, 403, or unknown host errors. Returns null otherwise.
     * @param e error to check if it is a connection error.
     * @return User-friendly error message IFF the error is due to a connection
     * error that resulted in a failed request to the server. Return null
     * otherwise.
     */
    public static String getConnectionError(CoreException e) {

        String error = getInvalidCredentialsError(e);
        if (error == null) {
            if (isUnknownHostException(e)) {
                error = Messages.ERROR_UNABLE_TO_ESTABLISH_CONNECTION_UNKNOWN_HOST;
            } else if (isRestClientException(e)) {
                error = NLS.bind(Messages.ERROR_FAILED_REST_CLIENT, e.getMessage());
            }
        }

        return error;
    }

    public static boolean isWebsocketDeploymentException(CoreException e) {
        if (e == null || e.getCause() == null) {
            return false;
        }
        Throwable t = e.getCause();
        return t instanceof DeploymentException || t.getCause() instanceof DeploymentException;
    }

    public static CoreException checkRestException(Throwable t) {
        String error = getInvalidCredentialsError(t);
        if (error == null) {

            if (t instanceof ResourceAccessException && t.getCause() instanceof UnknownHostException) {
                error = Messages.ERROR_UNABLE_TO_ESTABLISH_CONNECTION_UNKNOWN_HOST;
            } else if (t instanceof RestClientException) {
                error = NLS.bind(Messages.ERROR_FAILED_REST_CLIENT, t.getMessage());
            }

        }
        return error != null ? toCoreException(error, t) : toCoreException(t);
    }

    /**
     * If the error is a server communication error, it wraps it in a
     * {@link CoreException} with user-friendly message. If the server
     * communciation error is due to {@link SSLPeerUnverifiedException}, the
     * latter is set as the cause for the wrapped CoreException. Otherwise,
     * returns the error as the cause in a CoreException. Always returns a
     * {@link CoreException}.
     * @param e
     * @return CoreException wrapper if communication error with server, or
     * otherwise return CoreException with original error as cause. Never null.
     * 
     */
    public static CoreException checkServerCommunicationError(RuntimeException e) {
        if (e != null && e.getCause() instanceof IOException) {
            // Set the cause for SSL
            if ((e.getCause() instanceof SSLPeerUnverifiedException)) {
                return toCoreException(e.getCause());
            } else {
                // Log other IO errors.
                String errorMessage = NLS.bind(Messages.ERROR_UNABLE_TO_COMMUNICATE_SERVER, e.getMessage());
                CloudFoundryPlugin.logError(errorMessage, e);
                return new CoreException(new Status(IStatus.ERROR, CloudFoundryPlugin.PLUGIN_ID, errorMessage));
            }
        } else {
            return checkRestException(e);
        }
    }

    /**
     * True if a request error occurred due to connection issues. For example,
     * 401, 403, or unknown host.
     * @param e error to check if it is a connection error.
     * @return true if a request error occurred due to connection issues. False
     * otherwise
     */
    public static boolean isConnectionError(CoreException e) {
        return getConnectionError(e) != null;
    }

    /**
     * Error due to invalid credentials, typically 401 or 403 HTTP errors.
     * Returns null if the error is NOT an invalid credentials error.
     * @param error error to parse
     * @return Error message if invalid credentials error (401 or 403), or null.
     */
    public static String getInvalidCredentialsError(Throwable error) {
        if (isUnauthorisedException(error)) {
            return Messages.ERROR_WRONG_EMAIL_OR_PASSWORD_UNAUTHORISED;
        } else if (isForbiddenException(error)) {
            return Messages.ERROR_WRONG_EMAIL_OR_PASSWORD_FORBIDDEN;
        } else {
            OAuth2AccessDeniedException oauthException = null;

            if (error instanceof OAuth2AccessDeniedException) {
                oauthException = (OAuth2AccessDeniedException) error;
            } else if (error.getCause() instanceof OAuth2AccessDeniedException) {
                oauthException = (OAuth2AccessDeniedException) error.getCause();
            }
            if (oauthException != null) {
                return NLS.bind(Messages.ERROR_ACCESS_TOKEN, oauthException.getOAuth2ErrorCode());
            }
        }
        return null;
    }

    // check if error is caused by wrong credentials
    public static boolean isWrongCredentialsException(CoreException e) {
        Throwable cause = e.getCause();
        if (cause instanceof HttpClientErrorException) {
            HttpClientErrorException httpException = (HttpClientErrorException) cause;
            HttpStatus statusCode = httpException.getStatusCode();
            if (statusCode.equals(HttpStatus.FORBIDDEN) && httpException instanceof CloudFoundryException) {
                return ((CloudFoundryException) httpException).getDescription().equals("Operation not permitted"); //$NON-NLS-1$
            }
        }
        return false;
    }

    public static boolean isAppStoppedStateError(Exception e) {
        HttpClientErrorException badRequestException = getBadRequestException(e);
        if (badRequestException != null) {
            String message = getHttpErrorMessage(badRequestException);

            if (message != null) {
                message = message.toLowerCase();
                return message.contains("state") && message.contains("stop"); //$NON-NLS-1$ //$NON-NLS-2$
            }
        }
        return false;
    }

    public static boolean is503Error(Throwable t) {
        HttpServerErrorException httpException = getHttpServerError(t);

        if (httpException != null) {
            String message = getHttpErrorMessage(httpException);

            if (message != null) {
                message = message.toLowerCase();
                return message.contains("503"); //$NON-NLS-1$
            }
        }
        return false;
    }

    public static String getHostTakenError(Exception e) {
        HttpClientErrorException badRequestException = getBadRequestException(e);
        if (badRequestException != null) {
            String message = getHttpErrorMessage(badRequestException);

            if (message != null) {
                message = message.toLowerCase();
                if (message.contains("host") && message.contains("taken")) { //$NON-NLS-1$ //$NON-NLS-2$
                    return Messages.ERROR_HOST_TAKEN;
                }
            }
        }
        return null;
    }

    /**
     * 
     * @param error
     * @return Error message containing description of the error. If no
     * description is found, it will return the exception error or HTTP status
     * text message, if present. May return null if no message can be resolved.
     */
    protected static String getHttpErrorMessage(HttpStatusCodeException error) {
        String message = null;
        if (error instanceof CloudFoundryException) {
            message = ((CloudFoundryException) error).getDescription();
        }

        if (message == null) {
            message = error.getMessage();
            if (message == null) {
                message = error.getStatusText();
                if (message == null) {
                    message = error.getResponseBodyAsString();
                }
            }
        }
        return message;
    }

    public static boolean isFileNotFoundForInstance(Exception e) {
        HttpClientErrorException badRequestException = getBadRequestException(e);
        if (badRequestException != null) {
            String message = getHttpErrorMessage(badRequestException);

            if (message != null) {
                message = message.toLowerCase();
                return message.contains("file error") && message.contains("request failed") //$NON-NLS-1$ //$NON-NLS-2$
                        && message.contains("as the instance is not found"); //$NON-NLS-1$
            }
        }
        return false;
    }

    public static boolean isRequestedFileRangeNotSatisfiable(CloudFoundryException cfe) {
        return cfe != null && HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.equals(cfe.getStatusCode());
    }

    /**
     * 
     * @param e to check if it is a Bad Request 400 HTTP Error.
     * @return determines if the given exception is a Bad Request 400 Exception.
     * If so, returns it the corresponding HttpClientErrorException. Otherwise
     * returns null.
     */
    public static HttpClientErrorException getBadRequestException(Exception t) {
        HttpClientErrorException httpException = getHttpClientError(t);
        if (httpException != null) {
            HttpStatus statusCode = httpException.getStatusCode();
            if (HttpStatus.BAD_REQUEST.equals(statusCode)) {
                return httpException;
            }
        }
        return null;
    }

    protected static HttpClientErrorException getHttpClientError(Throwable t) {
        if (t == null) {
            return null;
        }
        HttpClientErrorException httpException = null;
        if (t instanceof HttpClientErrorException) {
            httpException = (HttpClientErrorException) t;
        } else {
            Throwable cause = t.getCause();
            if (cause instanceof HttpClientErrorException) {
                httpException = (HttpClientErrorException) cause;
            }
        }
        return httpException;

    }

    protected static HttpServerErrorException getHttpServerError(Throwable t) {
        if (t == null) {
            return null;
        }
        HttpServerErrorException httpException = null;
        if (t instanceof HttpServerErrorException) {
            httpException = (HttpServerErrorException) t;
        } else {
            Throwable cause = t.getCause();
            if (cause instanceof HttpServerErrorException) {
                httpException = (HttpServerErrorException) cause;
            }
        }
        return httpException;

    }

    public static CoreException toCoreException(Throwable e) {
        if (e instanceof CloudFoundryException) {
            if (((CloudFoundryException) e).getDescription() != null) {
                return new CoreException(
                        new Status(IStatus.ERROR, CloudFoundryPlugin.PLUGIN_ID, NLS.bind("{0} ({1})", //$NON-NLS-1$
                                ((CloudFoundryException) e).getDescription(), e.getMessage()), e));
            }
        }
        return new CoreException(new Status(IStatus.ERROR, CloudFoundryPlugin.PLUGIN_ID,
                NLS.bind(Messages.ERROR_PERFORMING_CLOUD_FOUNDRY_OPERATION, e.getMessage()), e));
    }

    /**
     * Checks if it is a {@link SSLPeerUnverifiedException} and returns a
     * wrapped CoreException around the {@link SSLPeerUnverifiedException}
     * @param ce
     * @return CoreException (either original or wrapper if the original
     * contains {@link SSLPeerUnverifiedException})
     */
    public static CoreException checkSSLPeerUnverifiedException(CoreException ce) {
        if (ce.getCause() instanceof ResourceAccessException
                && ce.getCause().getCause() instanceof javax.net.ssl.SSLPeerUnverifiedException) {
            return toCoreException(ce.getCause().getCause());
        } else {
            return ce;
        }
    }

    /**
     * check 403 error due to invalid credentials
     * @param t
     * @return true if 403. False otherwise
     */
    public static boolean isForbiddenException(Throwable t) {
        return isHttpException(t, HttpStatus.FORBIDDEN);
    }

    /**
     * check 401 error due to invalid credentials
     * @param t
     * @return true if 401. False otherwise
     */
    public static boolean isUnauthorisedException(Throwable t) {
        return isHttpException(t, HttpStatus.UNAUTHORIZED);
    }

    /**
     * check 404 error.
     * @param t
     * @return true if 404 error. False otherwise
     */
    public static boolean isNotFoundException(Throwable t) {
        return isHttpException(t, HttpStatus.NOT_FOUND);
    }

    public static boolean isHttpException(Throwable t, HttpStatus status) {

        HttpClientErrorException httpException = getHttpClientError(t);

        if (httpException != null) {
            HttpStatus statusCode = httpException.getStatusCode();
            return statusCode.equals(status);
        }

        return false;
    }

    public static boolean isUnknownHostException(CoreException e) {
        Throwable cause = e.getStatus().getException();
        if (cause instanceof ResourceAccessException) {
            return ((ResourceAccessException) cause).getCause() instanceof UnknownHostException;
        }
        return false;
    }

    public static boolean isRestClientException(CoreException e) {
        Throwable cause = e.getStatus().getException();
        return cause instanceof RestClientException;
    }

    public static CoreException toCoreException(String message) {
        return toCoreException(message, null);
    }

    public static CoreException toCoreException(String message, Throwable error) {
        if (message == null) {
            message = Messages.ERROR_UNKNOWN;
        }
        if (error != null) {
            if (error.getMessage() != null) {
                message += " - " + error.getMessage(); //$NON-NLS-1$
            }
            return new CoreException(CloudFoundryPlugin.getErrorStatus(message, error));
        } else {
            return new CoreException(CloudFoundryPlugin.getErrorStatus(message));
        }
    }

    /**
     * Wraps the given error as a {@link CoreException} under these two
     * conditions:
     * 
     * <p/>
     * 1. Additional error message is provided that should be added to the
     * CoreException. If the error is already a CoreException, the cause of the
     * error will be added to the new CoreException
     * <p/>
     * 2. If no error message is provided, and the error is not a CoreException,
     * a new CoreExpception will be created with the error as the cause.
     * <p/>
     * Otherwise, if the error already is a CoreException and no additional
     * message is provided, the same CoreException is returned.
     * @param message optional. Additional message to add to the CoreException.
     * @param error must not be null
     * @param replaceMessage true if existing messages in the error should be
     * replaced by the given message. False if given message should be appended
     * to existing message
     * @return error as {@link CoreException}, with the additional error message
     * added if provided.
     */
    public static CoreException asCoreException(String message, Throwable error, boolean replaceMessage) {

        if (message != null) {

            IStatus oldStatus = error instanceof CoreException ? ((CoreException) error).getStatus() : null;

            IStatus newStatus = null;
            if (oldStatus == null) {
                newStatus = CloudFoundryPlugin.getErrorStatus(message, error);
            } else {
                String enhancedMessage = replaceMessage ? message : message + " - " + oldStatus.getMessage(); //$NON-NLS-1$
                newStatus = new Status(oldStatus.getSeverity(), oldStatus.getPlugin(), oldStatus.getCode(),
                        enhancedMessage, oldStatus.getException());
            }

            return new CoreException(newStatus);
        } else {
            if (error instanceof CoreException) {
                return (CoreException) error;
            } else {
                return new CoreException(CloudFoundryPlugin.getErrorStatus(error));
            }
        }
    }

    public static String getCloudFoundryErrorMessage(CloudFoundryException cfe) {
        return cfe.getMessage();
    }

    public static String getMessage(CoreException ce) {
        return ce.getMessage();
    }

}