2012-11-09 3 views
0

Я работаю над плагином Eclipse и сталкиваюсь с проверенными исключениями, выброшенными из API, которые я использую в своем плагине. Какова практика обработки таких исключений в контексте плагина? Я не смог найти соответствующий подкласс Exception из API разработки плагинов.Обработка проверенных исключений для плагина eclipse

Заранее спасибо.

ответ

2

Я использую классы лесозаготовок, которые я нашел в книге под названием «Плагины Eclipse», Эриком Клейбергом и Дэном Рубелем.

Вот основной класс ведения журнала.

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); 
    } 

} 
+0

благодарит Gilbert за фрагменты кода! Мне любопытно, существует ли исключение, которое предоставляет Eclipse API, где я могу просто написать строку кода, например: «throw new EclipsePluginException (cause)», и он обрабатывается API Eclipse? – Neel

+1

Может быть уже сейчас. Я начал с Eclipse 3.2, и не было. Мне нравится, что я могу контролировать, что отображать и что не отображать, в зависимости от того, какое исключение запускается. –

+0

Привет, Гилберт, Спасибо, что обратились к плагинам Eclipse - это очень полезно! – Neel

Смежные вопросы