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

com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.event.DefaultEventClient Maven / Gradle / Ivy

There is a newer version: 2.20.1
Show newest version
/*
 * Copyright 2010-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.amazonmobileanalytics.internal.event;

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

import android.util.Log;

import com.amazonaws.mobileconnectors.amazonmobileanalytics.AnalyticsEvent;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.AnalyticsContext;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.util.JSONBuilder;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.util.JSONSerializable;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.util.StringUtil;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.delivery.DeliveryClient;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class DefaultEventClient implements InternalEventClient, JSONSerializable {
    private static String TAG = "DefaultEventClient";
    private static final String ANALYTICS_ENABLED = "isAnalyticsEnabled";
    private static final int MAX_EVENT_TYPE_LENGTH = 50;

    private final DeliveryClient deliveryClient;
    private final AnalyticsContext context;
    private final Map globalAttributes = new ConcurrentHashMap();
    private final Map globalMetrics = new ConcurrentHashMap();
    private final Map> eventTypeAttributes = new ConcurrentHashMap>();
    private final Map> eventTypeMetrics = new ConcurrentHashMap>();
    private List observers = new CopyOnWriteArrayList();
    private boolean allowEventCollection = true;
    private String sessionId;
    private long sessionStartTime;

    public DefaultEventClient(final AnalyticsContext context, final boolean allowEventCollection) {
        checkNotNull(context, "A valid context must be provided");
        checkNotNull(context.getDeliveryClient(), "A valid DeliveryClient must be provided");

        this.allowEventCollection = allowEventCollection;

        this.context = context;

        // add the delivery client as an observer of our events, and hold onto
        // the ref
        // so that we can force a submission of events
        this.deliveryClient = context.getDeliveryClient();
        addEventObserver(deliveryClient);
    }

    @Override
    public void recordEvent(AnalyticsEvent event) {
        if (event == null) {
            Log.i(TAG, "The provided event was null");
            return;
        }

        // If the configuration or user has the analytics enabled flag
        // explicitly set to false,
        // don't make any service calls
        if (!context.getConfiguration().optBoolean(ANALYTICS_ENABLED, true)
                || !getAllowEventCollection())
            return;

        InternalEvent eventToRecord = null;
        // TODO: Can we refactor this so we are not essentially passing a super
        // class to the library user while expecting it to be a subclass in our
        // Internal code?
        if (event instanceof InternalEvent) {
            eventToRecord = (InternalEvent) event;
        } else {
            Log.e(TAG, "Error recording event, this event cannot be stored");
            return;
        }
        InternalEvent recordEvent = DefaultEvent.createFromEvent(context, sessionId,
                System.currentTimeMillis(), eventToRecord);

        notifyObservers(recordEvent);
    }

    @Override
    public AnalyticsEvent createEvent(String eventType) {
        return createEvent(eventType, true);
    }

    @Override
    public AnalyticsEvent createEvent(String eventType, boolean applyGlobalAttributes) {
        if (eventType == null) {
            Log.v(TAG, "Null eventType provided to addGlobalAttribute");
            throw new IllegalArgumentException("The eventType passed into create event was null");
        }
        String trimmedEventType = StringUtil.clipString(eventType, MAX_EVENT_TYPE_LENGTH, false);
        if (trimmedEventType.length() < eventType.length()) {
            Log.w(TAG, "The event type has been trimmed to a length of " + MAX_EVENT_TYPE_LENGTH
                    + " characters");
        }

        InternalEvent event = createInternalEvent(trimmedEventType, sessionStartTime, null, null);
        event = EventConstraintDecorator.newInstance(event);

        // TODO Refactor lock to use ReentrantReadWriteLock
        synchronized (this) {
            if (applyGlobalAttributes) {

                for (final Entry attr : globalAttributes.entrySet()) {
                    event.addAttribute(attr.getKey(), attr.getValue());
                }

                if (eventTypeAttributes.containsKey(event.getEventType())) {
                    for (final Entry attr : eventTypeAttributes.get(
                            event.getEventType()).entrySet()) {
                        event.addAttribute(attr.getKey(), attr.getValue());
                    }
                }

                for (final Entry metric : globalMetrics.entrySet()) {
                    event.addMetric(metric.getKey(), metric.getValue());
                }

                if (eventTypeMetrics.containsKey(event.getEventType())) {
                    for (final Entry metric : eventTypeMetrics.get(
                            event.getEventType()).entrySet()) {
                        event.addMetric(metric.getKey(), metric.getValue());
                    }
                }
            }
        }

        return event;
    }

    @Override
    public InternalEvent createInternalEvent(String eventType, long sessionStart, Long sessionEnd,
            Long sessionDuration) {
        return DefaultEvent.newInstance(context, sessionId, sessionStart, sessionEnd,
                sessionDuration, System.currentTimeMillis(), eventType);
    }

    @Override
    public void submitEvents() {
        Log.v(TAG, "Notifying deliveryClient");
        deliveryClient.attemptDelivery();
    }

    @Override
    public void addGlobalAttribute(String attributeName, String attributeValue) {
        if (attributeName == null) {
            Log.d(TAG, "Null attribute name provided to addGlobalAttribute");
            return;
        }

        if (attributeValue == null) {
            Log.d(TAG, "Null attribute value provided to addGlobalAttribute. attribute name:"
                    + attributeName);
            return;
        }
        globalAttributes.put(attributeName, attributeValue);
    }

    @Override
    public void addGlobalAttribute(String eventType, String attributeName, String attributeValue) {
        if (eventType == null) {
            Log.w(TAG, "Null eventType provided to addGlobalAttribute");
            return;
        }

        if (attributeName == null) {
            Log.w(TAG, "Null attribute name provided to addGlobalAttribute. eventType:" + eventType);
            return;
        }

        if (attributeValue == null) {
            Log.w(TAG, "Null value provided to addGlobalAttribute. eventType:" + eventType
                    + ", attributeName:" + attributeName);
            return;
        }

        Map eventAttrs = eventTypeAttributes.get(eventType);
        if (eventAttrs == null) {
            eventAttrs = new ConcurrentHashMap();
            eventTypeAttributes.put(eventType, eventAttrs);
        }
        eventAttrs.put(attributeName, attributeValue);
    }

    @Override
    public void addGlobalMetric(String metricName, Double metricValue) {
        if (metricName == null) {
            Log.w(TAG, "Null metric name provided to addGlobalMetric");
            return;
        }

        if (metricValue == null) {
            Log.w(TAG, "Null metric value provided to addGlobalMetric.  metric name:" + metricName);
            return;
        }

        globalMetrics.put(metricName, metricValue);
    }

    @Override
    public void addGlobalMetric(String eventType, String metricName, Double metricValue) {
        if (eventType == null) {
            Log.w(TAG, "Null eventType provided to addGlobalMetric");
            return;
        }

        if (metricName == null) {
            Log.w(TAG, "Null metric name provided to addGlobalMetric. eventType:" + eventType);
            return;
        }

        if (metricValue == null) {
            Log.w(TAG, "Null metric value provided to addGlobalMetric. eventType:" + eventType
                    + ", metric name:" + metricName);
            return;
        }

        Map eventMetrics = eventTypeMetrics.get(eventType);
        if (eventMetrics == null) {
            eventMetrics = new ConcurrentHashMap();
            eventTypeMetrics.put(eventType, eventMetrics);
        }
        eventMetrics.put(metricName, metricValue);
    }

    @Override
    public void addEventObserver(EventObserver observer) {
        if (observer == null) {
            Log.w(TAG, "Null EventObserver provided to addObserver");
            return;
        }

        if (!getEventObservers().contains(observer)) {
            getEventObservers().add(observer);
        } else {
            Log.w(TAG, "Observer was already registered with this EventRecorder");
        }
    }

    @Override
    public void removeEventObserver(EventObserver observer) {
        Log.v(TAG, "Removing EventObserver");
        if (observer == null) {
            Log.w(TAG, "Null EventObserver provided to removeObserver");
            return;
        } else {
            Log.v(TAG, observer.toString());
        }

        if (getEventObservers().contains(observer)) {
            getEventObservers().remove(observer);
        } else {
            Log.w(TAG,
                    "Observer was not registered with this EventRecorder because it already exists");
        }
    }

    protected List getEventObservers() {
        if (observers == null) {
            observers = new ArrayList();
        }
        return observers;
    }

    protected void notifyObservers(InternalEvent event) {
        for (final EventObserver observer : getEventObservers()) {
            observer.notify(event);
        }
    }

    @Override
    public void removeGlobalAttribute(String attributeName) {
        if (attributeName == null) {
            Log.w(TAG, "Null attribute name provided to removeGlobalAttribute");
            return;
        }

        globalAttributes.remove(attributeName);
    }

    @Override
    public void removeGlobalAttribute(String eventType, String attributeName) {
        if (eventType == null) {
            Log.w(TAG, "Null eventType provided to removeGlobalAttribute");
            return;
        }

        if (attributeName == null) {
            Log.w(TAG, "Null attribute name provided to removeGlobalAttribute");
            return;
        }

        final Map eventAttrs = eventTypeAttributes.get(eventType);
        if (eventAttrs != null) {
            eventAttrs.remove(attributeName);
        }
    }

    @Override
    public void removeGlobalMetric(String metricName) {
        if (metricName == null) {
            Log.w(TAG, "Null metric name provided to removeGlobalMetric");
            return;
        }

        globalMetrics.remove(metricName);
    }

    @Override
    public void removeGlobalMetric(String eventType, String metricName) {
        if (eventType == null) {
            Log.w(TAG, "Null eventType provided to removeGlobalMetric");
            return;
        }

        if (metricName == null) {
            Log.w(TAG, "Null metric name provided to removeGlobalMetric");
            return;
        }

        final Map eventMetrics = eventTypeMetrics.get(eventType);
        if (eventMetrics != null) {
            eventMetrics.remove(metricName);
        }
    }

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

    @Override
    public JSONObject toJSONObject() {
        JSONArray observersJSON = new JSONArray();
        if (null != observers) {
            for (EventObserver observer : observers) {
                if (JSONSerializable.class.isAssignableFrom(observer.getClass())) {
                    observersJSON.put(((JSONSerializable) observer).toJSONObject());
                } else {
                    observersJSON.put(observer);
                }
            }
        }

        JSONArray globalAttrs = new JSONArray();
        if (null != globalAttributes) {
            for (Entry entry : globalAttributes.entrySet()) {
                try {
                    JSONObject attr = new JSONObject();
                    attr.put(entry.getKey(), entry.getValue());
                    globalAttrs.put(attr);
                } catch (JSONException e) {
                }
            }
        }

        JSONArray globalMets = new JSONArray();
        if (null != globalMetrics) {
            for (Entry entry : globalMetrics.entrySet()) {
                try {
                    JSONObject attr = new JSONObject();
                    attr.put(entry.getKey(), entry.getValue());
                    globalMets.put(attr);
                } catch (JSONException e) {
                }
            }
        }

        JSONObject eventTypesAttributesJson = new JSONObject();
        if (null != eventTypeAttributes) {
            for (Entry> entry : eventTypeAttributes.entrySet()) {
                JSONArray eventTypeAttrs = new JSONArray();
                for (Entry attrEntry : entry.getValue().entrySet()) {
                    try {
                        JSONObject attr = new JSONObject();
                        attr.put(attrEntry.getKey(), attrEntry.getValue());
                        eventTypeAttrs.put(attr);
                    } catch (JSONException e) {
                    }
                }
                try {
                    eventTypesAttributesJson.put(entry.getKey(), eventTypeAttrs);
                } catch (JSONException e) {
                }
            }
        }

        JSONObject eventTypesMetricsJson = new JSONObject();
        if (null != eventTypeMetrics) {
            for (Entry> entry : eventTypeMetrics.entrySet()) {
                JSONArray eventTypeMets = new JSONArray();
                for (Entry attrEntry : entry.getValue().entrySet()) {
                    try {
                        JSONObject attr = new JSONObject();
                        attr.put(attrEntry.getKey(), attrEntry.getValue());
                        eventTypeMets.put(attr);
                    } catch (JSONException e) {
                    }
                }
                try {
                    eventTypesMetricsJson.put(entry.getKey(), eventTypeMets);
                } catch (JSONException e) {
                }
            }
        }

        return new JSONBuilder(this).withAttribute("uniqueId", context.getUniqueId())
                .withAttribute("observers", observersJSON)
                .withAttribute("globalAttributes", globalAttrs)
                .withAttribute("globalMetrics", globalMets)
                .withAttribute("eventTypeAttributes", eventTypesAttributesJson)
                .withAttribute("eventTypeMetrics", eventTypesMetricsJson)
                .toJSONObject();
    }

    public boolean getAllowEventCollection() {
        return allowEventCollection;
    }

    @Override
    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    @Override
    public void setSessionStartTime(long sessionStartTime) {
        this.sessionStartTime = sessionStartTime;
    }

    @Override
    public String getSessionId() {
        return sessionId;
    }

    @Override
    public long getSessionStartTime() {
        return sessionStartTime;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy