All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.sii.ogham.email.builder.sendgrid.SendGridBuilder Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
package fr.sii.ogham.email.builder.sendgrid;

import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.activation.MimetypesFileTypeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sendgrid.SendGrid;

import fr.sii.ogham.core.builder.AbstractParent;
import fr.sii.ogham.core.builder.Builder;
import fr.sii.ogham.core.builder.MessagingBuilder;
import fr.sii.ogham.core.builder.env.EnvironmentBuilder;
import fr.sii.ogham.core.builder.env.EnvironmentBuilderDelegate;
import fr.sii.ogham.core.builder.env.SimpleEnvironmentBuilder;
import fr.sii.ogham.core.builder.mimetype.MimetypeDetectionBuilder;
import fr.sii.ogham.core.builder.mimetype.MimetypeDetectionBuilderDelegate;
import fr.sii.ogham.core.builder.mimetype.SimpleMimetypeDetectionBuilder;
import fr.sii.ogham.core.env.PropertyResolver;
import fr.sii.ogham.core.message.content.MultiContent;
import fr.sii.ogham.core.message.content.StringContent;
import fr.sii.ogham.core.mimetype.MimeTypeProvider;
import fr.sii.ogham.core.util.BuilderUtils;
import fr.sii.ogham.email.builder.EmailBuilder;
import fr.sii.ogham.email.message.Email;
import fr.sii.ogham.email.sender.impl.SendGridSender;
import fr.sii.ogham.email.sender.impl.sendgrid.client.DelegateSendGridClient;
import fr.sii.ogham.email.sender.impl.sendgrid.client.SendGridClient;
import fr.sii.ogham.email.sender.impl.sendgrid.client.SendGridInterceptor;
import fr.sii.ogham.email.sender.impl.sendgrid.handler.MapContentHandler;
import fr.sii.ogham.email.sender.impl.sendgrid.handler.MultiContentHandler;
import fr.sii.ogham.email.sender.impl.sendgrid.handler.StringContentHandler;

