Back to index

lightning-sunbird  0.9+nobinonly
nsRequestObserverProxy.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@netscape.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nscore.h"
00040 #include "nsRequestObserverProxy.h"
00041 #include "nsIRequest.h"
00042 #include "nsIEventQueueService.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsString.h"
00045 #include "prlog.h"
00046 
00047 #if defined(PR_LOGGING)
00048 static PRLogModuleInfo *gRequestObserverProxyLog;
00049 #endif
00050 
00051 #define LOG(args) PR_LOG(gRequestObserverProxyLog, PR_LOG_DEBUG, args)
00052 
00053 static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
00054 
00055 //-----------------------------------------------------------------------------
00056 // ProxyRelease
00057 //-----------------------------------------------------------------------------
00058 
00059 static void *PR_CALLBACK
00060 ProxyRelease_EventHandlerFunc(PLEvent *ev)
00061 {
00062     nsIRequestObserver *obs =
00063         NS_STATIC_CAST(nsIRequestObserver *, PL_GetEventOwner(ev));
00064     NS_RELEASE(obs);
00065     return nsnull;
00066 }
00067 
00068 static void PR_CALLBACK
00069 ProxyRelease_EventCleanupFunc(PLEvent *ev)
00070 {
00071     delete ev;
00072 }
00073 
00074 static void
00075 ProxyRelease(nsIEventQueue *eventQ, nsIRequestObserver *obs)
00076 {
00077     PLEvent *ev = new PLEvent;
00078     if (!ev) {
00079         NS_ERROR("failed to allocate PLEvent");
00080         return;
00081     }
00082 
00083     PL_InitEvent(ev, (void *) obs,
00084             ProxyRelease_EventHandlerFunc,
00085             ProxyRelease_EventCleanupFunc);
00086 
00087     nsresult rv = eventQ->PostEvent(ev);
00088     NS_ASSERTION(NS_SUCCEEDED(rv), "PostEvent failed");
00089 }
00090 
00091 //-----------------------------------------------------------------------------
00092 // nsARequestObserverEvent internal class...
00093 //-----------------------------------------------------------------------------
00094 
00095 nsARequestObserverEvent::nsARequestObserverEvent(nsIRequest *request,
00096                                                  nsISupports *context)
00097     : mRequest(request)
00098     , mContext(context)
00099 {
00100     NS_PRECONDITION(mRequest, "null pointer");
00101 
00102     PL_InitEvent(&mEvent, nsnull,
00103         (PLHandleEventProc) nsARequestObserverEvent::HandlePLEvent,
00104         (PLDestroyEventProc) nsARequestObserverEvent::DestroyPLEvent);
00105 }
00106 
00107 void PR_CALLBACK
00108 nsARequestObserverEvent::HandlePLEvent(PLEvent *plev)
00109 {
00110     nsARequestObserverEvent *ev = FromPLEvent(plev);
00111     NS_ASSERTION(ev, "null event");
00112 
00113     // Pass control to the real event handler
00114     if (ev)
00115         ev->HandleEvent();
00116 }
00117 
00118 void PR_CALLBACK
00119 nsARequestObserverEvent::DestroyPLEvent(PLEvent *plev)
00120 {
00121     nsARequestObserverEvent *ev = FromPLEvent(plev);
00122     NS_ASSERTION(ev, "null event");
00123     delete ev;
00124 }
00125 
00126 //-----------------------------------------------------------------------------
00127 // nsOnStartRequestEvent internal class...
00128 //-----------------------------------------------------------------------------
00129 
00130 class nsOnStartRequestEvent : public nsARequestObserverEvent
00131 {
00132     nsRequestObserverProxy *mProxy;
00133 public:
00134     nsOnStartRequestEvent(nsRequestObserverProxy *proxy,
00135                           nsIRequest *request,
00136                           nsISupports *context)
00137         : nsARequestObserverEvent(request, context)
00138         , mProxy(proxy)
00139     {
00140         NS_PRECONDITION(mProxy, "null pointer");
00141         MOZ_COUNT_CTOR(nsOnStartRequestEvent);
00142         NS_ADDREF(mProxy);
00143     }
00144 
00145    ~nsOnStartRequestEvent()
00146     {
00147         MOZ_COUNT_DTOR(nsOnStartRequestEvent);
00148         NS_RELEASE(mProxy);
00149     }
00150 
00151     void HandleEvent()
00152     {
00153         LOG(("nsOnStartRequestEvent::HandleEvent [req=%x]\n", mRequest.get()));
00154 
00155         if (!mProxy->mObserver) {
00156             NS_NOTREACHED("already handled onStopRequest event (observer is null)");
00157             return;
00158         }
00159 
00160         LOG(("handle startevent=%8lX\n",(long)this));
00161         nsresult rv = mProxy->mObserver->OnStartRequest(mRequest, mContext);
00162         if (NS_FAILED(rv)) {
00163             LOG(("OnStartRequest failed [rv=%x] canceling request!\n", rv));
00164             rv = mRequest->Cancel(rv);
00165             NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed for request!");
00166         }
00167     }
00168 };
00169 
00170 //-----------------------------------------------------------------------------
00171 // nsOnStopRequestEvent internal class...
00172 //-----------------------------------------------------------------------------
00173 
00174 class nsOnStopRequestEvent : public nsARequestObserverEvent
00175 {
00176     nsRequestObserverProxy *mProxy;
00177 public:
00178     nsOnStopRequestEvent(nsRequestObserverProxy *proxy,
00179                          nsIRequest *request, nsISupports *context)
00180         : nsARequestObserverEvent(request, context)
00181         , mProxy(proxy)
00182     {
00183         NS_PRECONDITION(mProxy, "null pointer");
00184         MOZ_COUNT_CTOR(nsOnStopRequestEvent);
00185         NS_ADDREF(mProxy);
00186     }
00187 
00188    ~nsOnStopRequestEvent()
00189     {
00190         MOZ_COUNT_DTOR(nsOnStopRequestEvent);
00191         NS_RELEASE(mProxy);
00192     }
00193 
00194     void HandleEvent()
00195     {
00196         nsresult rv, status = NS_OK;
00197 
00198         LOG(("nsOnStopRequestEvent::HandleEvent [req=%x]\n", mRequest.get()));
00199 
00200         nsCOMPtr<nsIRequestObserver> observer = mProxy->mObserver;
00201         if (!observer) {
00202             NS_NOTREACHED("already handled onStopRequest event (observer is null)");
00203             return;
00204         }
00205         // Do not allow any more events to be handled after OnStopRequest
00206         mProxy->mObserver = 0;
00207 
00208         rv = mRequest->GetStatus(&status);
00209         NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed for request!");
00210 
00211         LOG(("handle stopevent=%8lX\n",(long)this));
00212         (void) observer->OnStopRequest(mRequest, mContext, status);
00213     }
00214 };
00215 
00216 //-----------------------------------------------------------------------------
00217 // nsRequestObserverProxy <public>
00218 //-----------------------------------------------------------------------------
00219 
00220 nsRequestObserverProxy::~nsRequestObserverProxy()
00221 {
00222     if (mObserver) {
00223         // order is crucial here... we must be careful to clear mObserver
00224         // before posting the proxy release event.  otherwise, we'd risk
00225         // releasing the object on this thread.
00226         nsIRequestObserver *obs = mObserver;
00227         NS_ADDREF(obs);
00228         mObserver = 0;
00229         ProxyRelease(mEventQ, obs);
00230     }
00231 }
00232 
00233 //-----------------------------------------------------------------------------
00234 // nsRequestObserverProxy::nsISupports implementation...
00235 //-----------------------------------------------------------------------------
00236 
00237 NS_IMPL_THREADSAFE_ISUPPORTS2(nsRequestObserverProxy,
00238                               nsIRequestObserver,
00239                               nsIRequestObserverProxy)
00240 
00241 //-----------------------------------------------------------------------------
00242 // nsRequestObserverProxy::nsIRequestObserver implementation...
00243 //-----------------------------------------------------------------------------
00244 
00245 NS_IMETHODIMP 
00246 nsRequestObserverProxy::OnStartRequest(nsIRequest *request,
00247                                        nsISupports *context)
00248 {
00249     LOG(("nsRequestObserverProxy::OnStartRequest [this=%x req=%x]\n", this, request));
00250 
00251     nsOnStartRequestEvent *ev = 
00252         new nsOnStartRequestEvent(this, request, context);
00253     if (!ev)
00254         return NS_ERROR_OUT_OF_MEMORY;
00255 
00256     LOG(("post startevent=%8lX queue=%8lX\n",(long)ev,(long)mEventQ.get()));
00257     nsresult rv = FireEvent(ev);
00258     if (NS_FAILED(rv))
00259         delete ev;
00260     return rv;
00261 }
00262 
00263 NS_IMETHODIMP 
00264 nsRequestObserverProxy::OnStopRequest(nsIRequest *request,
00265                                       nsISupports *context,
00266                                       nsresult status)
00267 {
00268     LOG(("nsRequestObserverProxy: OnStopRequest [this=%x req=%x status=%x]\n",
00269         this, request, status));
00270 
00271     // The status argument is ignored because, by the time the OnStopRequestEvent
00272     // is actually processed, the status of the request may have changed :-( 
00273     // To make sure that an accurate status code is always used, GetStatus() is
00274     // called when the OnStopRequestEvent is actually processed (see above).
00275 
00276     nsOnStopRequestEvent *ev = 
00277         new nsOnStopRequestEvent(this, request, context);
00278     if (!ev)
00279         return NS_ERROR_OUT_OF_MEMORY;
00280 
00281     LOG(("post stopevent=%8lX queue=%8lX\n",(long)ev,(long)mEventQ.get()));
00282     nsresult rv = FireEvent(ev);
00283     if (NS_FAILED(rv))
00284         delete ev;
00285     return rv;
00286 }
00287 
00288 //-----------------------------------------------------------------------------
00289 // nsRequestObserverProxy::nsIRequestObserverProxy implementation...
00290 //-----------------------------------------------------------------------------
00291 
00292 NS_IMETHODIMP
00293 nsRequestObserverProxy::Init(nsIRequestObserver *observer,
00294                              nsIEventQueue *eventQ)
00295 {
00296     NS_ENSURE_ARG_POINTER(observer);
00297 
00298 #if defined(PR_LOGGING)
00299     if (!gRequestObserverProxyLog)
00300         gRequestObserverProxyLog = PR_NewLogModule("nsRequestObserverProxy");
00301 #endif
00302 
00303     mObserver = observer;
00304 
00305     return SetEventQueue(eventQ);
00306 }
00307 
00308 //-----------------------------------------------------------------------------
00309 // nsRequestObserverProxy implementation...
00310 //-----------------------------------------------------------------------------
00311 
00312 nsresult
00313 nsRequestObserverProxy::FireEvent(nsARequestObserverEvent *event)
00314 {
00315     NS_ENSURE_TRUE(mEventQ, NS_ERROR_NOT_INITIALIZED);
00316 
00317     return mEventQ->PostEvent(event->GetPLEvent());
00318 }
00319 
00320 nsresult
00321 nsRequestObserverProxy::SetEventQueue(nsIEventQueue *eq)
00322 {
00323     nsresult rv = NS_OK;
00324     if ((eq == NS_CURRENT_EVENTQ) || (eq == NS_UI_THREAD_EVENTQ)) {
00325         nsCOMPtr<nsIEventQueueService> serv = do_GetService(kEventQueueService, &rv);
00326         if (NS_FAILED(rv)) return rv;
00327         rv = serv->GetSpecialEventQueue(NS_PTR_TO_INT32(eq), getter_AddRefs(mEventQ));
00328     }
00329     else
00330         mEventQ = eq;
00331     return rv;
00332 }