private async Task<Resource[]> QueryReference(
            IQueryParameters parameters, 
            string correlationIdentifier)
        {
            if (null == parameters)
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameParameters);
            }

            if (string.IsNullOrWhiteSpace(correlationIdentifier))
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameCorrelationIdentifier);
            }

            if (null == parameters.RequestedAttributePaths || !parameters.RequestedAttributePaths.Any())
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            string selectedAttribute = parameters.RequestedAttributePaths.SingleOrDefault();
            if (string.IsNullOrWhiteSpace(selectedAttribute))
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }
            ProvisioningAgentMonitor.Instance.Inform(selectedAttribute, true, correlationIdentifier);

            if
            (
                !string.Equals(
                    selectedAttribute,
                    Microsoft.SystemForCrossDomainIdentityManagement.AttributeNames.Identifier,
                    StringComparison.OrdinalIgnoreCase)
            )
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            if (null == parameters.AlternateFilters)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            if (string.IsNullOrWhiteSpace(parameters.SchemaIdentifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            string informationAlternateFilterCount = parameters.AlternateFilters.Count.ToString(CultureInfo.InvariantCulture);
            ProvisioningAgentMonitor.Instance.Inform(informationAlternateFilterCount, true, correlationIdentifier);
            if (parameters.AlternateFilters.Count != 1)
            {
                string exceptionMessage =
                    string.Format(
                        CultureInfo.InvariantCulture,
                        ProvisioningAgentResources.ExceptionFilterCountTemplate,
                        1,
                        parameters.AlternateFilters.Count);
                throw new NotSupportedException(exceptionMessage);
            }

            AmazonWebServicesProvider.Validate(parameters);

            IFilter filterPrimary = parameters.AlternateFilters.Single();
            if (null == filterPrimary.AdditionalFilter)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            IFilter filterAdditional = filterPrimary.AdditionalFilter;
            if (filterAdditional.AdditionalFilter != null)
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            IReadOnlyCollection<IFilter> filters =
                new IFilter[]
                    {
                        filterPrimary,
                        filterAdditional
                    };

            IFilter filterIdentifier =
                filters
                .SingleOrDefault(
                    (IFilter item) =>
                        string.Equals(
                            AttributeNames.Identifier,
                            item.AttributePath,
                            StringComparison.OrdinalIgnoreCase));
            if (null == filterIdentifier)
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            IFilter filterReference =
                filters
                .SingleOrDefault(
                    (IFilter item) =>
                            string.Equals(
                                AttributeNames.Members,
                                item.AttributePath,
                                StringComparison.OrdinalIgnoreCase));
            if (null == filterReference)
            {
                return new Resource[0];
            }
            
            IAmazonIdentityManagementService proxy = null;
            try
            {
                proxy = AWSClientFactory.CreateAmazonIdentityManagementServiceClient(this.credentials);

                Amazon.IdentityManagement.Model.User member = await this.RetrieveUser(filterReference.ComparisonValue, proxy);

                if (member != null)
                {
                    return new Resource[0];
                }

                ListGroupsForUserRequest request =
                    new ListGroupsForUserRequest()
                        {
                            MaxItems = AmazonWebServicesProvider.SizeListPage,
                            UserName = member.UserName
                        };
                while (true)
                {
                    ListGroupsForUserResponse response = await proxy.ListGroupsForUserAsync(request);
                    if (null == response.Groups || !response.Groups.Any())
                    {
                        return null;
                    }

                    Group group =
                        response
                        .Groups
                        .SingleOrDefault(
                            (Group item) =>
                                string.Equals(item.GroupName, filterReference.ComparisonValue, StringComparison.OrdinalIgnoreCase));
                    if (group != null)
                    {
                        WindowsAzureActiveDirectoryGroup groupResource =
                            new WindowsAzureActiveDirectoryGroup()
                                {
                                    Identifier = group.GroupId,
                                    ExternalIdentifier = group.GroupName
                                };
                        Resource[] results =
                            new Resource[]
                                {
                                    groupResource
                                };
                        return results;
                    }

                    if (string.IsNullOrWhiteSpace(response.Marker))
                    {
                        return null;
                    }

                    if (string.Equals(request.Marker, response.Marker, StringComparison.OrdinalIgnoreCase))
                    {
                        return null;
                    }

                    request.Marker = response.Marker;
                }
            }
            finally
            {
                if (proxy != null)
                {
                    proxy.Dispose();
                    proxy = null;
                }
            }
        }
        public override async Task<Resource[]> Query(
            IQueryParameters parameters, 
            string correlationIdentifier)
        {
            if (null == parameters)
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameParameters);
            }

            if (string.IsNullOrWhiteSpace(correlationIdentifier))
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameCorrelationIdentifier);
            }

            if (null == parameters.AlternateFilters)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            if (string.IsNullOrWhiteSpace(parameters.SchemaIdentifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            string informationAlternateFilterCount = parameters.AlternateFilters.Count.ToString(CultureInfo.InvariantCulture);
            ProvisioningAgentMonitor.Instance.Inform(informationAlternateFilterCount, true, correlationIdentifier);

            if (parameters.AlternateFilters.Count != 1)
            {
                string exceptionMessage =
                    string.Format(
                        CultureInfo.InvariantCulture,
                        ProvisioningAgentResources.ExceptionFilterCountTemplate,
                        1,
                        parameters.AlternateFilters.Count);
                throw new NotSupportedException(exceptionMessage);
            }

            Resource[] results;
            IFilter queryFilter = parameters.AlternateFilters.Single();
            if (queryFilter.AdditionalFilter != null)
            {
                results = await this.QueryReference(parameters, correlationIdentifier);
                return results;
            }

            AmazonWebServicesProvider.Validate(parameters);

            if (string.IsNullOrWhiteSpace(queryFilter.AttributePath))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            if (string.IsNullOrWhiteSpace(queryFilter.ComparisonValue))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            if (!string.Equals(queryFilter.AttributePath, AttributeNames.ExternalIdentifier, StringComparison.Ordinal))
            {
                throw new NotSupportedException(queryFilter.AttributePath);
            }

            IAmazonIdentityManagementService proxy = null;
            try
            {
                proxy = AWSClientFactory.CreateAmazonIdentityManagementServiceClient(this.credentials);            

                switch (parameters.SchemaIdentifier)
                {
                    case SchemaIdentifiers.Core2EnterpriseUser:
                        GetUserRequest getRequestUser =
                            new GetUserRequest()
                                {
                                    UserName = queryFilter.ComparisonValue
                                };
                        GetUserResult responseUser = await proxy.GetUserAsync(getRequestUser);
                        if (null == responseUser.User)
                        {
                            return new Resource[0];
                        }

                        Core2EnterpriseUser resourceUser =
                            new Core2EnterpriseUser()
                            {
                                Identifier = responseUser.User.UserId,
                                ExternalIdentifier = responseUser.User.UserName
                            };
                        Resource[] resourceUsers =
                            new Resource[]
                            {
                                resourceUser
                            };
                        return resourceUsers;

                    case SchemaIdentifiers.WindowsAzureActiveDirectoryGroup:
                        GetGroupRequest getRequestGroup =
                            new GetGroupRequest()
                                {
                                    GroupName = queryFilter.ComparisonValue
                                };
                        GetGroupResult responseGroup = await proxy.GetGroupAsync(getRequestGroup);
                        if (null == responseGroup.Group)
                        {
                            return new Resource[0];
                        }

                        WindowsAzureActiveDirectoryGroup resourceGroup =
                            new WindowsAzureActiveDirectoryGroup()
                            {
                                Identifier = responseGroup.Group.GroupId,
                                ExternalIdentifier = responseGroup.Group.GroupName
                            };
                        Resource[] resourceGroups =
                            new Resource[]
                            {
                                resourceGroup
                            };
                        return resourceGroups;

                    default:
                        throw new NotSupportedException(parameters.SchemaIdentifier);
                }
            }
            finally
            {
                if (proxy != null)
                {
                    proxy.Dispose();
                    proxy = null;
                }
            }
        }
        public override async Task<Resource> Create(
            Resource resource, 
            string correlationIdentifier)
        {
            if (null == resource)
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameResource);
            }

            if (string.IsNullOrWhiteSpace(correlationIdentifier))
            {
                throw new ArgumentNullException(AmazonWebServicesProvider.ArgumentNameCorrelationIdentifier);
            }

            if (string.IsNullOrWhiteSpace(resource.Identifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidResource);
            }

            string informationStarting =
                string.Format(
                    CultureInfo.InvariantCulture,
                    AmazonProvisioningAgentResources.InformationCreating,
                    resource.Identifier);
            ProvisioningAgentMonitor.Instance.Inform(informationStarting, true, correlationIdentifier);

            IAmazonIdentityManagementService proxy = null;
            try
            {
                proxy = AWSClientFactory.CreateAmazonIdentityManagementServiceClient(this.credentials);

                WindowsAzureActiveDirectoryGroup group = resource as WindowsAzureActiveDirectoryGroup;
                if (group != null)
                {
                    CreateGroupRequest request = new CreateGroupRequest(group.ExternalIdentifier);
                    CreateGroupResult response = await proxy.CreateGroupAsync(request);
                    group.Identifier = this.AnchoringBehavior.Identify(response.Group);

                    if (group.Members != null && group.Members.Any())
                    {
                        await this.AddMembers(group.ExternalIdentifier, group.Members, proxy, correlationIdentifier);
                    }

                    return group;
                }

                UserBase user = resource as UserBase;
                if (user != null)
                {
                    CreateUserRequest request = new CreateUserRequest(user.ExternalIdentifier);
                    CreateUserResult response = await proxy.CreateUserAsync(request);
                    user.Identifier = this.AnchoringBehavior.Identify(response.User);
                    return user;
                }

                string unsupportedSchema =
                            string.Join(
                                Environment.NewLine,
                                resource.Schemas);
                throw new NotSupportedException(unsupportedSchema);
            }
            finally
            {
                if (proxy != null)
                {
                    proxy.Dispose();
                    proxy = null;
                }
            }
        }
        private async Task UpdateMembers(Resource resource, IPatch patch)
        {
            if (null == resource)
            {
                throw new ArgumentNullException(FileProvider.ArgumentNameResource);
            }

            if (null == patch)
            {
                throw new ArgumentNullException(FileProvider.ArgumentNamePatch);
            }

            if (null == patch.ResourceIdentifier)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidPatch);
            }

            if (string.IsNullOrWhiteSpace(patch.ResourceIdentifier.Identifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidPatch);
            }

            if (string.IsNullOrWhiteSpace(patch.ResourceIdentifier.SchemaIdentifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidPatch);
            }

            if (null == patch.PatchRequest)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidPatch);
            }

            PatchRequest2 patchRequest = patch.PatchRequest as PatchRequest2;
            if (null == patchRequest)
            {
                string unsupportedPatchTypeName = patch.GetType().FullName;
                throw new NotSupportedException(unsupportedPatchTypeName);
            }

            if
            (
                !FileProvider
                .SchemaIdentifiersGroup
                .Value
                .Any(
                    (string item) =>
                        string.Equals(item, patch.ResourceIdentifier.SchemaIdentifier, StringComparison.Ordinal))
            )
            {
                return;
            }

            IReadOnlyCollection<PatchOperation> memberOperations =
                patchRequest
                .Operations
                .Where(
                    (PatchOperation item) =>
                            item.Path != null
                        && string.Equals(item.Path.AttributePath, AttributeNames.Members, StringComparison.Ordinal))
                .ToArray();
            if (!memberOperations.Any())
            {
                return;
            }

            foreach (PatchOperation memberOperation in memberOperations)
            {
                if (null == memberOperation.Value)
                {
                    continue;
                }
                
                foreach (OperationValue value in memberOperation.Value)
                {
                    if (string.IsNullOrWhiteSpace(value.Value))
                    {
                        continue;
                    }

                    Dictionary<string, string> columnsQuery = 
                        new Dictionary<string,string>()
                            {
                                {
                                    AttributeNames.Schemas,
                                    patch.ResourceIdentifier.SchemaIdentifier
                                },
                                {
                                    AttributeNames.Identifier,
                                    patch.ResourceIdentifier.Identifier
                                },
                                {
                                    AttributeNames.Members,
                                    value.Value
                                }
                            };
                    IRow[] rows = await this.file.Query(columnsQuery);

                    switch (memberOperation.Name)
                    {
                        case OperationName.Add:
                            if (rows.Any())
                            {
                                break;
                            }

                            Member member = 
                                new Member()
                                    {
                                        Value = value.Value
                                    };
                            MemberColumnsFactory memberColumnsFactory = new MemberColumnsFactory(resource, member);
                            IReadOnlyDictionary<string, string> columnsMember = memberColumnsFactory.CreateColumns();
                            await this.file.InsertRow(columnsMember);
                            break;

                        case OperationName.Remove:
                            foreach (IRow row in rows)
                            {
                                await this.file.RemoveRow(row.Key);
                            }

                            break;
                    }
                }
            }
        }
        public override async Task<Resource> Create(Resource resource, string correlationIdentifier)
        {
            if (null == resource)
            {
                throw new ArgumentNullException(FileProvider.ArgumentNameResource);
            }

            if (string.IsNullOrWhiteSpace(correlationIdentifier))
            {
                throw new ArgumentNullException(FileProvider.ArgumentNameCorrelationIdentifier);
            }

            if (string.IsNullOrWhiteSpace(resource.Identifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidResource);
            }

            string informationStarting =
                string.Format(
                    CultureInfo.InvariantCulture,
                    FileProvisioningAgentResources.InformationCreating,
                    resource.Identifier);
            ProvisioningAgentMonitor.Instance.Inform(informationStarting, true, correlationIdentifier);

            ColumnsFactory columnsFactory;

            WindowsAzureActiveDirectoryGroup group = resource as WindowsAzureActiveDirectoryGroup;
            if (group != null)
            {
                columnsFactory = new GroupColumnsFactory(group);
            }
            else
            {
                Core2EnterpriseUser user = resource as Core2EnterpriseUser;
                if (user != null)
                {
                    columnsFactory = new UserColumnsFactory(user);
                }
                else
                {
                    string unsupportedSchema =
                        string.Join(
                            Environment.NewLine,
                            resource.Schemas);
                    throw new NotSupportedException(unsupportedSchema);
                }
            }

            IReadOnlyDictionary<string, string> columns = columnsFactory.CreateColumns();
            IRow row = await this.file.InsertRow(columns);

            ResourceFactory resourceFactory;
            if (group != null)
            {
                resourceFactory = new GroupFactory(row);
            }
            else
            {
                resourceFactory = new UserFactory(row);
            }

            Resource result = resourceFactory.CreateResource();

            if (group != null && group.Members != null && group.Members.Any())
            {
                foreach (Member member in group.Members)
                {
                    MemberColumnsFactory memberColumnsFactory = new MemberColumnsFactory(result, member);
                    IReadOnlyDictionary<string, string> memberColumns = memberColumnsFactory.CreateColumns();
                    await this.file.InsertRow(memberColumns);
                }
            }

            return result;
        }
        private async Task<Resource[]> QueryReference(IQueryParameters parameters, string correlationIdentifier)
        {
            if (null == parameters)
            {
                throw new ArgumentNullException(FileProvider.ArgumentNameParameters);
            }

            if (string.IsNullOrWhiteSpace(correlationIdentifier))
            {
                throw new ArgumentNullException(FileProvider.ArgumentNameCorrelationIdentifier);
            }

            if (null == parameters.RequestedAttributePaths || !parameters.RequestedAttributePaths.Any())
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            string selectedAttribute = parameters.RequestedAttributePaths.SingleOrDefault();
            if (string.IsNullOrWhiteSpace(selectedAttribute))
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }
            ProvisioningAgentMonitor.Instance.Inform(selectedAttribute, true, correlationIdentifier);

            if
            (
                !string.Equals(
                    selectedAttribute,
                    Microsoft.SystemForCrossDomainIdentityManagement.AttributeNames.Identifier,
                    StringComparison.OrdinalIgnoreCase)
            )
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            if (null == parameters.AlternateFilters)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            if (string.IsNullOrWhiteSpace(parameters.SchemaIdentifier))
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            string informationAlternateFilterCount = parameters.AlternateFilters.Count.ToString(CultureInfo.InvariantCulture);
            ProvisioningAgentMonitor.Instance.Inform(informationAlternateFilterCount, true, correlationIdentifier);
            if (parameters.AlternateFilters.Count != 1)
            {
                string exceptionMessage =
                    string.Format(
                        CultureInfo.InvariantCulture,
                        ProvisioningAgentResources.ExceptionFilterCountTemplate,
                        1,
                        parameters.AlternateFilters.Count);
                throw new NotSupportedException(exceptionMessage);
            }

            IReadOnlyCollection<string> requestedColumns = this.IdentifyRequestedColumns(parameters);

            IFilter filterPrimary = parameters.AlternateFilters.Single();
            if (null == filterPrimary.AdditionalFilter)
            {
                throw new ArgumentException(ProvisioningAgentResources.ExceptionInvalidParameters);
            }

            IFilter filterAdditional = filterPrimary.AdditionalFilter;

            if (filterAdditional.AdditionalFilter != null)
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            IReadOnlyCollection<IFilter> filters =
                new IFilter[]
                    {
                        filterPrimary,
                        filterAdditional
                    };

            IFilter filterIdentifier =
                filters
                .SingleOrDefault(
                    (IFilter item) =>
                        string.Equals(
                            AttributeNames.Identifier,
                            item.AttributePath,
                            StringComparison.OrdinalIgnoreCase));
            if (null == filterIdentifier)
            {
                throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
            }

            IRow row;
            IFilter filterReference =
                filters
                .SingleOrDefault(
                    (IFilter item) =>
                            string.Equals(
                                AttributeNames.Members,
                                item.AttributePath,
                                StringComparison.OrdinalIgnoreCase));
            if (filterReference != null)
            {
                Dictionary<string, string> columns =
                new Dictionary<string, string>()
                    {
                        {
                            AttributeNames.Schemas,
                            parameters.SchemaIdentifier
                        },
                        {
                            AttributeNames.Identifier,
                            filterIdentifier.ComparisonValue
                        },
                        {
                            filterReference.AttributePath,
                            filterReference.ComparisonValue
                        }
                    };

                IReadOnlyCollection<IRow> rows = await this.file.Query(columns);
                if (null == rows || !rows.Any())
                {
                    return new Resource[0];
                }

                row = await this.file.ReadRow(filterIdentifier.ComparisonValue);
            }
            else
            {
                filterReference =
                    filters
                    .SingleOrDefault(
                        (IFilter item) =>
                                string.Equals(
                                    AttributeNames.Manager,
                                    item.AttributePath,
                                    StringComparison.OrdinalIgnoreCase));
                if (null == filterReference)
                {
                    throw new NotSupportedException(ProvisioningAgentResources.ExceptionUnsupportedQuery);
                }

                row = await this.file.ReadRow(filterIdentifier.ComparisonValue);
                if
                (
                        null == row.Columns
                    || !row
                        .Columns
                        .Any(
                            (KeyValuePair<string, string> columnItem) =>
                                    string.Equals(columnItem.Key, filterReference.AttributePath, StringComparison.Ordinal)
                                && string.Equals(columnItem.Value, filterReference.ComparisonValue, StringComparison.Ordinal))
                )
                {
                    return new Resource[0];
                }
            }

            string rowSchema = null;
            if
            (
                    !row.Columns.TryGetValue(AttributeNames.Schemas, out rowSchema)
                || !string.Equals(rowSchema, parameters.SchemaIdentifier, StringComparison.Ordinal)
            )
            {
                return new Resource[0];
            }

            IRow reducedRow = FileProvider.FilterColumns(row, requestedColumns);

            ResourceFactory resourceFactory;
            switch (rowSchema)
            {
                case SchemaIdentifiers.Core2EnterpriseUser:
                    resourceFactory = new UserFactory(reducedRow);
                    break;
                case SchemaIdentifiers.WindowsAzureActiveDirectoryGroup:
                    resourceFactory = new GroupFactory(reducedRow);
                    break;
                default:
                    throw new NotSupportedException(parameters.SchemaIdentifier);
            }

            Resource resource = resourceFactory.CreateResource();
            Resource[] results =
                new Resource[]
                {
                    resource
                };
            return results;
        }