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

com.amazonaws.mobileconnectors.pinpoint.targeting.endpointProfile.EndpointProfile Maven / Gradle / Ivy

Go to download

The AWS Android SDK for Amazon Pinpoint module holds the client classes that are used for communicating with Amazon Pinpoint Service

There is a newer version: 2.77.0
Show newest version
/**
 * Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.amazonaws.mobileconnectors.pinpoint.targeting.endpointProfile;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.PinpointContext;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.util.DateUtil;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.util.JSONBuilder;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.util.JSONSerializable;
import com.amazonaws.mobileconnectors.pinpoint.internal.core.util.StringUtil;

import static com.amazonaws.mobileconnectors.pinpoint.internal.core.util.Preconditions.checkNotNull;

/**
 * Represents the device endpoint for which your application may add information to
 *
 * The example below demonstrates how to add custom attributes
 */
public class EndpointProfile implements JSONSerializable {

    static final int MAX_NUM_OF_METRICS_AND_ATTRIBUTES = 20;
    static final int MAX_ENDPOINT_ATTRIBUTE_METRIC_KEY_LENGTH = 50;
    static final int MAX_ENDPOINT_ATTRIBUTE_VALUE_LENGTH = 100;
    static final int MAX_ENDPOINT_ATTRIBUTE_VALUES = 50;
    private static final Log log =
        LogFactory.getLog(EndpointProfile.class);
    private static final int JSON_INDENTATION = 4;
    private final PinpointContext pinpointContext;
    private final Map> attributes = new ConcurrentHashMap>();
    private final Map metrics = new ConcurrentHashMap();
    private final AtomicInteger currentNumOfAttributesAndMetrics = new AtomicInteger(0);
    private String optOut;
    private EndpointProfileLocation location;
    private EndpointProfileDemographic demographic;
    private Long effectiveDate;
    private EndpointProfileUser user;

    /**
     * Constructor.
     *
     * @param pinpointContext the pinpoint context.
     */
    public EndpointProfile(final PinpointContext pinpointContext) {
        checkNotNull(pinpointContext,
                     "A valid pinpointContext must be provided.");

        this.pinpointContext = pinpointContext;
        this.effectiveDate = DateUtil.getCorrectedDate().getTime();
        this.demographic = new EndpointProfileDemographic(this.pinpointContext);
        this.location = new EndpointProfileLocation(this.pinpointContext);
        this.user = new EndpointProfileUser();
    }

    private static String processAttributeMetricKey(final String key) {

        final String trimmedKey = StringUtil.clipString(key, MAX_ENDPOINT_ATTRIBUTE_METRIC_KEY_LENGTH, false);
        if (trimmedKey.length() < key.length()) {
            log.warn("The attribute key has been trimmed to a length of " + MAX_ENDPOINT_ATTRIBUTE_METRIC_KEY_LENGTH + " characters.");
        }

        return trimmedKey;
    }

    private static java.util.List processAttributeValues(final List values) {

        final List trimmedValues = new ArrayList();
        int valuesCount = 0;
        for (final String value : values) {
            final String trimmedValue = StringUtil.clipString(value, MAX_ENDPOINT_ATTRIBUTE_VALUE_LENGTH, false);
            if (trimmedValue.length() < value.length()) {
                log.warn("The attribute value has been trimmed to a length of " + MAX_ENDPOINT_ATTRIBUTE_VALUE_LENGTH + " characters.");
            }
            trimmedValues.add(trimmedValue);
            if (++valuesCount >= MAX_ENDPOINT_ATTRIBUTE_VALUES) {
                log.warn("The attribute values has been reduced to" + MAX_ENDPOINT_ATTRIBUTE_VALUES + " values.");
                break;
            }
        }

        return trimmedValues;
    }

    /**
     * Returns the Mobile Analytics application Id
     *
     * @return the application id
     */
    public String getApplicationId() {
        return this.pinpointContext.getSystem().getAppDetails().getAppId();
    }

    /**
     * Returns the EndpointProfile Identifier of the device
     *
     * @return the endpoint id
     */
    public String getEndpointId() {
        return this.pinpointContext.getUniqueId();
    }

    /**
     * Returns the Channel Type of this endpoint, currently defaults to GCM
     *
     * @return the channel type
     */
    public String getChannelType() {
        return this.pinpointContext.getNotificationClient().getChannelType();
    }

    /**
     * Returns the Address of the endpoint. The token that is returned by the channel selected.
     *
     * @return the address
     */
    public String getAddress() {
        return this.pinpointContext.getNotificationClient().getDeviceToken();
    }

    /**
     * Returns the Demographic facet of the endpoint.
     *
     * @return EndpointProfileDemographic
     */
    public EndpointProfileDemographic getDemographic() {
        return this.demographic;
    }

    /**
     * Sets the Demographic facet of the endpoint.
     *
     * @param demographic The demographic facet.
     */
    public void setDemographic(EndpointProfileDemographic demographic) {
        this.demographic = demographic;
    }

    /**
     * Returns the Location facet of the endpoint.
     *
     * @return EndpointProfileLocation
     */
    public EndpointProfileLocation getLocation() {
        return this.location;
    }

    /**
     * Sets the Location facet of the endpoint.
     *
     * @param location The location facet.
     */
    public void setLocation(EndpointProfileLocation location) {
        this.location = location;
    }

    /**
     * Returns the effective date of the endpoint.
     *
     * @return long
     */
    public long getEffectiveDate() {
        return this.effectiveDate;
    }

    /**
     * Sets the effectiveDate of the endpoint.
     *
     * @param effectiveDate The demographic facet.
     */
    public void setEffectiveDate(long effectiveDate) {
        this.effectiveDate = effectiveDate;
    }

    /**
     * Returns weather the endpoint is opted out of notification.
     *
     * @return String (ALL | NONE)
     */
    public String getOptOut() {
        return (this.pinpointContext.getNotificationClient().areAppNotificationsEnabled() && !StringUtil.isBlank(
            this.pinpointContext.getNotificationClient().getDeviceToken())) ? "NONE" : "ALL";
    }

    /**
     * Adds a custom attribute to this {@link EndpointProfile} with the specified key.
     * Only 20 custom attributes/metrics are allowed to be added to a EndpointProfile. If 20
     * attributes already exist on this EndpointProfile, the call may be ignored.
     *
     * @param name   The name of the custom attribute. The name will be truncated if it
     *               exceeds 50 characters.
     * @param values An array of values of the custom attribute. The values will be truncated if
     *               it exceeds 100 characters.
     */
    public void addAttribute(final String name, final List values) {
        if (null == name) {
            return;
        }

        if (null != values) {
            if (currentNumOfAttributesAndMetrics.get() < MAX_NUM_OF_METRICS_AND_ATTRIBUTES) {
                final String key = processAttributeMetricKey(name);
                if (!attributes.containsKey(key)) {
                    currentNumOfAttributesAndMetrics.incrementAndGet();
                }
                attributes.put(key, processAttributeValues(values));
            } else {
                log.warn("Max number of attributes/metrics reached(" + MAX_NUM_OF_METRICS_AND_ATTRIBUTES + ").");
            }
        } else {
            if (attributes.remove(name) != null) {
                currentNumOfAttributesAndMetrics.decrementAndGet();
            }
        }
    }

    /**
     * Determines if this {@link EndpointProfile} contains a specific custom attribute
     *
     * @param attributeName The name of the custom attribute
     * @return true if this {@link EndpointProfile} has a custom attribute with the
     * specified name, false otherwise
     */
    public boolean hasAttribute(final String attributeName) {
        if (attributeName == null) {
            return false;
        }
        return attributes.containsKey(attributeName);
    }

    /**
     * Returns the array of values of the custom attribute with the specified name.
     *
     * @param name The name of the custom attribute to return
     * @return The array of custom attributes with the specified name, or null if attribute does
     * not exist
     */
    public List getAttribute(final String name) {
        if (name == null) {
            return null;
        }
        return attributes.get(name);
    }

    /**
     * Adds a custom attribute to this {@link EndpointProfile} with the specified key.
     * Only 20 custom attributes are allowed to be added to an
     * {@link EndpointProfile}. If 20 custom attributes/metrics already exist on this
     * {@link EndpointProfile}, the call may be ignored.
     *
     * @param name   The name of the custom attribute. The name will be truncated if it
     *               exceeds 50 characters.
     * @param values An array of values of the custom attribute. The values will be truncated if
     *               it exceeds 100 characters.
     * @return The same {@link EndpointProfile} instance is returned to allow for
     * method chaining.
     */
    public EndpointProfile withAttribute(final String name, final List values) {
        addAttribute(name, values);
        return this;
    }

    /**
     * Returns a map of all custom attributes contained within this
     * {@link EndpointProfile}
     *
     * @return a map of all custom attributes, where the attribute names are the keys
     * and the attribute values are the values
     */
    public Map> getAllAttributes() {
        return Collections.unmodifiableMap(attributes);
    }

