1/*
2 * Copyright (C) 2012 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 "IDBOpenDBRequest.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBDatabase.h"
32#include "IDBDatabaseCallbacksImpl.h"
33#include "IDBPendingTransactionMonitor.h"
34#include "IDBVersionChangeEvent.h"
35#include "Logging.h"
36#include "ScriptExecutionContext.h"
37
38namespace WebCore {
39
40PassRefPtr<IDBOpenDBRequest> IDBOpenDBRequest::create(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseCallbacks> callbacks, int64_t transactionId, uint64_t version, IndexedDB::VersionNullness versionNullness)
41{
42    RefPtr<IDBOpenDBRequest> request(adoptRef(new IDBOpenDBRequest(context, callbacks, transactionId, version, versionNullness)));
43    request->suspendIfNeeded();
44    return request.release();
45}
46
47IDBOpenDBRequest::IDBOpenDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBDatabaseCallbacks> callbacks, int64_t transactionId, uint64_t version, IndexedDB::VersionNullness versionNullness)
48    : IDBRequest(context, IDBAny::createNull(), IDBDatabaseBackend::NormalTask, 0)
49    , m_databaseCallbacks(callbacks)
50    , m_transactionId(transactionId)
51    , m_version(version)
52    , m_versionNullness(versionNullness)
53{
54    ASSERT(!m_result);
55}
56
57IDBOpenDBRequest::~IDBOpenDBRequest()
58{
59}
60
61EventTargetInterface IDBOpenDBRequest::eventTargetInterface() const
62{
63    return IDBOpenDBRequestEventTargetInterfaceType;
64}
65
66void IDBOpenDBRequest::onBlocked(uint64_t oldVersion)
67{
68    LOG(StorageAPI, "IDBOpenDBRequest::onBlocked()");
69    if (!shouldEnqueueEvent())
70        return;
71
72    enqueueEvent(IDBVersionChangeEvent::create(oldVersion, m_version, m_versionNullness, eventNames().blockedEvent));
73}
74
75void IDBOpenDBRequest::onUpgradeNeeded(uint64_t oldVersion, PassRefPtr<IDBDatabaseBackend> prpDatabaseBackend, const IDBDatabaseMetadata& metadata)
76{
77    LOG(StorageAPI, "IDBOpenDBRequest::onUpgradeNeeded()");
78    if (m_contextStopped || !scriptExecutionContext()) {
79        RefPtr<IDBDatabaseBackend> db = prpDatabaseBackend;
80        db->abort(m_transactionId);
81        db->close(m_databaseCallbacks);
82        return;
83    }
84    if (!shouldEnqueueEvent())
85        return;
86
87    ASSERT(m_databaseCallbacks);
88
89    RefPtr<IDBDatabaseBackend> databaseBackend = prpDatabaseBackend;
90
91    RefPtr<IDBDatabase> idbDatabase = IDBDatabase::create(scriptExecutionContext(), databaseBackend, m_databaseCallbacks);
92    idbDatabase->setMetadata(metadata);
93    m_databaseCallbacks->connect(idbDatabase.get());
94    m_databaseCallbacks = 0;
95
96    IDBDatabaseMetadata oldMetadata(metadata);
97    oldMetadata.version = oldVersion;
98
99    m_transaction = IDBTransaction::create(scriptExecutionContext(), m_transactionId, idbDatabase.get(), this, oldMetadata);
100    m_result = IDBAny::create(idbDatabase.release());
101
102    if (m_versionNullness == IndexedDB::VersionNullness::Null)
103        m_version = 1;
104    enqueueEvent(IDBVersionChangeEvent::create(oldVersion, m_version, m_versionNullness, eventNames().upgradeneededEvent));
105}
106
107void IDBOpenDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackend> prpBackend, const IDBDatabaseMetadata& metadata)
108{
109    LOG(StorageAPI, "IDBOpenDBRequest::onSuccess()");
110    if (!shouldEnqueueEvent())
111        return;
112
113    RefPtr<IDBDatabaseBackend> backend = prpBackend;
114    RefPtr<IDBDatabase> idbDatabase;
115    if (m_result) {
116        idbDatabase = m_result->idbDatabase();
117        ASSERT(idbDatabase);
118        ASSERT(!m_databaseCallbacks);
119    } else {
120        ASSERT(m_databaseCallbacks);
121        idbDatabase = IDBDatabase::create(scriptExecutionContext(), backend.release(), m_databaseCallbacks);
122        m_databaseCallbacks->connect(idbDatabase.get());
123        m_databaseCallbacks = 0;
124        m_result = IDBAny::create(idbDatabase.get());
125    }
126    idbDatabase->setMetadata(metadata);
127    enqueueEvent(Event::create(eventNames().successEvent, false, false));
128}
129
130bool IDBOpenDBRequest::shouldEnqueueEvent() const
131{
132    if (m_contextStopped || !scriptExecutionContext())
133        return false;
134    ASSERT(m_readyState == PENDING || m_readyState == DONE);
135    if (m_requestAborted)
136        return false;
137    return true;
138}
139
140bool IDBOpenDBRequest::dispatchEvent(PassRefPtr<Event> event)
141{
142    // If the connection closed between onUpgradeNeeded and the delivery of the "success" event,
143    // an "error" event should be fired instead.
144    if (event->type() == eventNames().successEvent && m_result->type() == IDBAny::IDBDatabaseType && m_result->idbDatabase()->isClosePending()) {
145        m_result.clear();
146        onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed."));
147        return false;
148    }
149
150    return IDBRequest::dispatchEvent(event);
151}
152
153} // namespace WebCore
154
155#endif
156