org.eclim.installer.step.EclipsePluginsStep.java Source code

Java tutorial

Introduction

Here is the source code for org.eclim.installer.step.EclipsePluginsStep.java

Source

/**
 * Copyright (C) 2005 - 2013  Eric Van Dewoestine
 *
 * 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/>.
 */
package org.eclim.installer.step;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;

import java.awt.event.ActionEvent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

import org.apache.commons.io.FilenameUtils;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;

import org.eclim.installer.step.command.Command;
import org.eclim.installer.step.command.InstallCommand;
import org.eclim.installer.step.command.ListCommand;
import org.eclim.installer.step.command.OutputHandler;

import org.eclim.installer.theme.DesertBlue;

import org.formic.Installer;

import org.formic.util.dialog.gui.GuiDialogs;

import org.formic.wizard.step.gui.InstallStep;

import com.jgoodies.looks.plastic.PlasticTheme;

import foxtrot.Worker;

/**
 * Step which installs necessary third party eclipse plugins.
 *
 * @author Eric Van Dewoestine
 */
public class EclipsePluginsStep extends InstallStep implements OutputHandler {
    private static final String BEGIN_TASK = "beginTask";
    private static final String PREPARE_TASK = "prepare";
    private static final String SUB_TASK = "subTask";
    private static final String INTERNAL_WORKED = "worked";
    private static final String SET_TASK_NAME = "setTaskName";

    private static final Color ERROR_COLOR = new Color(255, 201, 201);

    private String taskName = "";

    private JPanel stepPanel;
    private JPanel featuresPanel;
    private JLabel messageLabel;
    private ImageIcon errorIcon;
    private DefaultTableModel tableModel;
    private List<Dependency> dependencies;
    private Map<String, String> availableFeatures;
    private PlasticTheme theme;
    private int overallProgressStep;

    /**
     * Constructs this step.
     */
    public EclipsePluginsStep(String name, Properties properties) {
        super(name, properties);
    }

    @Override
    public Component init() {
        theme = new DesertBlue();
        stepPanel = (JPanel) super.init();
        stepPanel.setBorder(null);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
        messageLabel = new JLabel();
        messageLabel.setPreferredSize(new Dimension(25, 25));
        panel.add(messageLabel);
        panel.add(stepPanel);
        panel.setBorder(BorderFactory.createEmptyBorder(25, 25, 10, 25));

        return panel;
    }

    private void setMessage(String message) {
        if (errorIcon == null) {
            errorIcon = new ImageIcon(Installer.getImage("form.error.icon"));
        }
        if (message != null) {
            messageLabel.setIcon(errorIcon);
            messageLabel.setText(message);
        } else {
            messageLabel.setIcon(null);
            messageLabel.setText(null);
        }
    }

    @Override
    public void displayed() {
        setBusy(true);
        setPreviousEnabled(false);

        try {
            overallLabel.setText("");
            overallProgress.setValue(0);
            taskLabel.setText("");
            taskProgress.setValue(0);
            taskProgress.setIndeterminate(true);

            // handle step re-entry.
            if (featuresPanel != null) {
                stepPanel.remove(featuresPanel);
            }

            EclipseInfo info = (EclipseInfo) Installer.getContext().getValue("eclipse.info");

            // find chosen features dependencies which need to be installed/upgraded.
            dependencies = unsatisfiedDependencies(info);

            if (dependencies.size() == 0) {
                overallProgress.setMaximum(1);
                overallProgress.setValue(1);
                overallLabel.setText("All third party plugins are up to date.");
                taskProgress.setMaximum(1);
                taskProgress.setValue(1);
                taskLabel.setText("");
            } else {
                tableModel = new DefaultTableModel();
                tableModel.addColumn("Feature");
                tableModel.addColumn("Version");
                tableModel.addColumn("Install / Upgrade");
                JTable table = new JTable(tableModel);
                table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                table.setDefaultRenderer(Object.class, new DependencyCellRenderer());
                table.getSelectionModel().addListSelectionListener(new DependencySelectionListener());

                featuresPanel = new JPanel(new BorderLayout());
                featuresPanel.setAlignmentX(0.0f);

                JPanel container = new JPanel(new BorderLayout());
                container.add(table, BorderLayout.CENTER);

                JScrollPane scrollPane = new JScrollPane(container);
                scrollPane.setAlignmentX(0.0f);

                availableFeatures = loadAvailableFeatures();
                for (Dependency dependency : dependencies) {
                    String version = availableFeatures.get(dependency.getId());
                    String manual = "";
                    if (version == null) {
                        manual = " (Manual)";
                        version = dependency.getRequiredVersion();
                    }
                    tableModel.addRow(new Object[] { dependency.getId(), version,
                            (dependency.isUpgrade() ? "Upgrade" : "Install") + manual, });
                }

                JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
                buttons.setAlignmentX(0.0f);

                JButton skipButton = new JButton(new SkipPluginsAction());
                JButton installButton = new JButton(new InstallPluginsAction(skipButton));

                buttons.add(installButton);
                buttons.add(skipButton);

                featuresPanel.add(scrollPane, BorderLayout.CENTER);
                featuresPanel.add(buttons, BorderLayout.SOUTH);

                stepPanel.add(featuresPanel);
                overallProgress.setValue(0);
                overallLabel.setText("");
                taskProgress.setValue(0);
                taskLabel.setText("");
            }
        } catch (Exception e) {
            setError(e);
        } finally {
            setValid(dependencies != null && dependencies.size() == 0);
            setBusy(false);
            setPreviousEnabled(true);
            taskProgress.setIndeterminate(false);
        }
    }

    public void process(final String line) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (line.startsWith(BEGIN_TASK)) {
                    String l = line.substring(BEGIN_TASK.length() + 2);
                    double work = Double.parseDouble(l.substring(l.indexOf('=') + 1, l.indexOf(' ')));
                    taskProgress.setIndeterminate(false);
                    taskProgress.setMaximum((int) work);
                    taskProgress.setValue(0);
                } else if (line.startsWith(PREPARE_TASK)) {
                    taskLabel.setText(line.substring(PREPARE_TASK.length() + 1).trim());
                } else if (line.startsWith(SUB_TASK)) {
                    taskLabel.setText(taskName + line.substring(SUB_TASK.length() + 1).trim());
                } else if (line.startsWith(INTERNAL_WORKED)) {
                    double worked = Double.parseDouble(line.substring(INTERNAL_WORKED.length() + 2));
                    taskProgress.setValue((int) worked);
                    overallProgress.setValue(overallProgressStep + (int) (taskProgress.getPercentComplete() * 100));
                } else if (line.startsWith(SET_TASK_NAME)) {
                    taskName = line.substring(SET_TASK_NAME.length() + 1).trim() + ' ';
                }
            }
        });
    }

    private List<Dependency> unsatisfiedDependencies(EclipseInfo info) {
        List<Dependency> deps = new ArrayList<Dependency>();
        String[] features = Installer.getContext().getKeysByPrefix("featureList");
        Arrays.sort(features, new FeatureNameComparator());
        for (int ii = 0; ii < features.length; ii++) {
            Boolean enabled = (Boolean) Installer.getContext().getValue(features[ii]);
            if (enabled.booleanValue()) {
                String name = features[ii].substring(features[ii].indexOf('.') + 1);
                deps.addAll(info.getUnsatisfiedDependencies(name));
            }
        }
        return deps;
    }

    @SuppressWarnings("unchecked")
    private Map<String, String> loadAvailableFeatures() throws Exception {
        // load up available features from update sites.
        overallProgress.setMaximum(1);
        overallLabel.setText("Loading available features from update sites...");

        return (Map<String, String>) Worker.post(new foxtrot.Task() {
            public Object run() throws Exception {
                final Map<String, String> availableFeatures = new HashMap<String, String>();

                ArrayList<String> sites = new ArrayList<String>();
                for (Dependency dependency : dependencies) {
                    String site = dependency.getSite();
                    if (site == null) {
                        availableFeatures.put(dependency.getId(), dependency.getRequiredVersion());
                    } else if (!sites.contains(site)) {
                        sites.add(site);
                    }
                }

                OutputHandler handler = new OutputHandler() {
                    public void process(String line) {
                        String[] parts = StringUtils.split(line, "=");
                        if (parts.length == 2 && parts[0].endsWith(".feature.group")) {
                            availableFeatures.put(parts[0].replace(".feature.group", ""), parts[1]);
                        }
                    }
                };
                if (sites.size() > 0) {
                    Command command = new ListCommand(handler, sites.toArray(new String[sites.size()]));
                    try {
                        command.start();
                        command.join();
                        if (command.getReturnCode() != 0) {
                            throw new RuntimeException(
                                    "error: " + command.getErrorMessage() + " out: " + command.getResult());
                        }
                    } finally {
                        command.destroy();
                    }
                }
                return availableFeatures;
            }
        });
    }

    private class InstallPluginsAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        private JButton skipButton;

        public InstallPluginsAction(JButton skipButton) {
            super("Install Features");
            this.skipButton = skipButton;
        }

        public void actionPerformed(ActionEvent e) {
            ((JButton) e.getSource()).setEnabled(false);
            setPreviousEnabled(true);
            try {
                Boolean successful = (Boolean) Worker.post(new foxtrot.Task() {
                    public Object run() throws Exception {
                        // check if any of the features cannot be installed.
                        for (Dependency dependency : dependencies) {
                            Feature feature = dependency.getFeature();
                            if (feature != null) {
                                if (feature.getSite() == null) {
                                    String installLog = FilenameUtils.concat(SystemUtils.JAVA_IO_TMPDIR,
                                            "install.log");
                                    GuiDialogs.showWarning(Installer.getString(
                                            "eclipsePlugins.install.features.site.not.found", installLog));
                                    return Boolean.FALSE;
                                } else if (!feature.getSite().canWrite()) {
                                    GuiDialogs.showWarning(Installer
                                            .getString("eclipsePlugins.install.features.permission.denied"));
                                    return Boolean.FALSE;
                                }
                            }
                        }

                        int installCount = 0;
                        for (Iterator<Dependency> ii = dependencies.iterator(); ii.hasNext();) {
                            Dependency dependency = ii.next();
                            if (dependency.getSite() != null) {
                                installCount++;
                            }
                        }

                        overallProgress.setMaximum(installCount * 100);
                        overallProgress.setValue(0);

                        int removeIndex = 0;
                        for (Iterator<Dependency> ii = dependencies.iterator(); ii.hasNext();) {
                            Dependency dependency = ii.next();
                            String site = dependency.getSite();
                            String version = availableFeatures.get(dependency.getId());
                            if (site != null && version != null) {
                                if (!dependency.isUpgrade()) {
                                    overallLabel
                                            .setText("Installing feature: " + dependency.getId() + '-' + version);
                                } else {
                                    overallLabel.setText("Updating feature: " + dependency.getId() + '-' + version);
                                }

                                taskProgress.setValue(0);
                                taskProgress.setIndeterminate(true);

                                Command command = new InstallCommand(EclipsePluginsStep.this, dependency.getSite(),
                                        dependency.getId());
                                try {
                                    command.start();
                                    command.join();
                                    if (command.getReturnCode() != 0) {
                                        if (command.isShutdown()) {
                                            return Boolean.TRUE;
                                        }
                                        throw new RuntimeException("error: " + command.getErrorMessage() + " out: "
                                                + command.getResult());
                                    }
                                } finally {
                                    command.destroy();
                                }

                                ii.remove();
                                tableModel.removeRow(removeIndex);
                            } else {
                                removeIndex++;
                            }
                            overallProgressStep += 100;
                            overallProgress.setValue(overallProgressStep);
                        }
                        taskLabel.setText("");
                        taskProgress.setValue(taskProgress.getMaximum());
                        overallProgress.setValue(overallProgress.getMaximum());

                        if (dependencies.size() > 0) {
                            GuiDialogs.showWarning(Installer.getString("eclipsePlugins.manual"));
                        }

                        return Boolean.TRUE;
                    }
                });

                if (successful.booleanValue()) {
                    overallProgress.setValue(overallProgress.getMaximum());
                    overallLabel.setText(Installer.getString("install.done"));

                    taskProgress.setValue(taskProgress.getMaximum());
                    taskLabel.setText(Installer.getString("install.done"));

                    setBusy(false);
                    setValid(true);
                    taskProgress.setIndeterminate(false);

                    skipButton.setEnabled(false);
                }
            } catch (Exception ex) {
                setError(ex);
            }
        }
    }

    private class SkipPluginsAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        public SkipPluginsAction() {
            super("Skip");
        }

        public void actionPerformed(ActionEvent e) {
            if (GuiDialogs.showConfirm(Installer.getString("eclipsePlugins.skip"))) {
                setValid(true);
            }
        }
    }

    private class DependencyCellRenderer extends DefaultTableCellRenderer {
        private static final long serialVersionUID = 1L;

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                    column);
            Feature feature = ((Dependency) dependencies.get(row)).getFeature();
            if (feature != null && (feature.getSite() == null || !feature.getSite().canWrite())) {
                component.setBackground(isSelected ? theme.getMenuItemSelectedBackground() : ERROR_COLOR);
                component.setForeground(isSelected ? ERROR_COLOR : Color.BLACK);
            } else {
                component.setBackground(isSelected ? theme.getMenuItemSelectedBackground() : Color.WHITE);
                component.setForeground(
                        isSelected ? theme.getMenuItemSelectedForeground() : theme.getMenuForeground());
            }
            return component;
        }
    }

    /**
     * Mouse listener for the feature list.
     */
    private class DependencySelectionListener implements ListSelectionListener {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            ListSelectionModel model = (ListSelectionModel) e.getSource();
            int index = model.getMinSelectionIndex();
            Feature feature = index >= 0 ? ((Dependency) dependencies.get(index)).getFeature() : null;

            if (feature != null) {
                if (feature.getSite() == null) {
                    setMessage(Installer.getString("eclipsePlugins.upgrade.site.not.found"));
                } else if (!feature.getSite().canWrite()) {
                    setMessage(Installer.getString("eclipsePlugins.upgrade.permission.denied"));
                }
            } else {
                setMessage(null);
            }
        }
    }

    private static class FeatureNameComparator implements Comparator<String> {
        private static ArrayList<String> NAMES = new ArrayList<String>();
        static {
            NAMES.add("featureList.jdt");
            NAMES.add("featureList.wst");
            NAMES.add("featureList.adt");
            NAMES.add("featureList.cdt");
            NAMES.add("featureList.pdt");
            NAMES.add("featureList.python");
            NAMES.add("featureList.sdt");
        }

        public int compare(String ob1, String ob2) {
            return NAMES.indexOf(ob1) - NAMES.indexOf(ob2);
        }
    }
}