cn.dockerfoundry.ide.eclipse.server.ui.internal.ServerWizardValidator.java Source code

Java tutorial

Introduction

Here is the source code for cn.dockerfoundry.ide.eclipse.server.ui.internal.ServerWizardValidator.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014 Pivotal Software, Inc. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of 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.
 *  
 *  Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 ********************************************************************************/
package cn.dockerfoundry.ide.eclipse.server.ui.internal;

import javax.net.ssl.SSLPeerUnverifiedException;

import org.cloudfoundry.client.lib.CloudFoundryOperations;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;

import cn.dockerfoundry.ide.eclipse.server.core.internal.DockerFoundryPlugin;
import cn.dockerfoundry.ide.eclipse.server.core.internal.DockerFoundryServer;
import cn.dockerfoundry.ide.eclipse.server.core.internal.Messages;
import cn.dockerfoundry.ide.eclipse.server.core.internal.ValidationEvents;

/**
 * Performs both local and remote server validation of server account details
 * for a given Cloud Foundry server instance ( {@link DockerFoundryServer} ),
 * like credentials and cloud spaces, as well as handling self-signed errors
 * when remote server authorisations are attempted.
 * 
 */
public abstract class ServerWizardValidator implements ServerValidator {

    private final DockerFoundryServer cfServer;

    //   private final CloudSpacesDelegate cloudServerSpaceDelegate;

    /**
     * The Server validator acts as an event source (it generates events)
     */
    private final IEventSource<ServerWizardValidator> validatorEventSource = new IEventSource<ServerWizardValidator>() {

        public ServerWizardValidator getSource() {
            return ServerWizardValidator.this;
        }
    };

    // Session cache as long as the validator is used, as to not keep
    // prompting the user multiple times
    private boolean acceptSelfSigned = true;

    public ServerWizardValidator(DockerFoundryServer cloudServer) {
        this.cfServer = cloudServer;
        //      this.cloudServerSpaceDelegate = cloudServerSpaceDelegate;
    }

    //   public CloudSpacesDelegate getSpaceDelegate() {
    //      return cloudServerSpaceDelegate;
    //   }

    public DockerFoundryServer getCloudFoundryServer() {
        return cfServer;
    }

    /**
     * Can be run outside of UI thread. Does a local validation without
     * connecting to the server. It is mean to do a local check of credentials
     * (e.g. acceptable credential values), but not validate against the server.
     * 
     * @param validateAgainstServer
     * @param handle
     * @return
     */
    public ValidationStatus localValidation() {
        return validate(false, true, null);
    }

    /**
     * Note that this will be run in the UI thread.
     * 
     * @see cn.dockerfoundry.ide.eclipse.server.ui.internal.editor.ServerValidator
     * #validate(boolean, org.eclipse.jface.operation.IRunnableContext)
     */
    public synchronized ValidationStatus validate(boolean validateAgainstServer, boolean validateSpace,
            IRunnableContext runnableContext) {
        ValidationStatus status = serverValidation(validateAgainstServer, validateSpace, runnableContext);

        // If validating against server, also check self-signed errors.
        if (validateAgainstServer) {
            status = checkSelfSigned(status, runnableContext);
            if (status != null && status.getStatus().isOK()) {
                status = serverValidation(validateAgainstServer, validateSpace, runnableContext);
            }
        }

        return status;
    }

    /**
     * 
     * @param status containing possible self-signed information. If null, no
     * further checks or validation will occur
     * @param context
     * @return {@link IStatus#OK} if self-signed was accepted. IStatus.ERROR if
     * Null if initial status is also null.
     */
    protected ValidationStatus checkSelfSigned(final ValidationStatus status, final IRunnableContext context) {
        // If not status is passes that may contain self-signed information, no
        // further validation is possible
        if (status == null) {
            return null;
        }
        final ValidationStatus[] validationStatus = new ValidationStatus[] { status };

        IStatus iStatus = validationStatus[0].getStatus();

        if (validationStatus[0].getEventType() == ValidationEvents.SELF_SIGNED
                && iStatus.getException() instanceof SSLPeerUnverifiedException) {

            Display.getDefault().syncExec(new Runnable() {

                public void run() {

                    // Now check if for this server URL there is a stored
                    // value
                    // indicating whether to user self-signed certs or not.
                    boolean storedSelfSign = cfServer.getSelfSignedCertificate();

                    if (!storedSelfSign) {
                        String message = NLS.bind(Messages.WARNING_SELF_SIGNED_PROMPT_USER, cfServer.getUrl());

                        if (MessageDialog.openQuestion(Display.getDefault().getActiveShell(),
                                Messages.TITLE_SELF_SIGNED_PROMPT_USER, message)) {
                            acceptSelfSigned = true;
                        }
                    } else {
                        acceptSelfSigned = storedSelfSign;
                    }

                    // Re-validate if the user has selected to continue with
                    // self-signed certificate
                    if (acceptSelfSigned) {
                        validationStatus[0] = new ValidationStatus(Status.OK_STATUS, ValidationEvents.VALIDATION);
                    } else {
                        // If user selected not to accept self-signed server, no
                        // further validation
                        // can be possible. Indicate this as an error
                        validationStatus[0] = new ValidationStatus(
                                DockerFoundryPlugin
                                        .getErrorStatus(Messages.ERROR_UNABLE_CONNECT_SERVER_CREDENTIALS),
                                ValidationEvents.SELF_SIGNED);
                    }
                }
            });
        }

        // Always update the value in the server. For example, if a
        // previous run has determined that this URL needs
        // self-signed
        // certificate
        // but no SSL error was thrown, it means that Server
        // condition
        // has changed (i.e it no longer needs the certificate).
        cfServer.setSelfSignedCertificate(acceptSelfSigned);
        return validationStatus[0];
    }

