| 1 | package fr.sii.ogham.sms.builder; | |
| 2 | ||
| 3 | import org.slf4j.Logger; | |
| 4 | import org.slf4j.LoggerFactory; | |
| 5 | ||
| 6 | import fr.sii.ogham.core.async.Awaiter; | |
| 7 | import fr.sii.ogham.core.builder.ActivableAtRuntime; | |
| 8 | import fr.sii.ogham.core.builder.Builder; | |
| 9 | import fr.sii.ogham.core.builder.MessagingBuilder; | |
| 10 | import fr.sii.ogham.core.builder.condition.RequiredClass; | |
| 11 | import fr.sii.ogham.core.builder.condition.RequiredClasses; | |
| 12 | import fr.sii.ogham.core.builder.condition.RequiredProperties; | |
| 13 | import fr.sii.ogham.core.builder.condition.RequiredProperty; | |
| 14 | import fr.sii.ogham.core.builder.configurer.MessagingConfigurer; | |
| 15 | import fr.sii.ogham.core.builder.context.BuildContext; | |
| 16 | import fr.sii.ogham.core.builder.retry.RetryBuilder; | |
| 17 | import fr.sii.ogham.core.builder.sender.SenderImplementationBuilderHelper; | |
| 18 | import fr.sii.ogham.core.builder.template.DetectorBuilder; | |
| 19 | import fr.sii.ogham.core.builder.template.TemplateBuilderHelper; | |
| 20 | import fr.sii.ogham.core.builder.template.VariantBuilder; | |
| 21 | import fr.sii.ogham.core.condition.Condition; | |
| 22 | import fr.sii.ogham.core.condition.fluent.MessageConditions; | |
| 23 | import fr.sii.ogham.core.filler.MessageFiller; | |
| 24 | import fr.sii.ogham.core.fluent.AbstractParent; | |
| 25 | import fr.sii.ogham.core.message.content.MultiTemplateContent; | |
| 26 | import fr.sii.ogham.core.message.content.Variant; | |
| 27 | import fr.sii.ogham.core.retry.ExponentialDelayRetry; | |
| 28 | import fr.sii.ogham.core.retry.FixedDelayRetry; | |
| 29 | import fr.sii.ogham.core.retry.FixedIntervalRetry; | |
| 30 | import fr.sii.ogham.core.retry.PerExecutionDelayRetry; | |
| 31 | import fr.sii.ogham.core.retry.RetryExecutor; | |
| 32 | import fr.sii.ogham.core.sender.AutoRetrySender; | |
| 33 | import fr.sii.ogham.core.sender.ConditionalSender; | |
| 34 | import fr.sii.ogham.core.sender.ContentTranslatorSender; | |
| 35 | import fr.sii.ogham.core.sender.FillerSender; | |
| 36 | import fr.sii.ogham.core.sender.MessageSender; | |
| 37 | import fr.sii.ogham.core.template.parser.TemplateParser; | |
| 38 | import fr.sii.ogham.core.translator.content.ContentTranslator; | |
| 39 | import fr.sii.ogham.core.translator.content.EveryContentTranslator; | |
| 40 | import fr.sii.ogham.core.translator.content.TemplateContentTranslator; | |
| 41 | import fr.sii.ogham.core.util.BuilderUtils; | |
| 42 | import fr.sii.ogham.sms.message.PhoneNumber; | |
| 43 | import fr.sii.ogham.sms.message.Sms; | |
| 44 | import fr.sii.ogham.sms.message.addressing.AddressedPhoneNumber; | |
| 45 | import fr.sii.ogham.sms.sender.PhoneNumberTranslatorSender; | |
| 46 | import fr.sii.ogham.sms.sender.SmsSender; | |
| 47 | ||
| 48 | /** | |
| 49 | * Configures how to send {@link Sms} messages. It allows to: | |
| 50 | * <ul> | |
| 51 | * <li>register and configure several sender implementations</li> | |
| 52 | * <li>register and configure several template engines for parsing templates as | |
| 53 | * message content</li> | |
| 54 | * <li>configure handling of missing {@link Sms} information</li> | |
| 55 | * <li>configure number format handling</li> | |
| 56 | * </ul> | |
| 57 | * | |
| 58 | * You can send a {@link Sms} using the minimal behavior and using Cloudhopper | |
| 59 | * implementation: | |
| 60 | * | |
| 61 | * <pre> | |
| 62 | * <code> | |
| 63 | * // Instantiate the messaging service | |
| 64 | * MessagingService service = new MessagingBuilder() | |
| 65 | * .sms() | |
| 66 | * .sender(CloudhopperBuilder.class) // enable SMS sending using Cloudhopper | |
| 67 | * .host("your SMPP server host") | |
| 68 | * .port("your SMPP server port") | |
| 69 | * .systemId("your SMPP system_id") | |
| 70 | * .password("an optional password") | |
| 71 | * .and() | |
| 72 | * .and() | |
| 73 | * .build(); | |
| 74 | * // send the sms | |
| 75 | * service.send(new Sms() | |
| 76 | * .from("sender phone number") | |
| 77 | * .content("sms content") | |
| 78 | * .to("recipient phone number")); | |
| 79 | * </code> | |
| 80 | * </pre> | |
| 81 | * | |
| 82 | * You can also send a {@link Sms} using a template (using Freemarker for | |
| 83 | * example): | |
| 84 | * | |
| 85 | * The Freemarker template ("sms/sample.txt.ftl"): | |
| 86 | * | |
| 87 | * <pre> | |
| 88 | * Sms content with variables: ${name} ${value} | |
| 89 | * </pre> | |
| 90 | * | |
| 91 | * Then you can send the {@link Sms} like this: | |
| 92 | * | |
| 93 | * <pre> | |
| 94 | * <code> | |
| 95 | * // Instantiate the messaging service | |
| 96 | * MessagingService service = new MessagingBuilder() | |
| 97 | * .sms() | |
| 98 | * .sender(CloudhopperBuilder.class) // enable SMS sending using Cloudhopper | |
| 99 | * .host("your SMPP server host") | |
| 100 | * .port("your SMPP server port") | |
| 101 | * .systemId("your SMPP system_id") | |
| 102 | * .password("an optional password") | |
| 103 | * .and() | |
| 104 | * .and() | |
| 105 | * .template(FreemarkerSmsBuilder.class) // enable templating using Freemarker | |
| 106 | * .classpath() | |
| 107 | * .lookup("classpath:") // search resources/templates in the classpath if a path is prefixed by "classpath:" | |
| 108 | * .and() | |
| 109 | * .and() | |
| 110 | * .build(); | |
| 111 | * // send the sms | |
| 112 | * service.send(new Sms() | |
| 113 | * .from("sender phone number") | |
| 114 | * .content(new TemplateContent("classpath:sms/sample.txt.ftl", new SampleBean("foo", 42))) | |
| 115 | * .to("recipient phone number")); | |
| 116 | * </code> | |
| 117 | * </pre> | |
| 118 | * | |
| 119 | * <p> | |
| 120 | * Instead of explicitly configures SMPP host/port/system_id/password in your | |
| 121 | * code, it could be better to externalize the configuration in a properties | |
| 122 | * file for example (for example a file named "sms.properties" in the | |
| 123 | * classpath). The previous example becomes: | |
| 124 | * | |
| 125 | * <pre> | |
| 126 | * <code> | |
| 127 | * // Instantiate the messaging service | |
| 128 | * MessagingService service = new MessagingBuilder() | |
| 129 | * .environment() | |
| 130 | * .properties("sms.properties") | |
| 131 | * .and() | |
| 132 | * .sms() | |
| 133 | * .sender(CloudhopperBuilder.class) // enable SMS sending using Cloudhopper | |
| 134 | * .host("${smpp.host}") | |
| 135 | * .port("${smpp.port}") | |
| 136 | * .systemId("${smpp.system-id}") | |
| 137 | * .password("${smpp.password}") | |
| 138 | * .and() | |
| 139 | * .and() | |
| 140 | * .template(FreemarkerSmsBuilder.class) // enable templating using Freemarker | |
| 141 | * .classpath() | |
| 142 | * .lookup("classpath:") // search resources/templates in the classpath if a path is prefixed by "classpath:" | |
| 143 | * .and() | |
| 144 | * .and() | |
| 145 | * .build(); | |
| 146 | * // send the sms | |
| 147 | * service.send(new Sms() | |
| 148 | * .from("sender phone number") | |
| 149 | * .content(new TemplateContent("classpath:sms/sample.txt.ftl", new SampleBean("foo", 42))) | |
| 150 | * .to("recipient phone number")); | |
| 151 | * </code> | |
| 152 | * </pre> | |
| 153 | * | |
| 154 | * The content of the file "sms.properties": | |
| 155 | * | |
| 156 | * <pre> | |
| 157 | * smpp.host=your SMPP server host | |
| 158 | * smpp.port=your SMPP server port | |
| 159 | * smpp.system-id=your SMPP system_id | |
| 160 | * smpp.password=an optional password | |
| 161 | * </pre> | |
| 162 | * | |
| 163 | * | |
| 164 | * Some fields of the SMS may be automatically filled by a default value if they | |
| 165 | * are not defined. For example, the sender phone number could be configured | |
| 166 | * only once for your application: | |
| 167 | * | |
| 168 | * <pre> | |
| 169 | * <code> | |
| 170 | * // Instantiate the messaging service | |
| 171 | * MessagingService service = new MessagingBuilder() | |
| 172 | * .environment() | |
| 173 | * .properties("sms.properties") | |
| 174 | * .and() | |
| 175 | * .sms() | |
| 176 | * .sender(CloudhopperBuilder.class) // enable SMS sending using Cloudhopper | |
| 177 | * .host().properties("${smpp.host}").and() | |
| 178 | * .port().properties("${smpp.port}").and() | |
| 179 | * .systemId().properties("${smpp.system-id}").and() | |
| 180 | * .password().properties("${smpp.password}").and() | |
| 181 | * .and() | |
| 182 | * .autofill() // enables and configures autofilling | |
| 183 | * .from() | |
| 184 | * .defaultValue().properties("${sms.sender.number}").and() | |
| 185 | * .and() | |
| 186 | * .and() | |
| 187 | * .and() | |
| 188 | * .template(FreemarkerSmsBuilder.class) // enable templating using Freemarker | |
| 189 | * .classpath() | |
| 190 | * .lookup("classpath:") // search resources/templates in the classpath if a path is prefixed by "classpath:" | |
| 191 | * .and() | |
| 192 | * .and() | |
| 193 | * .build(); | |
| 194 | * // send the sms (now the sender phone number can be omitted) | |
| 195 | * service.send(new Sms() | |
| 196 | * .content(new TemplateContent("classpath:sms/sample.txt.ftl", new SampleBean("foo", 42))) | |
| 197 | * .to("recipient phone number")); | |
| 198 | * </code> | |
| 199 | * </pre> | |
| 200 | * | |
| 201 | * The new content of the file "sms.properties": | |
| 202 | * | |
| 203 | * <pre> | |
| 204 | * smpp.host=your SMPP server host | |
| 205 | * smpp.port=your SMPP server port | |
| 206 | * smpp.system-id=your SMPP system_id | |
| 207 | * smpp.password=an optional password | |
| 208 | * sms.sender.number=the sender phone number | |
| 209 | * </pre> | |
| 210 | * | |
| 211 | * <p> | |
| 212 | * All the previous examples are provided to understand what can be configured. | |
| 213 | * Hopefully, Ogham provides auto-configuration with a default behavior that | |
| 214 | * fits 95% of usages. This auto-configuration is provided by | |
| 215 | * {@link MessagingConfigurer}s. Those configurers are automatically applied | |
| 216 | * when using predefined {@link MessagingBuilder}s like | |
| 217 | * {@link MessagingBuilder#minimal()} and {@link MessagingBuilder#standard()}. | |
| 218 | * | |
| 219 | * The previous sample using standard configuration becomes: | |
| 220 | * | |
| 221 | * <pre> | |
| 222 | * <code> | |
| 223 | * // Instantiate the messaging service | |
| 224 | * MessagingService service = MessagingBuilder.standard() | |
| 225 | * .environment() | |
| 226 | * .properties("sms.properties") | |
| 227 | * .and() | |
| 228 | * .build(); | |
| 229 | * // send the sms | |
| 230 | * service.send(new Sms() | |
| 231 | * .content(new TemplateContent("classpath:sms/sample.txt.ftl", new SampleBean("foo", 42))) | |
| 232 | * .to("recipient phone number")); | |
| 233 | * </code> | |
| 234 | * </pre> | |
| 235 | * | |
| 236 | * The new content of the file "sms.properties": | |
| 237 | * | |
| 238 | * <pre> | |
| 239 | * ogham.sms.smpp.host=your SMPP server host | |
| 240 | * ogham.sms.smpp.port=your SMPP server port | |
| 241 | * ogham.sms.smpp.system-id=your SMPP system_id | |
| 242 | * ogham.sms.smpp.password=an optional password | |
| 243 | * ogham.sms.from.default-value=the sender phone number | |
| 244 | * </pre> | |
| 245 | * | |
| 246 | * <p> | |
| 247 | * You can also use the auto-configuration for benefit from default behaviors | |
| 248 | * and override some behaviors for your needs: | |
| 249 | * | |
| 250 | * <pre> | |
| 251 | * <code> | |
| 252 | * // Instantiate the messaging service | |
| 253 | * MessagingService service = MessagingBuilder.standard() | |
| 254 | * .environment() | |
| 255 | * .properties("sms.properties") | |
| 256 | * .and() | |
| 257 | * .sms() | |
| 258 | * .autofill() | |
| 259 | * .from() | |
| 260 | * .defaultValue().properties("${sms.sender.number}").and() // overrides default sender phone number property | |
| 261 | * .and() | |
| 262 | * .and() | |
| 263 | * .and() | |
| 264 | * .build(); | |
| 265 | * // send the sms | |
| 266 | * service.send(new Sms() | |
| 267 | * .content(new TemplateContent("classpath:sms/sample.txt.ftl", new SampleBean("foo", 42))) | |
| 268 | * .to("recipient phone number")); | |
| 269 | * </code> | |
| 270 | * </pre> | |
| 271 | * | |
| 272 | * The new content of the file "sms.properties": | |
| 273 | * | |
| 274 | * <pre> | |
| 275 | * ogham.sms.smpp.host=your SMPP server host | |
| 276 | * ogham.sms.smpp.port=your SMPP server port | |
| 277 | * ogham.sms.smpp.system-id=your SMPP system_id | |
| 278 | * ogham.sms.smpp.password=an optional password | |
| 279 | * sms.sender.number=the sender phone number | |
| 280 | * </pre> | |
| 281 | * | |
| 282 | * @author Aurélien Baudet | |
| 283 | * | |
| 284 | */ | |
| 285 | public class SmsBuilder extends AbstractParent<MessagingBuilder> implements Builder<ConditionalSender> { | |
| 286 | private static final Logger LOG = LoggerFactory.getLogger(SmsBuilder.class); | |
| 287 | ||
| 288 | private final BuildContext buildContext; | |
| 289 | private final TemplateBuilderHelper<SmsBuilder> templateBuilderHelper; | |
| 290 | private final SenderImplementationBuilderHelper<SmsBuilder> senderBuilderHelper; | |
| 291 | private AutofillSmsBuilder autofillBuilder; | |
| 292 | private PhoneNumbersBuilder phoneNumbersBuilder; | |
| 293 | private RetryBuilder<SmsBuilder> retryBuilder; | |
| 294 | ||
| 295 | /** | |
| 296 | * Initializes the builder with a parent builder. The parent builder is used | |
| 297 | * when calling {@link #and()} method. The {@link BuildContext} is used to | |
| 298 | * evaluate properties when {@link #build()} method is called. | |
| 299 | * | |
| 300 | * @param parent | |
| 301 | * the parent builder | |
| 302 | * @param buildContext | |
| 303 | * for registering instances and property evaluation | |
| 304 | */ | |
| 305 | public SmsBuilder(MessagingBuilder parent, BuildContext buildContext) { | |
| 306 | super(parent); | |
| 307 | this.buildContext = buildContext; | |
| 308 | templateBuilderHelper = new TemplateBuilderHelper<>(this, buildContext); | |
| 309 | senderBuilderHelper = new SenderImplementationBuilderHelper<>(this, buildContext); | |
| 310 | } | |
| 311 | ||
| 312 | /** | |
| 313 | * Configures how Ogham will add default values to the {@link Sms} if some | |
| 314 | * information is missing. | |
| 315 | * | |
| 316 | * If sender phone number is missing, a default one can be defined in | |
| 317 | * configuration properties. | |
| 318 | * | |
| 319 | * If recipient phone number is missing, a default one can be defined in | |
| 320 | * configuration properties. | |
| 321 | * | |
| 322 | * <pre> | |
| 323 | * <code> | |
| 324 | * builder | |
| 325 | * .autofill() | |
| 326 | * .from() | |
| 327 | * .defaultValue().properties("${ogham.sms.from.default-value}").and() | |
| 328 | * .and() | |
| 329 | * .to() | |
| 330 | * .defaultValue().properties("${ogham.sms.to.default-value}").and() | |
| 331 | * .and() | |
| 332 | * .and() | |
| 333 | * </code> | |
| 334 | * </pre> | |
| 335 | * | |
| 336 | * @return the builder to configure autofilling of SMS | |
| 337 | */ | |
| 338 | public AutofillSmsBuilder autofill() { | |
| 339 |
8
1. autofill : negated conditional → NO_COVERAGE 2. autofill : negated conditional → KILLED 3. autofill : negated conditional → KILLED 4. autofill : negated conditional → KILLED 5. autofill : negated conditional → KILLED 6. autofill : negated conditional → KILLED 7. autofill : negated conditional → KILLED 8. autofill : negated conditional → KILLED |
if (autofillBuilder == null) { |
| 340 | autofillBuilder = new AutofillSmsBuilder(this, buildContext); | |
| 341 | } | |
| 342 |
8
1. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → NO_COVERAGE 2. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 3. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 4. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 5. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 6. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 7. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED 8. autofill : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autofill → KILLED |
return autofillBuilder; |
| 343 | } | |
| 344 | ||
| 345 | /** | |
| 346 | * Configures the phone number conversions (from a {@link PhoneNumber} to an | |
| 347 | * {@link AddressedPhoneNumber}). | |
| 348 | * | |
| 349 | * The {@link PhoneNumber} is used by the developer to provide a simple | |
| 350 | * phone number without knowing how phone number works (no need to handle | |
| 351 | * formats, addressing, countries...). The {@link AddressedPhoneNumber} is | |
| 352 | * used by Ogham implementations to have a phone number that is usable by a | |
| 353 | * technical system. | |
| 354 | * | |
| 355 | * For example: | |
| 356 | * | |
| 357 | * <pre> | |
| 358 | * <code> | |
| 359 | * builder | |
| 360 | * .numbers() | |
| 361 | * .from() | |
| 362 | * .format() | |
| 363 | * .alphanumericCode().properties("${ogham.sms.from.alphanumeric-code-format.enable}").defaultValue(true).and() | |
| 364 | * .shortCode().properties("${ogham.sms.from.short-code-format.enable}").defaultValue(true).and() | |
| 365 | * .internationalNumber().properties("${ogham.sms.from.international-format.enable}").defaultValue(true).and() | |
| 366 | * .and() | |
| 367 | * .and() | |
| 368 | * .to() | |
| 369 | * .format() | |
| 370 | * .internationalNumber().properties("${ogham.sms.to.international-format.enable}").defaultValue(true); | |
| 371 | * </code> | |
| 372 | * </pre> | |
| 373 | * | |
| 374 | * @return the builder to configure phone number formats | |
| 375 | */ | |
| 376 | public PhoneNumbersBuilder numbers() { | |
| 377 |
8
1. numbers : negated conditional → NO_COVERAGE 2. numbers : negated conditional → KILLED 3. numbers : negated conditional → KILLED 4. numbers : negated conditional → KILLED 5. numbers : negated conditional → KILLED 6. numbers : negated conditional → KILLED 7. numbers : negated conditional → KILLED 8. numbers : negated conditional → KILLED |
if (phoneNumbersBuilder == null) { |
| 378 | phoneNumbersBuilder = new PhoneNumbersBuilder(this, buildContext); | |
| 379 | } | |
| 380 |
8
1. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → NO_COVERAGE 2. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 3. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 4. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 5. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 6. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 7. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED 8. numbers : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::numbers → KILLED |
return phoneNumbersBuilder; |
| 381 | } | |
| 382 | ||
| 383 | /** | |
| 384 | * Registers and configures a {@link TemplateParser} through a dedicated | |
| 385 | * builder. | |
| 386 | * | |
| 387 | * For example: | |
| 388 | * | |
| 389 | * <pre> | |
| 390 | * .register(ThymeleafSmsBuilder.class) | |
| 391 | * .detector(new ThymeleafEngineDetector()); | |
| 392 | * </pre> | |
| 393 | * | |
| 394 | * <p> | |
| 395 | * Your {@link Builder} may implement {@link VariantBuilder} to handle | |
| 396 | * template {@link Variant}s (used for {@link MultiTemplateContent} that | |
| 397 | * provide a single path to templates with different extensions for | |
| 398 | * example). | |
| 399 | * </p> | |
| 400 | * | |
| 401 | * <p> | |
| 402 | * Your {@link Builder} may also implement {@link DetectorBuilder} in order | |
| 403 | * to indicate which kind of templates your {@link TemplateParser} is able | |
| 404 | * to parse. If your template parse is able to parse any template file you | |
| 405 | * are using, you may not need to implement {@link DetectorBuilder}. | |
| 406 | * </p> | |
| 407 | * | |
| 408 | * <p> | |
| 409 | * In order to be able to keep chaining, you builder instance may provide a | |
| 410 | * constructor with two arguments: | |
| 411 | * <ul> | |
| 412 | * <li>The type of the parent builder ({@code <P>})</li> | |
| 413 | * <li>The {@link BuildContext} instance</li> | |
| 414 | * </ul> | |
| 415 | * If you don't care about chaining, just provide a default constructor. | |
| 416 | * | |
| 417 | * @param builderClass | |
| 418 | * the builder class to instantiate | |
| 419 | * @param <T> | |
| 420 | * the type of the builder | |
| 421 | * @return the builder to configure the implementation | |
| 422 | */ | |
| 423 | public <T extends Builder<? extends TemplateParser>> T template(Class<T> builderClass) { | |
| 424 |
4
1. template : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::template → NO_COVERAGE 2. template : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::template → KILLED 3. template : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::template → KILLED 4. template : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::template → KILLED |
return templateBuilderHelper.register(builderClass); |
| 425 | } | |
| 426 | ||
| 427 | /** | |
| 428 | * Registers a custom message sender implementation. | |
| 429 | * | |
| 430 | * <p> | |
| 431 | * If your custom implementation is annotated by one or several of: | |
| 432 | * <ul> | |
| 433 | * <li>{@link RequiredClass}</li> | |
| 434 | * <li>{@link RequiredProperty}</li> | |
| 435 | * <li>{@link RequiredClasses}</li> | |
| 436 | * <li>{@link RequiredProperties}</li> | |
| 437 | * </ul> | |
| 438 | * Then if condition evaluation returns true, your implementation will be | |
| 439 | * used. If you provide several annotations, your implementation will be | |
| 440 | * used only if all conditions are met (and operator). | |
| 441 | * | |
| 442 | * <p> | |
| 443 | * If your custom implementation implements {@link ActivableAtRuntime}, and | |
| 444 | * the provided condition evaluation returns true, then your implementation | |
| 445 | * will be used. | |
| 446 | * | |
| 447 | * See {@link MessageConditions} to build your condition. | |
| 448 | * </p> | |
| 449 | * | |
| 450 | * <p> | |
| 451 | * If neither annotations nor implementation of {@link ActivableAtRuntime} | |
| 452 | * is used, then your custom implementation will be always used. All other | |
| 453 | * implementations (even standard ones) will never be used. | |
| 454 | * </p> | |
| 455 | * | |
| 456 | * @param sender | |
| 457 | * the sender to register | |
| 458 | * @return this instance for fluent chaining | |
| 459 | */ | |
| 460 | public SmsBuilder customSender(MessageSender sender) { | |
| 461 |
4
1. customSender : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::customSender → NO_COVERAGE 2. customSender : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::customSender → KILLED 3. customSender : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::customSender → KILLED 4. customSender : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::customSender → KILLED |
senderBuilderHelper.customSender(sender); |
| 462 |
3
1. customSender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::customSender → NO_COVERAGE 2. customSender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::customSender → SURVIVED 3. customSender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::customSender → KILLED |
return this; |
| 463 | } | |
| 464 | ||
| 465 | /** | |
| 466 | * Registers and configures sender through a dedicated builder. | |
| 467 | * | |
| 468 | * For example: | |
| 469 | * | |
| 470 | * <pre> | |
| 471 | * .sender(CloudhopperBuilder.class) | |
| 472 | * .host("localhost"); | |
| 473 | * </pre> | |
| 474 | * | |
| 475 | * <p> | |
| 476 | * If your custom builder is annotated by one or several of: | |
| 477 | * <ul> | |
| 478 | * <li>{@link RequiredClass}</li> | |
| 479 | * <li>{@link RequiredProperty}</li> | |
| 480 | * <li>{@link RequiredClasses}</li> | |
| 481 | * <li>{@link RequiredProperties}</li> | |
| 482 | * </ul> | |
| 483 | * Then if condition evaluation returns true, your built implementation will | |
| 484 | * be used. If you provide several annotations, your built implementation | |
| 485 | * will be used only if all conditions are met (and operator). | |
| 486 | * | |
| 487 | * <p> | |
| 488 | * If your custom builder implements {@link ActivableAtRuntime}, and the | |
| 489 | * provided condition evaluation returns true, then your built | |
| 490 | * implementation will be used. | |
| 491 | * | |
| 492 | * See {@link MessageConditions} to build your condition. | |
| 493 | * </p> | |
| 494 | * | |
| 495 | * <p> | |
| 496 | * If neither annotations nor implementation of {@link ActivableAtRuntime} | |
| 497 | * is used, then your built implementation will be always used. All other | |
| 498 | * implementations (even standard ones) will never be used. | |
| 499 | * </p> | |
| 500 | * | |
| 501 | * <p> | |
| 502 | * In order to be able to keep chaining, you builder instance may provide a | |
| 503 | * constructor with one argument with the type of the parent builder | |
| 504 | * ({@link SmsBuilder}). If you don't care about chaining, just provide a | |
| 505 | * default constructor. | |
| 506 | * </p> | |
| 507 | * | |
| 508 | * <p> | |
| 509 | * Your builder may return {@code null} when calling | |
| 510 | * {@link Builder#build()}. In this case it means that your implementation | |
| 511 | * can't be used due to current environment. Your implementation is then not | |
| 512 | * registered. | |
| 513 | * </p> | |
| 514 | * | |
| 515 | * @param builderClass | |
| 516 | * the builder class to instantiate | |
| 517 | * @param <T> | |
| 518 | * the type of the builder | |
| 519 | * @return the builder to configure the implementation | |
| 520 | */ | |
| 521 | public <T extends Builder<? extends MessageSender>> T sender(Class<T> builderClass) { | |
| 522 |
6
1. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → NO_COVERAGE 2. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → KILLED 3. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → KILLED 4. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → KILLED 5. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → KILLED 6. sender : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::sender → KILLED |
return senderBuilderHelper.register(builderClass); |
| 523 | } | |
| 524 | ||
| 525 | /** | |
| 526 | * Configure automatic retry if message couldn't be sent. | |
| 527 | * | |
| 528 | * | |
| 529 | * For example: | |
| 530 | * | |
| 531 | * <pre> | |
| 532 | * .autoRetry() | |
| 533 | * .fixedDelay() | |
| 534 | * .maxRetries().properties("${ogham.sms.send-retry.max-attempts}").and() | |
| 535 | * .delay().properties("${ogham.sms.send-retry.delay-between-attempts}") | |
| 536 | * </pre> | |
| 537 | * | |
| 538 | * | |
| 539 | * <p> | |
| 540 | * This builder lets you configure: | |
| 541 | * <ul> | |
| 542 | * <li>The retry strategy: | |
| 543 | * <ul> | |
| 544 | * <li>{@link FixedDelayRetry}: wait for a fixed delay after the last | |
| 545 | * failure</li> | |
| 546 | * <li>{@link FixedIntervalRetry}: wait for a fixed delay between executions | |
| 547 | * (do not wait for the end of the action)</li> | |
| 548 | * <li>{@link ExponentialDelayRetry}: start with a delay, the next delay | |
| 549 | * will be doubled on so on</li> | |
| 550 | * <li>{@link PerExecutionDelayRetry}: provide a custom delay for each | |
| 551 | * execution</li> | |
| 552 | * </ul> | |
| 553 | * </li> | |
| 554 | * <li>The {@link RetryExecutor} implementation</li> | |
| 555 | * <li>The {@link Awaiter} implementation</li> | |
| 556 | * <li>The {@link Condition} used to determine if the raised error should | |
| 557 | * trigger a retry or not</li> | |
| 558 | * </ul> | |
| 559 | * | |
| 560 | * @return the builder to configure retry management | |
| 561 | */ | |
| 562 | public RetryBuilder<SmsBuilder> autoRetry() { | |
| 563 |
8
1. autoRetry : negated conditional → NO_COVERAGE 2. autoRetry : negated conditional → KILLED 3. autoRetry : negated conditional → KILLED 4. autoRetry : negated conditional → KILLED 5. autoRetry : negated conditional → KILLED 6. autoRetry : negated conditional → KILLED 7. autoRetry : negated conditional → KILLED 8. autoRetry : negated conditional → KILLED |
if (retryBuilder == null) { |
| 564 | retryBuilder = new RetryBuilder<>(this, buildContext); | |
| 565 | } | |
| 566 |
8
1. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → NO_COVERAGE 2. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 3. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 4. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 5. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 6. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 7. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED 8. autoRetry : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::autoRetry → KILLED |
return retryBuilder; |
| 567 | } | |
| 568 | ||
| 569 | @Override | |
| 570 | public ConditionalSender build() { | |
| 571 | SmsSender smsSender = buildContext.register(new SmsSender()); | |
| 572 | ConditionalSender sender = smsSender; | |
| 573 |
8
1. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → SURVIVED 2. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → NO_COVERAGE 3. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED 4. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED 5. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED 6. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED 7. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED 8. build : removed call to fr/sii/ogham/core/builder/sender/SenderImplementationBuilderHelper::addSenders → KILLED |
senderBuilderHelper.addSenders(smsSender); |
| 574 |
5
1. build : negated conditional → SURVIVED 2. build : negated conditional → NO_COVERAGE 3. build : negated conditional → KILLED 4. build : negated conditional → KILLED 5. build : negated conditional → KILLED |
if (templateBuilderHelper.hasRegisteredTemplates()) { |
| 575 | ContentTranslator translator = buildContentTranslator(); | |
| 576 | LOG.debug("Content translation enabled {}", translator); | |
| 577 | sender = buildContext.register(new ContentTranslatorSender(translator, sender)); | |
| 578 | } | |
| 579 |
3
1. build : negated conditional → SURVIVED 2. build : negated conditional → NO_COVERAGE 3. build : negated conditional → KILLED |
if (phoneNumbersBuilder != null) { |
| 580 | PhoneNumberTranslatorPair pair = phoneNumbersBuilder.build(); | |
| 581 | sender = buildContext.register(new PhoneNumberTranslatorSender(pair.getSender(), pair.getRecipient(), sender)); | |
| 582 | } | |
| 583 |
3
1. build : negated conditional → NO_COVERAGE 2. build : negated conditional → SURVIVED 3. build : negated conditional → KILLED |
if (autofillBuilder != null) { |
| 584 | MessageFiller messageFiller = autofillBuilder.build(); | |
| 585 | LOG.debug("Automatic filling of message enabled {}", messageFiller); | |
| 586 | sender = buildContext.register(new FillerSender(messageFiller, sender)); | |
| 587 | } | |
| 588 | RetryExecutor retryExecutor = BuilderUtils.build(retryBuilder); | |
| 589 |
7
1. build : negated conditional → NO_COVERAGE 2. build : negated conditional → SURVIVED 3. build : negated conditional → KILLED 4. build : negated conditional → KILLED 5. build : negated conditional → KILLED 6. build : negated conditional → KILLED 7. build : negated conditional → KILLED |
if (retryExecutor != null) { |
| 590 | LOG.debug("Automatic retry of message sending enabled {}", retryExecutor); | |
| 591 | sender = buildContext.register(new AutoRetrySender(sender, retryExecutor)); | |
| 592 | } | |
| 593 |
8
1. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → NO_COVERAGE 2. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → SURVIVED 3. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED 4. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED 5. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED 6. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED 7. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED 8. build : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::build → KILLED |
return sender; |
| 594 | } | |
| 595 | ||
| 596 | private ContentTranslator buildContentTranslator() { | |
| 597 | EveryContentTranslator translator = buildContext.register(new EveryContentTranslator()); | |
| 598 |
4
1. buildContentTranslator : removed call to fr/sii/ogham/sms/builder/SmsBuilder::addTemplateTranslator → NO_COVERAGE 2. buildContentTranslator : removed call to fr/sii/ogham/sms/builder/SmsBuilder::addTemplateTranslator → KILLED 3. buildContentTranslator : removed call to fr/sii/ogham/sms/builder/SmsBuilder::addTemplateTranslator → KILLED 4. buildContentTranslator : removed call to fr/sii/ogham/sms/builder/SmsBuilder::addTemplateTranslator → KILLED |
addTemplateTranslator(translator); |
| 599 |
4
1. buildContentTranslator : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::buildContentTranslator → NO_COVERAGE 2. buildContentTranslator : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::buildContentTranslator → KILLED 3. buildContentTranslator : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::buildContentTranslator → KILLED 4. buildContentTranslator : replaced return value with null for fr/sii/ogham/sms/builder/SmsBuilder::buildContentTranslator → KILLED |
return translator; |
| 600 | } | |
| 601 | ||
| 602 | private void addTemplateTranslator(EveryContentTranslator translator) { | |
| 603 |
4
1. addTemplateTranslator : negated conditional → NO_COVERAGE 2. addTemplateTranslator : negated conditional → KILLED 3. addTemplateTranslator : negated conditional → KILLED 4. addTemplateTranslator : negated conditional → KILLED |
if (!templateBuilderHelper.hasRegisteredTemplates()) { |
| 604 | return; | |
| 605 | } | |
| 606 | TemplateParser templateParser = templateBuilderHelper.buildTemplateParser(); | |
| 607 | LOG.debug("Registering content translator that parses templates using {}", templateParser); | |
| 608 |
4
1. addTemplateTranslator : removed call to fr/sii/ogham/core/translator/content/EveryContentTranslator::addTranslator → NO_COVERAGE 2. addTemplateTranslator : removed call to fr/sii/ogham/core/translator/content/EveryContentTranslator::addTranslator → KILLED 3. addTemplateTranslator : removed call to fr/sii/ogham/core/translator/content/EveryContentTranslator::addTranslator → KILLED 4. addTemplateTranslator : removed call to fr/sii/ogham/core/translator/content/EveryContentTranslator::addTranslator → KILLED |
translator.addTranslator(buildContext.register(new TemplateContentTranslator(templateParser))); |
| 609 | } | |
| 610 | ||
| 611 | } | |
Mutations | ||
| 339 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 342 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 377 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 380 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 424 |
1.1 2.2 3.3 4.4 |
|
| 461 |
1.1 2.2 3.3 4.4 |
|
| 462 |
1.1 2.2 3.3 |
|
| 522 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
| 563 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 566 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 573 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 574 |
1.1 2.2 3.3 4.4 5.5 |
|
| 579 |
1.1 2.2 3.3 |
|
| 583 |
1.1 2.2 3.3 |
|
| 589 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 |
|
| 593 |
1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 |
|
| 598 |
1.1 2.2 3.3 4.4 |
|
| 599 |
1.1 2.2 3.3 4.4 |
|
| 603 |
1.1 2.2 3.3 4.4 |
|
| 608 |
1.1 2.2 3.3 4.4 |