/// <summary> /// Enqueue changes. /// </summary> /// <param name="entries">Changes to process.</param> public void AddToQueue(List <SearchResultEntry> entries) { if ((entries != null) && entries.Any()) { lock (mQueueLock) { // Add items to query Queue.AddRange(entries); // Sort query by uSNChanged and process users first Queue.Sort((a, b) => { if (LdapHelper.IsUser(a) ^ LdapHelper.IsUser(b)) { return(LdapHelper.IsUser(a) ? -1 : 1); } return(LdapHelper.GetUsnChanged(a).CompareTo(LdapHelper.GetUsnChanged(b))); }); // Start sending changes if (DispatchAllowed && !DispatchRunning) { DispatchRunning = true; Task.Factory.StartNew(SendChanges, TaskCreationOptions.LongRunning); } } } }
/// <summary> /// Send changes to CMS one-by-one. /// </summary> private void SendChanges() { // Re-enumerate queue in each iteration while (Queue.Any() && DispatchAllowed) { lock (mQueueLock) { try { if (Replica == null) { LoadDirecotryReplica(); } // Process first entry var entry = Queue.First(); if (entry == null) { // Remove all nulls Queue.RemoveAll(e => e == null); continue; } // Handle incoming change if (LdapHelper.IsUser(entry)) { HandleUser(entry); } else if (LdapHelper.IsGroup(entry)) { HandleGroup(entry); } Queue.Remove(entry); // Set actual uSNChanged attribute long newUsn = LdapHelper.GetUsnChanged(entry); if ((Replica != null) && (Replica.HighestUsnChanged < newUsn)) { Replica.HighestUsnChanged = newUsn; } SaveDirecotryReplica(); } catch (Exception ex) { LogError("Exception occurred when processing object.", ex); } } } DispatchRunning = false; }
/// <summary> /// Asynchronous callback that processes changes from Active Directory. /// </summary> /// <param name="asyncResult">Result of permanens search</param> private void RunAsyncSearch(IAsyncResult asyncResult) { var results = new List <SearchResultEntry>(); // Get changes if (!asyncResult.IsCompleted) { PartialResultsCollection partialResults = null; try { partialResults = Connection.GetPartialResults(asyncResult); } catch (Exception e) { LogError("Retrieving partial results from Active Directory asynchronous search failed.", e); } if (partialResults != null) { // Add only users and groups results.AddRange(partialResults.OfType <SearchResultEntry>().Where(p => LdapHelper.IsUser(p, PersonObjectCategory) || LdapHelper.IsGroup(p, GroupObjectCategory))); } } else { LogMessage("The change notification control unexpectedly ended the search."); mSearches.Remove(asyncResult); StartIncrementalSynchronization(); } // Send changes to CMS Dispatcher.AddToQueue(results); }
/// <summary> /// Retrieves current state of LDAP database and reflects it to the CMS. /// </summary> public void Synchronize() { try { var request = new SearchRequest(DefaultNamingContext, "(&(|(objectClass=user)(objectClass=group))(usnchanged>=" + (Dispatcher.HighestUsnChanged + 1) + "))", SearchScope.Subtree, null); request.Controls.Add(new ShowDeletedControl()); // Page result var prc = new PageResultRequestControl(5); request.Controls.Add(prc); var soc = new SearchOptionsControl(System.DirectoryServices.Protocols.SearchOption.DomainScope); request.Controls.Add(soc); while (true) { var searchResponse = (SearchResponse)Connection.SendRequest(request); if (searchResponse != null) { // Find the returned page response control foreach (DirectoryControl control in searchResponse.Controls) { if (control is PageResultResponseControl) { //update the cookie for next set prc.Cookie = ((PageResultResponseControl)control).Cookie; break; } } Dispatcher.AddToQueue(searchResponse.Entries.Cast <SearchResultEntry>().Where(p => LdapHelper.IsUser(p, PersonObjectCategory) || LdapHelper.IsGroup(p, GroupObjectCategory)).ToList()); if (prc.Cookie.Length == 0) { break; } } else { break; } } } catch (Exception ex) { LogError("Full synchronization failed.", ex); } }