OvhSmsBuilder.java
package fr.sii.ogham.sms.builder.ovh;
import java.net.MalformedURLException;
import java.net.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.sii.ogham.core.builder.Builder;
import fr.sii.ogham.core.builder.MessagingBuilder;
import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilder;
import fr.sii.ogham.core.builder.configuration.ConfigurationValueBuilderHelper;
import fr.sii.ogham.core.builder.configurer.Configurer;
import fr.sii.ogham.core.builder.context.BuildContext;
import fr.sii.ogham.core.builder.context.DefaultBuildContext;
import fr.sii.ogham.core.fluent.AbstractParent;
import fr.sii.ogham.sms.builder.SmsBuilder;
import fr.sii.ogham.sms.message.Sms;
import fr.sii.ogham.sms.sender.impl.OvhSmsSender;
import fr.sii.ogham.sms.sender.impl.ovh.DefaultSmsCodingDetector;
import fr.sii.ogham.sms.sender.impl.ovh.OvhAuthParams;
import fr.sii.ogham.sms.sender.impl.ovh.OvhOptions;
import fr.sii.ogham.sms.sender.impl.ovh.SmsCoding;
/**
* Configures how to send {@link Sms} using OVH HTTP API.
*
* <p>
* To send {@link Sms} using OVH, you need to register this builder into a
* {@link MessagingBuilder} like this:
*
* <pre>
* <code>
* MessagingBuilder msgBuilder = ...
* msgBuilder.sms()
* .sender(OvhSmsBuilder.class) // registers the builder and accesses to that builder for configuring it
* </code>
* </pre>
*
* Once the builder is registered, sending sms through OVH requires URL,
* account, login and password values. You can define it using:
*
* <pre>
* <code>
* msgBuilder.email()
* .sender(OvhSmsBuilder.class) // registers the builder and accesses to that builder for configuring it
* .url("https://www.ovh.com/cgi-bin/sms/http2sms.cgi")
* </code>
* </pre>
*
* Or you can also use property keys (using interpolation):
*
* <pre>
* <code>
* msgBuilder
* .environment()
* .properties()
* .set("custom.property.for.url", "https://www.ovh.com/cgi-bin/sms/http2sms.cgi")
* .and()
* .and()
* .email()
* .sender(OvhSmsBuilder.class) // registers the builder and accesses to that builder for configuring it
* .url()
* .properties("${custom.property.for.url}")
* </code>
* </pre>
*
*
* @author Aurélien Baudet
*
*/
public class OvhSmsBuilder extends AbstractParent<SmsBuilder> implements Builder<OvhSmsSender> {
private static final Logger LOG = LoggerFactory.getLogger(OvhSmsBuilder.class);
private final BuildContext buildContext;
private final ConfigurationValueBuilderHelper<OvhSmsBuilder, URL> urlValueBuilder;
private final ConfigurationValueBuilderHelper<OvhSmsBuilder, String> accountValueBuilder;
private final ConfigurationValueBuilderHelper<OvhSmsBuilder, String> loginValueBuilder;
private final ConfigurationValueBuilderHelper<OvhSmsBuilder, String> passwordValueBuilder;
private OvhOptionsBuilder ovhOptionsBuilder;
/**
* Default constructor when using OVH SMS sender without all Ogham work.
*
* <strong>WARNING: use is only if you know what you are doing !</strong>
*/
public OvhSmsBuilder() {
this(null, new DefaultBuildContext());
}
/**
* Constructor that is called when using Ogham builder:
*
* <pre>
* MessagingBuilder msgBuilder = ...
* msgBuilder
* .email()
* .sender(OvhSmsBuilder.class)
* </pre>
*
* @param parent
* the parent builder instance for fluent chaining
* @param buildContext
* for registering instances and property evaluation
*/
public OvhSmsBuilder(SmsBuilder parent, BuildContext buildContext) {
super(parent);
this.buildContext = buildContext;
urlValueBuilder = buildContext.newConfigurationValueBuilder(this, URL.class);
accountValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
loginValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
passwordValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
}
/**
* Set the URL of the OVH SMS HTTP API.
*
* <p>
* The value set using this method takes precedence over any property and
* default value configured using {@link #url()}.
*
* <pre>
* .url(new URL("http://localhost"))
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue(new URL("https://www.ovh.com/cgi-bin/sms/http2sms.cgi"))
* </pre>
*
* <pre>
* .url(new URL("http://localhost"))
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue(new URL("https://www.ovh.com/cgi-bin/sms/http2sms.cgi"))
* </pre>
*
* In both cases, {@code url(new URL("http://localhost"))} is used.
*
* <p>
* If this method is called several times, only the last value is used.
*
* <p>
* If {@code null} value is set, it is like not setting a value at all. The
* property/default value configuration is applied.
*
* @param url
* the url for Ovh HTTP API
* @return this instance for fluent chaining
*/
public OvhSmsBuilder url(URL url) {
urlValueBuilder.setValue(url);
return this;
}
/**
* Set the URL of the OVH SMS HTTP API.
*
* <p>
* The value set using this method takes precedence over any property and
* default value configured using {@link #url()}.
*
* <pre>
* .url("http://localhost")
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("https://www.ovh.com/cgi-bin/sms/http2sms.cgi")
* </pre>
*
* <pre>
* .url("http://localhost")
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("https://www.ovh.com/cgi-bin/sms/http2sms.cgi")
* </pre>
*
* In both cases, {@code url("http://localhost")} is used.
*
* <p>
* If this method is called several times, only the last value is used.
*
* <p>
* If {@code null} value is set, it is like not setting a value at all. The
* property/default value configuration is applied.
*
* @param url
* the url for Ovh HTTP API
* @return this instance for fluent chaining
* @throws IllegalArgumentException
* when URL is not valid
*/
public OvhSmsBuilder url(String url) {
try {
return url(new URL(url));
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid URL " + url, e);
}
}
/**
* Set the URL of the OVH SMS HTTP API.
*
* <p>
* This method is mainly used by {@link Configurer}s to register some
* property keys and/or a default value. The aim is to let developer be able
* to externalize its configuration (using system properties, configuration
* file or anything else). If the developer doesn't configure any value for
* the registered properties, the default value is used (if set).
*
* <pre>
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue(new URL("https://www.ovh.com/cgi-bin/sms/http2sms.cgi"))
* </pre>
*
* <p>
* Non-null value set using {@link #url(URL)} takes precedence over property
* values and default value.
*
* <pre>
* .url(new URL("http://localhost"))
* .url()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue(new URL("https://www.ovh.com/cgi-bin/sms/http2sms.cgi"))
* </pre>
*
* The value {@code new URL("http://localhost")} is used regardless of the
* value of the properties and default value.
*
* <p>
* See {@link ConfigurationValueBuilder} for more information.
*
*
* @return the builder to configure property keys/default value
*/
public ConfigurationValueBuilder<OvhSmsBuilder, URL> url() {
return urlValueBuilder;
}
/**
* Set the OVH account identifier.
*
* <p>
* The value set using this method takes precedence over any property and
* default value configured using {@link #account()}.
*
* <pre>
* .account("my-account")
* .account()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-account")
* </pre>
*
* <pre>
* .account("my-account")
* .account()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-account")
* </pre>
*
* In both cases, {@code account("my-account")} is used.
*
* <p>
* If this method is called several times, only the last value is used.
*
* <p>
* If {@code null} value is set, it is like not setting a value at all. The
* property/default value configuration is applied.
*
* @param account
* the account identifier
* @return this instance for fluent chaining
*/
public OvhSmsBuilder account(String account) {
accountValueBuilder.setValue(account);
return this;
}
/**
* Set the OVH account identifier.
*
* <p>
* This method is mainly used by {@link Configurer}s to register some
* property keys and/or a default value. The aim is to let developer be able
* to externalize its configuration (using system properties, configuration
* file or anything else). If the developer doesn't configure any value for
* the registered properties, the default value is used (if set).
*
* <pre>
* .account()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-account")
* </pre>
*
* <p>
* Non-null value set using {@link #account(String)} takes precedence over
* property values and default value.
*
* <pre>
* .account("my-account")
* .account()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-account")
* </pre>
*
* The value {@code "my-account"} is used regardless of the value of the
* properties and default value.
*
* <p>
* See {@link ConfigurationValueBuilder} for more information.
*
*
* @return the builder to configure property keys/default value
*/
public ConfigurationValueBuilder<OvhSmsBuilder, String> account() {
return accountValueBuilder;
}
/**
* Set the OVH username.
*
* <p>
* The value set using this method takes precedence over any property and
* default value configured using {@link #login()}.
*
* <pre>
* .login("my-username")
* .login()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-username")
* </pre>
*
* <pre>
* .login("my-username")
* .login()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-username")
* </pre>
*
* In both cases, {@code login("my-username")} is used.
*
* <p>
* If this method is called several times, only the last value is used.
*
* <p>
* If {@code null} value is set, it is like not setting a value at all. The
* property/default value configuration is applied.
*
* @param login
* the OVH username
* @return this instance for fluent chaining
*/
public OvhSmsBuilder login(String login) {
loginValueBuilder.setValue(login);
return this;
}
/**
* Set the OVH username.
*
* <p>
* This method is mainly used by {@link Configurer}s to register some
* property keys and/or a default value. The aim is to let developer be able
* to externalize its configuration (using system properties, configuration
* file or anything else). If the developer doesn't configure any value for
* the registered properties, the default value is used (if set).
*
* <pre>
* .login()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-username")
* </pre>
*
* <p>
* Non-null value set using {@link #login(String)} takes precedence over
* property values and default value.
*
* <pre>
* .login("my-username")
* .login()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-username")
* </pre>
*
* The value {@code "my-username"} is used regardless of the value of the
* properties and default value.
*
* <p>
* See {@link ConfigurationValueBuilder} for more information.
*
*
* @return the builder to configure property keys/default value
*/
public ConfigurationValueBuilder<OvhSmsBuilder, String> login() {
return loginValueBuilder;
}
/**
* Set the OVH password.
*
* <p>
* The value set using this method takes precedence over any property and
* default value configured using {@link #password()}.
*
* <pre>
* .password("my-password")
* .password()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-password")
* </pre>
*
* <pre>
* .password("my-password")
* .password()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-password")
* </pre>
*
* In both cases, {@code password("my-password")} is used.
*
* <p>
* If this method is called several times, only the last value is used.
*
* <p>
* If {@code null} value is set, it is like not setting a value at all. The
* property/default value configuration is applied.
*
* @param password
* the OVH password
* @return this instance for fluent chaining
*/
public OvhSmsBuilder password(String password) {
passwordValueBuilder.setValue(password);
return this;
}
/**
* Set the OVH password.
*
* <p>
* This method is mainly used by {@link Configurer}s to register some
* property keys and/or a default value. The aim is to let developer be able
* to externalize its configuration (using system properties, configuration
* file or anything else). If the developer doesn't configure any value for
* the registered properties, the default value is used (if set).
*
* <pre>
* .password()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-password")
* </pre>
*
* <p>
* Non-null value set using {@link #password(String)} takes precedence over
* property values and default value.
*
* <pre>
* .password("my-password")
* .password()
* .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
* .defaultValue("default-password")
* </pre>
*
* The value {@code "my-password"} is used regardless of the value of the
* properties and default value.
*
* <p>
* See {@link ConfigurationValueBuilder} for more information.
*
*
* @return the builder to configure property keys/default value
*/
public ConfigurationValueBuilder<OvhSmsBuilder, String> password() {
return passwordValueBuilder;
}
/**
* Configures OVH SMS options:
* <ul>
* <li>Enable/disable the "STOP" indication at the end of the message
* (useful to disable for non-commercial SMS)</li>
* <li>Define the SMS encoding (see {@link SmsCoding}): 1 for 7bit encoding,
* 2 for 8bit encoding (UTF-8). If you use UTF-8, your SMS will have a
* maximum size of 70 characters instead of 160</li>
* <li>Define a tag to mark sent messages (a 20 maximum character
* string)</li>
* </ul>
*
* @return the builder to configure OVH SMS options
*/
public OvhOptionsBuilder options() {
if (ovhOptionsBuilder == null) {
ovhOptionsBuilder = new OvhOptionsBuilder(this, buildContext);
}
return ovhOptionsBuilder;
}
@Override
public OvhSmsSender build() {
URL url = buildUrl();
OvhAuthParams authParams = buildAuth();
if (url == null || authParams.getAccount() == null || authParams.getLogin() == null || authParams.getPassword() == null) {
return null;
}
LOG.info("Sending SMS using OVH API is registered");
LOG.debug("OVH account: account={}, login={}", authParams.getAccount(), authParams.getLogin());
return buildContext.register(new OvhSmsSender(url, authParams, buildOptions(), buildContext.register(new DefaultSmsCodingDetector())));
}
private URL buildUrl() {
return urlValueBuilder.getValue();
}
private OvhAuthParams buildAuth() {
String accountValue = accountValueBuilder.getValue();
String loginValue = loginValueBuilder.getValue();
String passwordValue = passwordValueBuilder.getValue();
return buildContext.register(new OvhAuthParams(accountValue, loginValue, passwordValue));
}
private OvhOptions buildOptions() {
return ovhOptionsBuilder.build();
}
}