/// <summary>
        /// Starts the HTTP streaming connection to the Couchbase Server and gets the latest configuration for a SASL authenticated Bucket.
        /// </summary>
        /// <param name="bucketName">The name of the Couchbase Bucket.</param>
        /// <param name="password">The SASL password used to connect to the Bucket.</param>
        /// <returns>A <see cref="IConfigInfo"/> object representing the latest configuration.</returns>
        public override IConfigInfo GetConfig(string bucketName, string password)
        {
            var bucketConfiguration = GetOrCreateConfiguration(bucketName);
            StartProvider(bucketName, password);
            var bucketConfig = GetBucketConfig(bucketName, password);

            try
            {
                ConfigLock.EnterWriteLock();
                IConfigInfo configInfo = null;
                var nodes = bucketConfig.Nodes.ToList();
                while (nodes.Any())
                {
                    try
                    {
                        nodes.Shuffle();
                        var node = nodes.First();
                        nodes.Remove(node);

                        IBucketConfig newConfig;
                        var uri = bucketConfig.GetTerseUri(node, bucketConfiguration.UseSsl);

                        using (new SynchronizationContextExclusion())
                        {
                            using (var httpClient = new CouchbaseHttpClient(bucketName, password))
                            {
                                var body = httpClient.GetStringAsync(uri).Result;
                                body = body.Replace("$HOST", uri.Host);
                                newConfig = JsonConvert.DeserializeObject<BucketConfig>(body);
                            }
                        }

                        newConfig.Password = password;
                        configInfo = CreateConfigInfo(newConfig);
                        Configs[bucketName] = configInfo;
                        break;

                    }
                    catch (AggregateException e)
                    {
                        Log.Error(e.InnerException);
                    }
                    catch (IOException e)
                    {
                        Log.Error(e);
                    }
                }

                if (configInfo == null)
                {
                    throw new BucketNotFoundException();
                }
                return configInfo;
            }
            finally
            {
                ConfigLock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Starts the streaming connection to couchbase server that will
        /// listen for configuration changes and then update the client as needed.
        /// </summary>
        /// <remarks>
        /// Should not be used when a <see cref="SynchronizationContext" /> is present on the thread, as this
        /// could cause deadlocks.  This method is currently only used from within a dedicated thread,
        /// created by <see cref="HttpStreamingProvider.RegisterObserver"/>, so it is safe because there will not
        /// be a SynchronizationContext present on the thread.
        /// </remarks>
        public void ListenForConfigChanges()
        {
            var count = 0;

            //Make a copy of the nodes and shuffle them for randomness
            var nodes = _bucketConfig.Nodes.ToList();

            using (var httpClient = new CouchbaseHttpClient(_bucketConfig.Name, _bucketConfig.Password))
            {
                httpClient.Timeout = Timeout.InfiniteTimeSpan;

                //This will keep trying until it runs out of servers to try in the cluster
                while (nodes.ToList().Any())
                {
                    try
                    {
                        //If the main thread has canceled, break out of the loop otherwise
                        //the next node in the server list will be tried; but in this case
                        //we want to shut things down and terminate the thread
                        if (_cancellationToken.IsCancellationRequested)
                        {
                            break;
                        }
                        nodes = nodes.Shuffle();
                        var node = nodes[0];
                        nodes.Remove(node);

                        var streamingUri = _bucketConfig.GetTerseStreamingUri(node, _bucketConfig.UseSsl);
                        Log.Info(m => m("Listening to {0}", streamingUri));

                        var response =
                            httpClient.GetAsync(streamingUri, HttpCompletionOption.ResponseHeadersRead,
                                _cancellationToken)
                                .Result;
                        response.EnsureSuccessStatusCode();

                        using (var stream = response.Content.ReadAsStreamAsync().Result)
                        {
                            //this will cancel the infinite wait below
                            _cancellationToken.Register(stream.Dispose);

                            stream.ReadTimeout = Timeout.Infinite;

                            using (var reader = new StreamReader(stream, Encoding.UTF8, false))
                            {
                                string config;
                                while (!_cancellationToken.IsCancellationRequested &&
                                       ((config = reader.ReadLineAsync().Result) != null))
                                {
                                    if (config != String.Empty)
                                    {
                                        Log.Info(m => m("configuration changed count: {0}", count++));
                                        Log.Info(m => m("Worker Thread: {0}", Thread.CurrentThread.ManagedThreadId));
                                        var config1 = config;
                                        Log.Debug(m => m("{0}", config1));

                                        config = config.Replace("$HOST", streamingUri.Host);
                                        var bucketConfig = JsonConvert.DeserializeObject<BucketConfig>(config);
                                        bucketConfig.SurrogateHost = GetSurrogateHost(streamingUri);
                                        if (_configChangedDelegate != null)
                                        {
                                            bucketConfig.Password = _bucketConfig.Password;
                                            _configChangedDelegate(bucketConfig);
                                        }
                                    }
                                }
                            }
                        }

                    }
                    catch (AggregateException e)
                    {
                        var exceptions = e.Flatten().InnerExceptions;
                        if (exceptions.OfType<ObjectDisposedException>().Any())
                        {
                            Log.Info("The config listener has shut down.");
                        }
                        foreach (var ex in exceptions.Where(x => x.GetType() != typeof(ObjectDisposedException)))
                        {
                            Log.Error(ex);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Error(e);
                    }
                }
            }

            //We tried all nodes in the current configuration, alert the provider that we
            //need to try to re-bootstrap from the beginning
            if (nodes.Count == 0)
            {
                _errorOccurredDelegate(_bucketConfig);
            }
        }