2011-02-28 Jeremy Orlow <jorlow@chromium.org>
[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 "IDBCursorWithValue.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     , m_cursorType(IDBCursorBackendInterface::InvalidCursorType)
62 {
63     if (m_transaction) {
64         m_transaction->registerRequest(this);
65         IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
66     }
67 }
68
69 IDBRequest::~IDBRequest()
70 {
71     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath);
72     if (m_transaction)
73         m_transaction->unregisterRequest(this);
74 }
75
76 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
77 {
78     if (m_readyState != DONE) {
79         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
80         return 0;
81     }
82     return m_result;
83 }
84
85 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
86 {
87     if (m_readyState != DONE) {
88         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
89         return 0;
90     }
91     return m_errorCode;
92 }
93
94 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
95 {
96     if (m_readyState != DONE) {
97         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
98         return String();
99     }
100     return m_errorMessage;
101 }
102
103 PassRefPtr<IDBAny> IDBRequest::source() const
104 {
105     return m_source;
106 }
107
108 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
109 {
110     return m_transaction;
111 }
112
113 unsigned short IDBRequest::readyState() const
114 {
115     ASSERT(m_readyState == LOADING || m_readyState == DONE);
116     return m_readyState;
117 }
118
119 void IDBRequest::markEarlyDeath()
120 {
121     ASSERT(m_readyState == LOADING);
122     m_readyState = EarlyDeath;
123 }
124
125 bool IDBRequest::resetReadyState(IDBTransaction* transaction)
126 {
127     ASSERT(!m_finished);
128     ASSERT(scriptExecutionContext());
129     ASSERT(transaction == m_transaction);
130     if (m_readyState != DONE)
131         return false;
132
133     m_readyState = LOADING;
134     m_result.clear();
135     m_errorCode = 0;
136     m_errorMessage = String();
137
138     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
139
140     return true;
141 }
142
143 IDBAny* IDBRequest::source()
144 {
145     return m_source.get();
146 }
147
148 void IDBRequest::abort()
149 {
150     if (m_readyState != LOADING) {
151         ASSERT(m_readyState == DONE);
152         return;
153     }
154
155     ASSERT(scriptExecutionContext()->isDocument());
156     EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
157     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
158         bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
159         ASSERT_UNUSED(removed, removed);
160     }
161     m_enqueuedEvents.clear();
162
163     m_errorCode = 0;
164     m_errorMessage = String();
165     m_result.clear();
166     onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
167 }
168
169 void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType)
170 {
171     ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
172     m_cursorType = cursorType;
173 }
174
175 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
176 {
177     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
178     m_errorCode = error->code();
179     m_errorMessage = error->message();
180     enqueueEvent(Event::create(eventNames().errorEvent, true, true));
181 }
182
183 static PassRefPtr<Event> createSuccessEvent()
184 {
185     return Event::create(eventNames().successEvent, false, false);
186 }
187
188 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
189 {
190     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
191     ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
192     if (m_cursorType == IDBCursorBackendInterface::IndexKeyCursor)
193         m_result = IDBAny::create(IDBCursor::create(backend, this, m_transaction.get()));
194     else
195         m_result = IDBAny::create(IDBCursorWithValue::create(backend, this, m_transaction.get()));
196     enqueueEvent(createSuccessEvent());
197 }
198
199 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
200 {
201     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
202     m_result = IDBAny::create(IDBDatabase::create(scriptExecutionContext(), backend));
203     enqueueEvent(createSuccessEvent());
204 }
205
206 void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend)
207 {
208     ASSERT_NOT_REACHED(); // FIXME: This method should go away.
209 }
210
211 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
212 {
213     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
214     m_result = IDBAny::create(idbKey);
215     enqueueEvent(createSuccessEvent());
216 }
217
218 void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend)
219 {
220     ASSERT_NOT_REACHED(); // FIXME: This method should go away.
221 }
222
223 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
224 {
225     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
226     if (!scriptExecutionContext())
227         return;
228
229     RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
230     RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, m_source->idbDatabase().get());
231     backend->setCallbacks(frontend.get());
232     m_transaction = frontend;
233
234     ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
235     m_source->idbDatabase()->setSetVersionTransaction(frontend.get());
236
237     IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
238
239     m_result = IDBAny::create(frontend.release());
240     enqueueEvent(createSuccessEvent());
241 }
242
243 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
244 {
245     ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
246     m_result = IDBAny::create(serializedScriptValue);
247     enqueueEvent(createSuccessEvent());
248 }
249
250 bool IDBRequest::hasPendingActivity() const
251 {
252     // FIXME: In an ideal world, we should return true as long as anyone has a or can
253     //        get a handle to us and we have event listeners. This is order to handle
254     //        user generated events properly.
255     return !m_finished || ActiveDOMObject::hasPendingActivity();
256 }
257
258 void IDBRequest::onBlocked()
259 {
260     ASSERT_NOT_REACHED();
261 }
262
263 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
264 {
265     return ActiveDOMObject::scriptExecutionContext();
266 }
267
268 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
269 {
270     ASSERT(!m_finished);
271     ASSERT(m_enqueuedEvents.size());
272     ASSERT(scriptExecutionContext());
273     ASSERT(event->target() == this);
274     ASSERT(m_readyState < DONE);
275     if (event->type() != eventNames().blockedEvent)
276         m_readyState = DONE;
277
278     for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
279         if (m_enqueuedEvents[i].get() == event.get())
280             m_enqueuedEvents.remove(i);
281     }
282
283     Vector<RefPtr<EventTarget> > targets;
284     targets.append(this);
285     if (m_transaction) {
286         targets.append(m_transaction);
287         // If there ever are events that are associated with a database but
288         // that do not have a transaction, then this will not work and we need
289         // this object to actually hold a reference to the database (to ensure
290         // it stays alive).
291         targets.append(m_transaction->db());
292     }
293
294     // FIXME: When we allow custom event dispatching, this will probably need to change.
295     ASSERT(event->type() == eventNames().successEvent || event->type() == eventNames().errorEvent || event->type() == eventNames().blockedEvent);
296     bool dontPreventDefault = IDBEventDispatcher::dispatch(event.get(), targets);
297
298     // If the result was of type IDBCursor, then we'll fire again.
299     if (m_result && m_result->type() != IDBAny::IDBCursorType && m_result->type() != IDBAny::IDBCursorWithValueType)
300         m_finished = true;
301
302     if (m_transaction) {
303         // If an error event and the default wasn't prevented...
304         if (dontPreventDefault && event->type() == eventNames().errorEvent)
305             m_transaction->backend()->abort();
306         m_transaction->backend()->didCompleteTaskEvents();
307     }
308     return dontPreventDefault;
309 }
310
311 void IDBRequest::uncaughtExceptionInEventHandler()
312 {
313     if (m_transaction)
314         m_transaction->backend()->abort();
315 }
316
317 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
318 {
319     ASSERT(!m_finished);
320     ASSERT(m_readyState < DONE);
321     if (!scriptExecutionContext())
322         return;
323
324     ASSERT(scriptExecutionContext()->isDocument());
325     EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
326     event->setTarget(this);
327     eventQueue->enqueueEvent(event.get());
328     m_enqueuedEvents.append(event);
329 }
330
331 EventTargetData* IDBRequest::eventTargetData()
332 {
333     return &m_eventTargetData;
334 }
335
336 EventTargetData* IDBRequest::ensureEventTargetData()
337 {
338     return &m_eventTargetData;
339 }
340
341 } // namespace WebCore
342
343 #endif