0

我正在开发一个 Eclipse 插件,并且面临着从我在插件中使用的 API 抛出的检查异常。在插件上下文中处理此类异常的做法是什么?我无法从插件开发 API 中找到合适的异常子类。

提前致谢。

4

1 回答 1

2

我使用在 Eric Clayberg 和 Dan Rubel 的名为“Eclipse Plug-ins”的书中找到的日志记录类。

这是主要的日志记录类。

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;

public class EclipseLogging {

    public static void logInfo(Plugin plugin, String pluginID, String message,
            boolean display) {
        log(plugin, pluginID, IStatus.INFO, IStatus.OK, message, null, display);
    }

    public static void logInfo(Plugin plugin, String pluginID,
            Throwable exception) {
        log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK,
                "Unexpected Exception", exception));
    }

    public static void logInfo(Plugin plugin, String pluginID, String message,
            Throwable exception) {
        log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK, message,
                exception));
    }

    public static void logError(Plugin plugin, String pluginID,
            Throwable exception) {
        logError(plugin, pluginID, "Unexpected Exception", exception);
    }

    public static void logError(Plugin plugin, String pluginID, String message,
            Throwable exception) {
        log(plugin, pluginID, IStatus.ERROR, IStatus.OK, message, exception,
                true);
    }

    public static void log(Plugin plugin, String pluginID, int severity,
            int code, String message, Throwable exception, boolean display) {
        if (display) {
            ExceptionAction action = new ExceptionAction(plugin, message,
                    exception);
            action.run();
        }
        log(plugin, createStatus(pluginID, severity, code, message, exception));
    }

    public static IStatus createStatus(String pluginID, int severity, int code,
            String message, Throwable exception) {
        return new Status(severity, pluginID, code, message, exception);
    }

    public static void log(Plugin plugin, IStatus status) {
        plugin.getLog().log(status);
    }
}

这是异常操作类。

import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

public class ExceptionAction extends Action {

    private Plugin plugin;
    private String message;
    private Throwable exception;

    public ExceptionAction(Plugin plugin, String message, Throwable exception) {
        this.plugin = plugin;
        this.message = message;
        this.exception = exception;
    }

    public void run() {
        IWorkbench workbench = PlatformUI.getWorkbench();
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();

        if (window != null) {
            Shell parentShell = window.getShell();
            parentShell.forceActive();
            try {
                ExceptionDetailsDialog dialog = new ExceptionDetailsDialog(
                        parentShell, null, null, message, exception, plugin);
                dialog.open();
            } catch (SWTException e) {
            }
        }
    }
}

最后,显示异常的类。

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

/**
 * An abstract dialog with a details section that can be shown or hidden by the
 * user. Subclasses are responsible for providing the content of the details
 * section.
 */
public abstract class AbstractDetailsDialog extends Dialog {

    private final String title;

    private final String message;

    private final Image image;

    private Button detailsButton;

    private Control detailsArea;

    private Point cachedWindowSize;

    /**
     * Construct a new instance with the specified elements. Note that the
     * window will have no visual representation (no widgets) until it is told
     * to open. By default, <code>open</code> blocks for dialogs.
     * 
     * @param parentShell
     *            the parent shell, or <code>null</code> to create a top-level
     *            shell
     * @param title
     *            the title for the dialog or <code>null</code> for none
     * @param image
     *            the image to be displayed
     * @param message
     *            the message to be displayed
     */
    public AbstractDetailsDialog(Shell parentShell, String title, Image image,
            String message) {
        this(new SameShellProvider(parentShell), title, image, message);
    }

