Package: DefaultNodeAndDelegate
DefaultNodeAndDelegate
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
lambda$load$1(Class) |
|
|
|
|
|
||||||||||||||||||||
lambda$of$0(Class, String) |
|
|
|
|
|
||||||||||||||||||||
load(Class, String) |
|
|
|
|
|
||||||||||||||||||||
of(Class) |
|
|
|
|
|
||||||||||||||||||||
of(Class, String) |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
Coverage
1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * SteelBlue: DCI User Interfaces
5: * http://tidalwave.it/projects/steelblue
6: *
7: * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * 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
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/steelblue-src
22: * git clone https://github.com/tidalwave-it/steelblue-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.ui.javafx.impl;
27:
28: import jakarta.annotation.Nonnull;
29: import java.io.IOException;
30: import java.io.UncheckedIOException;
31: import javafx.fxml.FXMLLoader;
32: import javafx.scene.Node;
33: import it.tidalwave.ui.javafx.NodeAndDelegate;
34: import org.slf4j.LoggerFactory;
35: import lombok.Getter;
36: import lombok.RequiredArgsConstructor;
37: import lombok.extern.slf4j.Slf4j;
38: import static it.tidalwave.ui.javafx.impl.DefaultJavaFXBinder.enforceFxApplicationThread;
39: import static it.tidalwave.ui.javafx.impl.JavaFXSafeRunner.runSafelyAndWait;
40: import static it.tidalwave.util.ReflectionUtils.*;
41:
42: /***************************************************************************************************************************************************************
43: *
44: * The implementation of {@link NodeAndDelegate}.
45: *
46: * @author Fabrizio Giudici
47: *
48: **************************************************************************************************************************************************************/
49: @RequiredArgsConstructor @Getter @Slf4j
50: public class DefaultNodeAndDelegate<T> implements NodeAndDelegate<T>
51: {
52: @Nonnull
53: private final Node node;
54:
55: @Nonnull
56: private final T delegate;
57:
58: /***********************************************************************************************************************************************************
59: * Creates a {@link NodeAndDelegate} for the given presentation class. The FXML resource name is inferred by default, For instance, is the class is named
60: * {@code JavaFXFooBarPresentation}, the resource name is {@code FooBar.fxml} and searched in the same packages as the class.
61: * @param presentationClass the class of the presentation for which the resources must be created.
62: * @since 1.0-ALPHA-13
63: * @see #of(java.lang.Class, java.lang.String)
64: **********************************************************************************************************************************************************/
65: @Nonnull
66: public static <T> NodeAndDelegate<T> of (@Nonnull final Class<T> presentationClass)
67: {
68: final var resource = presentationClass.getSimpleName().replaceAll("^JavaFX", "")
69: .replaceAll("^JavaFx", "")
70: .replaceAll("Presentation$", "")
71: + ".fxml";
72: return of(presentationClass, resource);
73: }
74:
75: /***********************************************************************************************************************************************************
76: * Creates a {@link NodeAndDelegate} for the given presentation class.
77: * @param presentationClass the class of the presentation for which the resources must be created.
78: * @param fxmlResourcePath the path of the FXML resource
79: **********************************************************************************************************************************************************/
80: @Nonnull
81: public static <T> NodeAndDelegate<T> of (@Nonnull final Class<T> presentationClass, @Nonnull final String fxmlResourcePath)
82: {
83: try
84: {
85: log.debug("of({}, {})", presentationClass, fxmlResourcePath);
86: return runSafelyAndWait(() -> load(presentationClass, fxmlResourcePath));
87: }
88: catch (RuntimeException e)
89: {
90: throw e;
91: }
92: catch (Exception e)
93: {
94: throw new RuntimeException(e);
95: }
96: }
97:
98: /***********************************************************************************************************************************************************
99: *
100: **********************************************************************************************************************************************************/
101: @Nonnull
102: private static <T> NodeAndDelegate<T> load (@Nonnull final Class<T> clazz, @Nonnull final String resource)
103: {
104: try
105: {
106: enforceFxApplicationThread();
107: final var log = LoggerFactory.getLogger(NodeAndDelegate.class);
108: log.debug("NodeAndDelegate({}, {})", clazz, resource);
109: final var loader = new FXMLLoader(clazz.getResource(resource), null, null, type -> instantiateWithDependencies(type, AbstractJavaFXSpringApplication.getBeans()));
110: final Node node = loader.load();
111: final T jfxController = loader.getController();
112: injectDependencies(jfxController, AbstractJavaFXSpringApplication.getBeans());
113: final var interfaces = jfxController.getClass().getInterfaces();
114:
115:• if (interfaces.length == 0)
116: {
117: log.warn("{} has no interface: not creating safe proxy", jfxController.getClass());
118: }
119:
120:• final T delegate = (interfaces.length > 0) ? JavaFXSafeProxy.of(jfxController, interfaces) : jfxController;
121: log.debug(">>>> load({}, {}) completed", clazz, resource);
122: return new DefaultNodeAndDelegate<>(node, delegate);
123: }
124: catch (IOException e)
125: {
126: throw new UncheckedIOException(e);
127: }
128: catch (IllegalStateException e)
129: {
130: final var message = String.format("ERROR: Cannot find resource: %s/%s", clazz.getPackageName().replace('.','/'), resource);
131: log.error("ERROR: Cannot find resource: {}", message);
132: throw new IllegalStateException(message, e);
133: }
134: }
135: }