    /**
     * Adds a metric to this {@link EndpointProfile} with the specified key. Only
     * 20 attributes/metrics are allowed to be added to an Event. If 20
     * attribute/metrics already exist on this Event, the call may be ignored.
     *
     * @param name  The name of the metric. The name will be truncated if it
     *              exceeds 50 characters.
     * @param value The value of the metric.
     */
    public void addMetric(final String name, final Double value) {
        if (null == name) {
            return;
        }

        if (null != value) {
            if (currentNumOfAttributesAndMetrics.get() <
                MAX_NUM_OF_METRICS_AND_ATTRIBUTES) {
                final String key = processAttributeMetricKey(name);
                if (!metrics.containsKey(key)) {
                    currentNumOfAttributesAndMetrics.incrementAndGet();
                }
                metrics.put(key, value);
            } else {
                log.warn("Max number of attributes/metrics reached(" +
                         MAX_NUM_OF_METRICS_AND_ATTRIBUTES +
                         ").");
            }
        } else {
            if (metrics.remove(name) != null) {
                currentNumOfAttributesAndMetrics.decrementAndGet();
            }
        }
    }

    /**
     * Determines if this {@link EndpointProfile} contains a specific metric.
     *
     * @param metricName The name of the metric
     * @return true if this {@link EndpointProfile} has a metric with the
     * specified name, false otherwise
     */
    public boolean hasMetric(final String metricName) {
        if (metricName == null) {
            return false;
        }
        return metrics.containsKey(metricName);
    }

    /**
     * Returns the value of the metric with the specified name.
     *
     * @param name The name of the metric to return
     * @return The metric with the specified name, or null if metric does not
     * exist
     */
    public Double getMetric(final String name) {
        if (name == null) {
            return null;
        }
        return metrics.get(name);
    }

    /**
     * Adds a metric to this {@link EndpointProfile} with the specified key. Only
     * 20 attributes/metrics are allowed to be added to an
     * {@link EndpointProfile}. If 20 attribute/metrics already exist on this
     * {@link EndpointProfile}, the call may be ignored.
     *
     * @param name  The name of the metric. The name will be truncated if it
     *              exceeds 50 characters.
     * @param value The value of the metric.
     * @return The same {@link EndpointProfile} instance is returned to allow for
     * method chaining.
     */
    public EndpointProfile withMetric(final String name, final Double value) {
        addMetric(name, value);
        return this;
    }

    /**
     * Returns a map of all metrics contained within this {@link EndpointProfile}
     *
     * @return a map of all metrics, where the metric names are the keys and the
     * metric values are the values
     */
    public Map getAllMetrics() {
        return Collections.unmodifiableMap(metrics);
    }

    /**
     * Returns the User facet of the endpoint.
     *
     * @return EndpointProfileUser
     */
    public EndpointProfileUser getUser() {
        return this.user;
    }

    /**
     * Sets the User facet of the endpoint.
     *
     * @param user The user facet
     */
    public void setUser(final EndpointProfileUser user) {
        this.user = user;
    }

    @Override
    public String toString() {
        final JSONObject json = toJSONObject();
        try {
            return json.toString(JSON_INDENTATION);
        } catch (final JSONException e) {
            return json.toString();
        }
    }

    @Override
    public JSONObject toJSONObject() {
        final JSONBuilder builder = new JSONBuilder(null);
        builder.withAttribute("ApplicationId", getApplicationId());
        builder.withAttribute("EndpointId", getEndpointId());
        builder.withAttribute("ChannelType", getChannelType());
        builder.withAttribute("Address", getAddress());
        builder.withAttribute("Location", getLocation().toJSONObject());
        builder.withAttribute("Demographic", getDemographic().toJSONObject());
        builder.withAttribute("EffectiveDate", DateUtil.isoDateFromMillis(getEffectiveDate()));
        builder.withAttribute("OptOut", getOptOut());

        final JSONObject attributesJson = new JSONObject();
        for (final Map.Entry> entry : getAllAttributes().entrySet()) {
            try {
                final JSONArray array = new JSONArray(entry.getValue());
                attributesJson.put(entry.getKey(), array);
            } catch (final JSONException e) {
                // Do not log e due to potentially sensitive information
                log.warn("Error serializing attributes.");
            }
        }

        // If there are any attributes put then add the attributes to the structure
        if (attributesJson.length() > 0) {
            builder.withAttribute("Attributes", attributesJson);
        }

        final JSONObject metricsJson = new JSONObject();
        for (final Map.Entry entry : getAllMetrics().entrySet()) {
            try {
                metricsJson.put(entry.getKey(), entry.getValue());
            } catch (final JSONException e) {
                // Do not log e due to potentially sensitive information
                log.error("Error serializing metric.");
            }
        }

        // If there are any metrics put then add the attributes to the structure
        if (metricsJson.length() > 0) {
            builder.withAttribute("Metrics", metricsJson);
        }

        builder.withAttribute("User", getUser().toJSONObject());
        return builder.toJSONObject();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy