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