Main Page | Class Hierarchy | Class List | File List | Class Members

PendingRequests.cs

00001 using System;
00002 using System.Collections;
00003 using System.Threading;
00004 using Common;
00005 
00006 
00007 namespace Client {
00011         public class PendingRequest     {
00012 
00013                 class WaitingRequest {
00014                         public Message messageToSend;
00015                         public IResponseHandler responseHandler;
00016                         public DateTime timeRequested;
00017 
00018                         public WaitingRequest(Message messageToSend, IResponseHandler responseHandler) {
00019                                 this.messageToSend = messageToSend;
00020                                 this.responseHandler = responseHandler;
00021                                 this.timeRequested = DateTime.MinValue;
00022                         }
00023 
00024                         public bool HasExpired {
00025                                 // TODO: Change Timeout to work from registry settings
00026                                 get { return (timeRequested == DateTime.MinValue) ? false :  (DateTime.Now - timeRequested) >= TimeSpan.FromSeconds(90); }
00027                         }
00028                 }
00029 
00030                 
00031                 protected Uri requestUri; // uri of pending request
00032                 private ArrayList waitingList; // list of requests waiting
00033                 PendingRequestManager manager;
00034                 protected Timer expiryTimer;
00035 
00040                 public PendingRequest(Uri uri, PendingRequestManager manager) {
00041                         this.requestUri = uri;
00042                         this.manager = manager;
00043                         waitingList = new ArrayList();
00044                         expiryTimer = new Timer(new TimerCallback(CheckForExpiry), null, 5 * 1000, 5* 1000); // timer starts after 5 seconds thru 3rd parameter
00045                 }
00046 
00053                 public PendingRequest(Uri uri, PendingRequestManager manager, Message messageToSend, IResponseHandler handler) : this(uri, manager) {
00054                         AddRequestToWaitingList(messageToSend, handler);
00055                 }
00056 
00061                 public void AddRequestToWaitingList(Message messageToSend, IResponseHandler responseHandler) {
00062                         lock (this) {
00063                                 ArrayList.Synchronized(waitingList).Add(new WaitingRequest(messageToSend, responseHandler));
00064                         }
00065                 }
00066 
00067                 public void ProcessWaitingList(Message response) {
00068                         lock (this) {
00069                                 try {
00070                                         foreach (object o in ArrayList.Synchronized(waitingList)) {
00071                                                 WaitingRequest waitingRequest = (WaitingRequest)o;
00072                                                 waitingRequest.responseHandler.Handle(response);
00073                                         }
00074                                         waitingList.Clear();
00075                                 } catch (InvalidOperationException invOpEx) {
00076                                         manager.msgLog.LogError("{0}\r\nClearing Waiting list to recover..", invOpEx);
00077                                         waitingList.Clear();
00078                                 } // end try .. catch
00079                         } // end while
00080                 }
00081 
00082                 protected void CheckForExpiry(object obj) {
00083                         bool done = false;
00084                         lock (this) {
00085                                 while (!done) {
00086                                         try {
00087                                                 foreach (object o in waitingList) {
00088                                                         WaitingRequest waitingRequest = (WaitingRequest)o;
00089                                                         if (waitingRequest.HasExpired) {
00090                                                                 manager.msgLog.Log("Request Timeout: Have been waiting over 90 seconds for {0}", requestUri);
00091                                                                 // TODO: We may want to send 'request timed out' after all messages tried rather than remove an entry on failure.
00092                                                                 // RemoveTopRequest();
00093                                                                 SendNextRequest();
00094                                                         }
00095                                                 }
00096                                                 done = true;
00097                         
00098                                         } catch (InvalidOperationException invOpEx) {
00099                                                 manager.msgLog.LogError("{0}", invOpEx);
00100                                                 done = false;
00101                                         } // end try .. catch
00102                                 } // end while
00103                         }
00104                 }
00105 
00110                 private PendingRequest.WaitingRequest GetNextWaiting() {
00111                         return (WaitingRequest)waitingList[0];
00112                 }
00113 
00117                 public void RemoveTopRequest(){
00118                         lock (this) {
00119                                 if (waitingList.Count > 0) {
00120                                         waitingList.RemoveAt(0);
00121                                         manager.msgLog.Log("Removed top request for {0}, {1} remaining", requestUri, Count);
00122                                 } else {
00123                                         manager.msgLog.Log("No complete requests to remove top of pending request {0}", requestUri);
00124                                 }
00125                         }
00126                 }
00127 
00128                 public int Count {
00129                         get { return waitingList.Count; }
00130 
00131                 }
00132                 public void SendNextRequest() {
00133                         lock (this) {
00134                                 if (Count > 0) {
00135                                         WaitingRequest wr = GetNextWaiting();
00136                                         wr.timeRequested = DateTime.Now;
00137                                         manager.msgLog.LogSend("{0} for {1} sent to server", wr.messageToSend.GetType().Name, requestUri);
00138                                         // TODO: Alter message so it is flagged as resend
00139                                         manager.clientControl.serverStub.toServerMsgQ.EnqueueBlocking(wr.messageToSend);
00140                                 } else {
00141                                         manager.msgLog.Log("No more requests for {0} pending", requestUri);
00142                                         RemoveSelf();
00143                                 }
00144                         }
00145                 }
00146                 
00147 
00148                 void RemoveSelf() {
00149                         manager.msgLog.Log("Self-Removing {0} from pending requests list", requestUri);
00150                         lock (manager.pendingRequests.SyncRoot) {
00151                                 Hashtable.Synchronized(manager.pendingRequests).Remove(requestUri);
00152                         }
00153                 }
00154 
00155         }
00156 
00157         
00161         public class PendingRequestManager {
00162                 internal Hashtable pendingRequests;
00163                 public ClientControl clientControl;
00164                 public MessageLogger msgLog;
00165                 
00166                 public PendingRequestManager(ClientControl clientControl) {
00167                         pendingRequests = new Hashtable();
00168                         this.clientControl = clientControl;
00169                         this.msgLog = clientControl.msgLog;
00170                 }
00171 
00177                 bool RequestIsPending(Uri uri) {
00178                                 return pendingRequests.Contains(uri);
00179                 }
00180 
00181                 public void ServiceRequest(Uri uri, Message messageToSend, IResponseHandler handler) {
00182                         if (clientControl.settings.PendingRequestsEnabled) {
00183                                 lock (pendingRequests.SyncRoot) {
00184                                         // TODO: Check for Pragma: no-cache
00185                                         if (RequestIsPending(uri)) {
00186                                                 msgLog.Log("Request for {0} is pending, adding to waiting list", uri);
00187                                                 AddToPendingRequest(uri, messageToSend, handler);
00188                                         } else { 
00189                                                 msgLog.Log("Request for {0} is not pending, creating pending request and sending to server", uri);
00190                                                 CreatePendingRequest(uri, messageToSend, handler); 
00191                                                 // send on the request here
00192                                                 ((PendingRequest)pendingRequests[uri]).SendNextRequest();
00193                                         }
00194                                 }
00195                         } else { // pending request not enabled
00196                                 clientControl.serverStub.toServerMsgQ.EnqueueBlocking(messageToSend);
00197                         }
00198                 }
00199 
00205                 void CreatePendingRequest(Uri uri) {
00206                         lock (pendingRequests.SyncRoot) {
00207                                 pendingRequests.Add(uri, new PendingRequest(uri, this));
00208                         }
00209                 }
00210 
00217                 void CreatePendingRequest(Uri uri, Message messageToSend, IResponseHandler handler) {
00218                         lock (pendingRequests.SyncRoot) {
00219                                 pendingRequests.Add(uri, new PendingRequest(uri, this, messageToSend, handler));
00220                         }
00221                 }
00222 
00223                 void AddToPendingRequest(Uri uri, Message messageToSend, IResponseHandler handler) {
00224                         PendingRequest myPendingRequest = (PendingRequest)pendingRequests[uri];
00225                         lock (myPendingRequest) {
00226                                 myPendingRequest.AddRequestToWaitingList(messageToSend, handler);
00227                         }
00228                 }
00229 
00230                 public void HandleRemainingRequests(Uri uri, Message responseMsg, bool haveJustHandledRequestInQueue) {
00231                         if (clientControl.settings.PendingRequestsEnabled) {
00232                                 lock (pendingRequests.SyncRoot) {
00233                                         if (pendingRequests.Contains(uri)) {
00234                                                 // remove the top item that should have been handled pre-call.
00235                                                 PendingRequest myPendingRequest = (PendingRequest)pendingRequests[uri];
00236                                                 lock (myPendingRequest) {
00237                                                         // TODO: Figure out if we want that next line or not: enumerate conditions of arrival / pending.
00238                                                         if (haveJustHandledRequestInQueue) {
00239                                                                 myPendingRequest.RemoveTopRequest();
00240                                                         }
00241                                                         myPendingRequest.ProcessWaitingList(responseMsg);
00242                                                         if (myPendingRequest.Count == 0) {
00243                                                                 pendingRequests.Remove(uri);
00244                                                                 msgLog.Log("Removed pending request holder for {0}", uri);
00245                                                         } else {
00246                                                                 msgLog.LogError("Expected {0} pending requests to be empty. It has {1} entries. Cannot delete", uri, ((PendingRequest)pendingRequests[uri]).Count);
00247                                                         }
00248                                                 }
00249                                         } else {
00250                                                 msgLog.Log("No pending request holder for {0}, nothing to do", uri);
00251                                         }
00252                                 }
00253                         } else { // pending requests not enabled
00254                                 /* do nothing */
00255                         }
00256                 }
00257         
00258 
00264                 public void AddPlaceholders(Uri[] requestUris) {
00265                         lock (pendingRequests.SyncRoot) {
00266                                 foreach (Uri currentUri in requestUris) {
00267                                         if (currentUri != null) {
00268                                                 if (RequestIsPending(currentUri)) {
00269                                                         // no-op, we just wait until it arrives
00270                                                         msgLog.Log("We already have a pending request for the placeholder for {0}", currentUri);
00271                                                 } else {
00272                                                         CreatePendingRequest(currentUri);
00273                                                 }
00274                                         }
00275                                 }
00276                                 msgLog.Log("Pending requests have been entered for {0} pushed URIs", requestUris.Length);
00277                         }
00278                 }
00279         }
00280 }

Generated on Mon May 8 22:07:27 2006 by  doxygen 1.3.9.1