59e937774de3e5bc91fa23cd711fdf1981e6bb0f
[WebKit-https.git] / Source / WebCore / storage / IDBRequest.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "IDBRequest.h"
31
32 #if ENABLE(INDEXED_DATABASE)
33
34 #include "Document.h"
35 #include "EventException.h"
36 #include "EventListener.h"
37 #include "EventNames.h"
38 #include "EventQueue.h"
39 #include "IDBCursor.h"
40 #include "IDBDatabase.h"
41 #include "IDBEventDispatcher.h"
42 #include "IDBIndex.h"
43 #include "IDBObjectStore.h"
44 #include "IDBPendingTransactionMonitor.h"
45 #include "IDBTransaction.h"
46
47 namespace WebCore {
48
49 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
50 {
51     return adoptRef(new IDBRequest(context, source, transaction));
52 }
53
54 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
55     : ActiveDOMObject(context, this)
56     , m_errorCode(0)
57     , m_source(source)
58     , m_transaction(transaction)
59     , m_readyState(LOADING)
60     , m_finished(false)
61 {
62     if (m_transaction) {
63         m_transaction->registerRequest(this);
64         IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
65     }
66 }
67
68 IDBRequest::~IDBRequest()
69 {
70     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath);
71     if (m_transaction)
72         m_transaction->unregisterRequest(this);
73 }
74
75 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
76 {
77     if (m_readyState != DONE) {
78         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
79         return 0;
80     }
81     return m_result;
82 }
83
84 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
85 {
86     if (m_readyState != DONE) {
87         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
88         return 0;
89     }
90     return m_errorCode;
91 }
92
93 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
94 {
95     if (m_readyState != DONE) {
96         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
97         return String();
98     }
99     return m_errorMessage;
100 }
101
102 PassRefPtr<IDBAny> IDBRequest::source() const
103 {
104     return m_source;
105 }
106
107 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
108 {
109     return m_transaction;
110 }
111
112 unsigned short IDBRequest::readyState() const
113 {
114     ASSERT(m_readyState == LOADING || m_readyState == DONE);
115     return m_readyState;
116 }
117
118 void IDBRequest::markEarlyDeath()
119 {
120     ASSERT(m_readyState == LOADING);
121     m_readyState = EarlyDeath;
122 }
123
124 bool IDBRequest::resetReadyState(IDBTransaction* transaction)
125 {
126     ASSERT(!m_finished);
127     ASSERT(scriptExecutionContext());
128     ASSERT(transaction == m_transaction);
129     if (m_readyState != DONE)
130         return false;
131
132     m_readyState = LOADING;
133     m_result.clear();
134     m_errorCode = 0;
135     m_errorMessage = String();
136
137     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
138
139     return true;
140 }
141
142 IDBAny* IDBRequest::source()
143 {
144     return m_source.get();
145 }
146
147 void IDBRequest::abort()
148 {
149     if (m_readyState != LOADING) {
150         ASSERT(m_readyState == DONE);
151         return;
152     }
153
154     ASSERT(scriptExecutionContext()->isDocument());
155     EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
156     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
157         bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
158         ASSERT_UNUSED(removed, removed);
159     }
160     m_enqueuedEvents.clear();
161
162     m_errorCode = 0;
163     m_errorMessage = String();
164     m_result.clear();
165     onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
166 }
167
168 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
169 {
170     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
171     m_errorCode = error->code();
172     m_errorMessage = error->message();
173     enqueueEvent(Event::create(eventNames().errorEvent, true, true));
174 }
175
176 static PassRefPtr<Event> createSuccessEvent()
177 {
178     return Event::create(eventNames().successEvent, false, false);
179 }
180
181 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
182 {
183     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
184     m_result = IDBAny::create(IDBCursor::create(backend, this, m_transaction.get()));
185     enqueueEvent(createSuccessEvent());
186 }
187
188 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
189 {
190     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
191     m_result = IDBAny::create(IDBDatabase::create(scriptExecutionContext(), backend));
192     enqueueEvent(createSuccessEvent());
193 }
194
195 void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend)
196 {
197     ASSERT_NOT_REACHED(); // FIXME: This method should go away.
198 }
199
200 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
201 {
202     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
203     m_result = IDBAny::create(idbKey);
204     enqueueEvent(createSuccessEvent());
205 }
206
207 void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend)
208 {
209     ASSERT_NOT_REACHED(); // FIXME: This method should go away.
210 }
211
212 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
213 {
214     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
215     if (!scriptExecutionContext())
216         return;
217
218     RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
219     RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, m_source->idbDatabase().get());
220     backend->setCallbacks(frontend.get());
221     m_transaction = frontend;
222
223     ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
224     m_source->idbDatabase()->setSetVersionTransaction(frontend.get());
225
226     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
227
228     m_result = IDBAny::create(frontend.release());
229     enqueueEvent(createSuccessEvent());
230 }
231
232 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
233 {
234     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
235     m_result = IDBAny::create(serializedScriptValue);
236     enqueueEvent(createSuccessEvent());
237 }
238
239 bool IDBRequest::hasPendingActivity() const
240 {
241     // FIXME: In an ideal world, we should return true as long as anyone has a or can
242     //        get a handle to us and we have event listeners. This is order to handle
243     //        user generated events properly.
244     return !m_finished || ActiveDOMObject::hasPendingActivity();
245 }
246
247 void IDBRequest::onBlocked()
248 {
249     ASSERT_NOT_REACHED();
250 }
251
252 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
253 {
254     return ActiveDOMObject::scriptExecutionContext();
255 }
256
257 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
258 {
259     ASSERT(!m_finished);
260     ASSERT(m_enqueuedEvents.size());
261     ASSERT(scriptExecutionContext());
262     ASSERT(event->target() == this);
263     ASSERT(m_readyState < DONE);
264     if (event->type() != eventNames().blockedEvent)
265         m_readyState = DONE;
266
267     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
268         if (m_enqueuedEvents[i].get() == event.get())
269             m_enqueuedEvents.remove(i);
270     }
271
272     Vector<RefPtr<EventTarget> > targets;
273     targets.append(this);
274     if (m_transaction) {
275         targets.append(m_transaction);
276         // If there ever are events that are associated with a database but
277         // that do not have a transaction, then this will not work and we need
278         // this object to actually hold a reference to the database (to ensure
279         // it stays alive).
280         targets.append(m_transaction->db());
281     }
282
283     // FIXME: When we allow custom event dispatching, this will probably need to change.
284     ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent);
285     bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
286
287     // If the result was of type IDBCursor, then we'll fire again.
288     if (m_result && m_result->type() != IDBAny::IDBCursorType)
289         m_finished = true;
290
291     if (m_transaction) {
292         // If an error event and the default wasn't prevented...
293         if (dontPreventDefault && event->type() == eventNames().errorEvent)
294             m_transaction->backend()->abort();
295         m_transaction->backend()->didCompleteTaskEvents();
296     }
297     return dontPreventDefault;
298 }
299
300 void IDBRequest::uncaughtExceptionInEventHandler()
301 {
302     if (m_transaction)
303         m_transaction->backend()->abort();
304 }
305
306 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
307 {
308     ASSERT(!m_finished);
309     ASSERT(m_readyState < DONE);
310     if (!scriptExecutionContext())
311         return;
312
313     ASSERT(scriptExecutionContext()->isDocument());
314     EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
315     event->setTarget(this);
316     eventQueue->enqueueEvent(event.get());
317     m_enqueuedEvents.append(event);
318 }
319
320 EventTargetData* IDBRequest::eventTargetData()
321 {
322     return &m_eventTargetData;
323 }
324
325 EventTargetData* IDBRequest::ensureEventTargetData()
326 {
327     return &m_eventTargetData;
328 }
329
330 } // namespace WebCore
331
332 #endif