2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "modules/webdatabase/DatabaseManager.h"
29 #include "bindings/core/v8/ExceptionMessages.h"
30 #include "bindings/core/v8/ExceptionState.h"
31 #include "core/dom/ExceptionCode.h"
32 #include "core/dom/ExecutionContext.h"
33 #include "core/dom/ExecutionContextTask.h"
34 #include "core/inspector/ConsoleMessage.h"
35 #include "platform/Logging.h"
36 #include "modules/webdatabase/AbstractDatabaseServer.h"
37 #include "modules/webdatabase/Database.h"
38 #include "modules/webdatabase/DatabaseBackend.h"
39 #include "modules/webdatabase/DatabaseBackendBase.h"
40 #include "modules/webdatabase/DatabaseBackendSync.h"
41 #include "modules/webdatabase/DatabaseCallback.h"
42 #include "modules/webdatabase/DatabaseClient.h"
43 #include "modules/webdatabase/DatabaseContext.h"
44 #include "modules/webdatabase/DatabaseServer.h"
45 #include "modules/webdatabase/DatabaseSync.h"
46 #include "modules/webdatabase/DatabaseTask.h"
47 #include "platform/weborigin/SecurityOrigin.h"
51 DatabaseManager& DatabaseManager::manager()
53 AtomicallyInitializedStatic(DatabaseManager*, dbManager = new DatabaseManager);
57 DatabaseManager::DatabaseManager()
59 : m_databaseContextRegisteredCount(0)
60 , m_databaseContextInstanceCount(0)
63 m_server = new DatabaseServer;
64 ASSERT(m_server); // We should always have a server to work with.
67 DatabaseManager::~DatabaseManager()
71 class DatabaseCreationCallbackTask FINAL : public ExecutionContextTask {
73 static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtrWillBeRawPtr<Database> database, PassOwnPtr<DatabaseCallback> creationCallback)
75 return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback));
78 virtual void performTask(ExecutionContext*) OVERRIDE
80 m_creationCallback->handleEvent(m_database.get());
84 DatabaseCreationCallbackTask(PassRefPtrWillBeRawPtr<Database> database, PassOwnPtr<DatabaseCallback> callback)
85 : m_database(database)
86 , m_creationCallback(callback)
90 RefPtrWillBePersistent<Database> m_database;
91 OwnPtr<DatabaseCallback> m_creationCallback;
94 DatabaseContext* DatabaseManager::existingDatabaseContextFor(ExecutionContext* context)
96 MutexLocker locker(m_contextMapLock);
98 ASSERT(m_databaseContextRegisteredCount >= 0);
99 ASSERT(m_databaseContextInstanceCount >= 0);
100 ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount);
102 const Persistent<DatabaseContext>* databaseContext = m_contextMap.get(context);
103 return databaseContext ? databaseContext->get() : 0;
105 return m_contextMap.get(context);
109 DatabaseContext* DatabaseManager::databaseContextFor(ExecutionContext* context)
111 if (DatabaseContext* databaseContext = existingDatabaseContextFor(context))
112 return databaseContext;
113 // We don't need to hold a reference returned by DatabaseContext::create
114 // because DatabaseContext::create calls registerDatabaseContext, and the
115 // DatabaseManager holds a reference.
116 return DatabaseContext::create(context).get();
119 void DatabaseManager::registerDatabaseContext(DatabaseContext* databaseContext)
121 MutexLocker locker(m_contextMapLock);
122 ExecutionContext* context = databaseContext->executionContext();
124 m_contextMap.set(context, adoptPtr(new Persistent<DatabaseContext>(databaseContext)));
126 m_contextMap.set(context, databaseContext);
129 m_databaseContextRegisteredCount++;
133 void DatabaseManager::unregisterDatabaseContext(DatabaseContext* databaseContext)
135 MutexLocker locker(m_contextMapLock);
136 ExecutionContext* context = databaseContext->executionContext();
137 ASSERT(m_contextMap.get(context));
139 m_databaseContextRegisteredCount--;
141 m_contextMap.remove(context);
145 void DatabaseManager::didConstructDatabaseContext()
147 MutexLocker lock(m_contextMapLock);
148 m_databaseContextInstanceCount++;
151 void DatabaseManager::didDestructDatabaseContext()
153 MutexLocker lock(m_contextMapLock);
154 m_databaseContextInstanceCount--;
155 ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount);
159 void DatabaseManager::throwExceptionForDatabaseError(DatabaseError error, const String& errorMessage, ExceptionState& exceptionState)
162 case DatabaseError::None:
164 case DatabaseError::GenericSecurityError:
165 exceptionState.throwSecurityError(errorMessage);
167 case DatabaseError::InvalidDatabaseState:
168 exceptionState.throwDOMException(InvalidStateError, errorMessage);
171 ASSERT_NOT_REACHED();
175 static void logOpenDatabaseError(ExecutionContext* context, const String& name)
177 WTF_LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(),
178 context->securityOrigin()->toString().ascii().data());
181 PassRefPtrWillBeRawPtr<DatabaseBackendBase> DatabaseManager::openDatabaseBackend(ExecutionContext* context,
182 DatabaseType type, const String& name, const String& expectedVersion, const String& displayName,
183 unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
185 ASSERT(error == DatabaseError::None);
187 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = m_server->openDatabase(
188 databaseContextFor(context)->backend(), type, name, expectedVersion,
189 displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
192 ASSERT(error != DatabaseError::None);
195 case DatabaseError::GenericSecurityError:
196 logOpenDatabaseError(context, name);
199 case DatabaseError::InvalidDatabaseState:
200 logErrorMessage(context, errorMessage);
204 ASSERT_NOT_REACHED();
208 return backend.release();
211 PassRefPtrWillBeRawPtr<Database> DatabaseManager::openDatabase(ExecutionContext* context,
212 const String& name, const String& expectedVersion, const String& displayName,
213 unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback,
214 DatabaseError& error, String& errorMessage)
216 ASSERT(error == DatabaseError::None);
218 bool setVersionInNewDatabase = !creationCallback;
219 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = openDatabaseBackend(context, DatabaseType::Async, name,
220 expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
224 RefPtrWillBeRawPtr<Database> database = Database::create(context, backend);
226 databaseContextFor(context)->setHasOpenDatabases();
227 DatabaseClient::from(context)->didOpenDatabase(database, context->securityOrigin()->host(), name, expectedVersion);
229 if (backend->isNew() && creationCallback.get()) {
230 WTF_LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get());
231 database->executionContext()->postTask(DatabaseCreationCallbackTask::create(database, creationCallback));
235 return database.release();
238 PassRefPtrWillBeRawPtr<DatabaseSync> DatabaseManager::openDatabaseSync(ExecutionContext* context,
239 const String& name, const String& expectedVersion, const String& displayName,
240 unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback,
241 DatabaseError& error, String& errorMessage)
243 ASSERT(context->isContextThread());
244 ASSERT(error == DatabaseError::None);
246 bool setVersionInNewDatabase = !creationCallback;
247 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = openDatabaseBackend(context, DatabaseType::Sync, name,
248 expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
252 RefPtrWillBeRawPtr<DatabaseSync> database = DatabaseSync::create(context, backend);
254 if (backend->isNew() && creationCallback.get()) {
255 WTF_LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get());
256 creationCallback->handleEvent(database.get());
260 return database.release();
263 String DatabaseManager::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfDoesNotExist)
265 return m_server->fullPathForDatabase(origin, name, createIfDoesNotExist);
268 void DatabaseManager::closeDatabasesImmediately(const String& originIdentifier, const String& name)
270 m_server->closeDatabasesImmediately(originIdentifier, name);
273 void DatabaseManager::interruptAllDatabasesForContext(DatabaseContext* databaseContext)
275 m_server->interruptAllDatabasesForContext(databaseContext->backend());
278 void DatabaseManager::logErrorMessage(ExecutionContext* context, const String& message)
280 context->addConsoleMessage(ConsoleMessage::create(StorageMessageSource, ErrorMessageLevel, message));