1 | package fr.sii.ogham.core.builder.sender; | |
2 | ||
3 | import static fr.sii.ogham.core.util.BuilderUtils.instantiateBuilder; | |
4 | ||
5 | import java.util.ArrayList; | |
6 | import java.util.List; | |
7 | ||
8 | import org.slf4j.Logger; | |
9 | import org.slf4j.LoggerFactory; | |
10 | ||
11 | import fr.sii.ogham.core.builder.ActivableAtRuntime; | |
12 | import fr.sii.ogham.core.builder.Builder; | |
13 | import fr.sii.ogham.core.builder.condition.RequiredClass; | |
14 | import fr.sii.ogham.core.builder.condition.RequiredClasses; | |
15 | import fr.sii.ogham.core.builder.condition.RequiredProperties; | |
16 | import fr.sii.ogham.core.builder.condition.RequiredProperty; | |
17 | import fr.sii.ogham.core.builder.context.BuildContext; | |
18 | import fr.sii.ogham.core.builder.env.EnvironmentBuilder; | |
19 | import fr.sii.ogham.core.builder.priority.ImplementationPriorityProvider; | |
20 | import fr.sii.ogham.core.builder.priority.PriorityProvider; | |
21 | import fr.sii.ogham.core.condition.Condition; | |
22 | import fr.sii.ogham.core.condition.fluent.MessageConditions; | |
23 | import fr.sii.ogham.core.condition.provider.ImplementationConditionProvider; | |
24 | import fr.sii.ogham.core.message.Message; | |
25 | import fr.sii.ogham.core.sender.MessageSender; | |
26 | import fr.sii.ogham.core.sender.MultiImplementationSender; | |
27 | ||
28 | /** | |
29 | * Helps to configure a {@link MultiImplementationSender}. | |
30 | * | |
31 | * <p> | |
32 | * It registers and uses {@link Builder}s to instantiate and configure a | |
33 | * {@link MessageSender} implementation. | |
34 | * </p> | |
35 | * | |
36 | * <p> | |
37 | * It also let you provide your own direct {@link MessageSender} implementation. | |
38 | * </p> | |
39 | * | |
40 | * @author Aurélien Baudet | |
41 | * | |
42 | * @param <P> | |
43 | * the type of the parent builder {@link MessageSender} | |
44 | * {@link Builder} | |
45 | */ | |
46 | public class SenderImplementationBuilderHelper<P> { | |
47 | private static final Logger LOG = LoggerFactory.getLogger(SenderImplementationBuilderHelper.class); | |
48 | ||
49 | private final P parent; | |
50 | private final BuildContext buildContext; | |
51 | private final List<Builder<? extends MessageSender>> senderBuilders; | |
52 | private final List<MessageSender> customSenders; | |
53 | private final PriorityProvider<MessageSender> priorityProvider; | |
54 | ||
55 | /** | |
56 | * Initializes the builder with a parent builder. The parent builder is used | |
57 | * when calling and() method of any registered {@link Message} | |
58 | * {@link Builder}. The {@link EnvironmentBuilder} is used to evaluate | |
59 | * properties at build time (when | |
60 | * {@link #addSenders(MultiImplementationSender)} is called). | |
61 | * | |
62 | * @param parent | |
63 | * the parent builder | |
64 | * @param buildContext | |
65 | * for registering instances and property evaluation | |
66 | */ | |
67 | public SenderImplementationBuilderHelper(P parent, BuildContext buildContext) { | |
68 | super(); | |
69 | this.parent = parent; | |
70 | this.buildContext = buildContext; | |
71 | senderBuilders = new ArrayList<>(); | |
72 | customSenders = new ArrayList<>(); | |
73 | priorityProvider = new ImplementationPriorityProvider<>(buildContext); | |
74 | } | |
75 | ||
76 | /** | |
77 | * Returns true if at least either one custom sender or a sender builder was | |
78 | * previously registered. | |
79 | * | |
80 | * @return true if at least one custom sender or one sender builder | |
81 | */ | |
82 | public boolean hasRegisteredSenders() { | |
83 |
3
1. hasRegisteredSenders : replaced boolean return with true for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::hasRegisteredSenders → NO_COVERAGE 2. hasRegisteredSenders : negated conditional → NO_COVERAGE 3. hasRegisteredSenders : negated conditional → NO_COVERAGE |
return !customSenders.isEmpty() || !senderBuilders.isEmpty(); |
84 | } | |
85 | ||
86 | /** | |
87 | * Registers a custom message sender implementation. | |
88 | * | |
89 | * <p> | |
90 | * If your custom implementation is annotated by one or several of: | |
91 | * <ul> | |
92 | * <li>{@link RequiredClass}</li> | |
93 | * <li>{@link RequiredProperty}</li> | |
94 | * <li>{@link RequiredClasses}</li> | |
95 | * <li>{@link RequiredProperties}</li> | |
96 | * </ul> | |
97 | * Then if condition evaluation returns true, your implementation will be | |
98 | * used. If you provide several annotations, your implementation will be | |
99 | * used only if all conditions are met (and operator). | |
100 | * | |
101 | * <p> | |
102 | * If your custom implementation implements {@link ActivableAtRuntime}, and | |
103 | * the provided condition evaluation returns true, then your implementation | |
104 | * will be used. | |
105 | * | |
106 | * See {@link MessageConditions} to build your condition. | |
107 | * </p> | |
108 | * | |
109 | * <p> | |
110 | * If neither annotations nor implementation of {@link ActivableAtRuntime} | |
111 | * is used, then your custom implementation will be always used. All other | |
112 | * implementations (even standard ones) will never be used. | |
113 | * </p> | |
114 | * | |
115 | * @param sender | |
116 | * the sender to register | |
117 | */ | |
118 | public void customSender(MessageSender sender) { | |
119 | customSenders.add(sender); | |
120 | } | |
121 | ||
122 | /** | |
123 | * Registers and configures sender through a dedicated builder. | |
124 | * | |
125 | * For example: | |
126 | * | |
127 | * <pre> | |
128 | * .register(JavaMailBuilder.class) | |
129 | * .host("localhost"); | |
130 | * </pre> | |
131 | * | |
132 | * <p> | |
133 | * If your custom builder is annotated by one or several of: | |
134 | * <ul> | |
135 | * <li>{@link RequiredClass}</li> | |
136 | * <li>{@link RequiredProperty}</li> | |
137 | * <li>{@link RequiredClasses}</li> | |
138 | * <li>{@link RequiredProperties}</li> | |
139 | * </ul> | |
140 | * Then if condition evaluation returns true, your built implementation will | |
141 | * be used. If you provide several annotations, your built implementation | |
142 | * will be used only if all conditions are met (and operator). | |
143 | * | |
144 | * <p> | |
145 | * If your custom builder implements {@link ActivableAtRuntime}, and the | |
146 | * provided condition evaluation returns true, then your built | |
147 | * implementation will be used. | |
148 | * | |
149 | * See {@link MessageConditions} to build your condition. | |
150 | * </p> | |
151 | * | |
152 | * <p> | |
153 | * If neither annotations nor implementation of {@link ActivableAtRuntime} | |
154 | * is used, then your built implementation will be always used. All other | |
155 | * implementations (even standard ones) will never be used. | |
156 | * </p> | |
157 | * | |
158 | * <p> | |
159 | * In order to be able to keep chaining, you builder instance may provide a | |
160 | * constructor with one argument with the type of the parent builder | |
161 | * ({@code <P>}). If you don't care about chaining, just provide a | |
162 | * default constructor. | |
163 | * </p> | |
164 | * | |
165 | * <p> | |
166 | * Your builder may return {@code null} when calling | |
167 | * {@link Builder#build()}. In this case it means that your implementation | |
168 | * can't be used due to current environment. Your implementation is then not | |
169 | * registered. | |
170 | * </p> | |
171 | * | |
172 | * @param builderClass | |
173 | * the builder class to instantiate | |
174 | * @param <B> | |
175 | * the type of the builder | |
176 | * @return the builder to configure the implementation | |
177 | * | |
178 | */ | |
179 | @SuppressWarnings("unchecked") | |
180 | public <B extends Builder<? extends MessageSender>> B register(Class<B> builderClass) { | |
181 | // if builder already registered => provide same instance | |
182 | for (Builder<? extends MessageSender> builder : senderBuilders) { | |
183 |
6
1. register : negated conditional → NO_COVERAGE 2. register : negated conditional → KILLED 3. register : negated conditional → KILLED 4. register : negated conditional → KILLED 5. register : negated conditional → KILLED 6. register : negated conditional → KILLED |
if (builderClass.isAssignableFrom(builder.getClass())) { |
184 |
5
1. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → NO_COVERAGE 2. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 3. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 4. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 5. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED |
return (B) builder; |
185 | } | |
186 | } | |
187 | B builder = instantiateBuilder(builderClass, parent, buildContext); | |
188 | senderBuilders.add(builder); | |
189 |
8
1. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → NO_COVERAGE 2. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → TIMED_OUT 3. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 4. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 5. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 6. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 7. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED 8. register : replaced return value with null for fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::register → KILLED |
return builder; |
190 | } | |
191 | ||
192 | /** | |
193 | * Add registered custom senders or built senders base on registered sender | |
194 | * builders to the provided {@link MultiImplementationSender}. | |
195 | * | |
196 | * <p> | |
197 | * A {@link MultiImplementationSender} is able to evaluate a | |
198 | * {@link Condition} when a message is being sent to determine which | |
199 | * implementation can and should handle the message and really send it. | |
200 | * </p> | |
201 | * | |
202 | * <p> | |
203 | * If a custom implementation was registered and is annotated by one or | |
204 | * several of: | |
205 | * <ul> | |
206 | * <li>{@link RequiredClass}</li> | |
207 | * <li>{@link RequiredProperty}</li> | |
208 | * <li>{@link RequiredClasses}</li> | |
209 | * <li>{@link RequiredProperties}</li> | |
210 | * </ul> | |
211 | * Then if condition evaluation returns true, the custom implementation will | |
212 | * be used. If you provide several annotations, the custom implementation | |
213 | * will be used only if all conditions are met (and operator). | |
214 | * | |
215 | * <p> | |
216 | * If a custom implementation was registered and implements | |
217 | * {@link ActivableAtRuntime}, and the provided condition evaluation returns | |
218 | * true, then the custom implementation will be used. | |
219 | * | |
220 | * See {@link MessageConditions} to build your condition. | |
221 | * </p> | |
222 | * | |
223 | * <p> | |
224 | * If neither annotations nor implementation of {@link ActivableAtRuntime} | |
225 | * is used, then the custom implementation will be always used. All other | |
226 | * implementations (even standard ones) will never be used. | |
227 | * </p> | |
228 | * | |
229 | * @param mainSender | |
230 | * the sender that manages several implementations | |
231 | */ | |
232 | public void addSenders(MultiImplementationSender<?> mainSender) { | |
233 | ImplementationConditionProvider implementationSelection = new ImplementationConditionProvider(buildContext.getPropertyResolver()); | |
234 | for (MessageSender customSender : customSenders) { | |
235 | LOG.debug("Custom implementation {} registered into {}", customSender, mainSender); | |
236 | mainSender.addImplementation(implementationSelection.provide(customSender), buildContext.register(customSender), priorityProvider.provide(customSender)); | |
237 | } | |
238 | for (Builder<? extends MessageSender> builder : senderBuilders) { | |
239 | MessageSender sender = builder.build(); | |
240 |
8
1. addSenders : negated conditional → NO_COVERAGE 2. addSenders : negated conditional → KILLED 3. addSenders : negated conditional → KILLED 4. addSenders : negated conditional → KILLED 5. addSenders : negated conditional → KILLED 6. addSenders : negated conditional → KILLED 7. addSenders : negated conditional → KILLED 8. addSenders : negated conditional → KILLED |
if (sender != null) { |
241 | LOG.debug("Implementation {} registered into {}", sender, mainSender); | |
242 | mainSender.addImplementation(implementationSelection.provide(builder), sender, priorityProvider.provide(sender)); | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | } | |
Mutations | ||
83 |
1.1 2.2 3.3 |
|
183 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
184 |
1.1 2.2 3.3 4.4 5.5 |
|
189 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
240 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |