UserDataBuilder.java

package fr.sii.ogham.sms.builder.cloudhopper;

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.builder.env.EnvironmentBuilder;
import fr.sii.ogham.core.fluent.AbstractParent;
import fr.sii.ogham.sms.builder.cloudhopper.UserDataBuilder.UserDataPropValues;
import fr.sii.ogham.sms.sender.impl.cloudhopper.preparator.MessagePreparator;

/**
 * "User Data" represents the text message or data to be transmitted the
 * end-user.
 * 
 * <p>
 * The length of the short message text (or user data) is defined in the
 * {@code sm_length} field of the {@code submit_sm}, {@code submit_multi},
 * {@code deliver_sm} and {@code replace_sm} SMPP PDUs. The maximum message
 * length which can be specified in {@code sm_length} field is 254 octets. If an
 * ESME wishes to submit a message of length greater than 254 octets, the
 * {@code sm_length} field must be set to {@code NULL} and the
 * {@code message_payload} optional parameter must be populated with the message
 * length value and user data. SMPP supports extended message lengths in the
 * {@code submit_sm}, {@code submit_multi}, {@code data_sm} and
 * {@code deliver_sm} PDUs. Note: The actual short message length which can be
 * transmitted to a MS may vary according to the underlying network.
 * 
 * <p>
 * This builder allows to select which field to use:
 * <ul>
 * <li>either {@code short_message} fields</li>
 * <li>or {@code message_payload} optional TLV (Tag-Length-Value) parameter</li>
 * </ul>
 * 
 * @author Aurélien Baudet
 *
 */
public class UserDataBuilder extends AbstractParent<CloudhopperBuilder> implements Builder<UserDataPropValues> {
	private final ConfigurationValueBuilderHelper<UserDataBuilder, Boolean> useShortMessageValueBuilder;
	private final ConfigurationValueBuilderHelper<UserDataBuilder, Boolean> useTlvMessagePayloadValueBuilder;

	/**
	 * Initializes the builder with a parent builder. The parent builder is used
	 * when calling {@link #and()} method. The {@link EnvironmentBuilder} is
	 * used to evaluate properties when {@link #build()} method is called.
	 * 
	 * @param parent
	 *            the parent builder
	 * @param buildContext
	 *            for registering instances and property evaluation
	 */
	public UserDataBuilder(CloudhopperBuilder parent, BuildContext buildContext) {
		super(parent);
		useShortMessageValueBuilder = buildContext.newConfigurationValueBuilder(this, Boolean.class);
		useTlvMessagePayloadValueBuilder = buildContext.newConfigurationValueBuilder(this, Boolean.class);
	}

	/**
	 * Enable/disable use of {@code short_message} field.
	 * 
	 * <p>
	 * The value set using this method takes precedence over any property and
	 * default value configured using {@link #useShortMessage()}.
	 * 
	 * <pre>
	 * .useShortMessage(true)
	 * .useShortMessage()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * <pre>
	 * .useShortMessage(true)
	 * .useShortMessage()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(false)
	 * </pre>
	 * 
	 * In both cases, {@code useShortMessage(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 useShortMessage
	 *            enable (true) or disable (false) use of {@code short_message}
	 *            field
	 * @return this instance for fluent chaining
	 */
	public UserDataBuilder useShortMessage(Boolean useShortMessage) {
		useShortMessageValueBuilder.setValue(useShortMessage);
		return this;
	}

	/**
	 * Enable/disable use of {@code short_message} field to carry text message
	 * (named User Data).
	 * 
	 * <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>
	 * .useShortMessage()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * <p>
	 * Non-null value set using {@link #useShortMessage(Boolean)} takes
	 * precedence over property values and default value:
	 * 
	 * <pre>
	 * .useShortMessage(false)
	 * .useShortMessage()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * The value {@code false} 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<UserDataBuilder, Boolean> useShortMessage() {
		return useShortMessageValueBuilder;
	}

	/**
	 * Enable/disable use of {@code message_payload} optional TLV
	 * (Tag-Value-Length) parameter to carry text message (named User Data).
	 * 
	 * <strong>NOTE:</strong> The TLV optional parameters are available since
	 * SMPP version 3.4.
	 * 
	 * <p>
	 * The value set using this method takes precedence over any property and
	 * default value configured using {@link #useTlvMessagePayload()}.
	 * 
	 * <pre>
	 * .useTlvMessagePayload(false)
	 * .useTlvMessagePayload()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * <pre>
	 * .useTlvMessagePayload(false)
	 * .useTlvMessagePayload()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * In both cases, {@code useTlvMessagePayload(false)} 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 useTlvMessagePayload
	 *            enable (true) or disable (false) use of
	 *            {@code message_payload} optional parameter to carry text
	 *            message
	 * @return this instance for fluent chaining
	 */
	public UserDataBuilder useTlvMessagePayload(Boolean useTlvMessagePayload) {
		useTlvMessagePayloadValueBuilder.setValue(useTlvMessagePayload);
		return this;
	}

	/**
	 * Enable/disable use of {@code message_payload} optional TLV
	 * (Tag-Value-Length) parameter to carry text message (named User Data).
	 * 
	 * <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>
	 * .useTlvMessagePayload()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * <p>
	 * Non-null value set using {@link #useTlvMessagePayload(Boolean)} takes
	 * precedence over property values and default value.
	 * 
	 * <pre>
	 * .useTlvMessagePayload(false)
	 * .useTlvMessagePayload()
	 *   .properties("${custom.property.high-priority}", "${custom.property.low-priority}")
	 *   .defaultValue(true)
	 * </pre>
	 * 
	 * The value {@code false} 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<UserDataBuilder, Boolean> useTlvMessagePayload() {
		return useTlvMessagePayloadValueBuilder;
	}

	@Override
	public UserDataPropValues build() {
		boolean useShort = useShortMessageValueBuilder.getValue(false);
		boolean useTlv = useTlvMessagePayloadValueBuilder.getValue(false);
		return new UserDataPropValues(useShort, useTlv);
	}

	/**
	 * Simple data class to provide configured values. This is used by parent
	 * builder to affect {@link MessagePreparator} strategy.
	 * 
	 * @author Aurélien Baudet
	 */
	public static class UserDataPropValues {
		private final boolean useShortMessage;
		private final boolean useTlvMessagePayload;

		/**
		 * Initializes with configured values.
		 * 
		 * @param useShortMessage
		 *            true if {@code short_message} field should be used
		 * @param useTlvMessagePayload
		 *            true {@code message_payload} optional parameter should be
		 *            used
		 */
		public UserDataPropValues(boolean useShortMessage, boolean useTlvMessagePayload) {
			super();
			this.useShortMessage = useShortMessage;
			this.useTlvMessagePayload = useTlvMessagePayload;
		}

		/**
		 * @return is the {@code short_message} field should be used
		 */
		public boolean isUseShortMessage() {
			return useShortMessage;
		}

		/**
		 * @return is the {@code message_payload} optional parameter should be
		 *         used
		 */
		public boolean isUseTlvMessagePayload() {
			return useTlvMessagePayload;
		}

	}
}