UsernamePasswordAuthenticatorBuilder.java

package fr.sii.ogham.email.builder.javamail;

import javax.mail.Authenticator;

import fr.sii.ogham.core.builder.Builder;
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.fluent.AbstractParent;
import fr.sii.ogham.email.sender.impl.javamail.UpdatableUsernamePasswordAuthenticator;
import fr.sii.ogham.email.sender.impl.javamail.UsernamePasswordAuthenticator;

/**
 * Configures authentication mechanism based on username/password.
 * 
 * <p>
 * You can define direct values for username and password:
 * 
 * <pre>
 * .username("foo")
 * .password("bar")
 * </pre>
 * 
 * Or you can specify one or several property keys:
 * 
 * <pre>
 * .username("${ogham.email.javamail.authenticator.username}")
 * .password("${ogham.email.javamail.authenticator.password}")
 * </pre>
 * 
 * The evaluation of the properties will be evaluated when {@link #build()} is
 * called (by default).
 * 
 * <p>
 * If {@link #updatable(Boolean)} is set to true, it means that properties are
 * not evaluated when calling {@link #build()}. Instead, the property keys are
 * kept for later evaluation. The evaluation will then be done each time an
 * authentication to the mail server is started.
 * </p>
 * 
 * @author Aurélien Baudet
 *
 */
public class UsernamePasswordAuthenticatorBuilder extends AbstractParent<JavaMailBuilder> implements Builder<Authenticator> {
	private final BuildContext buildContext;
	private final ConfigurationValueBuilderHelper<UsernamePasswordAuthenticatorBuilder, String> usernameValueBuilder;
	private final ConfigurationValueBuilderHelper<UsernamePasswordAuthenticatorBuilder, String> passwordValueBuilder;
	private final ConfigurationValueBuilderHelper<UsernamePasswordAuthenticatorBuilder, Boolean> updatableValueBuilder;

	/**
	 * Initializes the parent instance for fluent chaining (when method
	 * {@link #and()} is called).
	 * 
	 * @param parent
	 *            the parent builder
	 * @param buildContext
	 *            for registering instances and property evaluation
	 */
	public UsernamePasswordAuthenticatorBuilder(JavaMailBuilder parent, BuildContext buildContext) {
		super(parent);
		this.buildContext = buildContext;
		usernameValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
		passwordValueBuilder = buildContext.newConfigurationValueBuilder(this, String.class);
		updatableValueBuilder = buildContext.newConfigurationValueBuilder(this, Boolean.class);
	}

	/**
	 * Set the username to use for the authentication.
	 * 
	 * <p>
	 * The value set using this method takes precedence over any property and
	 * default value configured using {@link #username()}.
	 * 
	 * <pre>
	 * .username("my-username")
	 * .username()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue("default-username")
	 * </pre>
	 * 
	 * <pre>
	 * .username("my-username")
	 * .username()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue("default-username")
	 * </pre>
	 * 
	 * In both cases, {@code username("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 username
	 *            the username
	 * @return this instance for fluent chaining
	 */
	public UsernamePasswordAuthenticatorBuilder username(String username) {
		usernameValueBuilder.setValue(username);
		return this;
	}

	/**
	 * Set the username to use for the authentication.
	 * 
	 * <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>
	 * .username()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue("default-username")
	 * </pre>
	 * 
	 * <p>
	 * Non-null value set using {@link #username(String)} takes precedence over
	 * property values and default value.
	 * 
	 * <pre>
	 * .username("my-username")
	 * .username()
	 *   .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<UsernamePasswordAuthenticatorBuilder, String> username() {
		return usernameValueBuilder;
	}

	/**
	 * Set the password to use for the authentication.
	 * 
	 * <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 passowrd
	 * @return this instance for fluent chaining
	 */
	public UsernamePasswordAuthenticatorBuilder password(String password) {
		passwordValueBuilder.setValue(password);
		return this;
	}

	/**
	 * Set the password to use for the authentication.
	 * 
	 * <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<UsernamePasswordAuthenticatorBuilder, String> password() {
		return passwordValueBuilder;
	}

	/**
	 * If set to true, it means that properties are not evaluated when calling
	 * {@link #build()}. Instead, the property keys are kept for later
	 * evaluation. The evaluation will then be done each time an authentication
	 * to the mail server is started.
	 * 
	 * <p>
	 * The value set using this method takes precedence over any property and
	 * default value configured using {@link #updatable()}.
	 * 
	 * <pre>
	 * .updatable(true)
	 * .updatable()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * <pre>
	 * .updatable(true)
	 * .updatable()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * In both cases, {@code updatable(true)} 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 updatable
	 *            true to evaluate expression when connecting to server
	 * @return this instance for fluent chaining
	 */
	public UsernamePasswordAuthenticatorBuilder updatable(Boolean updatable) {
		updatableValueBuilder.setValue(updatable);
		return this;
	}

	/**
	 * If set to true, it means that properties are not evaluated when calling
	 * {@link #build()}. Instead, the property keys are kept for later
	 * evaluation. The evaluation will then be done each time an authentication
	 * to the mail server is started.
	 * 
	 * <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>
	 * .updatable()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * <p>
	 * Non-null value set using {@link #updatable(Boolean)} takes precedence
	 * over property values and default value.
	 * 
	 * <pre>
	 * .updatable(true)
	 * .updatable()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * The value {@code true} 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<UsernamePasswordAuthenticatorBuilder, Boolean> updatable() {
		return updatableValueBuilder;
	}

	@Override
	public Authenticator build() {
		boolean isUpdatable = updatableValueBuilder.getValue(false);
		if (isUpdatable) {
			if (usernameValueBuilder.hasValueOrProperties() && passwordValueBuilder.hasValueOrProperties()) {
				return buildContext.register(new UpdatableUsernamePasswordAuthenticator(usernameValueBuilder, passwordValueBuilder));
			}
			return null;
		}
		String u = usernameValueBuilder.getValue();
		String p = passwordValueBuilder.getValue();
		if (u != null && p != null) {
			return buildContext.register(new UsernamePasswordAuthenticator(u, p));
		}
		return null;
	}
}