
com.segment.analytics.messages.MessageBuilder Maven / Gradle / Ivy
package com.segment.analytics.messages;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
/**
* Fluent API to construct instances of a {@link Message}.
*
* Note: Although it is not enforced by the compiler, either the {@link Message#anonymousId} or
* {@link Message#userId} must be provided before calling {@link #build()}. Failure to do so will
* result in a {@link IllegalStateException} at runtime.
*/
public abstract class MessageBuilder {
private final Message.Type type;
private Map context;
private UUID anonymousId;
private String userId;
private Map integrationsBuilder;
private Date timestamp;
// Hidden from Public API.
MessageBuilder(Message.Type type) {
this.type = type;
// We would use Auto's Builders, but they don't provide a nice way of hiding internal details,
// like mapping Maps to ImmutableMaps
}
MessageBuilder(Message message) {
type = message.type();
context = message.context();
anonymousId = message.anonymousId();
userId = message.userId();
}
/** Returns {@code true} if the given string is null or empty. */
static boolean isNullOrEmpty(String string) {
return string == null || string.trim().length() == 0;
}
/**
* Set a map of information about the state of the device. You can add any custom data to the
* context dictionary that you'd like to have access to in the raw logs.
*
* Some keys in the context dictionary have semantic meaning and will be collected for you
* automatically, depending on the library you send data from. Some keys, such as location and
* speed need to be manually entered.
*
* @see Context
*/
public V context(Map context) {
if (context == null) {
throw new NullPointerException("Null context");
}
this.context = ImmutableMap.copyOf(context);
return self();
}
/**
* The Anonymous ID is a pseudo-unique substitute for a User ID, for cases when you don’t have an
* absolutely unique identifier.
*
* @see Identities
* @see Anonymous ID
*/
public V anonymousId(UUID anonymousId) {
if (anonymousId == null) {
throw new NullPointerException("Null anonymousId");
}
this.anonymousId = anonymousId;
return self();
}
/**
* The Anonymous ID is a pseudo-unique substitute for a User ID, for cases when you don’t have an
* absolutely unique identifier.
*
* @see Identities
* @see User ID
*/
public V userId(String userId) {
if (isNullOrEmpty(userId)) {
throw new IllegalArgumentException("userId cannot be null or empty.");
}
this.userId = userId;
return self();
}
/**
* Set whether this message is sent to the specified integration or not. 'All' is a special key
* that applies when no key for a specific integration is found.
*
* @see Integrations
*/
public V enableIntegration(String key, boolean enable) {
if (isNullOrEmpty(key)) {
throw new IllegalArgumentException("Key cannot be null or empty.");
}
if (integrationsBuilder == null) {
integrationsBuilder = new LinkedHashMap<>();
}
integrationsBuilder.put(key, enable);
return self();
}
/**
* Pass in some options that will only be used by the target integration. This will implicitly
* mark the integration as enabled.
*
* @see Integrations
*/
public V integrationOptions(String key, Map options) {
if (isNullOrEmpty(key)) {
throw new IllegalArgumentException("Key name cannot be null or empty.");
}
if (integrationsBuilder == null) {
integrationsBuilder = new LinkedHashMap<>();
}
integrationsBuilder.put(key, ImmutableMap.copyOf(options));
return self();
}
/**
* Set a timestamp for the event. By default, the current timestamp is used, but you may override
* it for historical import.
*
* @see Timestamp
*/
public V timestamp(Date timestamp) {
if (timestamp == null) {
throw new NullPointerException("Null timestamp");
}
this.timestamp = timestamp;
return self();
}
protected abstract T realBuild(Message.Type type, UUID messageId, Date timestamp,
Map context, UUID anonymousId, String userId, Map integrations);
abstract V self();
/**
* Create a {@link Message} instance.
*
* @throws IllegalStateException if both anonymousId and userId are not provided.
*/
public T build() {
if (anonymousId == null && userId == null) {
throw new IllegalStateException("Either anonymousId or userId must be provided.");
}
Map integrations = integrationsBuilder == null ? //
Collections.emptyMap() : ImmutableMap.copyOf(integrationsBuilder);
return realBuild(type, UUID.randomUUID(), timestamp == null ? new Date() : timestamp, context,
anonymousId, userId, integrations);
}
/** Returns the {@link Message.Type} of the message this builder is constructing. */
public Message.Type type() {
return type;
}
}