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;
|
package jpa.tools.swing;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
@ -22,119 +21,197 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.Box;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JEditorPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTextArea;
|
|
||||||
import javax.swing.JTextPane;
|
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")
|
@SuppressWarnings("serial")
|
||||||
public class ErrorDialog extends JDialog {
|
public class ErrorDialog extends JDialog {
|
||||||
private static List<String> filters = Arrays.asList("java.awt.", "javax.swing.", "sun.reflect.");
|
private static List<String> filters = Arrays.asList(
|
||||||
private static AttributeSet red, black;
|
"java.awt.",
|
||||||
static {
|
"javax.swing.",
|
||||||
StyleContext ctx = StyleContext.getDefaultStyleContext();
|
"sun.reflect.",
|
||||||
red = ctx.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.RED);
|
"java.util.concurrent.");
|
||||||
red = ctx.addAttribute(red, StyleConstants.Bold, true);
|
private static Dimension MESSAGE_SIZE = new Dimension(600,200);
|
||||||
red = ctx.addAttribute(red, StyleConstants.FontSize, 12);
|
private static Dimension STACKTRACE_SIZE = new Dimension(600,300);
|
||||||
red = ctx.addAttribute(red, StyleConstants.FontFamily, "Courier");
|
private static Dimension TOTAL_SIZE = new Dimension(600,500);
|
||||||
black = ctx.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.BLACK);
|
|
||||||
black = ctx.addAttribute(black, StyleConstants.Bold, false);
|
|
||||||
black = ctx.addAttribute(black, StyleConstants.FontFamily, "Courier");
|
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) {
|
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();
|
super();
|
||||||
|
setTitle(t.getClass().getName());
|
||||||
setModal(true);
|
setModal(true);
|
||||||
|
if (icon != null && icon instanceof ImageIcon)
|
||||||
|
setIconImage(((ImageIcon)icon).getImage());
|
||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
// Icon icon = Images.ERROR;
|
_error = t;
|
||||||
// setIconImage(((ImageIcon)icon).getImage());
|
_message = createErrorMessage(_error);
|
||||||
addException(t);
|
_main = createContent();
|
||||||
|
getContentPane().add(_main);
|
||||||
|
|
||||||
pack();
|
pack();
|
||||||
SwingHelper.position(this, owner);
|
SwingHelper.position(this, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorDialog(Throwable t) {
|
/**
|
||||||
this(null, t);
|
* Creates the display with the top-level exception message
|
||||||
}
|
* followed by a pane (that toggles) for detailed stack traces.
|
||||||
|
*
|
||||||
void addException(Throwable t) {
|
* @param t a non-null exception
|
||||||
setTitle("Error");
|
*/
|
||||||
String txt = t.getClass().getName() + ":" + t.getLocalizedMessage();
|
JComponent createContent() {
|
||||||
JTextArea message = new JTextArea(txt);
|
final JButton showDetails = new JButton("Show Details >>");
|
||||||
message.setLineWrap(true);
|
showDetails.addActionListener(new ActionListener() {
|
||||||
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() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
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);
|
JPanel messagePanel = new JPanel();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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();
|
Throwable cause = t.getCause();
|
||||||
if (cause !=null && cause != t) {
|
if (cause !=null && cause != t) {
|
||||||
printStackTrace(cause, text);
|
generateStackTrace(cause, buffer);
|
||||||
}
|
}
|
||||||
return null;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder toString(StackTraceElement[] traces) {
|
StringBuilder toString(StackTraceElement[] traces) {
|
||||||
StringBuilder error = new StringBuilder();
|
StringBuilder error = new StringBuilder();
|
||||||
for (StackTraceElement e : traces) {
|
for (StackTraceElement e : traces) {
|
||||||
if (!isFiltered(e.getClassName())) {
|
if (!_isFiltering || !isSuppressed(e.getClassName())) {
|
||||||
String str = e.toString();
|
String str = e.toString();
|
||||||
error.append(str).append("\r\n");
|
error.append(INDENT).append(str).append(NEWLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error;
|
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) {
|
for (String s : filters) {
|
||||||
if (className.startsWith(s))
|
if (className.startsWith(s))
|
||||||
return true;
|
return true;
|
||||||
|
@ -146,9 +223,14 @@ public class ErrorDialog extends JDialog {
|
||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new ErrorDialog(new IllegalArgumentException(
|
String m1 = "This is test error with very very very very very long line of error message that "
|
||||||
"This is test error with very long line of error message that should not be in a single line"))
|
+ " should not be in a single line. Another message string that shoul dbe split across word." +
|
||||||
.setVisible(true);
|
"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