Skip to content

Commit 26602b8

Browse files
javier-godoymlopezFC
authored andcommitted
feat: add error event observer
1 parent d9aefd2 commit 26602b8

File tree

6 files changed

+246
-0
lines changed

6 files changed

+246
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*-
2+
* #%L
3+
* Error Window Add-on
4+
* %%
5+
* Copyright (C) 2017 - 2023 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.errorwindow;
21+
22+
import com.vaadin.flow.component.UI;
23+
import java.util.EventObject;
24+
25+
/**
26+
* Event object with a exception trace.
27+
*/
28+
public class ErrorEvent extends EventObject {
29+
30+
private Throwable throwable;
31+
32+
private boolean preventDefault;
33+
34+
public ErrorEvent(UI ui, Throwable throwable) {
35+
super(ui);
36+
this.throwable = throwable;
37+
}
38+
39+
public Throwable getThrowable() {
40+
return throwable;
41+
}
42+
43+
/** Prevents the default processing by {@link ErrorWindowFactory}. */
44+
public void preventDefault() {
45+
preventDefault = true;
46+
}
47+
48+
public boolean isPreventDefault() {
49+
return preventDefault;
50+
}
51+
52+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*-
2+
* #%L
3+
* Error Window Add-on
4+
* %%
5+
* Copyright (C) 2017 - 2023 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.errorwindow;
21+
22+
import java.io.Serializable;
23+
24+
/**
25+
* Any {@code com.vaadin.ui.Component} implementing this interface will be informed when
26+
* {@link ErrorManager} handles an exception.
27+
*/
28+
@FunctionalInterface
29+
public interface ErrorEventObserver extends Serializable {
30+
31+
/**
32+
* Notifies when {@link ErrorManager} handles an exception.
33+
*
34+
* @param event error event with exception details
35+
*/
36+
void onError(ErrorEvent event);
37+
38+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*-
2+
* #%L
3+
* Error Window Add-on
4+
* %%
5+
* Copyright (C) 2017 - 2023 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.errorwindow;
21+
22+
import com.vaadin.flow.component.UI;
23+
import com.vaadin.flow.dom.Element;
24+
import com.vaadin.flow.router.EventUtil;
25+
import java.util.ArrayList;
26+
import java.util.Collection;
27+
import java.util.List;
28+
import java.util.Objects;
29+
import java.util.stream.Collectors;
30+
import java.util.stream.Stream;
31+
32+
final class ErrorEventWindowFactory implements ErrorWindowFactory {
33+
34+
private final ErrorWindowFactory delegate;
35+
36+
private ErrorEventWindowFactory(ErrorWindowFactory delegate) {
37+
this.delegate = Objects.requireNonNull(delegate);
38+
}
39+
40+
public static ErrorWindowFactory newInstance(ErrorWindowFactory delegate) {
41+
return new ErrorEventWindowFactory(delegate);
42+
}
43+
44+
@Override
45+
public void showError(ErrorDetails details) {
46+
UI ui = UI.getCurrent();
47+
ErrorEvent event = new ErrorEvent(ui, details.getThrowable());
48+
collectErrorEventObservers(ui.getElement()).forEach(observer -> observer.onError(event));
49+
if (!event.isPreventDefault()) {
50+
delegate.showError(details);
51+
}
52+
}
53+
54+
@Override
55+
public boolean isProductionMode() {
56+
return delegate.isProductionMode();
57+
}
58+
59+
public static List<ErrorEventObserver> collectErrorEventObservers(Element element) {
60+
return EventUtil
61+
.getImplementingComponents(flattenDescendants(element), ErrorEventObserver.class)
62+
.collect(Collectors.toList());
63+
}
64+
65+
// see EventUtil.flattenDescendants
66+
private static Stream<Element> flattenDescendants(Element element) {
67+
Collection<Element> descendants = new ArrayList<>();
68+
EventUtil.inspectHierarchy(element, descendants, item -> true);
69+
return descendants.stream();
70+
}
71+
72+
}

src/main/java/com/flowingcode/vaadin/addons/errorwindow/ErrorManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public static void setErrorWindowFactory(Class<? extends Throwable> clazz,
9090
*/
9191
public static ErrorWindowFactory getErrorWindowFactory(Class<?> clazz) {
9292
return Optional.ofNullable(factories.get(clazz))
93+
.map(ErrorEventWindowFactory::newInstance)
9394
.orElseGet(() -> getErrorWindowFactory(clazz.getSuperclass()));
9495
}
9596

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*-
2+
* #%L
3+
* Error Window Add-on
4+
* %%
5+
* Copyright (C) 2017 - 2023 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
21+
22+
package com.flowingcode.vaadin.addons.errorwindow;
23+
24+
import com.flowingcode.vaadin.addons.demo.DemoSource;
25+
import com.vaadin.flow.component.Text;
26+
import com.vaadin.flow.component.button.Button;
27+
import com.vaadin.flow.component.html.Div;
28+
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
29+
import com.vaadin.flow.component.upload.Upload;
30+
import com.vaadin.flow.router.PageTitle;
31+
import com.vaadin.flow.router.Route;
32+
33+
@DemoSource
34+
@PageTitle("Error Event")
35+
@Route(value = "error-window/error-event", layout = ErrorwindowDemoView.class)
36+
@SuppressWarnings("serial")
37+
public class ErrorEventObserverDemo extends VerticalLayout implements ErrorEventObserver {
38+
39+
private VerticalLayout target = new VerticalLayout();
40+
41+
@Override
42+
public void onError(ErrorEvent event) {
43+
String str = "We handled a " + event.getThrowable().getClass().getName();
44+
target.add(new Div(new Text(str)));
45+
event.preventDefault();
46+
}
47+
48+
public ErrorEventObserverDemo() {
49+
ErrorWindowI18n errorWindowI18n = ErrorWindowI18n.create(this::getTranslation);
50+
ErrorManager.setErrorWindowFactory(new I18nErrorWindowFactory(errorWindowI18n));
51+
52+
Button errorButton =
53+
new Button(
54+
"Throw Error",
55+
event -> {
56+
throw new RuntimeException("Uh oh!");
57+
});
58+
59+
Button throwErrorWithoutErrorHandler =
60+
new Button(
61+
"Throw Error without an error handler",
62+
ev -> {
63+
try {
64+
throw new RuntimeException("Uh oh!");
65+
} catch (RuntimeException e) {
66+
ErrorManager.showError(e);
67+
}
68+
});
69+
70+
Upload upload = new Upload(new NullMemoryBuffer());
71+
upload.addSucceededListener(ev -> {
72+
throw new UnsupportedOperationException("File upload is not allowed");
73+
});
74+
75+
setSizeFull();
76+
add(errorButton, throwErrorWithoutErrorHandler, upload);
77+
78+
add(target);
79+
target.add(new Text("Errors will be appended here:"));
80+
}
81+
82+
}

src/test/java/com/flowingcode/vaadin/addons/errorwindow/ErrorwindowDemoView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class ErrorwindowDemoView extends TabbedDemo {
3535

3636
public ErrorwindowDemoView() {
3737
addDemo(ErrorwindowDemo.class);
38+
addDemo(ErrorEventObserverDemo.class);
3839
setSizeFull();
3940
}
4041
}

0 commit comments

Comments
 (0)