Skip to content

Package: PanelGroupControlSupport

PanelGroupControlSupport

nameinstructionbranchcomplexitylinemethod
PanelGroupControlSupport(BeanFactory, String)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
PanelGroupControlSupport(Function, BeanFactory, String)
M: 0 C: 19
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
defaultPanelGroupProviders(As)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
destroy()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getMessageBus(BeanFactory, String)
M: 0 C: 16
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
initialize()
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$destroy$7(MessageBus)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$initialize$6(MessageBus)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$publish$5(Object, MessageBus)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$setup$0(PanelGroupControl.Group)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$setup$1(HashMap, PanelGroupProvider)
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$setup$2(PanelGroupControl.Group, List)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$setup$3(Map, PanelGroupControl.Group)
M: 2 C: 6
75%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$setup$4(Map, PanelGroupControl.Configuration, PanelGroupControl.Group, List)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
publish(Object)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setup(PanelGroupControl.Configuration)
M: 7 C: 41
85%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 9
90%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

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.core.spi;
27:
28: import jakarta.annotation.Nonnull;
29: import jakarta.annotation.PostConstruct;
30: import jakarta.annotation.PreDestroy;
31: import java.util.ArrayList;
32: import java.util.Collection;
33: import java.util.HashMap;
34: import java.util.List;
35: import java.util.Map;
36: import java.util.Optional;
37: import java.util.function.Function;
38: import org.springframework.beans.factory.BeanFactory;
39: import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
40: import it.tidalwave.ui.core.PanelGroupControl;
41: import it.tidalwave.ui.core.PanelGroupProvider;
42: import it.tidalwave.ui.core.message.PanelShowRequest;
43: import org.apiguardian.api.API;
44: import it.tidalwave.util.As;
45: import it.tidalwave.util.annotation.VisibleForTesting;
46: import it.tidalwave.messagebus.MessageBus;
47: import lombok.experimental.Delegate;
48: import lombok.extern.slf4j.Slf4j;
49: import static org.apiguardian.api.API.Status.EXPERIMENTAL;
50: import static java.util.stream.Collectors.*;
51: import static it.tidalwave.util.ShortNames.shortIds;
52:
53: /***************************************************************************************************************************************************************
54: *
55: * A support implementation of {@link PanelGroupControl}.
56: *
57: * @param <T> the type of the control
58: * @param <S> the type of the top container
59: * @since 2.0-ALPHA-3
60: * @author Fabrizio Giudici
61: *
62: **************************************************************************************************************************************************************/
63: @API(status = EXPERIMENTAL)
64: @Slf4j @SuppressWarnings("this-escape")
65: public abstract class PanelGroupControlSupport<T, S> implements As, PanelGroupControl<T>
66: {
67: @Delegate @Nonnull
68: private final As delegate = As.forObject(this);
69:
70: @Nonnull
71: private final Function<As, Collection<PanelGroupProvider<S>>> pgProvider;
72:
73: /** The message bus, if present on the system. */
74: @Nonnull
75: private final Optional<MessageBus> messageBus;
76:
77: /** The listener to the message bus. */
78: private final MessageBus.Listener<PanelShowRequest> messageListener = this::onShowRequest;
79:
80: /***********************************************************************************************************************************************************
81: * This class doesn't rely on the @SimpleSubscriber/@ListensTo annotations to avoid having a dependency on the MessageBus runtime, so it dynamically
82: * queries a {@link BeanFactory}.
83: **********************************************************************************************************************************************************/
84: @SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
85: protected PanelGroupControlSupport (@Nonnull final BeanFactory beanFactory, @Nonnull final String messageBusBeanName)
86: {
87: this(PanelGroupControlSupport::defaultPanelGroupProviders, beanFactory, messageBusBeanName);
88: }
89:
90: /***********************************************************************************************************************************************************
91: * Constructor for tets.
92: **********************************************************************************************************************************************************/
93: @SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
94: protected PanelGroupControlSupport (@Nonnull final Function<As, Collection<PanelGroupProvider<S>>> pgProvider,
95: @Nonnull final BeanFactory beanFactory,
96: @Nonnull final String messageBusBeanName)
97: {
98: this.pgProvider = pgProvider;
99: messageBus = getMessageBus(beanFactory, messageBusBeanName);
100: }
101:
102: /***********************************************************************************************************************************************************
103: * {@inheritDoc}
104: **********************************************************************************************************************************************************/
105: @Override
106: public void setup (@Nonnull final Configuration<T> configuration)
107: {
108: final var topContainersByGroup = configuration.getTopContainersByGroup();
109: final var providersByGroup = new HashMap<Group, List<PanelGroupProvider<S>>>();
110: pgProvider.apply(this).forEach(p -> providersByGroup.computeIfAbsent(p.getGroup(), ignored -> new ArrayList<>()).add(p));
111: log.debug("Providers by placement:");
112: providersByGroup.forEach((placement, provider) -> log.debug(">>>> {}: {}", placement, shortIds(provider)));
113:• final var unboundGroups = providersByGroup.keySet().stream().filter(p -> !topContainersByGroup.containsKey(p)).collect(toList());
114:
115:• if (!unboundGroups.isEmpty())
116: {
117: throw new IllegalArgumentException("No top container(s) provider for " + unboundGroups);
118: }
119:
120: providersByGroup.forEach((group, providers) ->
121: assemble(group, providers, topContainersByGroup.get(group), configuration.getGroupOptions(), configuration.getOptions()));
122: }
123:
124: /***********************************************************************************************************************************************************
125: * Assemble a set of panes for the given group.
126: * @param group the {@code Group}
127: * @param panelProviders the {@code PanelGroupProvider}s associated to the given {@code Group}
128: * @param topContainer the top container
129: * @param groupOptions options for each group
130: * @param options options for doing the job
131: **********************************************************************************************************************************************************/
132: protected abstract void assemble (@Nonnull final Group group,
133: @Nonnull final List<? extends PanelGroupProvider<S>> panelProviders,
134: @Nonnull final T topContainer,
135: @Nonnull final Map<Group, List<Options>> groupOptions,
136: @Nonnull final List<Options> options);
137:
138: /***********************************************************************************************************************************************************
139: *
140: **********************************************************************************************************************************************************/
141: protected abstract void onShowRequest (@Nonnull PanelShowRequest panelShowRequest);
142:
143: /***********************************************************************************************************************************************************
144: *
145: **********************************************************************************************************************************************************/
146: protected void publish (@Nonnull final Object message)
147: {
148: messageBus.ifPresent(mb -> mb.publish(message));
149: }
150:
151: /***********************************************************************************************************************************************************
152: *
153: **********************************************************************************************************************************************************/
154: @PostConstruct
155: @VisibleForTesting void initialize()
156: {
157: messageBus.ifPresent(mb -> mb.subscribe(PanelShowRequest.class, messageListener));
158: }
159:
160: /***********************************************************************************************************************************************************
161: *
162: **********************************************************************************************************************************************************/
163: @PreDestroy
164: @VisibleForTesting void destroy()
165: {
166: messageBus.ifPresent(mb -> mb.unsubscribe(messageListener));
167: }
168:
169: /***********************************************************************************************************************************************************
170: *
171: **********************************************************************************************************************************************************/
172: @Nonnull
173: private static Optional<MessageBus> getMessageBus (@Nonnull final BeanFactory beanFactory, @Nonnull final String messageBusBeanName)
174: {
175:• if (beanFactory.containsBean(messageBusBeanName))
176: {
177: return Optional.of(beanFactory.getBean(messageBusBeanName, MessageBus.class));
178: }
179: else
180: {
181: log.warn("No message bus");
182: return Optional.empty();
183: }
184: }
185:
186: /***********************************************************************************************************************************************************
187: *
188: **********************************************************************************************************************************************************/
189: @Nonnull
190: private static <S> Collection<PanelGroupProvider<S>> defaultPanelGroupProviders (@Nonnull final As as)
191: {
192: return as.asMany(As.<PanelGroupProvider<S>>type(PanelGroupProvider.class));
193: }
194: }