    /**
     * Construct a new instance with the specified elements. Note that the
     * window will have no visual representation (no widgets) until it is told
     * to open. By default, <code>open</code> blocks for dialogs.
     * 
     * @param parentShell
     *            the parent shell provider (not <code>null</code>)
     * @param title
     *            the title for the dialog or <code>null</code> for none
     * @param image
     *            the image to be displayed
     * @param message
     *            the message to be displayed
     */
    public AbstractDetailsDialog(IShellProvider parentShell, String title,
            Image image, String message) {
        super(parentShell);

        this.title = title;
        this.image = image;
        this.message = message;

        setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL);
    }

    /**
     * Configures the given shell in preparation for opening this window in it.
     * In our case, we set the title if one was provided.
     */
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
        if (title != null)
            shell.setText(title);
    }

    /**
     * Creates and returns the contents of the upper part of this dialog (above
     * the button bar). This includes an image, if specified, and a message.
     * 
     * @param parent
     *            the parent composite to contain the dialog area
     * @return the dialog area control
     */
    protected Control createDialogArea(Composite parent) {
        Composite composite = (Composite) super.createDialogArea(parent);
        composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        if (image != null) {
            ((GridLayout) composite.getLayout()).numColumns = 2;
            Label label = new Label(composite, 0);
            image.setBackground(label.getBackground());
            label.setImage(image);
            label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER
                    | GridData.VERTICAL_ALIGN_BEGINNING));
        }

        Label label = new Label(composite, SWT.WRAP);
        if (message != null)
            label.setText(message);
        GridData data = new GridData(GridData.FILL_HORIZONTAL
                | GridData.VERTICAL_ALIGN_CENTER);
        data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
        label.setLayoutData(data);
        label.setFont(parent.getFont());

        return composite;
    }

    /**
     * Adds OK and Details buttons to this dialog's button bar.
     * 
     * @param parent
     *            the button bar composite
     */
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
                false);
        detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
                IDialogConstants.SHOW_DETAILS_LABEL, false);
    }

    /**
     * The buttonPressed() method is called when either the OK or Details
     * buttons is pressed. We override this method to alternately show or hide
     * the details area if the Details button is pressed.
     */
    protected void buttonPressed(int id) {
        if (id == IDialogConstants.DETAILS_ID)
            toggleDetailsArea();
        else
            super.buttonPressed(id);
    }

    /**
     * Toggles the unfolding of the details area. This is triggered by the user
     * pressing the Details button.
     */
    protected void toggleDetailsArea() {
        Point oldWindowSize = getShell().getSize();
        Point newWindowSize = cachedWindowSize;
        cachedWindowSize = oldWindowSize;

        // Show the details area.
        if (detailsArea == null) {
            detailsArea = createDetailsArea((Composite) getContents());
            detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
        }

        // Hide the details area.
        else {
            detailsArea.dispose();
            detailsArea = null;
            detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
        }

        /*
         * Must be sure to call getContents().computeSize(SWT.DEFAULT,
         * SWT.DEFAULT) before calling getShell().setSize(newWindowSize) since
         * controls have been added or removed.
         */

        // Compute the new window size.
        Point oldSize = getContents().getSize();
        Point newSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT);
        if (newWindowSize == null)
            newWindowSize = new Point(oldWindowSize.x, oldWindowSize.y
                    + (newSize.y - oldSize.y));

        // Crop new window size to screen.
        Point windowLoc = getShell().getLocation();
        Rectangle screenArea = getContents().getDisplay().getClientArea();
        final int pos = screenArea.height - (windowLoc.y - screenArea.y);
        if (newWindowSize.y > pos)
            newWindowSize.y = pos;

        getShell().setSize(newWindowSize);
        ((Composite) getContents()).layout();
    }

    /**
     * subclasses must implement createDetailsArea to provide content for the
     * area of the dialog made visible when the Details button is clicked.
     * 
     * @param parent
     *            the details area parent
     * @return the details area
     */
    protected abstract Control createDetailsArea(Composite parent);
}

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Dictionary;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * A dialog to display one or more errors to the user, as contained in an
 * <code>IStatus</code> object along with the plug-in identifier, name, version
 * and provider. If an error contains additional detailed information then a
 * Details button is automatically supplied, which shows or hides an error
 * details viewer when pressed by the user.
 * 
 * @see org.eclipse.core.runtime.IStatus
 */
