• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
create(ScriptExecutionContext * context,PassRefPtr<IDBAny> source,IDBTransaction * transaction)47 PassRefPtr<IDBRequest> IDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransaction* transaction)
48 {
49     return adoptRef(new IDBRequest(context, source, transaction));
50 }
51 
IDBRequest(ScriptExecutionContext * context,PassRefPtr<IDBAny> source,IDBTransaction * transaction)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 
~IDBRequest()67 IDBRequest::~IDBRequest()
68 {
69     ASSERT(m_readyState == DONE || m_readyState == EarlyDeath);
70     if (m_transaction)
71         m_transaction->unregisterRequest(this);
72 }
73 
result(ExceptionCode & ec) const74 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 
errorCode(ExceptionCode & ec) const83 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 
webkitErrorMessage(ExceptionCode & ec) const92 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 
source() const101 PassRefPtr<IDBAny> IDBRequest::source() const
102 {
103     return m_source;
104 }
105 
transaction() const106 PassRefPtr<IDBTransaction> IDBRequest::transaction() const
107 {
108     return m_transaction;
109 }
110 
readyState() const111 unsigned short IDBRequest::readyState() const
112 {
113     ASSERT(m_readyState == LOADING || m_readyState == DONE);
114     return m_readyState;
115 }
116 
markEarlyDeath()117 void IDBRequest::markEarlyDeath()
118 {
119     ASSERT(m_readyState == LOADING);
120     m_readyState = EarlyDeath;
121 }
122 
resetReadyState(IDBTransaction * transaction)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 
source()141 IDBAny* IDBRequest::source()
142 {
143     return m_source.get();
144 }
145 
abort()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 
setCursorType(IDBCursorBackendInterface::CursorType cursorType)167 void IDBRequest::setCursorType(IDBCursorBackendInterface::CursorType cursorType)
168 {
169     ASSERT(m_cursorType == IDBCursorBackendInterface::InvalidCursorType);
170     m_cursorType = cursorType;
171 }
172 
onError(PassRefPtr<IDBDatabaseError> error)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 
createSuccessEvent()181 static PassRefPtr<Event> createSuccessEvent()
182 {
183     return Event::create(eventNames().successEvent, false, false);
184 }
185 
onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)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 
onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)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 
onSuccess(PassRefPtr<IDBKey> idbKey)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 
onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)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 
onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)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 
hasPendingActivity() const241 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 
onBlocked()249 void IDBRequest::onBlocked()
250 {
251     ASSERT_NOT_REACHED();
252 }
253 
scriptExecutionContext() const254 ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
255 {
256     return ActiveDOMObject::scriptExecutionContext();
257 }
258 
dispatchEvent(PassRefPtr<Event> event)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 
uncaughtExceptionInEventHandler()302 void IDBRequest::uncaughtExceptionInEventHandler()
303 {
304     if (m_transaction)
305         m_transaction->backend()->abort();
306 }
307 
enqueueEvent(PassRefPtr<Event> event)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 
eventTargetData()322 EventTargetData* IDBRequest::eventTargetData()
323 {
324     return &m_eventTargetData;
325 }
326 
ensureEventTargetData()327 EventTargetData* IDBRequest::ensureEventTargetData()
328 {
329     return &m_eventTargetData;
330 }
331 
332 } // namespace WebCore
333 
334 #endif
335