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

fr.sii.ogham.sms.builder.SmsBuilder Maven / Gradle / Ivy

package fr.sii.ogham.sms.builder;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

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

import fr.sii.ogham.core.builder.Builder;
import fr.sii.ogham.core.builder.ContentTranslatorBuilder;
import fr.sii.ogham.core.builder.MessageFillerBuilder;
import fr.sii.ogham.core.builder.MessagingSenderBuilder;
import fr.sii.ogham.core.builder.TemplateBuilder;
import fr.sii.ogham.core.condition.AndCondition;
import fr.sii.ogham.core.condition.Condition;
import fr.sii.ogham.core.condition.RequiredClassCondition;
import fr.sii.ogham.core.condition.RequiredPropertyCondition;
import fr.sii.ogham.core.exception.builder.BuildException;
import fr.sii.ogham.core.filler.MessageFiller;
import fr.sii.ogham.core.message.Message;
import fr.sii.ogham.core.sender.ConditionalSender;
import fr.sii.ogham.core.sender.ContentTranslatorSender;
import fr.sii.ogham.core.sender.FillerSender;
import fr.sii.ogham.core.sender.MessageSender;
import fr.sii.ogham.core.sender.MultiImplementationSender;
import fr.sii.ogham.core.translator.content.ContentTranslator;
import fr.sii.ogham.core.util.BuilderUtils;
import fr.sii.ogham.sms.SmsConstants;
import fr.sii.ogham.sms.message.addressing.translator.PhoneNumberTranslator;
import fr.sii.ogham.sms.sender.SmsSender;
import fr.sii.ogham.sms.sender.impl.CloudhopperSMPPSender;
import fr.sii.ogham.sms.sender.impl.OvhSmsSender;
import fr.sii.ogham.sms.sender.impl.PhoneNumberTranslatorSender;
import fr.sii.ogham.template.TemplateConstants;

/**
 * 

* Specialized builder for SMS sender. *

* There exists several implementations to send an SMS: *
    *
  • Using * cloudhopper (SMPP * library)
  • *
  • Using jsmpp (SMPP library)
  • *
  • Using any other library
  • *
  • Using HTTP request to drive OVH * API
  • *
  • Using REST, HTTP or SOAP requests to drive * smsglobal APIs
  • *
  • Using any other web service
  • *
  • ...
  • *
*

* This builder provides a {@link MultiImplementationSender}. The aim of the * {@link MultiImplementationSender} is to choose the best implementation for * sending the SMS according to the runtime environment (detection of libraries * in the classpath, availability of a particular property, ...). *

*

* This builder lets you the possibility to register any new implementation. It * allows you to enable or not templating support and automatic filling of * message values (like sender address for example). *

* * @author Aurélien Baudet * @see SmsSender * @see OvhSmsSender * @see CloudhopperSMPPSender * @see TemplateBuilder * @see ContentTranslatorBuilder * @see MessageFillerBuilder */ public class SmsBuilder implements MessagingSenderBuilder { private static final Logger LOG = LoggerFactory.getLogger(SmsBuilder.class); /** * The sender instance constructed by this builder */ private ConditionalSender sender; /** * The specialized {@link MultiImplementationSender}. It is useful to * register new implementations */ private SmsSender smsSender; /** * The builder for message filler used to add values to the message */ private MessageFillerBuilder messageFillerBuilder; /** * Map of possible implementations with associated conditions */ private final Map, Builder> implementations; /** * The builder for the translator that will update the content of the * message */ private ContentTranslatorBuilder contentTranslatorBuilder; /** * Builder for phone number transformations for receiver */ private PhoneNumberTranslatorBuilder recipientNumberTranslatorBuilder; /** * Builder for phone number transformations for sender */ private PhoneNumberTranslatorBuilder senderNumberTranslatorBuilder; /** * Own property key for template resolution parent path */ private String templateParentPathKey; /** * Own property key for template resolution extension */ private String templateExtensionKey; public SmsBuilder() { super(); smsSender = new SmsSender(); sender = smsSender; implementations = new HashMap<>(); } @Override public ConditionalSender build() throws BuildException { for (Entry, Builder> impl : implementations.entrySet()) { MessageSender s = impl.getValue().build(); LOG.debug("Implementation {} registered", s); smsSender.addImplementation(impl.getKey(), s); } if (contentTranslatorBuilder != null) { if (templateParentPathKey != null) { LOG.debug("Use custom property key {} for parent path template resolution", templateParentPathKey); getTemplateBuilder().setParentPathKey(templateParentPathKey); } if (templateExtensionKey != null) { LOG.debug("Use custom property key {} for extension template resolution", templateExtensionKey); getTemplateBuilder().setExtensionKey(templateExtensionKey); } sender = new ContentTranslatorSender(contentTranslatorBuilder.build(), sender); } if (senderNumberTranslatorBuilder == null) { LOG.debug("Using default phone number translation for sender phone number"); senderNumberTranslatorBuilder = new DefaultPhoneNumberTranslatorBuilder(); } if (recipientNumberTranslatorBuilder == null) { LOG.debug("Using default phone number translation for recipient phone number"); recipientNumberTranslatorBuilder = new DefaultPhoneNumberTranslatorBuilder(); } sender = new PhoneNumberTranslatorSender(senderNumberTranslatorBuilder.build(), recipientNumberTranslatorBuilder.build(), sender); if (messageFillerBuilder != null) { MessageFiller messageFiller = messageFillerBuilder.build(); LOG.debug("Automatic filling of message enabled {}", messageFiller); sender = new FillerSender(messageFiller, sender); } return sender; } /** * Tells the builder to use all default behaviors and values: *
    *
  • Registers OVH HTTP API implementation
  • *
  • Enables automatic filling of message based on configuration * properties
  • *
  • Enables templating support
  • *
*

* Configuration values come from system properties. *

* * @return this instance for fluent use */ public SmsBuilder useDefaults() { return useDefaults(BuilderUtils.getDefaultProperties()); } /** * Tells the builder to use all default behaviors and values: *
    *
  • Registers OVH HTTP API implementation
  • *
  • Enables automatic filling of message based on configuration * properties
  • *
  • Enables templating support
  • *
*

* Configuration values come from provided properties. *

* * @param properties * the properties to use instead of default ones * @return this instance for fluent use */ public SmsBuilder useDefaults(Properties properties) { registerDefaultImplementations(properties); withPhoneNumberTranslation(); withAutoFilling(properties); withTemplate(); return this; } /** * Register a new implementation for sending SMS. The implementation is * associated to a condition. If the condition evaluation returns true at * runtime then it means that the implementation can be used. If several * implementations are available, only the first implementation is really * invoked. * * @param condition * the condition that indicates at runtime if the implementation * can be used or not * @param implementation * the implementation to register * @return this instance for fluent use */ public SmsBuilder registerImplementation(Condition condition, MessageSender implementation) { smsSender.addImplementation(condition, implementation); return this; } /** * Register a new implementation for sending SMS. The implementation is * associated to a condition. If the condition evaluation returns true at * runtime then it means that the implementation can be used. If several * implementations are available, only the first implementation is really * invoked. * * @param condition * the condition that indicates at runtime if the implementation * can be used or not * @param builder * the builder for the implementation to register * @return this instance for fluent use */ public SmsBuilder registerImplementation(Condition condition, Builder builder) { implementations.put(condition, builder); return this; } /** * Register all default implementations: *
    *
  • OVH HTTP API implementation
  • *
*

* Configuration values come from system properties. *

*

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @return this instance for fluent use */ public SmsBuilder registerDefaultImplementations() { return registerDefaultImplementations(System.getProperties()); } /** * Register all default implementations: *
    *
  • OVH HTTP API implementation
  • *
  • smsgloabl REST API implementation
  • *
  • Cloudhopper SMPP implementation
  • *
*

* Configuration values come from provided properties. *

*

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @param properties * the properties to use * @return this instance for fluent use */ public SmsBuilder registerDefaultImplementations(Properties properties) { withOvhHttpApi(properties); withSmsglobalRestApi(properties); withCloudhopper(properties); return this; } /** * Enable smsglobal REST API implementation. This implementation is used * only if the associated condition indicates that smsglobal REST API can be * used. The condition checks if: *
    *
  • The property ogham.sms.smsglobal.api.key is set
  • *
* * @param properties * the properties to use for checking if property exists * @return this builder instance for fluent use */ public SmsBuilder withSmsglobalRestApi(Properties properties) { // Use smsglobal REST API only if // SmsConstants.SMSGLOBAL_REST_API_KEY_PROPERTY is set // registerImplementation(new // RequiredPropertyCondition(SmsConstants.SmsGlobal.SMSGLOBAL_REST_API_KEY_PROPERTY, // properties), new SmsglobalRestSender()); return this; } /** * Enable OVH HTTP API implementation. This implementation is used only if * the associated condition indicates that OVH HTTP API can be used. The * condition checks if: *
    *
  • The property ogham.sms.ovh.account is set
  • *
  • The property ogham.sms.ovh.login is set
  • *
  • The property ogham.sms.ovh.password is set
  • *
* * @param properties * the properties to use for checking if property exists * @return this builder instance for fluent use */ public SmsBuilder withOvhHttpApi(Properties properties) { try { // Use OVH implementation only if SmsConstants.ACCOUNT_PROPERTY is // set // @formatter:off registerImplementation(new AndCondition<>( new RequiredPropertyCondition(SmsConstants.OvhConstants.ACCOUNT_PROPERTY, properties), new RequiredPropertyCondition(SmsConstants.OvhConstants.LOGIN_PROPERTY, properties), new RequiredPropertyCondition(SmsConstants.OvhConstants.PASSWORD_PROPERTY, properties)), new OvhSmsBuilder().useDefaults(properties)); // @formatter:on } catch (Exception e) { LOG.debug("Can't register OVH implementation", e); } return this; } /** * Enable Cloudhoppder SMPP implementation. This implementation is used only * if the associated condition indicates that Cloudhopper SMPP can be used. * The condition checks if: *
    *
  • The property ogham.sms.smpp.host is set
  • *
  • The property ogham.sms.smpp.port is set
  • *
  • The class com.cloudhopper.smpp.SmppClient is available * in the classpath
  • *
* The registration can silently fail if the ch-smpp jar is not in the * classpath. In this case, the Cloudhopper implementation is not registered * at all. * * @param properties * the properties to use for checking if property exists * @return this builder instance for fluent use */ public SmsBuilder withCloudhopper(Properties properties) { try { // Use Cloudhopper SMPP implementation only if SmppClient class is // in the classpath and the SmppConstants.SMPP_HOST_PROPERTY // property is set // @formatter:off registerImplementation(new AndCondition<>( new RequiredPropertyCondition(SmsConstants.SmppConstants.HOST_PROPERTY, properties), new RequiredPropertyCondition(SmsConstants.SmppConstants.PORT_PROPERTY, properties), new RequiredClassCondition("com.cloudhopper.smpp.SmppClient")), new CloudhopperSMPPBuilder().useDefaults(properties)); // @formatter:on } catch (Exception e) { LOG.debug("Can't register Cloudhopper implementation", e); } return this; } /** * Enables automatic filling of SMS with values that come from multiple * sources. It let you use your own builder instead of using default * behaviors. * * @param builder * the builder for constructing the message filler * @return this instance for fluent use */ public SmsBuilder withAutoFilling(MessageFillerBuilder builder) { messageFillerBuilder = builder; return this; } /** * Enables filling of SMS with values that comes from provided configuration * properties. *

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @param props * the properties that contains the values to set on the SMS * @param baseKeys * the prefix(es) for the keys used for filling the message * @return this instance for fluent use */ public SmsBuilder withAutoFilling(Properties props, String... baseKeys) { withAutoFilling(new MessageFillerBuilder().useDefaults(props, baseKeys)); return this; } /** * Enables filling of SMS with values that comes from provided configuration * properties. It uses the default prefix for the keys ("sms" and * "ogham.sms"). *

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @param props * the properties that contains the values to set on the SMS * @return this instance for fluent use */ public SmsBuilder withAutoFilling(Properties props) { return withAutoFilling(props, SmsConstants.FILL_PREFIXES); } /** * Enables filling of SMS with values that comes from system configuration * properties. It uses the default prefixes for the keys ("sms" and * "ogham.sms"). *

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @return this instance for fluent use */ public SmsBuilder withAutoFilling() { withAutoFilling(BuilderUtils.getDefaultProperties()); return this; } /** * Enables templating support using all default behaviors and values. See * {@link ContentTranslatorBuilder#useDefaults()} for more information. * *

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @return this instance for fluent use */ public SmsBuilder withTemplate() { return withTemplate(new ContentTranslatorBuilder().useDefaults()); } /** * Enables templating support using the provided * {@link ContentTranslatorBuilder}. It decorates the SMS sender with a * {@link ContentTranslatorSender}. * * @param builder * the builder to use to build the {@link ContentTranslator} * instead of using the default one * @return this instance for fluent use */ public SmsBuilder withTemplate(ContentTranslatorBuilder builder) { contentTranslatorBuilder = builder; return this; } /** * Disable templating support. * * @return this instance for fluent use */ public SmsBuilder withoutTemplate() { this.contentTranslatorBuilder = null; return this; } /** *

* Calling this method will enable different location for SMS templates from * default one. The location will be specified by different property keys * for parent path and extension. *

* * By default default properties are: *
    *
  • ogham.template.prefix (see {@link TemplateConstants#PREFIX_PROPERTY}) *
  • *
  • ogham.template.suffix (see * {@link TemplateConstants#SUFFIX_PROPERTY}
  • *
* * Calling this method will change the property keys to: *
    *
  • ogham.sms.template.prefix (see * {@link fr.sii.ogham.sms.SmsConstants.TemplateConstants#PREFIX_PROPERTY}
  • *
  • ogham.sms.template.suffix (see * {@link fr.sii.ogham.sms.SmsConstants.TemplateConstants#SUFFIX_PROPERTY}
  • *
* * @return this instance for fluent use */ public SmsBuilder enableSmsTemplateKeys() { setTemplateParentPathKey(SmsConstants.TemplateConstants.PREFIX_PROPERTY); setTemplateExtensionKey(SmsConstants.TemplateConstants.SUFFIX_PROPERTY); return this; } /** *

* Calling this method will enable different location for SMS templates from * default one. The location will be specified by a different property key * for parent path. *

* *

* By default default property key is ogham.template.prefix (see * {@link TemplateConstants#PREFIX_PROPERTY}) *

* *

* Calling this method will change the property key to the provided key. *

* * @param parentPathKey * the new key for the SMS template parent path * @return this instance for fluent use */ public SmsBuilder setTemplateParentPathKey(String parentPathKey) { this.templateParentPathKey = parentPathKey; return this; } /** *

* Calling this method will enable different location for SMS templates from * default one. The location will be specified by a different property key * for extension. *

* *

* By default default property key is ogham.template.suffix (see * {@link TemplateConstants#SUFFIX_PROPERTY}) *

* *

* Calling this method will change the property key to the provided key. *

* * @param extensionKey * the new key for the SMS template extension * @return this instance for fluent use */ public SmsBuilder setTemplateExtensionKey(String extensionKey) { this.templateExtensionKey = extensionKey; return this; } /** * Enables Addressing strategy using all default behaviors and values. See * {@link SenderPhoneNumberTranslatorBuilder} and * {@link RecipientPhoneNumberTranslatorBuilder}. * *

* Automatically called by {@link #useDefaults()} and * {@link #useDefaults(Properties)} *

* * @return this instance for fluent use */ public SmsBuilder withPhoneNumberTranslation() { return withPhoneNumberTranslation(new SenderPhoneNumberTranslatorBuilder().useDefaults(), new RecipientPhoneNumberTranslatorBuilder().useDefaults()); } /** * Enables Addressing strategy using the provided * {@link SenderPhoneNumberTranslatorBuilder} and * {@link RecipientPhoneNumberTranslatorBuilder}. It decorates the SMS * sender with a {@link PhoneNumberTranslatorSender} * * @param senderBuilder * the builder to use to build the {@link PhoneNumberTranslator} * for sender instead of using the default one * @param recipientBuilder * the builder to use to build the {@link PhoneNumberTranslator} * for sender instead of using the default one * @return this instance for fluent use */ public SmsBuilder withPhoneNumberTranslation(PhoneNumberTranslatorBuilder senderBuilder, PhoneNumberTranslatorBuilder recipientBuilder) { withSenderPhoneNumberTranslation(senderBuilder); withReceiverPhoneNumberTranslation(recipientBuilder); return this; } /** * Enables Addressing strategy using the provided * {@link RecipientPhoneNumberTranslatorBuilder}. It decorates the SMS * sender with a {@link PhoneNumberTranslatorSender} * * @param builder * the builder to use to build the {@link PhoneNumberTranslator} * instead of using the default one * @return this instance for fluent use */ public SmsBuilder withReceiverPhoneNumberTranslation(PhoneNumberTranslatorBuilder builder) { recipientNumberTranslatorBuilder = builder; return this; } /** * Enables Addressing strategy using the provided * {@link SenderPhoneNumberTranslatorBuilder}. It decorates the SMS sender * with a {@link PhoneNumberTranslatorSender} * * @param builder * the builder to use to build the {@link PhoneNumberTranslator} * instead of using the default one * @return this instance for fluent use */ public SmsBuilder withSenderPhoneNumberTranslation(PhoneNumberTranslatorBuilder builder) { senderNumberTranslatorBuilder = builder; return this; } /** *

* Get the builder used for filling messages. *

* * Access this builder if you want to: *
    *
  • Enable/disable automatic filling of messages with values provided in * configuration
  • *
  • Enable/disable automatic filling of subject for messages based on * templates
  • *
  • Add your own message filler
  • *
* * @return the builder used for filling messages */ public MessageFillerBuilder getMessageFillerBuilder() { return messageFillerBuilder; } /** *

* Get the builder used transform the content of the message. It may be * useful to fine tune templating mechanism, resource inlining and messages * with with several contents. *

* * Access this builder if you want to: *
    *
  • Customize templating mechanism (see * {@link #getTemplateBuilder()})
  • *
  • Enable/disable support for messages with multiple contents
  • *
  • Enable/disable support for inlining of resources
  • *
  • Add your own content translator
  • *
* * @return the builder used to transform the content of the message */ public ContentTranslatorBuilder getContentTranslatorBuilder() { return contentTranslatorBuilder; } /** *

* Shortcut to directly access template builder for fine tuning templating * mechanism. *

* * Access this builder if you want to: *
    *
  • Customize how template resources are resolved
  • *
  • Register a custom lookup mapping resolver for template resources
  • *
  • Use your own template engine
  • *
  • Customize the template engine configuration
  • *
  • Set the parent path and extension for template resolution
  • *
  • Set the property key for parent path and extension resolution
  • *
* * @return the template builder */ public TemplateBuilder getTemplateBuilder() { return contentTranslatorBuilder.getTemplateBuilder(); } /** *

* Get the builder for transformation of recipient phone numbers. *

* * Access to this builder if you want to: *
    *
  • Enable/disable international format transformation
  • *
* * @return the builder for transformation of recipient phone numbers */ public PhoneNumberTranslatorBuilder getRecipientNumberTranslatorBuilder() { return recipientNumberTranslatorBuilder; } /** *

* Get the builder for transformation of sender phone numbers. *

* * Access to this builder if you want to: *
    *
  • Enable/disable alpha-numeric format transformation
  • *
  • Enable/disable short code format transformation
  • *
  • Enable/disable international format transformation
  • *
* * @return the builder for transformation of sender phone numbers */ public PhoneNumberTranslatorBuilder getSenderNumberTranslatorBuilder() { return senderNumberTranslatorBuilder; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy