Example #1
0
        /// <summary>
        /// Loads the configuration root entity from the durable cache.
        /// </summary>
        /// <returns>The root node and its children, or null if it cannot be found.</returns>
        protected ConfigRoot LoadConfigFromCache()
        {
            IJsonEntity <ConfigRoot> configRoot = _cacheProvider.Entities.FirstOrDefault(y => y.Contents.ComponentName == _componentName);

            if (configRoot != null)
            {
                return(configRoot.Contents);
            }
            return(null);
        }
Example #2
0
 internal void SetPendingDelete(IJsonEntity entity, bool value)
 {
     if (value && !_pendingDeleteEntities.Contains(entity))
     {
         _pendingDeleteEntities.Add(entity);
     }
     else if (!value && _pendingDeleteEntities.Contains(entity))
     {
         _pendingDeleteEntities.Remove(entity);
     }
 }
Example #3
0
        /// <summary>
        /// Saves the configuration root entity to the durable cache.
        /// </summary>
        /// <param name="config">The node to store</param>
        protected void SaveConfigToCache(ConfigRoot config)
        {
            IJsonEntity <ConfigRoot> configEntity = _cacheProvider.Entities.FirstOrDefault(y => y.Contents.ComponentName == _componentName);

            if (configEntity == null)
            {
                configEntity = _cacheProvider.Create();
            }
            configEntity.Contents = config;
            _cacheProvider.Update(configEntity);
            _cacheProvider.Save();
        }
        /// <summary>
        /// Performs an update on an existing Config resource and returns a copy of the saved data if successful.
        /// </summary>
        /// <param name="componentName">The name of the resource to update.  Not case-sensitive.</param>
        /// <param name="config">The new config data to store - overwrites any exsiting data</param>
        /// <returns>
        /// 200 - If update is successful
        /// 409 - If an attempt is made to change the name of an existing resource and that name change would cause it to overwrite another resource (see remarks)
        /// 404 - If the requested resource does not exist
        /// </returns>
        /// <remarks>
        /// This operation allows resource renaming.  If you change the component name in the config JSON, when the operation completes the resource will have a
        /// new Location returned in the headers, provided that no other resource exists with the same name.
        /// </remarks>
        public OperationResult Put(string componentName, ConfigRoot config)
        {
            _log.Debug("Entering ConfigHandler.Put()");

            try
            {
                var requestedEntity = _repository.Entities.FirstOrDefault(
                    x => x.Contents.ComponentName.ToUpper() == componentName.ToUpper());

                if (requestedEntity == null)
                {
                    _log.Debug(string.Format("Returning 404 Not Found for resource {0}", componentName));
                    return(new OperationResult.NotFound());
                }

                if (config.ComponentName == null || Regex.IsMatch(config.ComponentName, @"\W"))
                {
                    return(new OperationResult.BadRequest());
                }

                IJsonEntity <ConfigRoot> existingEntity =
                    _repository.Entities.FirstOrDefault(
                        x => x.Contents.ComponentName.ToUpper() == config.ComponentName.ToUpper());
                if (existingEntity != null && config.ComponentName.ToUpper() != componentName.ToUpper())
                {
                    _log.Debug(
                        string.Format(
                            "Returning 409 Conflict for resource {0} - attempted to change name to existing resource {1}",
                            componentName, config.ComponentName));
                    return(new ConflictOperationResult());
                }

                requestedEntity.Contents = config;

                _repository.Update(requestedEntity);
                _repository.Save();

                var location = HttpHelper.GetLocation(_request.Uri, config.ComponentName);
                _response.Headers[HttpHelper.LocationHeader] = location.ToString();
                return(new OperationResult.OK {
                    ResponseResource = requestedEntity.Contents
                });
            }
            catch (Exception exception)
            {
                _log.Error(string.Format("Error in Put for component '{0}': {1}", componentName, exception));
                throw;
            }
        }
Example #5
0
        /// <summary>
        /// Operation to update a resource in the repository
        /// </summary>
        /// <param name="item">The item to update</param>
        public void Update(IJsonEntity <T> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            _readWriteLock.EnterWriteLock();
            try
            {
                _context[item.Id] = item;
            }
            finally
            {
                _readWriteLock.ExitWriteLock();
            }
        }
Example #6
0
        /// <summary>
        /// Operation to delete a resource from the repository
        /// </summary>
        /// <param name="item">The item to delete</param>
        public void Delete(IJsonEntity <T> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            _readWriteLock.EnterWriteLock();
            try
            {
                _deleteList.Add(item);
                _context.Remove(item.Id);
            }
            finally
            {
                _readWriteLock.ExitWriteLock();
            }
        }
        private static void FillJsonEntity(BaseDbEntity entity, IJsonEntity newJsonEntity)
        {
            List<MapToField> mappedFields = GetMappedFields(entity);
            Type jsonEntityType = newJsonEntity.GetType();
            Type dbEntityType = entity.GetType();

            mappedFields.ForEach(mappedAttr =>
            {
                var jsonEntityProp = jsonEntityType.GetProperty(mappedAttr.JsonModelField);
                var dbEntityProp = dbEntityType.GetProperty(mappedAttr.JsonModelField);

                if (jsonEntityProp != null && dbEntityProp != null)
                {
                    var dbValue = dbEntityProp.GetValue(entity);
                    jsonEntityProp.SetValue(newJsonEntity, dbValue);
                }
            });
        }
        public void AddEntityThenDeleteFromMemory()
        {
            using (var testRepository = new DurableMemoryRepository <EntityTest>(MockDataPath, _mockProvider.MockFileSystem.Object))
            {
                IJsonEntity <EntityTest> entity = testRepository.Create();
                entity.Contents = new EntityTest {
                    Name = "foo", Number = 1
                };
                testRepository.Add(entity);

                IJsonEntity <EntityTest> entityFromRepo = testRepository.Entities.FirstOrDefault(x => x.Contents.Name == "foo");
                Assert.IsNotNull(entityFromRepo);

                testRepository.Delete(entity);

                entityFromRepo = testRepository.Entities.FirstOrDefault(x => x.Contents.Name == "foo");
                Assert.IsNull(entityFromRepo);
            }
        }
Example #9
0
        /// <summary>
        /// Operation to add a new resource in the repository
        /// </summary>
        /// <param name="item">The item to create</param>
        public void Add(IJsonEntity <T> item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            _readWriteLock.EnterWriteLock();
            try
            {
                if (!_context.ContainsKey(item.Id))
                {
                    _context[item.Id] = item;
                }
            }
            finally
            {
                _readWriteLock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Handles POST for creating new resource.
        /// </summary>
        /// <param name="config">Config root deserialized from JSON in request body</param>
        /// <returns>
        /// 409 Conflict - If config exists for component of same name already in repository
        /// 201 Created - If adding new config succeeds
        /// 500 Internal Server Error - If error occurs
        /// </returns>
        public OperationResult Post(ConfigRoot config)
        {
            _log.Debug("Entering ConfigHandler.Post()");

            try
            {
                IJsonEntity <ConfigRoot> configEntity = _repository.Entities.FirstOrDefault(
                    x => x.Contents.ComponentName.ToLower() == config.ComponentName.ToLower());

                if (configEntity != null)
                {
                    _log.Debug(string.Format("Returning 400 Bad Request for POST to component {0}", config.ComponentName));
                    return(new OperationResult.BadRequest());
                }

                if (config.ComponentName == null || Regex.IsMatch(config.ComponentName, @"\W"))
                {
                    _log.Debug(string.Format("Returning 400 Bad Request for POST to component {0}", config.ComponentName));
                    return(new OperationResult.BadRequest());
                }

                configEntity          = _repository.Create();
                configEntity.Contents = config;

                _repository.Add(configEntity);
                _repository.Save();


                var location = HttpHelper.GetLocation(_request.Uri, config.ComponentName);
                _response.Headers[HttpHelper.LocationHeader] = location.ToString();
                return(new OperationResult.Created {
                    ResponseResource = configEntity.Contents
                });
            }
            catch (Exception exception)
            {
                _log.Error(string.Format("Error in Post for component '{0}': {1}", config != null ? config.ComponentName : null, exception));
                throw;
            }
        }
Example #11
0
        internal void Initialize(IJsonEntity entity)
        {
            var type = entity.GetType();

            var id = entity.Id;

            if (!id.HasValue)
            {
                throw new InvalidOperationException("Cannot initialize entity of type '" + type.Name + "' with no id.");
            }

            Dictionary <string, object> instanceData;

            var typeData = GetTypeData(type);

            if (!typeData.TryGetValue(id.Value.ToString(CultureInfo.InvariantCulture), out instanceData))
            {
                throw new InvalidOperationException("Cannot initialize entity: " + type.Name + "|" + id + ".");
            }

            InitializeInstance(type, entity, instanceData);
        }
Example #12
0
        internal bool IsModified(IJsonEntity entity)
        {
            var type = entity.GetType();

            var id = entity.Id;

            if (_deletedEntities.Contains(entity))
            {
                if (!id.HasValue)
                {
                    throw new Exception("Accessed deleted entity with no id: " + type.Name + "|.");
                }

                throw new Exception("Accessed deleted entity: " + type.Name + "|" + id + ".");
            }

            if (_pendingDeleteEntities.Contains(entity))
            {
                return(true);
            }

            if (_newEntities.Contains(entity))
            {
                return(true);
            }

            if (!id.HasValue)
            {
                throw new Exception("Found existing entity with no id: " + type.Name + "|.");
            }

            var typeData = GetTypeData(type);

            Dictionary <string, object> instanceData;

            if (typeData == null || !typeData.TryGetValue(id.Value.ToString(CultureInfo.InvariantCulture), out instanceData))
            {
                throw new Exception("Couldn't find data for existing entity: " + type.Name + "|.");
            }

            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (property.Name == "Id")
                {
                    continue;
                }

                var value = property.GetValue(entity, null);

                var propertyType = property.PropertyType;

                object propertyData;
                var    hasPropertyData = instanceData.TryGetValue(property.Name, out propertyData);

                Type referenceType;
                bool isReferenceList;
                if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList))
                {
                    if (isReferenceList)
                    {
                        var referenceIds = new List <int>();

                        foreach (IJsonEntity reference in (IEnumerable)value)
                        {
                            var referenceId = reference.Id;
                            if (!referenceId.HasValue)
                            {
                                throw new InvalidOperationException();
                            }
                            referenceIds.Add(referenceId.Value);
                        }

                        if (!hasPropertyData || IsReferenceListModified(referenceIds.ToArray(), propertyData))
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        var referenceId = ((IJsonEntity)value).Id;
                        if (!referenceId.HasValue)
                        {
                            throw new InvalidOperationException();
                        }

                        if (!hasPropertyData || IsReferenceModified(referenceId, propertyData))
                        {
                            return(true);
                        }
                    }
                }
                else if (!hasPropertyData || IsValueModified(value, propertyData))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #13
0
        private void UpdateData(Type type, IJsonEntity entity, bool allowDelete, out Type[] affectedTypes, out object[] addedEntities, out object[] removedEntities)
        {
            var affected = new List <Type>();
            var added    = new List <object>();
            var removed  = new List <object>();

            var typeData = GetTypeData(type, true);

            if (_deletedEntities.Contains(entity))
            {
                var id = entity.Id;

                if (!id.HasValue)
                {
                    throw new Exception("Found deleted entity with no id: " + type.Name + "|.");
                }

                throw new Exception("Found deleted entity: " + type.Name + "|" + id + ".");
            }

            if (_pendingDeleteEntities.Contains(entity))
            {
                var id = entity.Id;

                if (!allowDelete)
                {
                    throw new Exception("Cannot delete entity: " + type.Name + "|" + id + ".");
                }

                // Only need to delete Entities that were actually saved previously.
                if (id.HasValue)
                {
                    if (typeData.ContainsKey(id.Value.ToString(CultureInfo.InvariantCulture)))
                    {
                        typeData.Remove(id.Value.ToString(CultureInfo.InvariantCulture));
                    }

                    removed.Add(entity);
                    affected.Add(type);

                    if (!_deletedEntities.Contains(entity))
                    {
                        _deletedEntities.Add(entity);
                    }
                }

                _pendingDeleteEntities.Remove(entity);
            }
            else
            {
                var updated = false;

                Dictionary <string, object> instanceData;

                if (_newEntities.Contains(entity))
                {
                    int newId;

                    if (typeData.Count == 0)
                    {
                        newId = 1;
                    }
                    else
                    {
                        var largestId = typeData.Keys.Max(k => int.Parse(k));
                        newId = largestId + 1;
                    }

                    entity.Id = newId;

                    typeData[newId.ToString(CultureInfo.InvariantCulture)] = instanceData = new Dictionary <string, object>();

                    _newEntities.Remove(entity);

                    added.Add(entity);

                    Dictionary <int, IJsonEntity> instanceCache;
                    if (!_existingEntities.TryGetValue(type, out instanceCache))
                    {
                        _existingEntities[type] = instanceCache = new Dictionary <int, IJsonEntity>();
                    }

                    instanceCache[newId] = entity;

                    updated = true;
                }
                else
                {
                    var id = entity.Id;

                    if (!id.HasValue)
                    {
                        throw new Exception("Found existing entity with no id: " + type.Name + "|.");
                    }

                    if (!typeData.TryGetValue(id.Value.ToString(CultureInfo.InvariantCulture), out instanceData))
                    {
                        throw new Exception("Couldn't find data for existing entity: " + type.Name + "|.");
                    }
                }

                foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (property.Name == "Id")
                    {
                        continue;
                    }

                    var value = property.GetValue(entity, null);

                    object serializedValue;

                    var propertyType = property.PropertyType;

                    object propertyData;
                    var    hasPropertyData = instanceData.TryGetValue(property.Name, out propertyData);

                    Type referenceType;
                    bool isReferenceList;
                    if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList))
                    {
                        if (isReferenceList)
                        {
                            var references   = ((IEnumerable)value).Cast <IJsonEntity>().ToArray();
                            var referenceIds = new List <int>();

                            foreach (var reference in references)
                            {
                                Type[]   refAffectedTypes;
                                object[] refAdded;
                                object[] refRemoved;

                                UpdateData(referenceType, reference, false, out refAffectedTypes, out refAdded, out refRemoved);

                                affected.AddRange(refAffectedTypes);
                                added.AddRange(refAdded);
                                removed.AddRange(refRemoved);

                                var referenceId = reference.Id;
                                if (!referenceId.HasValue)
                                {
                                    throw new InvalidOperationException();
                                }
                                referenceIds.Add(referenceId.Value);
                            }

                            serializedValue = referenceIds.ToArray();

                            if (!hasPropertyData)
                            {
                                updated = true;
                            }
                            else
                            {
                                if (IsReferenceListModified(referenceIds.ToArray(), propertyData))
                                {
                                    updated = true;
                                }

                                var persistedReferences = ((IEnumerable)propertyData).Cast <object>().Select(i => (int)Convert.ChangeType(i, typeof(int))).ToArray();
                                foreach (var priorReference in persistedReferences.Select(id => Fetch(referenceType, id)).Where(r => !references.Contains(r)))
                                {
                                    Type[]   refAffectedTypes;
                                    object[] refAdded;
                                    object[] refRemoved;

                                    UpdateData(referenceType, (IJsonEntity)priorReference, true, out refAffectedTypes, out refAdded, out refRemoved);

                                    affected.AddRange(refAffectedTypes);
                                    added.AddRange(refAdded);
                                    removed.AddRange(refRemoved);
                                }
                            }
                        }
                        else
                        {
                            int?referenceId;

                            if (value == null)
                            {
                                referenceId = null;
                            }
                            else
                            {
                                Type[]   refAffectedTypes;
                                object[] refAdded;
                                object[] refRemoved;

                                UpdateData(referenceType, (IJsonEntity)value, false, out refAffectedTypes, out refAdded, out refRemoved);

                                affected.AddRange(refAffectedTypes);
                                added.AddRange(refAdded);
                                removed.AddRange(refRemoved);

                                referenceId = ((IJsonEntity)value).Id;
                                if (!referenceId.HasValue)
                                {
                                    throw new InvalidOperationException();
                                }
                            }

                            serializedValue = referenceId;

                            if (!hasPropertyData)
                            {
                                updated = true;
                            }
                            else
                            {
                                if (IsReferenceModified(referenceId, propertyData))
                                {
                                    updated = true;
                                }

                                if (propertyData != null)
                                {
                                    var priorReferenceId = (int?)propertyData;

                                    if (priorReferenceId != referenceId)
                                    {
                                        var priorReference = (IJsonEntity)Fetch(referenceType, priorReferenceId.Value);

                                        Type[]   refAffectedTypes;
                                        object[] refAdded;
                                        object[] refRemoved;

                                        UpdateData(referenceType, priorReference, true, out refAffectedTypes, out refAdded, out refRemoved);

                                        affected.AddRange(refAffectedTypes);
                                        added.AddRange(refAdded);
                                        removed.AddRange(refRemoved);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        serializedValue = value;

                        if (!hasPropertyData || IsValueModified(value, propertyData))
                        {
                            updated = true;
                        }
                    }

                    instanceData[property.Name] = serializedValue;
                }

                if (updated)
                {
                    affected.Add(type);
                }
            }

            affectedTypes   = affected.ToArray();
            addedEntities   = added.ToArray();
            removedEntities = removed.ToArray();
        }
Example #14
0
 internal static void OnInitExisting(IJsonEntity entity)
 {
     JsonEntityContext.GetContextForEntity(entity).Initialize(entity);
 }
Example #15
0
        private void InitializeInstance(IReflect type, IJsonEntity entity, Dictionary <string, object> data)
        {
            var jsonProperties = data.Keys.ToArray();

            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                var propertyType = property.PropertyType;

                Type referenceType;
                bool isReferenceList;

                object propData;
                if (jsonProperties.Contains(property.Name))
                {
                    propData = data[property.Name];
                }
                else
                {
                    propData = null;

                    if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList))
                    {
                        if (isReferenceList)
                        {
                            var list = JsonEntityAdapter <JsonEntity> .CreateList(referenceType);

                            property.SetValue(entity, list, null);
                        }
                    }
                }

                if (propData == null)
                {
                    continue;
                }

                object value;

                if (JsonEntity.TryGetReferenceType(propertyType, supportedTypes, out referenceType, out isReferenceList))
                {
                    if (isReferenceList)
                    {
                        var list = JsonEntityAdapter <JsonEntity> .CreateList(referenceType);

                        var addMethod = list.GetType().GetMethod("Add", BindingFlags.Instance | BindingFlags.Public, null, new[] { referenceType }, null);

                        foreach (var referenceId in (IEnumerable)propData)
                        {
                            var reference = Fetch(referenceType, (int)Convert.ChangeType(referenceId, typeof(int)));
                            if (reference == null)
                            {
                                throw new InvalidOperationException();
                            }

                            addMethod.Invoke(list, new[] { reference });
                        }

                        value = list;
                    }
                    else
                    {
                        var referenceId = (int)Convert.ChangeType(propData, typeof(int));

                        value = Fetch(referenceType, referenceId);
                    }
                }
                else
                {
                    Type targetType;
                    if (!TryGetNullableType(propertyType, out targetType))
                    {
                        targetType = propertyType;
                    }

                    if (targetType == typeof(DateTime) && propData is string)
                    {
                        value = DateTime.Parse((string)propData);
                    }
                    else if (propData.GetType() != targetType)
                    {
                        value = Convert.ChangeType(propData, targetType);
                    }
                    else
                    {
                        value = propData;
                    }
                }

                property.SetValue(entity, value, null);
            }
        }
Example #16
0
 internal static void OnInitNew(IJsonEntity entity)
 {
     JsonEntityContext.GetContextForEntity(entity).Add(entity);
 }
Example #17
0
 internal static void OnInitExisting(IJsonEntity entity)
 {
     JsonEntityContext.GetContextForEntity(entity).Initialize(entity);
 }
Example #18
0
        /// <summary>
        /// Given an entity, constructs the full path to the data file that should be used by that entity
        /// </summary>
        /// <param name="jsonEntity">The entity for which to construct a path</param>
        /// <returns>The path</returns>
        private string GetDataFilePath(IJsonEntity <T> jsonEntity)
        {
            var dataFileName = string.Format("{0:d10}_" + typeof(T) + ".json", jsonEntity.Id);

            return(System.IO.Path.Combine(_path, dataFileName));
        }
Example #19
0
 internal bool IsPendingDelete(IJsonEntity entity)
 {
     return(_pendingDeleteEntities.Contains(entity));
 }
Example #20
0
 internal static void OnInitNew(IJsonEntity entity)
 {
     JsonEntityContext.GetContextForEntity(entity).Add(entity);
 }
Example #21
0
 internal bool IsDeleted(IJsonEntity entity)
 {
     return(_deletedEntities.Contains(entity));
 }
Example #22
0
 public bool Equals(IJsonEntity obj)
 => Id == obj?.Id;
Example #23
0
 /// <summary>
 /// Returns a copy of this <see cref="IJsonEntity{T}"/> object with the same ID and version, but replaces the
 /// body with a new one.
 /// </summary>
 public static IJsonEntity <T> Modify <T>(this IJsonEntity <T> entity, T newValue)
     where T : class?
 {
     return(new JsonEntity <T>(entity.Id, newValue, entity.Version));