com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeystorePage.java Source code

Java tutorial

Introduction

Here is the source code for com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeystorePage.java

Source

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;

import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;

import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;

public class CreateKeystorePage extends WizardPage {

    private static final String CREATE_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID + ".new_keystore"; //$NON-NLS-1$

    private Text keystoreFilenameText;

    private ComboViewer keystoreTypeComboViewer;

    private Text keystorePasswordText;

    private Text keystoreConfirmPasswordText;

    private String keystorePassword;

    private boolean initialValidation = true;

    private boolean userChangedPasswordConfirmation = false;

    private boolean userChangedPassword = false;

    SelectionListener selectionListener = new SelectionListener() {

        @Override
        public void widgetSelected(SelectionEvent e) {
            validatePage();
        }

        @Override
        public void widgetDefaultSelected(SelectionEvent e) {
            //nothing to do...
        }
    };

    private Button savePassword;

    private Button useTypeAsExtensionCheckBox;

    protected boolean useTypeAsExtensionCheckBoxPreviousState = true;

    /**
     * @param pageName
     */
    protected CreateKeystorePage(String pageName) {
        super(pageName);
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
     */
    @Override
    public void createControl(Composite parent) {
        Composite mainComposite = new Composite(parent, SWT.FILL);
        mainComposite.setLayout(new GridLayout(3, false));
        mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));

        setTitle(CertificateManagerNLS.CreateKeystorePage_CreateKeystore);
        setMessage(CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage);

        createFilenameSection(mainComposite);
        createKeystoreTypeSection(mainComposite);
        createFilenameExtensionSection(mainComposite);

        setKeystoreFilenameExtension();

        //LINE TO SEPARATE PASSWORD SECTION FROM KEYSTORE DETAILS SECTION
        Label separator1 = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

        createKeystorePasswordSection(mainComposite);
        createConfirmPasswordSection(mainComposite);
        createSavePasswordSection(mainComposite);

        validatePage();

        setControl(mainComposite);

        //set help id for this page
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, CREATE_KEYSTORE_HELP_ID);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, CREATE_KEYSTORE_HELP_ID);
    }

    /**
     * @param mainComposite
     */
    private void createKeystoreTypeSection(Composite parent) {
        Label keystoreTypeLabel = new Label(parent, SWT.NONE);
        keystoreTypeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
        keystoreTypeLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreType);

        keystoreTypeComboViewer = new ComboViewer(parent, SWT.READ_ONLY);
        keystoreTypeComboViewer.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false, 1, 1));
        keystoreTypeComboViewer.setContentProvider(new IStructuredContentProvider() {

            @Override
            public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
                //do nothing
            }

            @Override
            public void dispose() {
                //do nothing
            }

            @SuppressWarnings("unchecked")
            @Override
            public Object[] getElements(Object inputElement) {
                return ((List<String>) inputElement).toArray();
            }
        });
        keystoreTypeComboViewer.setLabelProvider(new ILabelProvider() {

            @Override
            public void removeListener(ILabelProviderListener listener) {
                //do nothing
            }

            @Override
            public boolean isLabelProperty(Object element, String property) {
                return false;
            }

            @Override
            public void dispose() {
                //do nothing
            }

            @Override
            public void addListener(ILabelProviderListener listener) {
                //do nothing
            }

            @Override
            public String getText(Object element) {
                return (String) element;
            }

            @Override
            public Image getImage(Object element) {
                return null;
            }
        });

        keystoreTypeComboViewer.setInput(KeyStoreManager.getInstance().getAvailableTypes());

        keystoreTypeComboViewer.getCombo().addSelectionListener(new SelectionAdapter() {
            /* (non-Javadoc)
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                useTypeAsExtensionCheckBox.setEnabled(true);
                useTypeAsExtensionCheckBox.setSelection(useTypeAsExtensionCheckBoxPreviousState);

                if (useTypeAsExtensionCheckBox.getSelection()) {
                    setKeystoreFilenameExtension();
                }
            }
        });

        for (int i = 0; i < keystoreTypeComboViewer.getCombo().getItemCount(); i++) {
            if (keystoreTypeComboViewer.getCombo().getItem(i)
                    .compareToIgnoreCase(KeyStoreManager.getInstance().getDefaultType()) == 0) {
                keystoreTypeComboViewer.getCombo().select(i);
            }
        }

        keystoreTypeComboViewer.getCombo().addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent e) {
                if (useTypeAsExtensionCheckBox != null) {
                    useTypeAsExtensionCheckBox.setEnabled(false);
                    useTypeAsExtensionCheckBox.setSelection(false);
                }
            }
        });

        //fill the third column with a blank label
        Label separator2 = new Label(parent, SWT.NONE);
        separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
    }

    /**
     * Set the extension of the keystore based on selected keystore type and the user's choice to use it or not as the extension.
     * If the user typed a custom keystore type, then the filename extension is set to ".keystore".
     * */
    protected void setKeystoreFilenameExtension() {
        String keystoreFilename = keystoreFilenameText.getText();
        String keystoreType = keystoreTypeComboViewer.getCombo().getText();

        List<String> availableTypes = KeyStoreManager.getInstance().getAvailableTypes();
        availableTypes.add(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilenameExtension);

        for (String availableType : availableTypes) {
            String availableTypeExtension = "." + availableType.toLowerCase(); //$NON-NLS-1$
            if (keystoreFilename.endsWith(availableTypeExtension)) {
                keystoreFilename = keystoreFilename.substring(0,
                        keystoreFilename.length() - availableTypeExtension.length());
                break;
            }
        }

        keystoreFilenameText.setText(keystoreFilename + "." + keystoreType.toLowerCase()); //$NON-NLS-1$
    }

    private void createFilenameExtensionSection(Composite mainComposite) {
        useTypeAsExtensionCheckBox = new Button(mainComposite, SWT.CHECK);
        useTypeAsExtensionCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
        useTypeAsExtensionCheckBox.setText(CertificateManagerNLS.CreateKeystorePage_UseKeystoreTypeAsExtension);
        useTypeAsExtensionCheckBox.setSelection(true);

        useTypeAsExtensionCheckBox.addSelectionListener(new SelectionAdapter() {
            /* (non-Javadoc)
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                useTypeAsExtensionCheckBoxPreviousState = useTypeAsExtensionCheckBox.getSelection();
                if (useTypeAsExtensionCheckBox.getSelection()) {
                    setKeystoreFilenameExtension();
                }
            }
        });
    }

    /**
     * @param mainComposite
     */
    private void createSavePasswordSection(Composite mainComposite) {
        savePassword = new Button(mainComposite, SWT.CHECK);
        savePassword.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
        savePassword.setText(CertificateManagerNLS.CreateKeystorePage_SaveThisPassword);
        savePassword.setSelection(false);
    }

    /**
     * @param mainComposite
     */
    private void createConfirmPasswordSection(Composite mainComposite) {
        Label keystoreConfirmPasswordLabel = new Label(mainComposite, SWT.NONE);
        keystoreConfirmPasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
        keystoreConfirmPasswordLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreConfirmPasswordLabel);

        keystoreConfirmPasswordText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
        keystoreConfirmPasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        keystoreConfirmPasswordText.addSelectionListener(selectionListener);
        keystoreConfirmPasswordText.addModifyListener(new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent e) {
                userChangedPasswordConfirmation = true;
                validatePage();
            }
        });

        //fill the third column with a blank label
        Label separator2 = new Label(mainComposite, SWT.NONE);
        separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
    }

    /**
     * @param mainComposite
     */
    private void createKeystorePasswordSection(Composite mainComposite) {
        Label keystorePasswordLabel = new Label(mainComposite, SWT.NONE);
        keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
        keystorePasswordLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystorePasswordLabel);

        keystorePasswordText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
        keystorePasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        keystorePasswordText.addSelectionListener(selectionListener);
        keystorePasswordText.addModifyListener(new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent e) {
                keystorePassword = keystorePasswordText.getText();
                userChangedPassword = true;
                validatePage();
            }
        });

        //fill the third column with a blank label
        @SuppressWarnings("unused")
        Label separator = new Label(mainComposite, SWT.NONE);
        keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
    }

    /**
     * @param mainComposite
     */
    private void createFilenameSection(Composite mainComposite) {
        Label keystoreFilenameLabel = new Label(mainComposite, SWT.NONE);
        keystoreFilenameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
        keystoreFilenameLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameLabel);

        keystoreFilenameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
        keystoreFilenameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        keystoreFilenameText.setText(generateKeyStoreFilename());
        keystoreFilenameText.addSelectionListener(selectionListener);
        keystoreFilenameText.addModifyListener(new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent e) {
                validatePage();
            }
        });

        Button chooseLocation = new Button(mainComposite, SWT.PUSH);
        chooseLocation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
        chooseLocation.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameBrowse);
        chooseLocation.addSelectionListener(new SelectionAdapter() {
            /* (non-Javadoc)
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                Shell shell = Display.getCurrent().getActiveShell();

                FileDialog dialog = new FileDialog(shell, SWT.SAVE);

                String keystoreFilenameStr = dialog.open();

                if (keystoreFilenameStr != null) {
                    keystoreFilenameText.setText(keystoreFilenameStr);
                }
            }
        });
    }

    private void validatePage() {
        boolean pageComplete = true;

        String errorMessage = null;

        String message = CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage;

        int messageType = IMessageProvider.NONE;

        if (initialValidation == true) {
            //when the wizard opens, does not show any errors
            pageComplete = false;
            initialValidation = false;
        } else {
            //password text and confirmation password text must match
            if (!keystorePasswordText.getText().equals(keystoreConfirmPasswordText.getText())) {
                //if the user hasn't started typing the confirmation password,
                //then just show an info, instead of an error
                if (userChangedPasswordConfirmation) {
                    errorMessage = CertificateManagerNLS.CreateKeystorePage_PasswordDoesNotMatch;
                    pageComplete = false;
                } else {
                    message = CertificateManagerNLS.CreateKeystorePage_ConfirmPasswordInfoMsg;
                    messageType = IMessageProvider.INFORMATION;
                    pageComplete = false;
                }
            }
            //check password size according to keytool specification
            if (keystorePasswordText.getText().length() < KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE) {
                if (userChangedPassword) {
                    errorMessage = CertificateManagerNLS.bind(
                            CertificateManagerNLS.CreateKeystorePage_PasswordMinSizeMessage,
                            KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE); //$NON-NLS-1$
                    pageComplete = false;
                } else {
                    message = CertificateManagerNLS.CreateKeystorePage_SetPasswordInfoMsg;
                    messageType = IMessageProvider.INFORMATION;
                    pageComplete = false;
                }
            }

            //check if store type is filled
            if (keystoreTypeComboViewer.getCombo().getText().isEmpty()) {
                errorMessage = CertificateManagerNLS.CreateKeystorePage_SetKeystoreType;
                pageComplete = false;
            }

            //check if filename is valid
            try {
                File keystoreFile = new File(keystoreFilenameText.getText().trim());
                Path keystorePath = new Path(keystoreFilenameText.getText().trim());
                if (!keystorePath.isValidPath(keystoreFile.getCanonicalPath())) {
                    //throw the same exception as getCanonicalPath() in order to do not duplicate code
                    throw new IOException();
                }
            } catch (IOException e) {
                errorMessage = CertificateManagerNLS.CreateKeystorePage_FilenameSyntaxError;
                pageComplete = false;
            }
            if (keystoreFilenameText.getText().trim().isEmpty()) {
                errorMessage = CertificateManagerNLS.ImportKeystorePage_FilenameCannotBeEmpty;
                pageComplete = false;
            }
        }

        setMessage(message, messageType);
        setErrorMessage(errorMessage);
        setPageComplete(pageComplete);
    }

    /**
     * Generate a valid filename for a new keystore.
     * The file must not exist, so a serial number is added to it as necessary.
     * @return An standard keystore filename.
     * */
    private String generateKeyStoreFilename() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss_SSS"); //$NON-NLS-1$
        String timestamp = dateFormat.format(Calendar.getInstance().getTime());

        //initial keystore filename with timestamp
        String keystoreFilenameStr = System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
                + CertificateManagerNLS.bind(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
                        timestamp);

        File keystoreFile = new File(keystoreFilenameStr);

        //while file already exists, generate a new one using a new timestamp
        while (keystoreFile.exists()) {
            timestamp = dateFormat.format(Calendar.getInstance().getTime());
            keystoreFilenameStr = System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
                    + CertificateManagerNLS.bind(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
                            timestamp);
            keystoreFile = new File(keystoreFilenameStr);
        }

        return keystoreFilenameStr;
    }

    /**
     * As this page works independently of other pages, it has its own version of performFinish().
     * Wizards that use this page must call this method to effectively create the new keystore.
     * @return {@code true} if the keystore were successfully created, {@code false} otherwise. 
     * */
    public KeyStoreNode createKeyStore() {
        boolean successfullyCreated = true;
        File keystoreFile = null;
        KeyStoreNode keystoreNode = null;

        try {
            keystoreFile = new File(keystoreFilenameText.getText().trim());
            if (validateKeyStoreFile(keystoreFile)) {
                keystoreNode = (KeyStoreNode) KeyStoreManager.createKeyStore(keystoreFile,
                        keystoreTypeComboViewer.getCombo().getText(), keystorePasswordText.getText().toCharArray());

                SigningAndKeysModelManager.getInstance().mapKeyStore(keystoreNode);
            } else {
                //file already exist and will not be overwritten
                successfullyCreated = false;
            }
        } catch (KeyStoreManagerException e) {
            //in case of error, the keystore wasn't properly created and the file should not be left on file system
            if (keystoreFile != null) {
                keystoreFile.delete();
            }

            EclipseUtils.showErrorDialog(CertificateManagerNLS.CreateKeystorePage_ErrorCreatingKeystore,
                    NLS.bind(CertificateManagerNLS.CreateKeystorePage_ErrorOnKeyStoreFileCreation,
                            keystoreFilenameText.getText()));
            successfullyCreated = false;
        }

        if (successfullyCreated && savePassword.getSelection()) {
            savePassword(keystoreFile);
        }

        return successfullyCreated ? keystoreNode : null;
    }

    /**
     * @param keystoreFile
     */
    private void savePassword(File keystoreFile) {
        try {
            PasswordProvider passwordProvider = new PasswordProvider(keystoreFile);
            passwordProvider.saveKeyStorePassword(keystorePasswordText.getText());
        } catch (KeyStoreManagerException e) {
            EclipseUtils.showWarningDialog(CertificateManagerNLS.CreateKeystorePage_CouldNotSavePassword,
                    e.getLocalizedMessage());
        }
    }

    /* If file exists and the user chooses to overwrite it, the key store file is valid and return value is true.
     * If file exists and the user do not want to overwrite the file, then the keystore file is considered invalid and the return value is false.
     * If file does not exist, then the file is valid and the return value is true.
     * */
    private boolean validateKeyStoreFile(File keystoreFile) {
        boolean result = true;

        if (keystoreFile.exists()) {
            Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

            result = MessageDialog.openQuestion(shell,
                    CertificateManagerNLS.CreateKeystorePage_ConfirmFileOverwrite,
                    NLS.bind(CertificateManagerNLS.CreateKeystorePage_ConfirmReplaceFile,
                            keystoreFile.getAbsolutePath()));
            if (result) {
                //file will be recreated
                keystoreFile.delete();
            }
        }
        return result;
    }

    public String getPassword() {
        return keystorePassword;
    }

}