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); 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 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 167 void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType) 168 { 169 ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType); 170 m_cursorType = cursorType; 171 } 172 173 void 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 181 static PassRefPtr<Event> createSuccessEvent() 182 { 183 return Event::create(eventNames().successEvent, false, false); 184 } 185 186 void 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 197 void 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 207 void 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 214 void 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 234 void 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 241 bool 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 249 void IDBRequest::onBlocked() 250 { 251 ASSERT_NOT_REACHED(); 252 } 253 254 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const 255 { 256 return ActiveDOMObject::scriptExecutionContext(); 257 } 258 259 bool 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 302 void IDBRequest::uncaughtExceptionInEventHandler() 303 { 304 if (m_transaction) 305 m_transaction->backend()->abort(); 306 } 307 308 void 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 322 EventTargetData* IDBRequest::eventTargetData() 323 { 324 return &m_eventTargetData; 325 } 326 327 EventTargetData* IDBRequest::ensureEventTargetData() 328 { 329 return &m_eventTargetData; 330 } 331 332 } // namespace WebCore 333 334 #endif 335