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