/* * Copyright 2015-2015 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. */ using System.Collections; using System.Collections.Generic; using System; using System.Collections.ObjectModel; using Amazon.MobileAnalytics.MobileAnalyticsManager; using Amazon.Util; using Amazon.MobileAnalytics.MobileAnalyticsManager.Internal; namespace Amazon.MobileAnalytics.MobileAnalyticsManager { /// /// Represents any useful event you wish to record in your application. /// /// The example below shows how to use CustomEvent /// /// CustomEvent customEvent = new CustomEvent("level_complete"); /// /// customEvent.AddAttribute("LevelName","Level1"); /// customEvent.AddAttribute("Successful","True"); /// customEvent.AddMetric("Score",12345); /// customEvent.AddMetric("TimeInLevel",64); /// /// analyticsManager.RecordEvent(customEvent); /// /// /// public class CustomEvent : IEvent { /// /// Event type string that defines event type. /// internal string EventType { get; set; } /// /// Dictionary that stores global attribute for specific event type. /// private static Dictionary> _eventTypeGlobalAttributes = new Dictionary>(); /// /// Dictionary that stores global metric for specific event type. /// private static Dictionary> _eventTypeGlobalMetrics = new Dictionary>(); /// /// Dictionary that stores global attribute for all event type. /// private static Dictionary _globalAttributes = new Dictionary(); /// /// Dictionary that stores global metric for all event type. /// private static Dictionary _globalMetrics = new Dictionary(); /// /// Dictionary that stores attribute for this event only. /// private Dictionary _attributes = new Dictionary(); /// /// Dictionary that stores metric for this event only. /// private Dictionary _metrics = new Dictionary(); /// /// Unique Identifier of Session /// internal string SessionId {get;set;} /// /// Duration of the session in milliseconds. /// internal long Duration { get; set; } /// /// Start time stamp of seesion. /// internal DateTime StartTimestamp {get;set;} /// /// Stop time stamp of session. /// internal DateTime? StopTimestamp { get; set; } /// /// Timestamp of when event is recorded. /// internal DateTime Timestamp { get; set; } /// /// Lock that protects global attribute and metric. /// private static Object _globalLock = new Object(); /// /// Lock that protects attribute and metric. /// private Object _lock = new Object(); private const int MAX_KEY_SIZE = 50; private const int MAX_ATTRIB_VALUE_SIZE = 255; #region constructor /// /// Initializes a new instance of the /// class. /// /// Event type. public CustomEvent(string eventType) { if (null == eventType) throw new ArgumentNullException("eventType"); this.EventType = eventType; } #endregion /// /// Converts to mobile analytics model event. /// /// The to mobile analytics model event. /// Session. internal virtual Amazon.MobileAnalytics.Model.Event ConvertToMobileAnalyticsModelEvent(Amazon.MobileAnalytics.MobileAnalyticsManager.Internal.Session session) { Amazon.MobileAnalytics.Model.Event modelEvent = new Amazon.MobileAnalytics.Model.Event(); this.StartTimestamp = session.StartTime; this.SessionId = session.SessionId; // assign session info from custom event to model event modelEvent.EventType = this.EventType; modelEvent.Session = new Amazon.MobileAnalytics.Model.Session(); modelEvent.Session.Id = session.SessionId; modelEvent.Session.StartTimestampUtc = session.StartTime; if (session.StopTime != null) modelEvent.Session.StopTimestampUtc = session.StopTime.Value; if(this.EventType == Constants.SESSION_STOP_EVENT_TYPE) { modelEvent.Session.StopTimestampUtc = this.StopTimestamp.Value; modelEvent.Session.Duration = this.Duration; } lock(_globalLock) { AddDict(_globalAttributes,modelEvent.Attributes); if(_eventTypeGlobalAttributes.ContainsKey(EventType)) { AddDict(_eventTypeGlobalAttributes[EventType],modelEvent.Attributes); } AddDict(_globalMetrics,modelEvent.Metrics); if(_eventTypeGlobalMetrics.ContainsKey(EventType)) { AddDict(_eventTypeGlobalMetrics[EventType],modelEvent.Metrics); } } lock(_lock) { AddDict(_attributes,modelEvent.Attributes); AddDict(_metrics,modelEvent.Metrics); } modelEvent.TimestampUtc = Timestamp; modelEvent.Version = "v2.0"; return modelEvent; } #region attribute /// /// Adds the attribute. /// /// Attribute name. Max name length is 50. /// Attribute value. Max value length is 255. public void AddAttribute(string attributeName, string attributeValue) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } if (null == attributeValue) { throw new ArgumentNullException("attributeValue"); } if(attributeName.Length > MAX_KEY_SIZE) { throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE); } if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE) { throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE); } lock(_lock) { _attributes[attributeName] = attributeValue; } } /// /// Determines whether this instance has attribute the specified attributeName. /// /// Attribute name. /// Return true if the event has the attribute, else false. public bool HasAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } bool ret = false; lock(_lock) { ret = _attributes.ContainsKey(attributeName); } return ret; } /// /// Gets the attribute. /// /// Attribute name. /// The attribute. Return null of attribute doesn't exist. public string GetAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } string ret = null; lock(_lock) { if(attributeName.Contains(attributeName)) ret = _attributes[attributeName]; } return ret; } /// /// Gets copy of all attributes. /// /// Copy of all the attributes. public IDictionary AllAttributes { get { IDictionary ret; lock(_lock) { ret = CopyDict(_attributes); } return ret; } } #endregion #region metric /// /// Adds the metric. /// /// Metric name. Max length is 50. /// Metric value. public void AddMetric(string metricName, double metricValue) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } if(metricName.Length > MAX_KEY_SIZE) { throw new ArgumentException("length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE); } lock(_lock) { _metrics[metricName] = metricValue; } } /// /// Determines whether this instance has metric the specified metricName. /// /// Metric name. /// Return true if the event has the attribute, else false. public bool HasMetric(string metricName) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } bool ret = false; lock(_lock) { ret = _metrics.ContainsKey(metricName); } return ret; } /// /// Gets the metric. /// /// Metric name. /// The metric. Return null of metric doesn't exist. public double? GetMetric(string metricName) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } double? ret = null; lock(_lock) { if(_metrics.ContainsKey(metricName)) ret = _metrics[metricName]; } return ret; } /// /// Gets copy of all metrics. /// /// Copy of all the metrics. public IDictionary AllMetrics { get { IDictionary ret; lock(_lock) { ret = CopyDict(_metrics); } return ret; } } #endregion #region gloablattribute /// /// Adds the global attribute, which is valid for all events. /// /// Attribute name. Max length is 50. /// Attribute value. Max length is 255. public void AddGlobalAttribute(string attributeName, string attributeValue) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } if( null == attributeValue) { throw new ArgumentNullException("attributeValue"); } if(attributeName.Length > MAX_KEY_SIZE) { throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE); } if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE) { throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE); } lock(_globalLock) { _globalAttributes[attributeName] = attributeValue; } } /// /// Adds the global attribute, which is valid to some specific event type. /// /// Event type. /// Attribute name. Max length is 50. /// Attribute value. Max length is 255. public void AddGlobalAttribute(string eventType, string attributeName, string attributeValue) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } if( null == attributeValue) { throw new ArgumentNullException("attributeValue"); } if(attributeName.Length > MAX_KEY_SIZE) { throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE); } if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE) { throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE); } lock(_globalLock) { if(!_eventTypeGlobalAttributes.ContainsKey(eventType)) { _eventTypeGlobalAttributes.Add(eventType,new Dictionary()); _eventTypeGlobalAttributes[eventType].Add(attributeName, attributeValue); } else if(_eventTypeGlobalAttributes.ContainsKey(eventType) && !_eventTypeGlobalAttributes[eventType].ContainsKey(attributeName)) { _eventTypeGlobalAttributes[eventType].Add(attributeName, attributeValue); } } } /// /// Removes the global attribute, which is valid for all events. /// /// Attribute name. public void RemoveGlobalAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } lock(_globalLock) { if(_globalAttributes.ContainsKey(attributeName)) { _globalAttributes.Remove(attributeName); } } } /// /// Removes the global attribute, which is valid to some specific event type. /// /// Event type. /// Attribute name. public void RemoveGlobalAttribute(string eventType, string attributeName) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } lock(_globalLock) { if(_eventTypeGlobalAttributes.ContainsKey(eventType) && _eventTypeGlobalAttributes[eventType].ContainsKey(attributeName)) { _eventTypeGlobalAttributes[eventType].Remove(attributeName); } } } /// /// Gets the global attribute, which is valid for all events. /// /// Attribute name. /// The global attribute. Return null if attribute doesn't exist. public string GetGlobalAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } string ret = null; lock(_globalLock) { if(_globalAttributes.ContainsKey(attributeName)) { ret = _globalAttributes[attributeName]; } } return ret; } /// /// Gets the global attribute, which is valid for some specific event type. /// /// Event type. /// Attribute name. /// The global attribute. Return null if attribute doesn't exist. public string GetGlobalAttribute(string eventType, string attributeName) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } string ret = null; lock(_globalLock) { if(_eventTypeGlobalAttributes.ContainsKey(eventType) && _eventTypeGlobalAttributes[eventType].ContainsKey(attributeName)) { ret = _eventTypeGlobalAttributes[eventType][attributeName]; } } return ret; } #endregion #region globalmetric /// /// Adds the global metric, which is valid for all events. /// /// Metric name. Max length is 50. /// Metric value. public void AddGlobalMetric(string metricName, double metricValue) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } if(metricName.Length > MAX_KEY_SIZE) { throw new ArgumentException("Length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE); } lock(_globalLock) { _globalMetrics[metricName] = metricValue; } } /// /// Adds the global metric, which is valid for some specific event type. /// /// Event type. /// Metric name. Max length is 50. /// Metric value. public void AddGlobalMetric(string eventType, string metricName, double metricValue) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } if(metricName.Length > MAX_KEY_SIZE) { throw new ArgumentException("Length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE); } lock(_globalLock) { if(!_eventTypeGlobalMetrics.ContainsKey(eventType)) { _eventTypeGlobalMetrics.Add(eventType,new Dictionary()); _eventTypeGlobalMetrics[eventType][metricName] = metricValue; return; } else if(_eventTypeGlobalMetrics.ContainsKey(eventType)) { _eventTypeGlobalMetrics[eventType][metricName] = metricValue; return; } } } /// /// Removes the global metric, which is valid for all events. /// /// Metric name. public void RemoveGlobalMetric(string metricName) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } lock(_globalLock) { if(_globalMetrics.ContainsKey(metricName)) { _globalMetrics.Remove(metricName); } } } /// /// Removes the global metric, which is valid for some specific event type. /// /// Event type. /// Metric name. public void RemoveGlobalMetric(string eventType,string metricName) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } lock(_globalLock) { if(_eventTypeGlobalMetrics.ContainsKey(eventType) && _eventTypeGlobalMetrics[eventType].ContainsKey(metricName)) { _eventTypeGlobalMetrics[eventType].Remove(metricName); } } } /// /// Gets the global metric, which is valid for all events. /// /// The global metric. Return null if metric doesn't exist. /// Metric name. public double? GetGlobalMetric(string metricName) { if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } double? ret = null; lock(_globalLock) { if(_globalMetrics.ContainsKey(metricName)) ret = _globalMetrics[metricName]; } return ret; } /// /// Gets the global metric, which is valid for some specific event type. /// /// Event type. /// Metric name. /// The global metric. Return null if metric doesn't exist. public double? GetGlobalMetric(string eventType, string metricName) { if(string.IsNullOrEmpty(eventType)) { throw new ArgumentNullException("eventType"); } if(string.IsNullOrEmpty(metricName)) { throw new ArgumentNullException("metricName"); } double? ret = null; lock(_globalLock) { if(_eventTypeGlobalMetrics.ContainsKey(eventType) && _eventTypeGlobalMetrics[eventType].ContainsKey(metricName)) { ret = _eventTypeGlobalMetrics[eventType][metricName]; } } return ret; } #endregion #region util private static void AddDict(Dictionary srcDict, Dictionary dstDict) { if(srcDict == null) { throw new ArgumentNullException("srcDict"); } if (dstDict == null) { throw new ArgumentNullException("dstDict"); } foreach (var item in srcDict) { dstDict[item.Key] = item.Value; } } private static Dictionary CopyDict(Dictionary srcDict) { if(srcDict == null) { throw new ArgumentNullException("srcDict"); } Dictionary dstDict = new Dictionary(); foreach (var item in srcDict) { dstDict.Add(item.Key, item.Value); } return dstDict; } #endregion } }