mirror of https://github.com/apache/openjpa.git
Improve error handling and reporting
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@947913 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e0db67ee48
commit
893198dec4
|
@ -14,7 +14,6 @@
|
|||
package jpa.tools.swing;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
@ -22,119 +21,197 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
|
||||
/**
|
||||
* A dialog to display runtime error.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ErrorDialog extends JDialog {
|
||||
private static List<String> filters = Arrays.asList("java.awt.", "javax.swing.", "sun.reflect.");
|
||||
private static AttributeSet red, black;
|
||||
static {
|
||||
StyleContext ctx = StyleContext.getDefaultStyleContext();
|
||||
red = ctx.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.RED);
|
||||
red = ctx.addAttribute(red, StyleConstants.Bold, true);
|
||||
red = ctx.addAttribute(red, StyleConstants.FontSize, 12);
|
||||
red = ctx.addAttribute(red, StyleConstants.FontFamily, "Courier");
|
||||
black = ctx.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.BLACK);
|
||||
black = ctx.addAttribute(black, StyleConstants.Bold, false);
|
||||
black = ctx.addAttribute(black, StyleConstants.FontFamily, "Courier");
|
||||
private static List<String> filters = Arrays.asList(
|
||||
"java.awt.",
|
||||
"javax.swing.",
|
||||
"sun.reflect.",
|
||||
"java.util.concurrent.");
|
||||
private static Dimension MESSAGE_SIZE = new Dimension(600,200);
|
||||
private static Dimension STACKTRACE_SIZE = new Dimension(600,300);
|
||||
private static Dimension TOTAL_SIZE = new Dimension(600,500);
|
||||
|
||||
|
||||
static String NEWLINE = "\r\n";
|
||||
static String INDENT = " ";
|
||||
|
||||
private boolean _showingDetails;
|
||||
private boolean _isFiltering = true;
|
||||
private JComponent _message;
|
||||
private JComponent _main;
|
||||
private JScrollPane _details;
|
||||
private JTextPane _stacktrace;
|
||||
private final Throwable _error;
|
||||
|
||||
/**
|
||||
* Creates a modal dialog to display the given exception message.
|
||||
*
|
||||
* @param t the exception to display
|
||||
*/
|
||||
public ErrorDialog(Throwable t) {
|
||||
this(null, null, t);
|
||||
}
|
||||
|
||||
public ErrorDialog(JComponent owner, Throwable t) {
|
||||
this(owner, null, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a modal dialog to display the given exception message.
|
||||
*
|
||||
* @param owner if non-null, then the dialog is positioned (centered) w.r.t. this component
|
||||
* @param t the exception to display
|
||||
*/
|
||||
public ErrorDialog(JComponent owner, Icon icon, Throwable t) {
|
||||
super();
|
||||
setTitle(t.getClass().getName());
|
||||
setModal(true);
|
||||
if (icon != null && icon instanceof ImageIcon)
|
||||
setIconImage(((ImageIcon)icon).getImage());
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
// Icon icon = Images.ERROR;
|
||||
// setIconImage(((ImageIcon)icon).getImage());
|
||||
addException(t);
|
||||
_error = t;
|
||||
_message = createErrorMessage(_error);
|
||||
_main = createContent();
|
||||
getContentPane().add(_main);
|
||||
|
||||
pack();
|
||||
SwingHelper.position(this, owner);
|
||||
}
|
||||
|
||||
public ErrorDialog(Throwable t) {
|
||||
this(null, t);
|
||||
}
|
||||
|
||||
void addException(Throwable t) {
|
||||
setTitle("Error");
|
||||
String txt = t.getClass().getName() + ":" + t.getLocalizedMessage();
|
||||
JTextArea message = new JTextArea(txt);
|
||||
message.setLineWrap(true);
|
||||
message.setWrapStyleWord(true);
|
||||
message.setForeground(Color.RED);
|
||||
message.setText(txt);
|
||||
message.setEditable(false);
|
||||
|
||||
JTextPane window = new JTextPane();
|
||||
printStackTrace(t, window);
|
||||
window.setEditable(false);
|
||||
JScrollPane pane = new JScrollPane(window,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
pane.setPreferredSize(new Dimension(400, 200));
|
||||
pane.setBorder(BorderFactory.createTitledBorder("Stacktrace"));
|
||||
pane.setPreferredSize(new Dimension(400, 200));
|
||||
JPanel main = new JPanel();
|
||||
main.setLayout(new BorderLayout());
|
||||
main.add(message, BorderLayout.NORTH);
|
||||
main.add(pane, BorderLayout.CENTER);
|
||||
JPanel buttonPanel = new JPanel();
|
||||
JButton ok = new JButton("OK");
|
||||
ok.addActionListener(new ActionListener() {
|
||||
/**
|
||||
* Creates the display with the top-level exception message
|
||||
* followed by a pane (that toggles) for detailed stack traces.
|
||||
*
|
||||
* @param t a non-null exception
|
||||
*/
|
||||
JComponent createContent() {
|
||||
final JButton showDetails = new JButton("Show Details >>");
|
||||
showDetails.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ErrorDialog.this.dispose();
|
||||
if (_showingDetails) {
|
||||
_main.remove(_details);
|
||||
_main.validate();
|
||||
_main.setPreferredSize(MESSAGE_SIZE);
|
||||
} else {
|
||||
if (_details == null) {
|
||||
_details = createDetailedMessage(_error);
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
_stacktrace.setText(generateStackTrace(_error, buffer).toString());
|
||||
_stacktrace.setBackground(_main.getBackground());
|
||||
_stacktrace.setPreferredSize(STACKTRACE_SIZE);
|
||||
}
|
||||
_main.add(_details, BorderLayout.CENTER);
|
||||
_main.validate();
|
||||
_main.setPreferredSize(TOTAL_SIZE);
|
||||
}
|
||||
_showingDetails = !_showingDetails;
|
||||
showDetails.setText(_showingDetails ? "<< Hide Details" : "Show Details >>");
|
||||
ErrorDialog.this.pack();
|
||||
}
|
||||
});
|
||||
buttonPanel.add(ok);
|
||||
main.add(buttonPanel, BorderLayout.SOUTH);
|
||||
getContentPane().add(main);
|
||||
}
|
||||
static String NEWLINE = "\r\n";
|
||||
StringBuilder printStackTrace(Throwable t, JTextPane text) {
|
||||
String message = t.getClass().getName() + ": " + t.getMessage() + NEWLINE;
|
||||
text.setCaretPosition(text.getDocument().getLength());
|
||||
text.setCharacterAttributes(red, false);
|
||||
text.replaceSelection(message);
|
||||
StackTraceElement[] traces = t.getStackTrace();
|
||||
text.setCharacterAttributes(black, false);
|
||||
for (StackTraceElement e : traces) {
|
||||
if (!isFiltered(e.getClassName())) {
|
||||
String str = " " + e.toString() + NEWLINE;
|
||||
text.setCaretPosition(text.getDocument().getLength());
|
||||
text.replaceSelection(str);
|
||||
JPanel messagePanel = new JPanel();
|
||||
|
||||
final JCheckBox filter = new JCheckBox("Filter stack traces");
|
||||
filter.setSelected(_isFiltering);
|
||||
filter.addActionListener(new ActionListener(){
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
_isFiltering = filter.isSelected();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
_stacktrace.setText(generateStackTrace(_error, buffer).toString());
|
||||
_stacktrace.repaint();
|
||||
}
|
||||
});
|
||||
_message.setBackground(messagePanel.getBackground());
|
||||
JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.add(Box.createHorizontalStrut(20));
|
||||
buttonPanel.add(showDetails);
|
||||
buttonPanel.add(filter);
|
||||
buttonPanel.add(Box.createHorizontalGlue());
|
||||
messagePanel.setLayout(new BorderLayout());
|
||||
messagePanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
messagePanel.add(_message, BorderLayout.CENTER);
|
||||
messagePanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
messagePanel.setPreferredSize(MESSAGE_SIZE);
|
||||
|
||||
JPanel main = new JPanel();
|
||||
main.setLayout(new BorderLayout());
|
||||
main.add(messagePanel, BorderLayout.NORTH);
|
||||
return main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a non-editable widget to display the error message.
|
||||
*
|
||||
*/
|
||||
JComponent createErrorMessage(Throwable t) {
|
||||
String txt = t.getLocalizedMessage();
|
||||
JEditorPane message = new JEditorPane();
|
||||
message.setContentType("text/plain");
|
||||
message.setEditable(false);
|
||||
message.setText(txt);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a non-editable widget to display the detailed stack trace.
|
||||
*/
|
||||
JScrollPane createDetailedMessage(Throwable t) {
|
||||
_stacktrace = new JTextPane();
|
||||
_stacktrace.setEditable(false);
|
||||
JScrollPane pane = new JScrollPane(_stacktrace,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively print the stack trace on the given buffer.
|
||||
*/
|
||||
StringBuilder generateStackTrace(Throwable t, StringBuilder buffer) {
|
||||
buffer.append(t.getClass().getName() + ": " + t.getMessage() + NEWLINE);
|
||||
buffer.append(toString(t.getStackTrace()));
|
||||
Throwable cause = t.getCause();
|
||||
if (cause !=null && cause != t) {
|
||||
printStackTrace(cause, text);
|
||||
generateStackTrace(cause, buffer);
|
||||
}
|
||||
return null;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
StringBuilder toString(StackTraceElement[] traces) {
|
||||
StringBuilder error = new StringBuilder();
|
||||
for (StackTraceElement e : traces) {
|
||||
if (!isFiltered(e.getClassName())) {
|
||||
if (!_isFiltering || !isSuppressed(e.getClassName())) {
|
||||
String str = e.toString();
|
||||
error.append(str).append("\r\n");
|
||||
error.append(INDENT).append(str).append(NEWLINE);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
private boolean isFiltered(String className) {
|
||||
/**
|
||||
* Affirms if the error messages from the given class name is to be suppressed.
|
||||
*/
|
||||
private boolean isSuppressed(String className) {
|
||||
for (String s : filters) {
|
||||
if (className.startsWith(s))
|
||||
return true;
|
||||
|
@ -146,9 +223,14 @@ public class ErrorDialog extends JDialog {
|
|||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new ErrorDialog(new IllegalArgumentException(
|
||||
"This is test error with very long line of error message that should not be in a single line"))
|
||||
.setVisible(true);
|
||||
String m1 = "This is test error with very very very very very long line of error message that "
|
||||
+ " should not be in a single line. Another message string that shoul dbe split across word." +
|
||||
"The quick brown fox jumpled over the lazy dog";
|
||||
String m2 = "This is another test error with very long line of error message that "
|
||||
+ " should not be in a single line";
|
||||
Throwable nested = new NumberFormatException(m2);
|
||||
Throwable top = new IllegalArgumentException(m1, nested);
|
||||
new ErrorDialog(top).setVisible(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 openbook.client;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import jpa.tools.swing.ErrorDialog;
|
||||
|
||||
/**
|
||||
* Handles error.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class ErrorHandler implements Thread.UncaughtExceptionHandler{
|
||||
|
||||
static {
|
||||
System.setProperty("sun.awt.exception.handler", ErrorHandler.class.getName());
|
||||
}
|
||||
|
||||
public void handle(Throwable e) {
|
||||
uncaughtException(Thread.currentThread(), e);
|
||||
}
|
||||
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
new ErrorDialog(null, Images.ERROR, e).setVisible(true);
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue