Example #1
0
        public virtual void Run()
        {
            running = true;
            HttpClient httpClient;

            if (client == null)
            {
                // This is a race condition that can be reproduced by calling cbpuller.start() and cbpuller.stop()
                // directly afterwards.  What happens is that by the time the Changetracker thread fires up,
                // the cbpuller has already set this.client to null.  See issue #109
                Log.W(Database.Tag, this + ": ChangeTracker run() loop aborting because client == null"
                      );
                return;
            }
            if (mode == ChangeTracker.ChangeTrackerMode.Continuous)
            {
                // there is a failing unit test for this, and from looking at the code the Replication
                // object will never use Continuous mode anyway.  Explicitly prevent its use until
                // it is demonstrated to actually work.
                throw new RuntimeException("ChangeTracker does not correctly support continuous mode"
                                           );
            }
            httpClient = client.GetHttpClient();
            backoff    = new ChangeTrackerBackoff();
            while (running)
            {
                Uri url = GetChangesFeedURL();
                request = new HttpGet(url.ToString());
                AddRequestHeaders(request);
                // if the URL contains user info AND if this a DefaultHttpClient
                // then preemptively set the auth credentials
                if (url.GetUserInfo() != null)
                {
                    Log.V(Database.Tag, this + ": url.getUserInfo(): " + url.GetUserInfo());
                    if (url.GetUserInfo().Contains(":") && !url.GetUserInfo().Trim().Equals(":"))
                    {
                        string[]    userInfoSplit = url.GetUserInfo().Split(":");
                        Credentials creds         = new UsernamePasswordCredentials(URIUtils.Decode(userInfoSplit
                                                                                                    [0]), URIUtils.Decode(userInfoSplit[1]));
                        if (httpClient is DefaultHttpClient)
                        {
                            DefaultHttpClient        dhc            = (DefaultHttpClient)httpClient;
                            MessageProcessingHandler preemptiveAuth = new _MessageProcessingHandler_221(creds
                                                                                                        );
                            dhc.AddRequestInterceptor(preemptiveAuth, 0);
                        }
                    }
                    else
                    {
                        Log.W(Database.Tag, this + ": ChangeTracker Unable to parse user info, not setting credentials"
                              );
                    }
                }
                try
                {
                    string maskedRemoteWithoutCredentials = GetChangesFeedURL().ToString();
                    maskedRemoteWithoutCredentials = maskedRemoteWithoutCredentials.ReplaceAll("://.*:.*@"
                                                                                               , "://---:---@");
                    Log.V(Database.Tag, this + ": Making request to " + maskedRemoteWithoutCredentials
                          );
                    HttpResponse response = httpClient.Execute(request);
                    StatusLine   status   = response.GetStatusLine();
                    if (status.GetStatusCode() >= 300)
                    {
                        Log.E(Database.Tag, this + ": Change tracker got error " + Sharpen.Extensions.ToString
                                  (status.GetStatusCode()));
                        string msg = string.Format(status.ToString());
                        this.error = new CouchbaseLiteException(msg, new Status(status.GetStatusCode()));
                        Stop();
                    }
                    HttpEntity  entity = response.GetEntity();
                    InputStream input  = null;
                    if (entity != null)
                    {
                        try
                        {
                            input = entity.GetContent();
                            if (mode == ChangeTracker.ChangeTrackerMode.LongPoll)
                            {
                                // continuous replications
                                IDictionary <string, object> fullBody = Manager.GetObjectMapper().ReadValue <IDictionary
                                                                                                             >(input);
                                bool responseOK = ReceivedPollResponse(fullBody);
                                if (mode == ChangeTracker.ChangeTrackerMode.LongPoll && responseOK)
                                {
                                    Log.V(Database.Tag, this + ": Starting new longpoll");
                                    backoff.ResetBackoff();
                                    continue;
                                }
                                else
                                {
                                    Log.W(Database.Tag, this + ": Change tracker calling stop (LongPoll)");
                                    Stop();
                                }
                            }
                            else
                            {
                                // one-shot replications
                                JsonFactory jsonFactory = Manager.GetObjectMapper().GetJsonFactory();
                                JsonParser  jp          = jsonFactory.CreateJsonParser(input);
                                while (jp.NextToken() != JsonToken.StartArray)
                                {
                                }
                                // ignore these tokens
                                while (jp.NextToken() == JsonToken.StartObject)
                                {
                                    IDictionary <string, object> change = (IDictionary)Manager.GetObjectMapper().ReadValue
                                                                          <IDictionary>(jp);
                                    if (!ReceivedChange(change))
                                    {
                                        Log.W(Database.Tag, string.Format("Received unparseable change line from server: %s"
                                                                          , change));
                                    }
                                }
                                Log.W(Database.Tag, this + ": Change tracker calling stop (OneShot)");
                                Stop();
                                break;
                            }
                            backoff.ResetBackoff();
                        }
                        finally
                        {
                            try
                            {
                                entity.ConsumeContent();
                            }
                            catch (IOException)
                            {
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    if (!running && e is IOException)
                    {
                    }
                    else
                    {
                        // in this case, just silently absorb the exception because it
                        // frequently happens when we're shutting down and have to
                        // close the socket underneath our read.
                        Log.E(Database.Tag, this + ": Exception in change tracker", e);
                    }
                    backoff.SleepAppropriateAmountOfTime();
                }
            }
            Log.V(Database.Tag, this + ": Change tracker run loop exiting");
        }
        public virtual void Run()
        {
            running = true;
            HttpClient httpClient;

            if (client == null)
            {
                // This is a race condition that can be reproduced by calling cbpuller.start() and cbpuller.stop()
                // directly afterwards.  What happens is that by the time the Changetracker thread fires up,
                // the cbpuller has already set this.client to null.  See issue #109
                Log.W(Log.TagChangeTracker, "%s: ChangeTracker run() loop aborting because client == null"
                      , this);
                return;
            }
            if (mode == ChangeTracker.ChangeTrackerMode.Continuous)
            {
                // there is a failing unit test for this, and from looking at the code the Replication
                // object will never use Continuous mode anyway.  Explicitly prevent its use until
                // it is demonstrated to actually work.
                throw new RuntimeException("ChangeTracker does not correctly support continuous mode"
                                           );
            }
            httpClient = client.GetHttpClient();
            backoff    = new ChangeTrackerBackoff();
            while (running)
            {
                Uri url = GetChangesFeedURL();
                if (usePOST)
                {
                    HttpPost postRequest = new HttpPost(url.ToString());
                    postRequest.SetHeader("Content-Type", "application/json");
                    StringEntity entity;
                    try
                    {
                        entity = new StringEntity(ChangesFeedPOSTBody());
                    }
                    catch (UnsupportedEncodingException e)
                    {
                        throw new RuntimeException(e);
                    }
                    postRequest.SetEntity(entity);
                    request = postRequest;
                }
                else
                {
                    request = new HttpGet(url.ToString());
                }
                AddRequestHeaders(request);
                // Perform BASIC Authentication if needed
                bool isUrlBasedUserInfo = false;
                // If the URL contains user info AND if this a DefaultHttpClient then preemptively set the auth credentials
                string userInfo = url.GetUserInfo();
                if (userInfo != null)
                {
                    isUrlBasedUserInfo = true;
                }
                else
                {
                    if (authenticator != null)
                    {
                        AuthenticatorImpl auth = (AuthenticatorImpl)authenticator;
                        userInfo = auth.AuthUserInfo();
                    }
                }
                if (userInfo != null)
                {
                    if (userInfo.Contains(":") && !userInfo.Trim().Equals(":"))
                    {
                        string[] userInfoElements = userInfo.Split(":");
                        string   username         = isUrlBasedUserInfo ? URIUtils.Decode(userInfoElements[0]) : userInfoElements
                                                    [0];
                        string password = isUrlBasedUserInfo ? URIUtils.Decode(userInfoElements[1]) : userInfoElements
                                          [1];
                        Credentials credentials = new UsernamePasswordCredentials(username, password);
                        if (httpClient is DefaultHttpClient)
                        {
                            DefaultHttpClient        dhc            = (DefaultHttpClient)httpClient;
                            MessageProcessingHandler preemptiveAuth = new _MessageProcessingHandler_285(credentials
                                                                                                        );
                            dhc.AddRequestInterceptor(preemptiveAuth, 0);
                        }
                    }
                    else
                    {
                        Log.W(Log.TagChangeTracker, "RemoteRequest Unable to parse user info, not setting credentials"
                              );
                    }
                }
                try
                {
                    string maskedRemoteWithoutCredentials = GetChangesFeedURL().ToString();
                    maskedRemoteWithoutCredentials = maskedRemoteWithoutCredentials.ReplaceAll("://.*:.*@"
                                                                                               , "://---:---@");
                    Log.V(Log.TagChangeTracker, "%s: Making request to %s", this, maskedRemoteWithoutCredentials
                          );
                    HttpResponse response = httpClient.Execute(request);
                    StatusLine   status   = response.GetStatusLine();
                    if (status.GetStatusCode() >= 300 && !Utils.IsTransientError(status))
                    {
                        Log.E(Log.TagChangeTracker, "%s: Change tracker got error %d", this, status.GetStatusCode
                                  ());
                        this.error = new HttpResponseException(status.GetStatusCode(), status.GetReasonPhrase
                                                                   ());
                        Stop();
                    }
                    HttpEntity  entity = response.GetEntity();
                    InputStream input  = null;
                    if (entity != null)
                    {
                        try
                        {
                            input = entity.GetContent();
                            if (mode == ChangeTracker.ChangeTrackerMode.LongPoll)
                            {
                                // continuous replications
                                IDictionary <string, object> fullBody = Manager.GetObjectMapper().ReadValue <IDictionary
                                                                                                             >(input);
                                bool responseOK = ReceivedPollResponse(fullBody);
                                if (mode == ChangeTracker.ChangeTrackerMode.LongPoll && responseOK)
                                {
                                    Log.V(Log.TagChangeTracker, "%s: Starting new longpoll", this);
                                    backoff.ResetBackoff();
                                    continue;
                                }
                                else
                                {
                                    Log.W(Log.TagChangeTracker, "%s: Change tracker calling stop (LongPoll)", this);
                                    Stop();
                                }
                            }
                            else
                            {
                                // one-shot replications
                                JsonFactory jsonFactory = Manager.GetObjectMapper().GetJsonFactory();
                                JsonParser  jp          = jsonFactory.CreateJsonParser(input);
                                while (jp.NextToken() != JsonToken.StartArray)
                                {
                                }
                                // ignore these tokens
                                while (jp.NextToken() == JsonToken.StartObject)
                                {
                                    IDictionary <string, object> change = (IDictionary)Manager.GetObjectMapper().ReadValue
                                                                          <IDictionary>(jp);
                                    if (!ReceivedChange(change))
                                    {
                                        Log.W(Log.TagChangeTracker, "Received unparseable change line from server: %s", change
                                              );
                                    }
                                }
                                Log.W(Log.TagChangeTracker, "%s: Change tracker calling stop (OneShot)", this);
                                Stop();
                                break;
                            }
                            backoff.ResetBackoff();
                        }
                        finally
                        {
                            try
                            {
                                entity.ConsumeContent();
                            }
                            catch (IOException)
                            {
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    if (!running && e is IOException)
                    {
                    }
                    else
                    {
                        // in this case, just silently absorb the exception because it
                        // frequently happens when we're shutting down and have to
                        // close the socket underneath our read.
                        Log.E(Log.TagChangeTracker, this + ": Exception in change tracker", e);
                    }
                    backoff.SleepAppropriateAmountOfTime();
                }
            }
            Log.V(Log.TagChangeTracker, "%s: Change tracker run loop exiting", this);
        }
 /// <exception cref="System.IO.IOException"></exception>      [System.ObsoleteAttribute(@"(4.1) Either use GetContent() and call System.IO.InputStream.Close() on that; otherwise call WriteTo(System.IO.OutputStream) which is required to free the resources.")]
 public virtual void ConsumeContent()
 {
     wrappedEntity.ConsumeContent();
 }