public class ExceptionDetailsDialog extends AbstractDetailsDialog {
    /**
     * The details to be shown ({@link Exception}, {@link IStatus}, or
     * <code>null</code> if no details).
     */
    private final Object details;

    /**
     * The plugin triggering this details dialog and whose information is to be
     * shown in the details area or <code>null</code> if no plugin details
     * should be shown.
     */
    private final Plugin plugin;

    /**
     * Construct a new instance with the specified elements. Note that the
     * window will have no visual representation (no widgets) until it is told
     * to open. By default, <code>open</code> blocks for dialogs.
     * 
     * @param parentShell
     *            the parent shell, or <code>null</code> to create a top-level
     *            shell
     * @param title
     *            the title for the dialog or <code>null</code> for none
     * @param image
     *            the image to be displayed
     * @param message
     *            the message to be displayed
     * @param details
     *            an object whose content is to be displayed in the details
     *            area, or <code>null</code> for none
     * @param plugin
     *            The plugin triggering this deatils dialog and whose
     *            information is to be shown in the details area or
     *            <code>null</code> if no plugin details should be shown.
     */
    public ExceptionDetailsDialog(Shell parentShell, String title, Image image,
            String message, Object details, Plugin plugin) {
        this(new SameShellProvider(parentShell), title, image, message,
                details, plugin);
    }

    /**
     * Construct a new instance with the specified elements. Note that the
     * window will have no visual representation (no widgets) until it is told
     * to open. By default, <code>open</code> blocks for dialogs.
     * 
     * @param parentShell
     *            the parent shell provider (not <code>null</code>)
     * @param title
     *            the title for the dialog or <code>null</code> for none
     * @param image
     *            the image to be displayed
     * @param message
     *            the message to be displayed
     * @param details
     *            an object whose content is to be displayed in the details
     *            area, or <code>null</code> for none
     * @param plugin
     *            The plugin triggering this deatils dialog and whose
     *            information is to be shown in the details area or
     *            <code>null</code> if no plugin details should be shown.
     */
    public ExceptionDetailsDialog(IShellProvider parentShell, String title,
            Image image, String message, Object details, Plugin plugin) {
        super(parentShell, getTitle(title, details), getImage(image, details),
                getMessage(message, details));

        this.details = details;
        this.plugin = plugin;
    }

    /**
     * Build content for the area of the dialog made visible when the Details
     * button is clicked.
     * 
     * @param parent
     *            the details area parent
     * @return the details area
     */
    protected Control createDetailsArea(Composite parent) {

        // Create the details area.
        Composite panel = new Composite(parent, SWT.NONE);
        panel.setLayoutData(new GridData(GridData.FILL_BOTH));
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        panel.setLayout(layout);

        // Create the details content.
        createProductInfoArea(panel);
        createDetailsViewer(panel);

        return panel;
    }

    /**
     * Create fields displaying the plugin information such as name, identifer,
     * version and vendor. Do nothing if the plugin is not specified.
     * 
     * @param parent
     *            the details area in which the fields are created
     * @return the product info composite or <code>null</code> if no plugin
     *         specified.
     */
    protected Composite createProductInfoArea(Composite parent) {

        // If no plugin specified, then nothing to display here
        if (plugin == null)
            return null;

        Composite composite = new Composite(parent, SWT.NULL);
        composite.setLayoutData(new GridData());
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
        composite.setLayout(layout);

        Dictionary<?, ?> bundleHeaders = plugin.getBundle().getHeaders();
        String pluginId = plugin.getBundle().getSymbolicName();
        String pluginVendor = (String) bundleHeaders.get("Bundle-Vendor");
        String pluginName = (String) bundleHeaders.get("Bundle-Name");
        String pluginVersion = (String) bundleHeaders.get("Bundle-Version");

        new Label(composite, SWT.NONE).setText("Provider:");
        new Label(composite, SWT.NONE).setText(pluginVendor);
        new Label(composite, SWT.NONE).setText("Plug-in Name:");
        new Label(composite, SWT.NONE).setText(pluginName);
        new Label(composite, SWT.NONE).setText("Plug-in ID:");
        new Label(composite, SWT.NONE).setText(pluginId);
        new Label(composite, SWT.NONE).setText("Version:");
        new Label(composite, SWT.NONE).setText(pluginVersion);

        return composite;
    }

    /**
     * Create the details field based upon the details object. Do nothing if the
     * details object is not specified.
     * 
     * @param parent
     *            the details area in which the fields are created
     * @return the details field
     */
    protected Control createDetailsViewer(Composite parent) {
        if (details == null)
            return null;

        Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER
                | SWT.H_SCROLL | SWT.V_SCROLL);
        text.setLayoutData(new GridData(GridData.FILL_BOTH));

        // Create the content.
        StringWriter writer = new StringWriter(1000);
        if (details instanceof Throwable)
            appendException(new PrintWriter(writer), (Throwable) details);
        else if (details instanceof IStatus)
            appendStatus(new PrintWriter(writer), (IStatus) details, 0);
        text.setText(writer.toString());

        return text;
    }

    // /////////////////////////////////////////////////////////////////
    //
    // Utility methods for building content
    //
    // /////////////////////////////////////////////////////////////////

    /**
     * Answer the title based on the provided title and details object.
     */
    public static String getTitle(String title, Object details) {
        if (title != null)
            return title;
        if (details instanceof Throwable) {
            Throwable e = (Throwable) details;
            while (e instanceof InvocationTargetException)
                e = ((InvocationTargetException) e).getTargetException();
            String name = e.getClass().getName();
            return name.substring(name.lastIndexOf('.') + 1);
        }
        return "Exception";
    }

    /**
     * Answer the image based on the provided image and details object.
     */
    public static Image getImage(Image image, Object details) {
        if (image != null)
            return image;
        Display display = Display.getCurrent();
        if (details instanceof IStatus) {
            switch (((IStatus) details).getSeverity()) {
            case IStatus.ERROR:
                return display.getSystemImage(SWT.ICON_ERROR);
            case IStatus.WARNING:
                return display.getSystemImage(SWT.ICON_WARNING);
            case IStatus.INFO:
                return display.getSystemImage(SWT.ICON_INFORMATION);
            case IStatus.OK:
                return null;
            }
        }
        return display.getSystemImage(SWT.ICON_ERROR);
    }

    /**
     * Answer the message based on the provided message and details object.
     */
    public static String getMessage(String message, Object details) {
        if (details instanceof Throwable) {
            Throwable e = (Throwable) details;
            while (e instanceof InvocationTargetException)
                e = ((InvocationTargetException) e).getTargetException();
            if (message == null)
                return e.toString();
            return MessageFormat.format(message, new Object[] { e.toString() });
        }
        if (details instanceof IStatus) {
            String statusMessage = ((IStatus) details).getMessage();
            if (message == null)
                return statusMessage;
            return MessageFormat
                    .format(message, new Object[] { statusMessage });
        }
        if (message != null)
            return message;
        return "An Exception occurred.";
    }

    public static void appendException(PrintWriter writer, Throwable ex) {
        if (ex instanceof CoreException) {
            appendStatus(writer, ((CoreException) ex).getStatus(), 0);
            writer.println();
        }
        appendStackTrace(writer, ex);
        if (ex instanceof InvocationTargetException)
            appendException(writer, ((InvocationTargetException) ex)
                    .getTargetException());
    }

    public static void appendStatus(PrintWriter writer, IStatus status,
            int nesting) {
        for (int i = 0; i < nesting; i++)
            writer.print("  ");
        writer.println(status.getMessage());
        IStatus[] children = status.getChildren();
        for (int i = 0; i < children.length; i++)
            appendStatus(writer, children[i], nesting + 1);
    }

    public static void appendStackTrace(PrintWriter writer, Throwable ex) {
        ex.printStackTrace(writer);
    }

}
于 2012-11-09T18:02:25.507 回答