通过ErrorHandler接口的StreamResourceWriter错误处理

时间:2019-03-19 11:39:24

标签: java vaadin vaadin-flow vaadin10

我有一个实现StreamResourceWriter接口的FileCreator类和一个实现ErrorHandler的MainErrorHandler类。我在项目中使用MainErrorHandler类作为集中式异常处理程序,该处理程序主要记录异常并向用户显示通知。问题在于StreamResourceWriter.accept()方法在非UI线程中运行,并且在引发Exception时将其定向到ErrorHandler,该错误处理由于“ IllegalStateException ”而无法显示通知:UI实例为无法使用”。 当FileCreator在accept()方法中引发错误时,是否可以通过MainErrorHandler向用户显示通知窗口?

在FileCreator片段下方。

public class FileCreator implements StreamResourceWriter {
    @Override
    public void accept(OutputStream stream, VaadinSession session) throws IOException {
        // Run in a non ui thread.
        // Writes to OutputStream but an Exception might be thrown during this process
    }
}

MainErrorHandler代码段下方。

/**
 * Centralized error handler
 */
public class MainErrorHandler implements ErrorHandler {
    private static final Logger log = LoggerFactory.getLogger(MainErrorHandler.class);
    @Override
    public void error(ErrorEvent event) {
        log.error("Error occurred", event.getThrowable());
        //Cannot show a notification if ErrorEvent came from FileCreator.
        //Will get an IllegalStateException: UI instance is not available.
        Notification.show("Error occurred");
        //Tried UI.getCurrent but it returns null if ErrorEvent came from FileCreator.
        UI.getCurrent();
    }
}

使用Vaadin 13.0.1。

编辑

解决此问题的一种方法是将UI引用直接传递给FileCreator。下面是一个例子。

public class FileCreator implements StreamResourceWriter {
    private UI ui;
    //Pass UI reference directly
    public FileCreator(UI ui){
       this.ui = ui;                                                        
    }
    @Override
    public void accept(OutputStream stream, VaadinSession session) throws IOException {
       try{
        // Run in a non ui thread.
        // Writes to OutputStream but an Exception might be thrown during this process
       }catch(Exception e){
           //I don't like this since have to catch all exceptions and have to call ErrorHandeler directly with a UI reference. Also what if somewhere in code ErrorHandler is changed and is not of type MainErrorHandler.
           ((MainErrorHandler)VaadinSession.getCurrent().getErrorHandler()).error(e, ui);
       }
    }
}

正如我在评论中所说,我真的也不喜欢这种方法,因为我被迫捕获所有异常,必须将ErrorHandler强制转换为MainErrorHandler并直接调用它。

1 个答案:

答案 0 :(得分:0)

有办法,但并不完美。

您可以通过VaadinSession.getCurrent().getUIs()获取所有UI实例。

要过滤掉无效/分离的UI,您可以检查ui.getSession()是否返回VaadinSession(因此,不为null)。 getSession的JavaDoc说:

  

如果UI当前未附加到VaadinSession,则该方法将返回null。

然后,您可以在每个UI上调用access方法,并在UI上下文中创建并显示通知。

for(UI ui : VaadinSession.getCurrent().getUIs()) {
    // Filtering out detached/inactive UIs
    if (ui.getSession() != null) {
        ui.access(() -> {
            // create Notification here
        });
    }   

我说这并不完美,因为您必须牢记用户可以同时打开多个UI(例如,多个选项卡)。