/**
 * Configures how SendGrid implementation will send {@link Email}s.
 * 
 * This implementation uses SendGrid HTTP API.
 * 
 * 

* To send {@link Email} using SendGrid, you need to register this builder into * a {@link MessagingBuilder} like this: * *

 * 
 * MessagingBuilder msgBuilder = ...
 * msgBuilder.email()
 *    .sender(SendGridBuilder.class)    // registers the builder and accesses to that builder for configuring it
 * 
 * 
* * Once the builder is registered, sending email through SendGrid requires * either an API key or a username/password pair. You can define it using: * *
 * 
 * msgBuilder.email()
 *    .sender(SendGridBuilder.class)    // registers the builder and accesses to that builder for configuring it
 *       .apiKey("foo")
 * 
 * 
* * Or you can also use property keys (using interpolation): * *
 * 
 * msgBuilder
 * .environment()
 *    .properties()
 *       .set("custom.property.for.api-key", "foo")
 *       .and()
 *    .and()
 * .email()
 *    .sender(SendGridBuilder.class)    // registers the builder and accesses to that builder for configuring it
 *       .host("${custom.property.for.api-key}")
 * 
 * 
* *

* Finally, Ogham will transform general {@link Email} object into * {@link SendGrid}.Email object. This transformation will fit almost all use * cases but you may need to customize a part of the SendGrid message. Instead * of doing again the same work Ogham does, this builder allows you to intercept * the message to modify it just before sending it: * *

 * 
 * .sender(SendGridBuilder.class)
 *    .intercept(new MyCustomInterceptor())
 * 
 * 
* * See {@link SendGridInterceptor} for more information. * * @author Aurélien Baudet * */ public class SendGridBuilder extends AbstractParent implements Builder { private static final Logger LOG = LoggerFactory.getLogger(SendGridBuilder.class); private EnvironmentBuilder environmentBuilder; private MimetypeDetectionBuilder mimetypeBuilder; private List apiKeys; private List usernames; private List passwords; private SendGridClient client; private SendGridInterceptor interceptor; /** * Default constructor when using SendGrid sender without all Ogham work. * * WARNING: use is only if you know what you are doing ! */ public SendGridBuilder() { this(null); environment(); mimetype(); } /** * Constructor that is called when using Ogham builder: * *
	 * MessagingBuilder msgBuilder = ...
	 * msgBuilder
	 * .email()
	 *    .sender(SendGridBuilder.class)
	 * 
* * @param parent * the parent builder instance for fluent chaining */ public SendGridBuilder(EmailBuilder parent) { super(parent); apiKeys = new ArrayList<>(); usernames = new ArrayList<>(); passwords = new ArrayList<>(); } /** * Set SendGrid API * key. * * You can specify a direct value. For example: * *
	 * .apiKey("localhost");
	 * 
* *

* You can also specify one or several property keys. For example: * *

	 * .apiKey("${custom.property.high-priority}", "${custom.property.low-priority}");
	 * 
* * The properties are not immediately evaluated. The evaluation will be done * when the {@link #build()} method is called. * * If you provide several property keys, evaluation will be done on the * first key and if the property exists (see {@link EnvironmentBuilder}), * its value is used. If the first property doesn't exist in properties, * then it tries with the second one and so on. * * @param key * one value, or one or several property keys * @return this instance for fluent chaining */ public SendGridBuilder apiKey(String... key) { for (String k : key) { if (k != null) { apiKeys.add(k); } } return this; } /** * Set username for SendGrid HTTP API. * * You can specify a direct value. For example: * *
	 * .username("foo");
	 * 
* *

* You can also specify one or several property keys. For example: * *

	 * .username("${custom.property.high-priority}", "${custom.property.low-priority}");
	 * 
* * The properties are not immediately evaluated. The evaluation will be done * when the {@link #build()} method is called. * * If you provide several property keys, evaluation will be done on the * first key and if the property exists (see {@link EnvironmentBuilder}), * its value is used. If the first property doesn't exist in properties, * then it tries with the second one and so on. * * @param username * one value, or one or several property keys * @return this instance for fluent chaining */ public SendGridBuilder username(String... username) { for (String u : username) { if (u != null) { usernames.add(u); } } return this; } /** * Set password for SendGrid HTTP API. * * You can specify a direct value. For example: * *
	 * .password("foo");
	 * 
* *

* You can also specify one or several property keys. For example: * *

	 * .password("${custom.property.high-priority}", "${custom.property.low-priority}");
	 * 
* * The properties are not immediately evaluated. The evaluation will be done * when the {@link #build()} method is called. * * If you provide several property keys, evaluation will be done on the * first key and if the property exists (see {@link EnvironmentBuilder}), * its value is used. If the first property doesn't exist in properties, * then it tries with the second one and so on. * * @param password * one value, or one or several property keys * @return this instance for fluent chaining */ public SendGridBuilder password(String... password) { for (String p : password) { if (p != null) { passwords.add(p); } } return this; } /** * By default, calling SendGrid HTTP API is done through the default * {@link SendGrid} implementation. If you want to use another client * implementation (creating your custom HTTP API caller for example), you * can implement the {@link SendGridClient} interface and provide it: * *
	 * .client(new MyCustomHttpApiCaller())
	 * 
* * NOTE: if you provide your custom implementation, any defined properties * and values using {@link #apiKey(String...)}, {@link #username(String...)} * or {@link #password(String...)} won't be used at all. You then have to * handle it by yourself. * * @param client * the custom client used to call SendGrid HTTP API * @return this instance for fluent chaining */ public SendGridBuilder client(SendGridClient client) { this.client = client; return this; } /** * Builder that configures mimetype detection. * * There exists several implementations to provide the mimetype: *
    *
  • Using Java {@link MimetypesFileTypeMap}
  • *
  • Using Java 7 {@link Files#probeContentType(java.nio.file.Path)}
  • *
  • Using Apache Tika
  • *
  • Using * JMimeMagic
  • *
* *

* Both implementations provided by Java are based on file extensions. This * can't be used in most cases as we often handle {@link InputStream}s. *

* *

* In previous version of Ogham, JMimeMagic was used and was working quite * well. Unfortunately, the library is no more maintained. *

* *

* You can configure how Tika will detect mimetype: * *

	 * .mimetype()
	 *    .tika()
	 *       ...
	 * 
* *

* This builder allows to use several providers. It will chain them until * one can find a valid mimetype. If none is found, you can explicitly * provide the default one: * *

	 * .mimetype()
	 *    .defaultMimetype("text/html")
	 * 
* *

* If no mimetype detector was previously defined, it creates a new one. * Then each time you call {@link #mimetype()}, the same instance is used. *

* * @return the builder to configure mimetype detection */ public MimetypeDetectionBuilder mimetype() { if (mimetypeBuilder == null) { mimetypeBuilder = new SimpleMimetypeDetectionBuilder<>(this, environmentBuilder); } return mimetypeBuilder; } /** * NOTE: this is mostly for advance usage (when creating a custom module). * * Inherits mimetype configuration from another builder. This is useful for * configuring independently different parts of Ogham but keeping a whole * coherence (see {@link DefaultSendGridConfigurer} for an example of use). * * The same instance is shared meaning that all changes done here will also * impact the other builder. * *

* If a previous builder was defined (by calling {@link #mimetype()} for * example), the new builder will override it. * * @param builder * the builder to inherit * @return this instance for fluent chaining */ public SendGridBuilder mimetype(MimetypeDetectionBuilder builder) { mimetypeBuilder = new MimetypeDetectionBuilderDelegate<>(this, builder); return this; } /** * Configures environment for the builder (and sub-builders). Environment * consists of configuration properties/values that are used to configure * the system (see {@link EnvironmentBuilder} for more information). * * You can use system properties: * *

	 * .environment()
	 *    .systemProperties();
	 * 
* * Or, you can load properties from a file: * *
	 * .environment()
	 *    .properties("/path/to/file.properties")
	 * 
* * Or using directly a {@link Properties} object: * *
	 * Properties myprops = new Properties();
	 * myprops.setProperty("foo", "bar");
	 * .environment()
	 *    .properties(myprops)
	 * 
* * Or defining directly properties: * *
	 * .environment()
	 *    .properties()
	 *       .set("foo", "bar")
	 * 
* * *

* If no environment was previously used, it creates a new one. Then each * time you call {@link #environment()}, the same instance is used. *

* * @return the builder to configure properties handling */ public EnvironmentBuilder environment() { if (environmentBuilder == null) { environmentBuilder = new SimpleEnvironmentBuilder<>(this); } return environmentBuilder; } /** * NOTE: this is mostly for advance usage (when creating a custom module). * * Inherits environment configuration from another builder. This is useful * for configuring independently different parts of Ogham but keeping a * whole coherence (see {@link DefaultSendGridConfigurer} for an example of * use). * * The same instance is shared meaning that all changes done here will also * impact the other builder. * *

* If a previous builder was defined (by calling {@link #environment()} for * example), the new builder will override it. * * @param builder * the builder to inherit * @return this instance for fluent chaining */ public SendGridBuilder environment(EnvironmentBuilder builder) { environmentBuilder = new EnvironmentBuilderDelegate<>(this, builder); return this; } /** * Ogham will transform general {@link Email} object into * {@link SendGrid}.Email objects. This transformation will fit almost all * use cases but you may need to customize a part of the SendGrid message. * Instead of doing again the same work Ogham does, this builder allows you * to intercept the message to modify it just before sending it: * *

	 * .sender(SendGridBuilder.class)
	 *    .intercept(new MyCustomInterceptor())
	 * 
* * See {@link SendGridInterceptor} for more information. * * @param interceptor * the custom interceptor used to modify {@link SendGrid}.Email * @return this instance for fluent chaining */ public SendGridBuilder intercept(SendGridInterceptor interceptor) { this.interceptor = interceptor; return this; } @Override public SendGridSender build() { PropertyResolver propertyResolver = environmentBuilder.build(); String apiKey = BuilderUtils.evaluate(this.apiKeys, propertyResolver, String.class); String username = BuilderUtils.evaluate(this.usernames, propertyResolver, String.class); String password = BuilderUtils.evaluate(this.passwords, propertyResolver, String.class); SendGridClient builtClient = buildClient(apiKey, username, password); if (builtClient == null) { return null; } LOG.info("Sending email using SendGrid API is registered"); LOG.debug("SendGrid account: apiKey={}, username={}", apiKey, username); return new SendGridSender(builtClient, buildContentHandler(), interceptor); } private SendGridClient buildClient(String apiKey, String username, String password) { if (client != null) { return client; } if (apiKey != null) { return new DelegateSendGridClient(apiKey); } if (username != null && password != null) { return new DelegateSendGridClient(username, password); } return null; } private MapContentHandler buildContentHandler() { MimeTypeProvider mimetypeProvider = mimetypeBuilder.build(); MapContentHandler contentHandler = new MapContentHandler(); contentHandler.register(MultiContent.class, new MultiContentHandler(contentHandler)); contentHandler.register(StringContent.class, new StringContentHandler(mimetypeProvider)); return contentHandler; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy