AbstractSendGridBuilder.java

1
package fr.sii.ogham.email.sendgrid.builder;
2
3
import java.io.InputStream;
4
import java.net.MalformedURLException;
5
import java.net.URL;
6
import java.nio.file.Files;
7
8
9
import org.apache.http.client.HttpClient;
10
import org.apache.http.impl.client.CloseableHttpClient;
11
12
import com.sendgrid.SendGrid;
13
14
import fr.sii.ogham.core.builder.Builder;
15
import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilder;
16
import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilderHelper;
17
import fr.sii.ogham.core.builder.configurer.Configurer;
18
import fr.sii.ogham.core.builder.context.BuildContext;
19
import fr.sii.ogham.core.builder.mimetype.MimetypeDetectionBuilder;
20
import fr.sii.ogham.core.builder.mimetype.MimetypeDetectionBuilderDelegate;
21
import fr.sii.ogham.core.builder.mimetype.SimpleMimetypeDetectionBuilder;
22
import fr.sii.ogham.core.fluent.AbstractParent;
23
import fr.sii.ogham.email.sendgrid.sender.SendGridSender;
24
25
@SuppressWarnings("squid:S00119")
26
public abstract class AbstractSendGridBuilder<MYSELF extends AbstractSendGridBuilder<MYSELF, EmailBuilder>, EmailBuilder> extends AbstractParent<EmailBuilder> implements Builder<SendGridSender> {
27
	protected final MYSELF myself;
28
	protected final BuildContext buildContext;
29
	protected MimetypeDetectionBuilder<MYSELF> mimetypeBuilder;
30
	protected final ConfigurationValueBuilderHelper<MYSELF, String> apiKeyValueBuilder;
31
	protected final ConfigurationValueBuilderHelper<MYSELF, URL> urlValueBuilder;
32
	protected CloseableHttpClient httpClient;
33
34
	@SuppressWarnings("unchecked")
35
	protected AbstractSendGridBuilder(Class<?> selfType, EmailBuilder parent, BuildContext buildContext, MimetypeDetectionBuilder<?> mimetypeBuilder) {
36
		super(parent);
37
		myself = (MYSELF) selfType.cast(this);
38
		this.buildContext = buildContext;
39
		apiKeyValueBuilder = buildContext.newConfigurationValueBuilder(myself, String.class);
40
		urlValueBuilder = buildContext.newConfigurationValueBuilder(myself, URL.class);
41 1 1. <init> : negated conditional → RUN_ERROR
		if (mimetypeBuilder != null) {
42
			mimetype(mimetypeBuilder);
43
		}
44
	}
45
46
	public AbstractSendGridBuilder(Class<?> selfType, EmailBuilder parent, BuildContext buildContext) {
47
		this(selfType, parent, buildContext, null);
48
		mimetype();
49
	}
50
51
	/**
52
	 * Set SendGrid <a href=
53
	 * "https://sendgrid.com/docs/Classroom/Send/How_Emails_Are_Sent/api_keys.html">API
54
	 * key</a>.
55
	 * 
56
	 * <p>
57
	 * The value set using this method takes precedence over any property and
58
	 * default value configured using {@link #apiKey()}.
59
	 * 
60
	 * <pre>
61
	 * .apiKey("my-key")
62
	 * .apiKey()
63
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
64
	 *   .defaultValue("default-key")
65
	 * </pre>
66
	 * 
67
	 * <pre>
68
	 * .apiKey("my-key")
69
	 * .apiKey()
70
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
71
	 *   .defaultValue("default-key")
72
	 * </pre>
73
	 * 
74
	 * In both cases, {@code apiKey("my-key")} is used.
75
	 * 
76
	 * <p>
77
	 * If this method is called several times, only the last value is used.
78
	 * 
79
	 * <p>
80
	 * If {@code null} value is set, it is like not setting a value at all. The
81
	 * property/default value configuration is applied.
82
	 * 
83
	 * @param apiKey
84
	 *            the API key to use
85
	 * @return this instance for fluent chaining
86
	 */
87
	public MYSELF apiKey(String apiKey) {
88 1 1. apiKey : removed call to fr/sii/ogham/core/builder/configuration/ConfigurationValueBuilderHelper::setValue → NO_COVERAGE
		apiKeyValueBuilder.setValue(apiKey);
89 1 1. apiKey : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::apiKey → NO_COVERAGE
		return myself;
90
	}
91
92
	/**
93
	 * Set SendGrid <a href=
94
	 * "https://sendgrid.com/docs/Classroom/Send/How_Emails_Are_Sent/api_keys.html">API
95
	 * key</a>.
96
	 * 
97
	 * <p>
98
	 * This method is mainly used by {@link Configurer}s to register some
99
	 * property keys and/or a default value. The aim is to let developer be able
100
	 * to externalize its configuration (using system properties, configuration
101
	 * file or anything else). If the developer doesn't configure any value for
102
	 * the registered properties, the default value is used (if set).
103
	 * 
104
	 * <pre>
105
	 * .apiKey()
106
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
107
	 *   .defaultValue("default-key")
108
	 * </pre>
109
	 * 
110
	 * <p>
111
	 * Non-null value set using {@link #apiKey(String)} takes precedence over
112
	 * property values and default value.
113
	 * 
114
	 * <pre>
115
	 * .apiKey("my-key")
116
	 * .apiKey()
117
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
118
	 *   .defaultValue("default-key")
119
	 * </pre>
120
	 * 
121
	 * The value {@code "my-key"} is used regardless of the value of the
122
	 * properties and default value.
123
	 * 
124
	 * <p>
125
	 * See {@link ConfigurationValueBuilder} for more information.
126
	 * 
127
	 * 
128
	 * @return the builder to configure property keys/default value
129
	 */
130
	public ConfigurationValueBuilder<MYSELF, String> apiKey() {
131 1 1. apiKey : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::apiKey → RUN_ERROR
		return apiKeyValueBuilder;
132
	}
133
134
	/**
135
	 * Set username for SendGrid HTTP API.
136
	 * 
137
	 * <p>
138
	 * <strong>WARNING:</strong> SendGrid v4 doesn't use username/password
139
	 * anymore. You must use an {@link #apiKey(String)}.
140
	 * 
141
	 * <p>
142
	 * The value set using this method takes precedence over any property and
143
	 * default value configured using {@link #username()}.
144
	 * 
145
	 * <pre>
146
	 * .username("my-username")
147
	 * .username()
148
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
149
	 *   .defaultValue("default-username")
150
	 * </pre>
151
	 * 
152
	 * <pre>
153
	 * .username("my-username")
154
	 * .username()
155
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
156
	 *   .defaultValue("default-username")
157
	 * </pre>
158
	 * 
159
	 * In both cases, {@code username("my-username")} is used.
160
	 * 
161
	 * <p>
162
	 * If this method is called several times, only the last value is used.
163
	 * 
164
	 * <p>
165
	 * If {@code null} value is set, it is like not setting a value at all. The
166
	 * property/default value configuration is applied.
167
	 * 
168
	 * @param username
169
	 *            the user name for SendGrid HTTP API
170
	 * @return this instance for fluent chaining
171
	 * 
172
	 */
173
	public abstract MYSELF username(String username);
174
175
	/**
176
	 * Set username for SendGrid HTTP API.
177
	 * 
178
	 * <p>
179
	 * <strong>WARNING:</strong> SendGrid v4 doesn't use username/password
180
	 * anymore. You must use an {@link #apiKey(String)}.
181
	 * 
182
	 * <p>
183
	 * This method is mainly used by {@link Configurer}s to register some
184
	 * property keys and/or a default value. The aim is to let developer be able
185
	 * to externalize its configuration (using system properties, configuration
186
	 * file or anything else). If the developer doesn't configure any value for
187
	 * the registered properties, the default value is used (if set).
188
	 * 
189
	 * <pre>
190
	 * .username()
191
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
192
	 *   .defaultValue("default-username")
193
	 * </pre>
194
	 * 
195
	 * <p>
196
	 * Non-null value set using {@link #username(String)} takes precedence over
197
	 * property values and default value.
198
	 * 
199
	 * <pre>
200
	 * .username("my-username")
201
	 * .username()
202
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
203
	 *   .defaultValue("default-username")
204
	 * </pre>
205
	 * 
206
	 * The value {@code "my-username"} is used regardless of the value of the
207
	 * properties and default value.
208
	 * 
209
	 * <p>
210
	 * See {@link ConfigurationValueBuilder} for more information.
211
	 * 
212
	 * @return the builder to configure property keys/default value
213
	 */
214
	public abstract ConfigurationValueBuilder<MYSELF, String> username();
215
216
	/**
217
	 * Set password for SendGrid HTTP API.
218
	 * 
219
	 * <p>
220
	 * <strong>WARNING:</strong> SendGrid v4 doesn't use username/password
221
	 * anymore. You must use an {@link #apiKey(String)}.
222
	 * 
223
	 * <p>
224
	 * The value set using this method takes precedence over any property and
225
	 * default value configured using {@link #password()}.
226
	 * 
227
	 * <pre>
228
	 * .password("my-password")
229
	 * .password()
230
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
231
	 *   .defaultValue("default-password")
232
	 * </pre>
233
	 * 
234
	 * <pre>
235
	 * .password("my-password")
236
	 * .password()
237
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
238
	 *   .defaultValue("default-password")
239
	 * </pre>
240
	 * 
241
	 * In both cases, {@code password("my-password")} is used.
242
	 * 
243
	 * <p>
244
	 * If this method is called several times, only the last value is used.
245
	 * 
246
	 * <p>
247
	 * If {@code null} value is set, it is like not setting a value at all. The
248
	 * property/default value configuration is applied.
249
	 * 
250
	 * @param password
251
	 *            the password value
252
	 * @return this instance for fluent chaining
253
	 */
254
	public abstract MYSELF password(String password);
255
256
	/**
257
	 * Set password for SendGrid HTTP API.
258
	 * 
259
	 * <p>
260
	 * <strong>WARNING:</strong> SendGrid v4 doesn't use username/password
261
	 * anymore. You must use an {@link #apiKey(String)}.
262
	 * 
263
	 * <p>
264
	 * This method is mainly used by {@link Configurer}s to register some
265
	 * property keys and/or a default value. The aim is to let developer be able
266
	 * to externalize its configuration (using system properties, configuration
267
	 * file or anything else). If the developer doesn't configure any value for
268
	 * the registered properties, the default value is used (if set).
269
	 * 
270
	 * <pre>
271
	 * .password()
272
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
273
	 *   .defaultValue("default-password")
274
	 * </pre>
275
	 * 
276
	 * <p>
277
	 * Non-null value set using {@link #password(String)} takes precedence over
278
	 * property values and default value.
279
	 * 
280
	 * <pre>
281
	 * .password("my-password")
282
	 * .password()
283
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
284
	 *   .defaultValue("default-password")
285
	 * </pre>
286
	 * 
287
	 * The value {@code "my-password"} is used regardless of the value of the
288
	 * properties and default value.
289
	 * 
290
	 * <p>
291
	 * See {@link ConfigurationValueBuilder} for more information.
292
	 * 
293
	 * @return the builder to configure property keys/default value
294
	 */
295
	public abstract ConfigurationValueBuilder<MYSELF, String> password();
296
297
	/**
298
	 * Set SendGrid API base URL.
299
	 * 
300
	 * <p>
301
	 * The value set using this method takes precedence over any property and
302
	 * default value configured using {@link #url()}.
303
	 * 
304
	 * <pre>
305
	 * .url("http://localhost/sendgrid")
306
	 * .url()
307
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
308
	 *   .defaultValue("http://api.sendgrid.com")
309
	 * </pre>
310
	 * 
311
	 * <pre>
312
	 * .url("http://localhost/sendgrid")
313
	 * .url()
314
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
315
	 *   .defaultValue("http://api.sendgrid.com")
316
	 * </pre>
317
	 * 
318
	 * In both cases, {@code url("http://localhost/sendgrid")} is used.
319
	 * 
320
	 * <p>
321
	 * If this method is called several times, only the last value is used.
322
	 * 
323
	 * <p>
324
	 * If {@code null} value is set, it is like not setting a value at all. The
325
	 * property/default value configuration is applied.
326
	 * 
327
	 * @param url
328
	 *            the base URL for SendGrid HTTP API
329
	 * @return this instance for fluent chaining
330
	 */
331
	public MYSELF url(URL url) {
332 1 1. url : removed call to fr/sii/ogham/core/builder/configuration/ConfigurationValueBuilderHelper::setValue → NO_COVERAGE
		urlValueBuilder.setValue(url);
333 1 1. url : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → NO_COVERAGE
		return myself;
334
	}
335
336
	/**
337
	 * Set SendGrid API base URL.
338
	 * 
339
	 * <p>
340
	 * The value set using this method takes precedence over any property and
341
	 * default value configured using {@link #url()}.
342
	 * 
343
	 * <pre>
344
	 * .url("http://localhost/sendgrid")
345
	 * .url()
346
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
347
	 *   .defaultValue("http://api.sendgrid.com")
348
	 * </pre>
349
	 * 
350
	 * <pre>
351
	 * .url("http://localhost/sendgrid")
352
	 * .url()
353
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
354
	 *   .defaultValue("http://api.sendgrid.com")
355
	 * </pre>
356
	 * 
357
	 * In both cases, {@code url("http://localhost/sendgrid")} is used.
358
	 * 
359
	 * <p>
360
	 * If this method is called several times, only the last value is used.
361
	 * 
362
	 * <p>
363
	 * If {@code null} value is set, it is like not setting a value at all. The
364
	 * property/default value configuration is applied.
365
	 * 
366
	 * @param url
367
	 *            the base URL for SendGrid HTTP API
368
	 * @return this instance for fluent chaining
369
	 * @throws IllegalArgumentException
370
	 *             if URL is malformed
371
	 */
372
	public MYSELF url(String url) {
373
		try {
374 1 1. url : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → NO_COVERAGE
			return url(new URL(url));
375
		} catch (MalformedURLException e) {
376
			throw new IllegalArgumentException("Invalid URL " + url, e);
377
		}
378
	}
379
380
	/**
381
	 * Set SendGrid API base URL.
382
	 * 
383
	 * <p>
384
	 * This method is mainly used by {@link Configurer}s to register some
385
	 * property keys and/or a default value. The aim is to let developer be able
386
	 * to externalize its configuration (using system properties, configuration
387
	 * file or anything else). If the developer doesn't configure any value for
388
	 * the registered properties, the default value is used (if set).
389
	 * 
390
	 * <pre>
391
	 * .url()
392
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
393
	 *   .defaultValue("http://api.sendgrid.com")
394
	 * </pre>
395
	 * 
396
	 * <p>
397
	 * Non-null value set using {@link #url(URL)} takes precedence over property
398
	 * values and default value.
399
	 * 
400
	 * <pre>
401
	 * .url("http://localhost/sendgrid")
402
	 * .url()
403
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
404
	 *   .defaultValue("http://api.sendgrid.com")
405
	 * </pre>
406
	 * 
407
	 * The value {@code "http://localhost/sendgrid"} is used regardless of the
408
	 * value of the properties and default value.
409
	 * 
410
	 * <p>
411
	 * See {@link ConfigurationValueBuilder} for more information.
412
	 * 
413
	 * 
414
	 * @return the builder to configure property keys/default value
415
	 */
416
	public ConfigurationValueBuilder<MYSELF, URL> url() {
417 1 1. url : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → RUN_ERROR
		return urlValueBuilder;
418
	}
419
420
	/**
421
	 * By default, calling SendGrid HTTP API is done through the default
422
	 * {@link SendGrid} implementation that uses default {@link HttpClient}
423
	 * (calling {@code HttpClientBuilder.create().build()}). If you want to use
424
	 * another HTTP client implementation, you can extend the
425
	 * {@link CloseableHttpClient} class and provide it:
426
	 * 
427
	 * <pre>
428
	 * .client(new MyCustomHttpClient())
429
	 * </pre>
430
	 * 
431
	 * @param httpClient
432
	 *            the custom implementation of {@link HttpClient} used to call
433
	 *            SendGrid HTTP API. SendGrid requires a
434
	 *            {@link CloseableHttpClient}.
435
	 * @return this instance for fluent chaining
436
	 */
437
	public MYSELF httpClient(CloseableHttpClient httpClient) {
438
		this.httpClient = httpClient;
439 1 1. httpClient : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::httpClient → NO_COVERAGE
		return myself;
440
	}
441
442
	/**
443
	 * Builder that configures mimetype detection.
444
	 * 
445
	 * There exists several implementations to provide the mimetype:
446
	 * <ul>
447
	 * <li>Using Java activation</li>
448
	 * <li>Using Java 7 {@link Files#probeContentType(java.nio.file.Path)}</li>
449
	 * <li>Using <a href="http://tika.apache.org/">Apache Tika</a></li>
450
	 * <li>Using
451
	 * <a href="https://github.com/arimus/jmimemagic">JMimeMagic</a></li>
452
	 * </ul>
453
	 * 
454
	 * <p>
455
	 * Both implementations provided by Java are based on file extensions. This
456
	 * can't be used in most cases as we often handle {@link InputStream}s.
457
	 * </p>
458
	 * 
459
	 * <p>
460
	 * In previous version of Ogham, JMimeMagic was used and was working quite
461
	 * well. Unfortunately, the library is no more maintained.
462
	 * </p>
463
	 * 
464
	 * <p>
465
	 * You can configure how Tika will detect mimetype:
466
	 * 
467
	 * <pre>
468
	 * .mimetype()
469
	 *    .tika()
470
	 *       ...
471
	 * </pre>
472
	 * 
473
	 * <p>
474
	 * This builder allows to use several providers. It will chain them until
475
	 * one can find a valid mimetype. If none is found, you can explicitly
476
	 * provide the default one:
477
	 * 
478
	 * <pre>
479
	 * .mimetype()
480
	 *    .defaultMimetype("text/html")
481
	 * </pre>
482
	 * 
483
	 * <p>
484
	 * If no mimetype detector was previously defined, it creates a new one.
485
	 * Then each time you call {@link #mimetype()}, the same instance is used.
486
	 * </p>
487
	 * 
488
	 * @return the builder to configure mimetype detection
489
	 */
490
	public MimetypeDetectionBuilder<MYSELF> mimetype() {
491 1 1. mimetype : negated conditional → RUN_ERROR
		if (mimetypeBuilder == null) {
492
			mimetypeBuilder = new SimpleMimetypeDetectionBuilder<>(myself, buildContext);
493
		}
494 1 1. mimetype : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::mimetype → RUN_ERROR
		return mimetypeBuilder;
495
	}
496
497
	/**
498
	 * NOTE: this is mostly for advance usage (when creating a custom module).
499
	 * 
500
	 * Inherits mimetype configuration from another builder. This is useful for
501
	 * configuring independently different parts of Ogham but keeping a whole
502
	 * coherence.
503
	 * 
504
	 * The same instance is shared meaning that all changes done here will also
505
	 * impact the other builder.
506
	 * 
507
	 * <p>
508
	 * If a previous builder was defined (by calling {@link #mimetype()} for
509
	 * example), the new builder will override it.
510
	 * 
511
	 * @param builder
512
	 *            the builder to inherit
513
	 * @return this instance for fluent chaining
514
	 */
515
	public MYSELF mimetype(MimetypeDetectionBuilder<?> builder) {
516
		mimetypeBuilder = new MimetypeDetectionBuilderDelegate<>(myself, builder);
517 1 1. mimetype : replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::mimetype → RUN_ERROR
		return myself;
518
	}
519
520
}

Mutations

41

1.1
Location : <init>
Killed by :
negated conditional → RUN_ERROR

88

1.1
Location : apiKey
Killed by :
removed call to fr/sii/ogham/core/builder/configuration/ConfigurationValueBuilderHelper::setValue → NO_COVERAGE

89

1.1
Location : apiKey
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::apiKey → NO_COVERAGE

131

1.1
Location : apiKey
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::apiKey → RUN_ERROR

332

1.1
Location : url
Killed by :
removed call to fr/sii/ogham/core/builder/configuration/ConfigurationValueBuilderHelper::setValue → NO_COVERAGE

333

1.1
Location : url
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → NO_COVERAGE

374

1.1
Location : url
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → NO_COVERAGE

417

1.1
Location : url
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::url → RUN_ERROR

439

1.1
Location : httpClient
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::httpClient → NO_COVERAGE

491

1.1
Location : mimetype
Killed by :
negated conditional → RUN_ERROR

494

1.1
Location : mimetype
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::mimetype → RUN_ERROR

517

1.1
Location : mimetype
Killed by :
replaced return value with null for fr/sii/ogham/email/sendgrid/builder/AbstractSendGridBuilder::mimetype → RUN_ERROR

Active mutators

Tests examined


Report generated by PIT 1.13.1