From 96043c3e1ef439e9b65ec349661b66b01e9facca Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 20 Oct 2010 16:16:21 +0400 Subject: [PATCH] report exceptions in the backgroud (IDEA-33675) --- .../diagnostic/ErrorReportSubmitter.java | 5 + .../intellij/diagnostic/AbstractMessage.java | 9 + .../com/intellij/diagnostic/ITNReporter.java | 161 ++++++++++-------- .../intellij/diagnostic/IdeErrorsDialog.java | 24 ++- .../errorreport/ErrorReportSender.java | 61 +++---- 5 files changed, 142 insertions(+), 118 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java b/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java index 520abaa99634..9c6b45a6833e 100644 --- a/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java +++ b/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java @@ -17,6 +17,7 @@ package com.intellij.openapi.diagnostic; import com.intellij.openapi.extensions.PluginAware; import com.intellij.openapi.extensions.PluginDescriptor; +import com.intellij.util.Consumer; import java.awt.*; @@ -57,4 +58,8 @@ public abstract class ErrorReportSubmitter implements PluginAware { * @return submission result status. */ public abstract SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent); + + public void submitAsync(IdeaLoggingEvent[] events, Component parentComponent, Consumer consumer) { + consumer.consume(submit(events, parentComponent)); + } } diff --git a/platform/platform-impl/src/com/intellij/diagnostic/AbstractMessage.java b/platform/platform-impl/src/com/intellij/diagnostic/AbstractMessage.java index eb561e47b29d..50de1d415489 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/AbstractMessage.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/AbstractMessage.java @@ -23,6 +23,7 @@ import java.util.Date; public abstract class AbstractMessage { private boolean myIsRead = false; + private boolean myIsSubmitting = false; private SubmittedReportInfo mySubmissionInfo; private String myScrID; @@ -52,6 +53,14 @@ public abstract class AbstractMessage { return mySubmissionInfo; } + public boolean isSubmitting() { + return myIsSubmitting; + } + + public void setSubmitting(boolean isSubmitting) { + myIsSubmitting = isSubmitting; + } + public boolean isSubmitted() { return mySubmissionInfo != null && (mySubmissionInfo.getStatus() == SubmittedReportInfo.SubmissionStatus.NEW_ISSUE || diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java index 1a4ad75788ed..b41d02c1397e 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java @@ -23,6 +23,9 @@ import com.intellij.errorreport.error.NoSuchEAPUserException; import com.intellij.ide.DataManager; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.idea.IdeaLogger; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -32,12 +35,10 @@ import com.intellij.openapi.diagnostic.SubmittedReportInfo; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; -import com.intellij.util.net.IOExceptionDialog; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NonNls; -import javax.swing.*; import java.awt.*; -import java.io.IOException; /** * @author max @@ -52,98 +53,110 @@ public class ITNReporter extends ErrorReportSubmitter { } public SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent) { - return sendError(events[0], parentComponent); + // obsolete API + return new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED); + } + + @Override + public void submitAsync(IdeaLoggingEvent[] events, Component parentComponent, Consumer consumer) { + sendError(events [0], parentComponent, consumer); } /** * @noinspection ThrowablePrintStackTrace */ - private static SubmittedReportInfo sendError(IdeaLoggingEvent event, Component parentComponent) { + private static void sendError(IdeaLoggingEvent event, final Component parentComponent, final Consumer callback) { String newBuild = ErrorReportSender.checkNewBuild(); if (newBuild != null) { Messages.showMessageDialog(parentComponent, DiagnosticBundle.message("error.report.new.eap.build.message", newBuild), CommonBundle.getWarningTitle(), Messages.getWarningIcon()); - return new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED); + callback.consume(new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED)); } ErrorBean errorBean = new ErrorBean(event.getThrowable(), IdeaLogger.ourLastActionId); - int threadId = 0; - SubmittedReportInfo.SubmissionStatus submissionStatus = SubmittedReportInfo.SubmissionStatus.FAILED; + String description = ""; + doSubmit(event, parentComponent, callback, errorBean, description); + } + + private static void doSubmit(final IdeaLoggingEvent event, + final Component parentComponent, + final Consumer callback, + final ErrorBean errorBean, final String description) { final DataContext dataContext = DataManager.getInstance().getDataContext(parentComponent); Project project = PlatformDataKeys.PROJECT.getData(dataContext); - String description = ""; - do { - // prepare - try { - EAPSendErrorDialog dlg = new EAPSendErrorDialog(); - dlg.setErrorDescription(description); - dlg.show(); - - @NonNls String login = ErrorReportConfigurable.getInstance().ITN_LOGIN; - @NonNls String password = ErrorReportConfigurable.getInstance().getPlainItnPassword(); - if (login.trim().length() == 0 && password.trim().length() == 0) { - login = "idea_anonymous"; - password = "guest"; - } - - description = dlg.getErrorDescription(); - @NonNls StringBuilder descBuilder = buildDescription(event, description); - errorBean.setDescription(descBuilder.toString()); - - if (dlg.isShouldSend()) { - threadId = ErrorReportSender.sendError(project, login, password, errorBean); - previousExceptionThreadId = threadId; - wasException = true; - submissionStatus = SubmittedReportInfo.SubmissionStatus.NEW_ISSUE; - - Messages.showInfoMessage(parentComponent, - DiagnosticBundle.message("error.report.confirmation"), - ReportMessages.ERROR_REPORT); - break; - } - else { - break; - } - - } - catch (NoSuchEAPUserException e) { - if (Messages.showYesNoDialog(parentComponent, DiagnosticBundle.message("error.report.authentication.failed"), - ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) { - break; - } - } - catch (InternalEAPException e) { - if (Messages.showYesNoDialog(parentComponent, DiagnosticBundle.message("error.report.posting.failed", e.getMessage()), - ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) { - break; - } - } - catch (IOException e) { - if (!IOExceptionDialog.showErrorDialog(DiagnosticBundle.message("error.report.exception.title"), - DiagnosticBundle.message("error.report.failure.message"))) { - break; - } - } - catch (Exception e) { - if (Messages.showYesNoDialog(JOptionPane.getRootFrame(), DiagnosticBundle.message("error.report.sending.failure"), - ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) { - break; - } - } - + final EAPSendErrorDialog dlg = new EAPSendErrorDialog(); + dlg.setErrorDescription(description); + dlg.show(); + if (!dlg.isShouldSend()) { + return; } - while (true); - return new SubmittedReportInfo(submissionStatus != SubmittedReportInfo.SubmissionStatus.FAILED ? URL_HEADER + threadId : null, - String.valueOf(threadId), - submissionStatus); + @NonNls String login = ErrorReportConfigurable.getInstance().ITN_LOGIN; + @NonNls String password = ErrorReportConfigurable.getInstance().getPlainItnPassword(); + if (login.trim().length() == 0 && password.trim().length() == 0) { + login = "idea_anonymous"; + password = "guest"; + } + + errorBean.setDescription(buildDescription(event, dlg.getErrorDescription())); + + ErrorReportSender.sendError(project, login, password, errorBean, new Consumer() { + @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"}) + @Override + public void consume(Integer threadId) { + previousExceptionThreadId = threadId; + wasException = true; + callback.consume(new SubmittedReportInfo(URL_HEADER + threadId, String.valueOf(threadId), + SubmittedReportInfo.SubmissionStatus.NEW_ISSUE)); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Notification notification = new Notification(ReportMessages.ERROR_REPORT, ReportMessages.ERROR_REPORT, + DiagnosticBundle.message("error.report.confirmation"), + NotificationType.INFORMATION); + Notifications.Bus.notify(notification); + } + }); + } + }, new Consumer() { + @Override + public void consume(final Exception e) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + String msg; + if (e instanceof NoSuchEAPUserException) { + msg = DiagnosticBundle.message("error.report.authentication.failed"); + } + else if (e instanceof InternalEAPException) { + msg = DiagnosticBundle.message("error.report.posting.failed", e.getMessage()); + } + else { + msg = DiagnosticBundle.message("error.report.sending.failure"); + } + if (Messages.showYesNoDialog(parentComponent, msg, + ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != 0) { + callback.consume(new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED)); + } + else { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + doSubmit(event, parentComponent, callback, errorBean, dlg.getErrorDescription()); + } + }); + } + } + }); + } + }); } - private static StringBuilder buildDescription(IdeaLoggingEvent event, String description) { + private static String buildDescription(IdeaLoggingEvent event, String description) { String message = event.getMessage(); @NonNls StringBuilder descBuilder = new StringBuilder(); @@ -171,6 +184,6 @@ public class ITNReporter extends ErrorReportSubmitter { if (wasException) { descBuilder.append("There was at least one exception before this one.\n"); } - return descBuilder; + return descBuilder.toString(); } } diff --git a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java index 66f6b15a9409..2eeed8dc10d5 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java @@ -48,6 +48,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.util.Consumer; import com.intellij.util.text.DateFormatUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; @@ -182,11 +183,11 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene if (message.isSubmitted()) { final SubmittedReportInfo info = message.getSubmissionInfo(); if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.FAILED) { - txt.append(DiagnosticBundle.message("error.list.message.submission.failed")); + txt.append(" ").append(DiagnosticBundle.message("error.list.message.submission.failed")); } else { if (info.getLinkText() != null) { - txt.append(DiagnosticBundle.message("error.list.message.submitted.as.link", info.getLinkText())); + txt.append(" ").append(DiagnosticBundle.message("error.list.message.submitted.as.link", info.getLinkText())); if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.DUPLICATE) { txt.append(DiagnosticBundle.message("error.list.message.duplicate")); } @@ -197,6 +198,9 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene } txt.append(". "); } + else if (message.isSubmitting()) { + txt.append(" Submitting..."); + } else if (!message.isRead()) { txt.append(" ").append(DiagnosticBundle.message("error.list.message.unread")); } @@ -508,7 +512,21 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene ErrorReportSubmitter submitter = getSubmitter(logMessage.getThrowable()); if (submitter != null) { - logMessage.setSubmitted(submitter.submit(getEvents(logMessage), getContentPane())); + logMessage.setSubmitting(true); + updateControls(); + submitter.submitAsync(getEvents(logMessage), getContentPane(), new Consumer() { + @Override + public void consume(SubmittedReportInfo submittedReportInfo) { + logMessage.setSubmitting(false); + logMessage.setSubmitted(submittedReportInfo); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + updateControls(); + } + }); + } + }); } } diff --git a/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java b/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java index 5ab173712b8e..333ff16c9567 100644 --- a/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java +++ b/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java @@ -17,24 +17,24 @@ package com.intellij.errorreport; import com.intellij.diagnostic.DiagnosticBundle; import com.intellij.errorreport.bean.ErrorBean; -import com.intellij.errorreport.error.InternalEAPException; -import com.intellij.errorreport.error.NoSuchEAPUserException; import com.intellij.errorreport.itn.ITNProxy; import com.intellij.ide.reporter.ConnectionException; import com.intellij.idea.IdeaLogger; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.updateSettings.impl.BuildInfo; import com.intellij.openapi.updateSettings.impl.UpdateChannel; import com.intellij.openapi.updateSettings.impl.UpdateChecker; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Consumer; import com.intellij.util.net.HttpConfigurable; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.IOException; - /** * Created by IntelliJ IDEA. * User: stathik @@ -44,7 +44,9 @@ import java.io.IOException; */ public class ErrorReportSender { @NonNls public static final String PREPARE_URL = "http://www.intellij.net/"; - //public static String REPORT_URL = "http://unit-038:8080/error/report?sender=i"; + + private ErrorReportSender() { + } @Nullable public static String checkNewBuild() { @@ -64,74 +66,51 @@ public class ErrorReportSender { private String myLogin; private String myPassword; private ErrorBean errorBean; - private int myThreadId; public SendTask(final Project project, ErrorBean errorBean) { myProject = project; this.errorBean = errorBean; } - public int getThreadId () { - return myThreadId; - } - public void setCredentials(String login, String password) { myLogin = login; myPassword = password; } - public void sendReport() throws Exception { - final Ref err = new Ref(); - Runnable runnable = new Runnable() { - public void run() { + public void sendReport(final Consumer callback, final Consumer errback) { + Task.Backgroundable task = new Task.Backgroundable(myProject, DiagnosticBundle.message("title.submitting.error.report")) { + @Override + public void run(@NotNull ProgressIndicator indicator) { try { HttpConfigurable.getInstance().prepareURL(PREPARE_URL); if (!StringUtil.isEmpty(myLogin)) { - myThreadId = ITNProxy.postNewThread( + int threadId = ITNProxy.postNewThread( myLogin, myPassword, errorBean, IdeaLogger.getOurCompilationTimestamp()); + callback.consume(threadId); } } catch (Exception ex) { - err.set(ex); + errback.consume(ex); } } }; if (myProject == null) { - runnable.run(); + task.run(new EmptyProgressIndicator()); } else { - ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, - DiagnosticBundle.message("title.submitting.error.report"), - false, myProject); - } - if (!err.isNull()) { - throw err.get(); + ProgressManager.getInstance().run(task); } } } - public static int sendError(Project project, String login, String password, ErrorBean error) - throws IOException, NoSuchEAPUserException, InternalEAPException { - + public static void sendError(Project project, String login, String password, ErrorBean error, + Consumer callback, Consumer errback) { SendTask sendTask = new SendTask (project, error); sendTask.setCredentials(login, password); - - try { - sendTask.sendReport(); - return sendTask.getThreadId(); - } catch (IOException e) { - throw e; - } catch (NoSuchEAPUserException e) { - throw e; - } catch (InternalEAPException e) { - throw e; - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } + sendTask.sendReport(callback, errback); } }