2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "IDBRequest.h"
32 #if ENABLE(INDEXED_DATABASE)
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"
47 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
49 return adoptRef(new IDBRequest(context, source, transaction));
52 IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
53 : ActiveDOMObject(context, this)
56 , m_transaction(transaction)
57 , m_readyState(LOADING)
59 , m_cursorType(IDBCursorBackendInterface::InvalidCursorType)
62 m_transaction->registerRequest(this);
63 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
67 IDBRequest::~IDBRequest()
69 ASSERT(m_readyState == DONE || m_readyState == EarlyDeath || !scriptExecutionContext());
71 m_transaction->unregisterRequest(this);
74 PassRefPtr<IDBAny> IDBRequest::result(ExceptionCode& ec) const
76 if (m_readyState != DONE) {
77 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
83 unsigned short IDBRequest::errorCode(ExceptionCode& ec) const
85 if (m_readyState != DONE) {
86 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
92 String IDBRequest::webkitErrorMessage(ExceptionCode& ec) const
94 if (m_readyState != DONE) {
95 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
98 return m_errorMessage;
101 PassRefPtr<IDBAny> IDBRequest::source() const
106 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
108 return m_transaction;
111 unsigned short IDBRequest::readyState() const
113 ASSERT(m_readyState == LOADING || m_readyState == DONE);
117 void IDBRequest::markEarlyDeath()
119 ASSERT(m_readyState == LOADING);
120 m_readyState = EarlyDeath;
123 bool IDBRequest::resetReadyState(IDBTransaction* transaction)
126 ASSERT(scriptExecutionContext());
127 ASSERT(transaction == m_transaction);
128 if (m_readyState != DONE)
131 m_readyState = LOADING;
134 m_errorMessage = String();
136 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
141 IDBAny* IDBRequest::source()
143 return m_source.get();
146 void IDBRequest::abort()
148 if (m_readyState != LOADING) {
149 ASSERT(m_readyState == DONE);
152 // FIXME: Remove isDocument check when
153 // https://bugs.webkit.org/show_bug.cgi?id=57789 is resolved.
154 if (!scriptExecutionContext() || !scriptExecutionContext()->isDocument())
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);
162 m_enqueuedEvents.clear();
165 m_errorMessage = String();
167 onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
170 void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType)
172 ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
173 m_cursorType = cursorType;
176 void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
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));
184 static PassRefPtr<Event> createSuccessEvent()
186 return Event::create(eventNames().successEvent, false, false);
189 void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
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()));
196 m_result = IDBAny::create(IDBCursorWithValue::create(backend, this, m_source.get(), m_transaction.get()));
197 enqueueEvent(createSuccessEvent());
200 void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
202 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
203 RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend);
206 m_result = IDBAny::create(idbDatabase.release());
207 enqueueEvent(createSuccessEvent());
210 void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
212 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
213 m_result = IDBAny::create(idbKey);
214 enqueueEvent(createSuccessEvent());
217 void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
219 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
220 if (!scriptExecutionContext())
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;
228 ASSERT(m_source->type() == IDBAny::IDBDatabaseType);
229 m_source->idbDatabase()->setSetVersionTransaction(frontend.get());
231 IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
233 m_result = IDBAny::create(frontend.release());
234 enqueueEvent(createSuccessEvent());
237 void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
239 ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
240 m_result = IDBAny::create(serializedScriptValue);
241 enqueueEvent(createSuccessEvent());
244 bool IDBRequest::hasPendingActivity() const
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();
252 void IDBRequest::onBlocked()
254 ASSERT_NOT_REACHED();
257 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
259 return ActiveDOMObject::scriptExecutionContext();
262 bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
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)
272 for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
273 if (m_enqueuedEvents[i].get() == event.get())
274 m_enqueuedEvents.remove(i);
277 Vector<RefPtr<EventTarget> > targets;
278 targets.append(this);
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
285 targets.append(m_transaction->db());
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);
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)
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();
302 return dontPreventDefault;
305 void IDBRequest::uncaughtExceptionInEventHandler()
308 m_transaction->backend()->abort();
311 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
314 ASSERT(m_readyState < DONE);
315 if (!scriptExecutionContext())
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);
325 EventTargetData* IDBRequest::eventTargetData()
327 return &m_eventTargetData;
330 EventTargetData* IDBRequest::ensureEventTargetData()
332 return &m_eventTargetData;
335 } // namespace WebCore