SendGridV2Builder.java

  1. package fr.sii.ogham.email.sendgrid.v2.builder.sendgrid;

  2. import java.net.URL;

  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;

  5. import com.sendgrid.SendGrid;

  6. import fr.sii.ogham.core.builder.MessagingBuilder;
  7. import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilder;
  8. import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilderHelper;
  9. import fr.sii.ogham.core.builder.context.BuildContext;
  10. import fr.sii.ogham.core.builder.context.DefaultBuildContext;
  11. import fr.sii.ogham.core.message.content.MayHaveStringContent;
  12. import fr.sii.ogham.core.message.content.MultiContent;
  13. import fr.sii.ogham.core.mimetype.MimeTypeProvider;
  14. import fr.sii.ogham.email.builder.EmailBuilder;
  15. import fr.sii.ogham.email.message.Email;
  16. import fr.sii.ogham.email.message.content.ContentWithAttachments;
  17. import fr.sii.ogham.email.sendgrid.builder.AbstractSendGridBuilder;
  18. import fr.sii.ogham.email.sendgrid.v2.sender.impl.SendGridV2Sender;
  19. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.client.DelegateSendGridClient;
  20. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.client.SendGridClient;
  21. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.client.SendGridInterceptor;
  22. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.handler.ContentWithAttachmentsHandler;
  23. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.handler.MultiContentHandler;
  24. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.handler.PriorizedContentHandler;
  25. import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.handler.StringContentHandler;

  26. /**
  27.  * Configures how SendGrid implementation will send {@link Email}s.
  28.  *
  29.  * This implementation uses SendGrid HTTP API.
  30.  *
  31.  * <p>
  32.  * To send {@link Email} using SendGrid, you need to register this builder into
  33.  * a {@link MessagingBuilder} like this:
  34.  *
  35.  * <pre>
  36.  * <code>
  37.  * MessagingBuilder msgBuilder = ...
  38.  * msgBuilder.email()
  39.  *    .sender(SendGridV2Builder.class)    // registers the builder and accesses to that builder for configuring it
  40.  * </code>
  41.  * </pre>
  42.  *
  43.  * Once the builder is registered, sending email through SendGrid requires
  44.  * either an API key or a username/password pair. You can define it using:
  45.  *
  46.  * <pre>
  47.  * <code>
  48.  * msgBuilder.email()
  49.  *    .sender(SendGridV2Builder.class)    // registers the builder and accesses to that builder for configuring it
  50.  *       .apiKey("foo")
  51.  * </code>
  52.  * </pre>
  53.  *
  54.  * Or you can also use property keys (using interpolation):
  55.  *
  56.  * <pre>
  57.  * <code>
  58.  * msgBuilder
  59.  * .environment()
  60.  *    .properties()
  61.  *       .set("custom.property.for.api-key", "foo")
  62.  *       .and()
  63.  *    .and()
  64.  * .email()
  65.  *    .sender(SendGridV2Builder.class)    // registers the builder and accesses to that builder for configuring it
  66.  *       .apiKey("${custom.property.for.api-key}")
  67.  * </code>
  68.  * </pre>
  69.  *
  70.  * <p>
  71.  * Finally, Ogham will transform general {@link Email} object into
  72.  * {@link SendGrid}.Email object. This transformation will fit almost all use
  73.  * cases but you may need to customize a part of the SendGrid message. Instead
  74.  * of doing again the same work Ogham does, this builder allows you to intercept
  75.  * the message to modify it just before sending it:
  76.  *
  77.  * <pre>
  78.  * <code>
  79.  * .sender(SendGridV2Builder.class)
  80.  *    .intercept(new MyCustomInterceptor())
  81.  * </code>
  82.  * </pre>
  83.  *
  84.  * See {@link SendGridInterceptor} for more information.
  85.  *
  86.  * @author AurĂ©lien Baudet
  87.  *
  88.  */
  89. public class SendGridV2Builder extends AbstractSendGridBuilder<SendGridV2Builder, EmailBuilder> {
  90.     private static final Logger LOG = LoggerFactory.getLogger(SendGridV2Builder.class);

  91.     private final ConfigurationValueBuilderHelper<SendGridV2Builder, String> usernameValueBuilder;
  92.     private final ConfigurationValueBuilderHelper<SendGridV2Builder, String> passwordValueBuilder;
  93.     private SendGridClient client;
  94.     private SendGridInterceptor interceptor;

  95.     /**
  96.      * Default constructor when using SendGrid sender without all Ogham work.
  97.      *
  98.      * <strong>WARNING: use is only if you know what you are doing !</strong>
  99.      */
  100.     public SendGridV2Builder() {
  101.         this(null, new DefaultBuildContext());
  102.     }

  103.     /**
  104.      * Constructor that is called when using Ogham builder:
  105.      *
  106.      * <pre>
  107.      * MessagingBuilder msgBuilder = ...
  108.      * msgBuilder
  109.      * .email()
  110.      *    .sender(SendGridV2Builder.class)
  111.      * </pre>
  112.      *
  113.      * @param parent
  114.      *            the parent builder instance for fluent chaining
  115.      * @param buildContext
  116.      *            for registering instances and property evaluation
  117.      */
  118.     public SendGridV2Builder(EmailBuilder parent, BuildContext buildContext) {
  119.         super(SendGridV2Builder.class, parent, buildContext);
  120.         usernameValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
  121.         passwordValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
  122.     }

  123.     @Override
  124.     public SendGridV2Builder username(String username) {
  125.         usernameValueBuilder.setValue(username);
  126.         return this;
  127.     }

  128.     @Override
  129.     public ConfigurationValueBuilder<SendGridV2Builder, String> username() {
  130.         return usernameValueBuilder;
  131.     }

  132.     @Override
  133.     public SendGridV2Builder password(String password) {
  134.         passwordValueBuilder.setValue(password);
  135.         return this;
  136.     }

  137.     @Override
  138.     public ConfigurationValueBuilder<SendGridV2Builder, String> password() {
  139.         return passwordValueBuilder;
  140.     }

  141.     /**
  142.      * By default, calling SendGrid HTTP API is done through the default
  143.      * {@link SendGrid} implementation. If you want to use another client
  144.      * implementation (creating your custom HTTP API caller for example), you
  145.      * can implement the {@link SendGridClient} interface and provide it:
  146.      *
  147.      * <pre>
  148.      * .client(new MyCustomHttpApiCaller())
  149.      * </pre>
  150.      *
  151.      * NOTE: if you provide your custom implementation, any defined properties
  152.      * and values using {@link #apiKey(String)}, {@link #username(String)} or
  153.      * {@link #password(String)} won't be used at all. You then have to handle
  154.      * it by yourself.
  155.      *
  156.      * @param client
  157.      *            the custom client used to call SendGrid HTTP API
  158.      * @return this instance for fluent chaining
  159.      */
  160.     public SendGridV2Builder client(SendGridClient client) {
  161.         this.client = client;
  162.         return this;
  163.     }

  164.     /**
  165.      * Ogham will transform general {@link Email} object into
  166.      * {@link SendGrid}.Email objects. This transformation will fit almost all
  167.      * use cases but you may need to customize a part of the SendGrid message.
  168.      * Instead of doing again the same work Ogham does, this builder allows you
  169.      * to intercept the message to modify it just before sending it:
  170.      *
  171.      * <pre>
  172.      * .sender(SendGridV2Builder.class)
  173.      *    .intercept(new MyCustomInterceptor())
  174.      * </pre>
  175.      *
  176.      * See {@link SendGridInterceptor} for more information.
  177.      *
  178.      * @param interceptor
  179.      *            the custom interceptor used to modify {@link SendGrid}.Email
  180.      * @return this instance for fluent chaining
  181.      */
  182.     public SendGridV2Builder intercept(SendGridInterceptor interceptor) {
  183.         this.interceptor = interceptor;
  184.         return this;
  185.     }

  186.     @Override
  187.     public SendGridV2Sender build() {
  188.         String apiKey = apiKeyValueBuilder.getValue();
  189.         String username = usernameValueBuilder.getValue();
  190.         String password = passwordValueBuilder.getValue();
  191.         URL url = urlValueBuilder.getValue();
  192.         SendGridClient builtClient = buildClient(apiKey, username, password, url);
  193.         if (builtClient == null) {
  194.             return null;
  195.         }
  196.         LOG.info("Sending email using SendGrid API is registered");
  197.         LOG.debug("SendGrid account: apiKey={}, username={}", apiKey, username);
  198.         return buildContext.register(new SendGridV2Sender(builtClient, buildContentHandler(), interceptor));
  199.     }

  200.     private SendGridClient buildClient(String apiKey, String username, String password, URL url) {
  201.         if (client != null) {
  202.             return client;
  203.         }
  204.         if (apiKey != null || (username != null && password != null)) {
  205.             return buildContext.register(new DelegateSendGridClient(buildSendGrid(apiKey, username, password, url)));
  206.         }
  207.         return null;
  208.     }

  209.     private SendGrid buildSendGrid(String apiKey, String username, String password, URL url) {
  210.         SendGrid sendGrid = newSendGrid(apiKey, username, password);
  211.         if (url != null) {
  212.             sendGrid.setUrl(url.toString());
  213.         }
  214.         if (httpClient != null) {
  215.             sendGrid.setClient(httpClient);
  216.         }
  217.         return sendGrid;
  218.     }

  219.     private SendGrid newSendGrid(String apiKey, String username, String password) {
  220.         if (apiKey != null) {
  221.             return buildContext.register(new SendGrid(apiKey));
  222.         }
  223.         return buildContext.register(new SendGrid(username, password));
  224.     }

  225.     private PriorizedContentHandler buildContentHandler() {
  226.         MimeTypeProvider mimetypeProvider = mimetypeBuilder.build();
  227.         PriorizedContentHandler contentHandler = buildContext.register(new PriorizedContentHandler());
  228.         contentHandler.register(MultiContent.class, buildContext.register(new MultiContentHandler(contentHandler)));
  229.         contentHandler.register(ContentWithAttachments.class, buildContext.register(new ContentWithAttachmentsHandler(contentHandler)));
  230.         contentHandler.register(MayHaveStringContent.class, buildContext.register(new StringContentHandler(mimetypeProvider)));
  231.         return contentHandler;
  232.     }
  233. }