Home | History | Annotate | Download | only in storage
      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 
     42 namespace WebCore {
     43 
     44 PassRefPtr<IDBTransaction> IDBTransaction::create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db)
     45 {
     46     return adoptRef(new IDBTransaction(context, backend, db));
     47 }
     48 
     49 IDBTransaction::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 
     60 IDBTransaction::~IDBTransaction()
     61 {
     62 }
     63 
     64 IDBTransactionBackendInterface* IDBTransaction::backend() const
     65 {
     66     return m_backend.get();
     67 }
     68 
     69 bool IDBTransaction::finished() const
     70 {
     71     return m_finished;
     72 }
     73 
     74 unsigned short IDBTransaction::mode() const
     75 {
     76     return m_mode;
     77 }
     78 
     79 IDBDatabase* IDBTransaction::db() const
     80 {
     81     return m_database.get();
     82 }
     83 
     84 PassRefPtr<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 
     99 void IDBTransaction::abort()
    100 {
    101     RefPtr<IDBTransaction> selfRef = this;
    102     if (m_backend)
    103         m_backend->abort();
    104 }
    105 
    106 void IDBTransaction::registerRequest(IDBRequest* request)
    107 {
    108     m_childRequests.add(request);
    109 }
    110 
    111 void IDBTransaction::unregisterRequest(IDBRequest* request)
    112 {
    113     // If we aborted the request, it will already have been removed.
    114     m_childRequests.remove(request);
    115 }
    116 
    117 void 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 
    128 void IDBTransaction::onComplete()
    129 {
    130     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
    131 }
    132 
    133 bool 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 
    141 ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
    142 {
    143     return ActiveDOMObject::scriptExecutionContext();
    144 }
    145 
    146 bool 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 
    163 bool 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 
    170 void 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 
    183 void 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 
    195 EventTargetData* IDBTransaction::eventTargetData()
    196 {
    197     return &m_eventTargetData;
    198 }
    199 
    200 EventTargetData* IDBTransaction::ensureEventTargetData()
    201 {
    202     return &m_eventTargetData;
    203 }
    204 
    205 }
    206 
    207 #endif // ENABLE(INDEXED_DATABASE)
    208