    /**
     * Validates the server credentials and URL using a standalone disposable
     * Java client ( {@link CloudFoundryOperations} ).
     * @param validateAgainstServer true if credentials should be validated
     * against a server. False if validation should be local (e.g. checking
     * credential and URL syntax)
     * @param runnableContext
     * @return non-null validation status.
     */
    protected ValidationStatus serverValidation(boolean validateAgainstServer, boolean validateSpace,
            IRunnableContext runnableContext) {

        // Check for valid username, password, and server URL syntax first
        // before attempting a remote validation
        ValidationStatus validationStatus = validateLocally();

        String userName = cfServer.getUsername();
        String password = cfServer.getPassword();
        String url = cfServer.getUrl();

        IStatus eventStatus = null;

        if (validationStatus.getStatus().isOK()) {

            // If credentials changed, clear the space descriptor. If a server
            // validation is required later on
            // the new credentials will be validated and a new descriptor will
            // be obtained.
            //         if (!cloudServerSpaceDelegate.matchesCurrentDescriptor(url, userName, password)) {
            //            cloudServerSpaceDelegate.clearDescriptor();
            //         }

            try {

                // Space validation also validates credentials, so if request is made
                // to validate space, there is no need to do a separate credential validation.
                /*if (validateSpace) {
                   cloudServerSpaceDelegate.resolveDescriptor(url, userName, password, acceptSelfSigned, runnableContext,
                 validateAgainstServer);
                }
                else */if (validateAgainstServer) {
                    // If validation is requested but not space validation.
                    // Indicate that the URL may be a display URL (in which case
                    // the validation will convert
                    // it to an actual URL)
                    boolean displayURL = true;
                    CloudUiUtil.validateCredentials(cfServer, userName, password, url, displayURL, acceptSelfSigned,
                            runnableContext);
                }

            } catch (CoreException e) {
                // Even if an error occurred, classify the event as a validaiton
                // event, UNLESS it is a
                // self-signed error
                int eventType = ValidationEvents.VALIDATION;
                if (e.getCause() instanceof javax.net.ssl.SSLPeerUnverifiedException) {
                    eventType = ValidationEvents.SELF_SIGNED;
                }
                eventStatus = e.getStatus();
                validationStatus = getValidationStatus(eventStatus, eventType);
            } catch (OperationCanceledException oce) {
                eventStatus = null;
                validationStatus = getValidationStatus(Status.OK_STATUS, ValidationEvents.EVENT_NONE);
            }

        }
        return validationStatus;

    }

    protected ValidationStatus getValidationStatus(int statusType, String validationMessage, int eventType) {
        IStatus status = DockerFoundryPlugin.getStatus(validationMessage, statusType);
        return getValidationStatus(status, eventType);
    }

    protected ValidationStatus getValidationStatus(IStatus status, int eventType) {
        return new ServerWizardValidationStatus(status, eventType);
    }

    /**
     * 
     * @return status of local validation of account information, without
     * requiring connection to a remote Cloud Foundry server. Should not be used
     * for long running validation. Must not return null status.
     */
    protected abstract ValidationStatus validateLocally();

    /**
     * Local validation of account values. Checks if any values (like username,
     * password, or server URL) are missing or have incorrect syntax.
     * <p/>
     * Does not attempt to authorise the account against the server.
     * @return non-null local validation status.
     */

    private class ServerWizardValidationStatus extends ValidationStatus implements IAdaptable {

        public ServerWizardValidationStatus(IStatus status, int eventType) {
            super(status, eventType);
        }

        @SuppressWarnings("rawtypes")
        public Object getAdapter(Class clazz) {
            if (clazz.equals(PartChangeEvent.class)) {
                return new PartChangeEvent(null, getStatus(), validatorEventSource, getEventType());
            }
            return null;
        }
    }
}