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  * 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