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
00026 get { return (timeRequested == DateTime.MinValue) ? false : (DateTime.Now - timeRequested) >= TimeSpan.FromSeconds(90); }
00027 }
00028 }
00029
00030
00031 protected Uri requestUri;
00032 private ArrayList waitingList;
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);
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 }
00079 }
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
00092
00093 SendNextRequest();
00094 }
00095 }
00096 done = true;
00097
00098 } catch (InvalidOperationException invOpEx) {
00099 manager.msgLog.LogError("{0}", invOpEx);
00100 done = false;
00101 }
00102 }
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
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
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
00192 ((PendingRequest)pendingRequests[uri]).SendNextRequest();
00193 }
00194 }
00195 } else {
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
00235 PendingRequest myPendingRequest = (PendingRequest)pendingRequests[uri];
00236 lock (myPendingRequest) {
00237
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 {
00254
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
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 }