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 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "IDBTransaction.h" 28 29#if ENABLE(INDEXED_DATABASE) 30 31#include "Document.h" 32#include "EventException.h" 33#include "EventQueue.h" 34#include "IDBDatabase.h" 35#include "IDBDatabaseException.h" 36#include "IDBEventDispatcher.h" 37#include "IDBIndex.h" 38#include "IDBObjectStore.h" 39#include "IDBObjectStoreBackendInterface.h" 40#include "IDBPendingTransactionMonitor.h" 41 42namespace WebCore { 43 44PassRefPtr<IDBTransaction> IDBTransaction::create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db) 45{ 46 return adoptRef(new IDBTransaction(context, backend, db)); 47} 48 49IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db) 50 : ActiveDOMObject(context, this) 51 , m_backend(backend) 52 , m_database(db) 53 , m_mode(m_backend->mode()) 54 , m_finished(false) 55{ 56 ASSERT(m_backend); 57 IDBPendingTransactionMonitor::addPendingTransaction(m_backend.get()); 58} 59 60IDBTransaction::~IDBTransaction() 61{ 62} 63 64IDBTransactionBackendInterface* IDBTransaction::backend() const 65{ 66 return m_backend.get(); 67} 68 69bool IDBTransaction::finished() const 70{ 71 return m_finished; 72} 73 74unsigned short IDBTransaction::mode() const 75{ 76 return m_mode; 77} 78 79IDBDatabase* IDBTransaction::db() const 80{ 81 return m_database.get(); 82} 83 84PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, ExceptionCode& ec) 85{ 86 if (m_finished) { 87 ec = IDBDatabaseException::NOT_ALLOWED_ERR; 88 return 0; 89 } 90 RefPtr<IDBObjectStoreBackendInterface> objectStoreBackend = m_backend->objectStore(name, ec); 91 if (!objectStoreBackend) { 92 ASSERT(ec); 93 return 0; 94 } 95 RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, this); 96 return objectStore.release(); 97} 98 99void IDBTransaction::abort() 100{ 101 RefPtr<IDBTransaction> selfRef = this; 102 if (m_backend) 103 m_backend->abort(); 104} 105 106void IDBTransaction::registerRequest(IDBRequest* request) 107{ 108 m_childRequests.add(request); 109} 110 111void IDBTransaction::unregisterRequest(IDBRequest* request) 112{ 113 // If we aborted the request, it will already have been removed. 114 m_childRequests.remove(request); 115} 116 117void IDBTransaction::onAbort() 118{ 119 while (!m_childRequests.isEmpty()) { 120 IDBRequest* request = *m_childRequests.begin(); 121 m_childRequests.remove(request); 122 request->abort(); 123 } 124 125 enqueueEvent(Event::create(eventNames().abortEvent, true, false)); 126} 127 128void IDBTransaction::onComplete() 129{ 130 enqueueEvent(Event::create(eventNames().completeEvent, false, false)); 131} 132 133bool IDBTransaction::hasPendingActivity() const 134{ 135 // FIXME: In an ideal world, we should return true as long as anyone has a or can 136 // get a handle to us or any child request object and any of those have 137 // event listeners. This is in order to handle user generated events properly. 138 return !m_finished || ActiveDOMObject::hasPendingActivity(); 139} 140 141ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const 142{ 143 return ActiveDOMObject::scriptExecutionContext(); 144} 145 146bool IDBTransaction::dispatchEvent(PassRefPtr<Event> event) 147{ 148 ASSERT(!m_finished); 149 ASSERT(scriptExecutionContext()); 150 ASSERT(event->target() == this); 151 ASSERT(!m_finished); 152 m_finished = true; 153 154 Vector<RefPtr<EventTarget> > targets; 155 targets.append(this); 156 targets.append(db()); 157 158 // FIXME: When we allow custom event dispatching, this will probably need to change. 159 ASSERT(event->type() == eventNames().completeEvent || event->type() == eventNames().abortEvent); 160 return IDBEventDispatcher::dispatch(event.get(), targets); 161} 162 163bool IDBTransaction::canSuspend() const 164{ 165 // FIXME: Technically we can suspend before the first request is schedule 166 // and after the complete/abort event is enqueued. 167 return m_finished; 168} 169 170void IDBTransaction::contextDestroyed() 171{ 172 ActiveDOMObject::contextDestroyed(); 173 174 // Must happen in contextDestroyed since it can result in ActiveDOMObjects being destructed 175 // (and contextDestroyed is the only one resilient against this). 176 RefPtr<IDBTransaction> selfRef = this; 177 if (m_backend) 178 m_backend->abort(); 179 180 m_finished = true; 181} 182 183void IDBTransaction::enqueueEvent(PassRefPtr<Event> event) 184{ 185 ASSERT(!m_finished); 186 if (!scriptExecutionContext()) 187 return; 188 189 ASSERT(scriptExecutionContext()->isDocument()); 190 EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue(); 191 event->setTarget(this); 192 eventQueue->enqueueEvent(event); 193} 194 195EventTargetData* IDBTransaction::eventTargetData() 196{ 197 return &m_eventTargetData; 198} 199 200EventTargetData* IDBTransaction::ensureEventTargetData() 201{ 202 return &m_eventTargetData; 203} 204 205} 206 207#endif // ENABLE(INDEXED_DATABASE) 208