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);
 }
示例#2
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(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);
        }