com.atlassian.clover.eclipse.core.CloverPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.atlassian.clover.eclipse.core.CloverPlugin.java

Source

package com.atlassian.clover.eclipse.core;

import com.atlassian.clover.CloverLicense;
import com.atlassian.clover.CloverLicenseDecoder;
import com.atlassian.clover.CloverLicenseInfo;
import com.atlassian.clover.CloverStartup;
import com.atlassian.clover.Logger;
import com.atlassian.clover.eclipse.core.ui.editors.java.EditorCoverageSynchronizer;
import com.atlassian.clover.eclipse.core.exclusion.ExclusionLabelDecorator;
import com.atlassian.clover.eclipse.core.projects.model.CoverageModelsMonitor;
import com.atlassian.clover.eclipse.core.reports.model.ReportHistoryEntry;
import com.atlassian.clover.eclipse.core.settings.InstallationSettings;
import com.atlassian.clover.eclipse.core.settings.WorkspaceSettings;
import com.atlassian.clover.eclipse.core.views.coverageexplorer.CoverageView;
import com.atlassian.clover.eclipse.core.views.dashboard.DashboardView;
import com.atlassian.clover.eclipse.core.views.testcontributions.TestContributionsView;
import com.atlassian.clover.eclipse.core.views.testrunexplorer.TestRunExplorerView;
import com.atlassian.clover.eclipse.core.ui.workingset.CloverWorkingSet;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Version;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static clover.com.google.common.collect.Lists.newLinkedList;
import static clover.com.google.common.collect.Maps.newHashMap;

/**
 * The Clover plugin. Ta-dah!
 */
public class CloverPlugin extends AbstractUIPlugin {
    /* Wait 10s after plugin start() completes before starting background processes */
    private static final long STARTUP_BACKOFF_DELAY = 10000;

    public static final String ID = "com.atlassian.clover.eclipse.core";

    public static final IPath CLOVER_RUNTIME_VARIABLE = new Path("CLOVER_RUNTIME");

    public static CloverPlugin instance;
    private BundleListener startListener;

    public static CloverPlugin getInstance() {
        return instance;
    }

    private PluginLoggingAdapter cloverLogger;
    private CoverageModelsMonitor coverageMonitor;
    private EditorCoverageSynchronizer editorSynchronizer;
    private CloverWorkingSet workingSet;
    private List customColumns;
    private InstallationSettings installationSettings;
    private WorkspaceSettings workspaceSettings;
    private CloverLicense license;

    public static boolean isLoggingDebugFor(String category) {
        return getInstance().isDebugging() && getInstance().debugPlatformOptionOn(category);
    }

    public static void logVerbose(String message) {
        getInstance().cloverLogger.verbose(message);
    }

    public static void logVerbose(String message, Throwable t) {
        getInstance().cloverLogger.verbose(message, t);
    }

    public static void logDebug(String message) {
        getInstance().cloverLogger.debug(message);
    }

    public static void logDebug(String message, Throwable t) {
        getInstance().cloverLogger.debug(message, t);
    }

    public static void logInfo(String message) {
        getInstance().cloverLogger.info(message);
    }

    public static void logInfo(String message, Throwable t) {
        getInstance().cloverLogger.info(message, t);
    }

    public static void logWarning(String message) {
        getInstance().cloverLogger.warn(message);
    }

    public static void logWarning(String message, Throwable t) {
        getInstance().cloverLogger.warn(message, t);
    }

    public static CoreException logAndThrowError(String message) {
        logError(message);
        return new CoreException(new Status(Status.ERROR, ID, 0, message, null));
    }

    public static CoreException logAndThrowError(String message, Throwable t) {
        logError(message, t);
        return new CoreException(new Status(Status.ERROR, ID, 0, message, t));
    }

    public static void logError(String message) {
        getInstance().cloverLogger.error(message);
    }

    public static void logError(String message, Throwable t) {
        getInstance().cloverLogger.error(message, t);
    }

    public CloverPlugin() {
        super();

        //Take over logging
        cloverLogger = new PluginLoggingAdapter(getLog(), false);
        Logger.setInstance(cloverLogger);

        instance = this;

        logInfo("Clover plugin constructed");
    }

    public CloverLicense getLicense() {
        return license;
    }

    /**
     * This method is called upon plug-in activation
     */
    @Override
    public void start(final BundleContext context) throws Exception {
        super.start(context);

        buildSettings();

        ensureInstallDateGenerated();

        setLoggingLevel(getInstallationSettings().getLoggingLevel());
        loadLicense();
        loadCustomColumns();
        buildWorkingSet();

        editorSynchronizer = new EditorCoverageSynchronizer(getWorkbench());
        coverageMonitor = new CoverageModelsMonitor();

        //Wait until the bundle is fully started before starting background jobs
        //as there is a real danger of classloader deadlock in Equinox when the bundle state changes
        //or so it appears. See CEP-313. This may be a case of shadow boxing. Unclear ATM.
        final long thisBundleId = context.getBundle().getBundleId();
        startListener = new BundleListener() {
            @Override
            public void bundleChanged(BundleEvent bundleEvent) {
                if (bundleEvent.getBundle().getBundleId() == thisBundleId
                        && bundleEvent.getType() == BundleEvent.STARTED) {
                    new SystemJob("Clover background processing starter") {
                        @Override
                        protected IStatus run(IProgressMonitor progressMonitor) {
                            try {
                                startMonitorEditors();
                                startMonitoringCoverage();
                                listenForSettingsChanges();
                            } catch (Exception e) {
                                CloverPlugin.logError("Failed to start background processing", e);
                            }
                            return Status.OK_STATUS;
                        }
                    }.schedule(STARTUP_BACKOFF_DELAY);
                }
            }
        };
        context.addBundleListener(startListener);
        logInfo("Clover plugin started");
    }

    private void startMonitoringCoverage() {
        coverageMonitor.start();
    }

    private void startMonitorEditors() {
        editorSynchronizer.syncWithCoverageSetting(installationSettings.getEditorCoverageStyle());
    }

    private void buildWorkingSet() {
        workingSet = new CloverWorkingSet(getWorkbench().getWorkingSetManager());
    }

    private void listenForSettingsChanges() {
        //Watch license preference and reload when necessary
        installationSettings.addListener(new IEclipsePreferences.IPreferenceChangeListener() {
            @Override
            public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
                final String propertyName = event.getKey();

                if (InstallationSettings.Keys.CLOVER_LICENSE.equals(propertyName)) {
                    CloverStartup.loadLicense(cloverLogger, false, getInstallationSettings().getInstallDate());
                    getCoverageMonitor().fireCoverageChange();
                } else if (InstallationSettings.Keys.LOGGING_LEVEL.equals(propertyName)) {
                    // event.getNewValue() returns null if current value is a default installation value
                    setLoggingLevel(event.getNewValue() != null ? (String) event.getNewValue()
                            : getInstallationSettings().getLoggingLevel());
                } else if (InstallationSettings.Keys.COVERAGE_STYLE_IN_EDITORS.equals(propertyName)) {
                    try {
                        editorSynchronizer.syncWithCoverageSetting(Integer.parseInt((String) event.getNewValue()));
                    } catch (ClassCastException e) {
                        logError(
                                "Coverage style setting invalid type: " + event.getNewValue().getClass().getName());
                    } catch (NumberFormatException e) {
                        logError("Coverage style setting invalid integer string: " + event.getNewValue());
                    }
                } else if (InstallationSettings.Keys.SHOW_EXCLUSION_ANNOTATIONS.equals(propertyName)) {
                    ExclusionLabelDecorator.decorationChanged();
                }
            }
        });
    }

    private void loadCustomColumns() {
        customColumns = installationSettings.getCustomColumns();
    }

    private void buildSettings() {
        installationSettings = new InstallationSettings();
        workspaceSettings = new WorkspaceSettings();
    }

    /**
     * This method is called when the plug-in is stopped
     */
    @Override
    public void stop(BundleContext context) throws Exception {
        try {
            if (startListener != null) {
                context.removeBundleListener(startListener);
            }

            editorSynchronizer.dispose();
            coverageMonitor.stop();

            installationSettings.save();
            workspaceSettings.save();
        } finally {
            super.stop(context);
            cloverLogger.info("Clover plugin stopped");
        }
    }

    private String prefixed(String key) {
        return CloverPlugin.ID + ".preferences." + key;
    }

    private void loadLicense() {
        //Load license through preferences
        CloverStartup.setLicenseLoader(new CloverStartup.LicenseLoader() {
            @Override
            public CloverLicense loadLicense(Logger log) {
                String licenseText = getInstallationSettings().getLicenseText();

                try {
                    license = CloverLicenseDecoder.decode(licenseText);
                } catch (Exception e) {
                    license = null;
                    log.error("Unable to load licence from preferences", e);
                }
                return license;
            }
        });

        //Load license
        CloverStartup.loadLicense(cloverLogger, false, getInstallationSettings().getInstallDate());
    }

    private void ensureInstallDateGenerated() {
        long installDate = getInstallationSettings().getInstallDate();
        if (installDate == -1L) {
            installDate = System.currentTimeMillis();
            logInfo("Setting installation date for this product to " + installDate);
            getInstallationSettings().setInstallDate(installDate);
        }
    }

    public InstallationSettings getInstallationSettings() {
        return installationSettings;
    }

    public PluginLoggingAdapter getCloverLogger() {
        return cloverLogger;
    }

    private void setLoggingLevel(String propertyValue) {
        if (InstallationSettings.Values.NO_LOGGING_LEVEL.equals(propertyValue)) {
            cloverLogger.setEnabled(false);
        } else {
            boolean debug;
            boolean verbose;
            if (InstallationSettings.Values.DEBUG_LOGGING_LEVEL.equals(propertyValue)) {
                debug = true;
                verbose = true;
            } else if (InstallationSettings.Values.VERBOSE_LOGGING_LEVEL.equals(propertyValue)) {
                debug = false;
                verbose = true;
            } else {
                debug = false;
                verbose = false;
            }
            super.setDebugging(debug);
            Logger.setDebug(debug);
            Logger.setVerbose(verbose);
            cloverLogger.setEnabled(true);
            cloverLogger.info("Setting logging level: debug=" + debug + " verbose=" + verbose);
        }
    }

    public boolean debugPlatformOptionOn(String category) {
        return "true".equalsIgnoreCase(
                Platform.getDebugOption(ID + (category == null ? "" : "/" + category) + "/debug"));
    }

    public String getPluginOption(String option) {
        return Platform.getDebugOption(ID + "/" + option);
    }

    public List<ReportHistoryEntry> getReportHistory() {
        try {
            org.osgi.service.prefs.Preferences instancePrefs = Platform.getPreferencesService().getRootNode()
                    .node(InstanceScope.SCOPE).node(ID);

            int historyCount = instancePrefs.getInt(WorkspaceSettings.Keys.REPORT_HISTORY_COUNT, 0);
            LinkedList<ReportHistoryEntry> history = newLinkedList();
            for (int i = 0; i < historyCount; i++) {
                if (instancePrefs.nodeExists(WorkspaceSettings.Keys.REPORT_HISTORY_PREFIX + i)) {
                    history.add(new ReportHistoryEntry(
                            instancePrefs.node(WorkspaceSettings.Keys.REPORT_HISTORY_PREFIX + i)));

                }
            }

            return history;
        } catch (BackingStoreException e) {
            return Collections.emptyList();
        }
    }

    private void setReportHistory(List<ReportHistoryEntry> history) {
        Map<String, ReportHistoryEntry> pathToHistory = newHashMap();

        //Keep only the last valid generated report for a given project
        for (ReportHistoryEntry report : history) {
            if (report.isValid()) {
                pathToHistory.put(report.getPath(), report);
            }
        }
        List<ReportHistoryEntry> savedHistory = newLinkedList(history);
        history.retainAll(pathToHistory.values());

        //Keep only the last N generated reports in any case
        savedHistory = savedHistory.subList(Math.max(0, savedHistory.size() - 5), savedHistory.size());

        org.osgi.service.prefs.Preferences instancePrefs = Platform.getPreferencesService().getRootNode()
                .node(InstanceScope.SCOPE).node(ID);

        int nodeCount = 0;
        for (ReportHistoryEntry entry : savedHistory) {
            entry.saveTo(instancePrefs.node(WorkspaceSettings.Keys.REPORT_HISTORY_PREFIX + nodeCount++));
        }
        instancePrefs.putInt(WorkspaceSettings.Keys.REPORT_HISTORY_COUNT, nodeCount);
    }

    public void addReportToHistory(final ReportHistoryEntry report) {
        setReportHistory(new LinkedList<ReportHistoryEntry>(getReportHistory()) {
            {
                add(report);
            }
        });
    }

    /**
     * Returns an image descriptor for the image file at the given
     * plug-in relative path.
     *
     * @param path the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        return AbstractUIPlugin.imageDescriptorFromPlugin(ID, path);
    }

    public static Image getImage(String path) {
        ImageRegistry reg = getInstance().getImageRegistry();
        if (reg.getDescriptor(path) == null) {
            reg.put(path, ImageDescriptor.createFromURL(instance.getBundle().getEntry(path)));
        }
        return reg.get(path);
    }

    public CoverageModelsMonitor getCoverageMonitor() {
        return coverageMonitor;
    }

    public boolean isInWorkingSetMode() {
        final Preferences prefs = InstanceScope.INSTANCE.getNode(CloverPlugin.ID);
        return prefs.getBoolean(InstallationSettings.Keys.WORKING_SET_ENABLED, false);
    }

    public void setIsInWorkingSetMode(boolean enabled) throws BackingStoreException {
        final Preferences prefs = InstanceScope.INSTANCE.getNode(CloverPlugin.ID);
        prefs.putBoolean(InstallationSettings.Keys.WORKING_SET_ENABLED, enabled);
        prefs.flush();
        getCoverageMonitor().fireCoverageChange();
    }

    public CloverWorkingSet getCloverWorkingSet() {
        return workingSet;
    }

    public boolean isLicensePresent() {
        return !CloverLicenseInfo.TERMINATED;
    }

    public void showViews(IWorkbenchPage page) throws PartInitException {
        if (page.findView(CoverageView.ID) == null) {
            page.showView(CoverageView.ID);
        }
        if (page.findView(TestRunExplorerView.ID) == null) {
            page.showView(TestRunExplorerView.ID);
        }
        if (page.findView(TestContributionsView.ID) == null) {
            page.showView(TestContributionsView.ID);
        }
        if (page.findView(DashboardView.ID) == null) {
            page.showView(DashboardView.ID);
        }
    }

    public Version getJDTVersion() {
        try {
            Bundle jdtCore = Platform.getBundle("org.eclipse.jdt.core");
            String versionString = jdtCore == null ? null : (String) jdtCore.getHeaders().get("Bundle-Version");
            return versionString == null ? null : Version.parseVersion(versionString);
        } catch (Exception e) {
            CloverPlugin.logError("Unable to calculate JDT version", e);
            return null;
        }
    }
}