michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_indexeddb_asyncconnectionhelper_h__ michael@0: #define mozilla_dom_indexeddb_asyncconnectionhelper_h__ michael@0: michael@0: // Only meant to be included in IndexedDB source files, not exported. michael@0: #include "DatabaseInfo.h" michael@0: #include "IndexedDatabase.h" michael@0: #include "IDBDatabase.h" michael@0: #include "IDBRequest.h" michael@0: michael@0: #include "mozIStorageProgressHandler.h" michael@0: #include "nsIEventTarget.h" michael@0: #include "nsIRunnable.h" michael@0: michael@0: class mozIStorageConnection; michael@0: michael@0: BEGIN_INDEXEDDB_NAMESPACE michael@0: michael@0: class AutoSetCurrentTransaction; michael@0: class IDBTransaction; michael@0: michael@0: namespace ipc { michael@0: class ResponseValue; michael@0: } michael@0: michael@0: // A common base class for AsyncConnectionHelper and OpenDatabaseHelper that michael@0: // IDBRequest can use. michael@0: class HelperBase : public nsIRunnable michael@0: { michael@0: friend class IDBRequest; michael@0: michael@0: public: michael@0: michael@0: virtual nsresult GetResultCode() = 0; michael@0: michael@0: virtual nsresult GetSuccessResult(JSContext* aCx, michael@0: JS::MutableHandle aVal) = 0; michael@0: michael@0: IDBRequest* GetRequest() const michael@0: { michael@0: return mRequest; michael@0: } michael@0: michael@0: protected: michael@0: HelperBase(IDBRequest* aRequest) michael@0: : mRequest(aRequest) michael@0: { } michael@0: michael@0: virtual ~HelperBase(); michael@0: michael@0: /** michael@0: * Helper to wrap a native into a jsval. Uses the global object of the request michael@0: * to parent the native. michael@0: */ michael@0: nsresult WrapNative(JSContext* aCx, michael@0: nsISupports* aNative, michael@0: JS::MutableHandle aResult); michael@0: michael@0: /** michael@0: * Gives the subclass a chance to release any objects that must be released michael@0: * on the main thread, regardless of success or failure. Subclasses that michael@0: * implement this method *MUST* call the base class implementation as well. michael@0: */ michael@0: virtual void ReleaseMainThreadObjects(); michael@0: michael@0: nsRefPtr mRequest; michael@0: }; michael@0: michael@0: /** michael@0: * Must be subclassed. The subclass must implement DoDatabaseWork. It may then michael@0: * choose to implement OnSuccess and OnError depending on the needs of the michael@0: * subclass. If the default implementation of OnSuccess is desired then the michael@0: * subclass can implement GetSuccessResult to properly set the result of the michael@0: * success event. Call Dispatch to start the database operation. Must be created michael@0: * and Dispatched from the main thread only. Target thread may not be the main michael@0: * thread. michael@0: */ michael@0: class AsyncConnectionHelper : public HelperBase, michael@0: public mozIStorageProgressHandler michael@0: { michael@0: friend class AutoSetCurrentTransaction; michael@0: michael@0: public: michael@0: typedef ipc::ResponseValue ResponseValue; michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: NS_DECL_MOZISTORAGEPROGRESSHANDLER michael@0: michael@0: virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread); michael@0: michael@0: // Only for transactions! michael@0: nsresult DispatchToTransactionPool(); michael@0: michael@0: void SetError(nsresult aErrorCode) michael@0: { michael@0: NS_ASSERTION(NS_FAILED(aErrorCode), "Not a failure code!"); michael@0: mResultCode = aErrorCode; michael@0: } michael@0: michael@0: static IDBTransaction* GetCurrentTransaction(); michael@0: michael@0: bool HasTransaction() const michael@0: { michael@0: return !!mTransaction; michael@0: } michael@0: michael@0: IDBTransaction* GetTransaction() const michael@0: { michael@0: return mTransaction; michael@0: } michael@0: michael@0: virtual nsresult GetResultCode() MOZ_OVERRIDE michael@0: { michael@0: return mResultCode; michael@0: } michael@0: michael@0: enum ChildProcessSendResult michael@0: { michael@0: // The result was successfully sent to the child process michael@0: Success_Sent = 0, michael@0: michael@0: // The result was not sent, because this is not an out-of-process request. michael@0: Success_NotSent, michael@0: michael@0: // The result was not sent, because the actor has been disconnected michael@0: // (if the child process has shut down or crashed). michael@0: Success_ActorDisconnected, michael@0: michael@0: // An error occurred. michael@0: Error michael@0: }; michael@0: michael@0: ChildProcessSendResult michael@0: MaybeSendResponseToChildProcess(nsresult aResultCode); michael@0: michael@0: virtual nsresult OnParentProcessRequestComplete( michael@0: const ResponseValue& aResponseValue); michael@0: michael@0: virtual nsresult michael@0: UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0; michael@0: michael@0: protected: michael@0: AsyncConnectionHelper(IDBDatabase* aDatabase, michael@0: IDBRequest* aRequest); michael@0: michael@0: AsyncConnectionHelper(IDBTransaction* aTransaction, michael@0: IDBRequest* aRequest); michael@0: michael@0: virtual ~AsyncConnectionHelper(); michael@0: michael@0: /** michael@0: * This is called on the main thread after Dispatch is called but before the michael@0: * runnable is actually dispatched to the database thread. Allows the subclass michael@0: * to initialize itself. michael@0: */ michael@0: virtual nsresult Init(); michael@0: michael@0: /** michael@0: * This callback is run on the database thread. michael@0: */ michael@0: virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) = 0; michael@0: michael@0: /** michael@0: * This function returns the event to be dispatched at the request when michael@0: * OnSuccess is called. A subclass can override this to fire an event other michael@0: * than "success" at the request. michael@0: */ michael@0: virtual already_AddRefed CreateSuccessEvent( michael@0: mozilla::dom::EventTarget* aOwner); michael@0: michael@0: /** michael@0: * This callback is run on the main thread if DoDatabaseWork returned NS_OK. michael@0: * The default implementation fires a "success" DOM event with its target set michael@0: * to the request. Returning anything other than NS_OK from the OnSuccess michael@0: * callback will trigger the OnError callback. michael@0: */ michael@0: virtual nsresult OnSuccess(); michael@0: michael@0: /** michael@0: * This callback is run on the main thread if DoDatabaseWork or OnSuccess michael@0: * returned an error code. The default implementation fires an "error" DOM michael@0: * event with its target set to the request. michael@0: */ michael@0: virtual void OnError(); michael@0: michael@0: /** michael@0: * This function is called by the request on the main thread when script michael@0: * accesses the result property of the request. michael@0: */ michael@0: virtual nsresult GetSuccessResult(JSContext* aCx, michael@0: JS::MutableHandle aVal) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Gives the subclass a chance to release any objects that must be released michael@0: * on the main thread, regardless of success or failure. Subclasses that michael@0: * implement this method *MUST* call the base class implementation as well. michael@0: */ michael@0: virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Helper to make a JS array object out of an array of clone buffers. michael@0: */ michael@0: static nsresult ConvertToArrayAndCleanup( michael@0: JSContext* aCx, michael@0: nsTArray& aReadInfos, michael@0: JS::MutableHandle aResult); michael@0: michael@0: /** michael@0: * This should only be called by AutoSetCurrentTransaction. michael@0: */ michael@0: static void SetCurrentTransaction(IDBTransaction* aTransaction); michael@0: michael@0: /** michael@0: * Allows the subclass to send its results to the child process. Will only michael@0: * be called if all of the IPC infrastructure is available (there is an michael@0: * actor, the child is stil alive and hasn't begun shutting down). michael@0: */ michael@0: virtual ChildProcessSendResult michael@0: SendResponseToChildProcess(nsresult aResultCode) = 0; michael@0: michael@0: protected: michael@0: nsRefPtr mDatabase; michael@0: nsRefPtr mTransaction; michael@0: michael@0: private: michael@0: nsCOMPtr mOldProgressHandler; michael@0: nsresult mResultCode; michael@0: bool mDispatched; michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS StackBasedEventTarget : public nsIEventTarget michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS ImmediateRunEventTarget : public StackBasedEventTarget michael@0: { michael@0: public: michael@0: NS_DECL_NSIEVENTTARGET michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS NoDispatchEventTarget : public StackBasedEventTarget michael@0: { michael@0: public: michael@0: NS_DECL_NSIEVENTTARGET michael@0: }; michael@0: michael@0: END_INDEXEDDB_NAMESPACE michael@0: michael@0: #endif // mozilla_dom_indexeddb_asyncconnectionhelper_h__