Home | History | Annotate | Download | only in inspector
      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 
     31 #include "InspectorDatabaseAgent.h"
     32 
     33 #if ENABLE(INSPECTOR) && ENABLE(DATABASE)
     34 
     35 #include "Database.h"
     36 #include "ExceptionCode.h"
     37 #include "InspectorDatabaseResource.h"
     38 #include "InspectorFrontend.h"
     39 #include "InspectorState.h"
     40 #include "InspectorValues.h"
     41 #include "InstrumentingAgents.h"
     42 #include "SQLError.h"
     43 #include "SQLStatementCallback.h"
     44 #include "SQLStatementErrorCallback.h"
     45 #include "SQLResultSetRowList.h"
     46 #include "SQLTransaction.h"
     47 #include "SQLTransactionCallback.h"
     48 #include "SQLTransactionErrorCallback.h"
     49 #include "SQLValue.h"
     50 #include "VoidCallback.h"
     51 
     52 #include <wtf/Vector.h>
     53 
     54 namespace WebCore {
     55 
     56 namespace DatabaseAgentState {
     57 static const char databaseAgentEnabled[] = "databaseAgentEnabled";
     58 };
     59 
     60 class InspectorDatabaseAgent::FrontendProvider : public RefCounted<InspectorDatabaseAgent::FrontendProvider> {
     61 public:
     62     static PassRefPtr<FrontendProvider> create(InspectorFrontend* inspectorFrontend)
     63     {
     64         return adoptRef(new FrontendProvider(inspectorFrontend));
     65     }
     66 
     67     virtual ~FrontendProvider() { }
     68 
     69     InspectorFrontend::Database* frontend() { return m_inspectorFrontend; }
     70     void clearFrontend() { m_inspectorFrontend = 0; }
     71 private:
     72     FrontendProvider(InspectorFrontend* inspectorFrontend) : m_inspectorFrontend(inspectorFrontend->database()) { }
     73     InspectorFrontend::Database* m_inspectorFrontend;
     74 };
     75 
     76 namespace {
     77 
     78 int lastTransactionId = 0;
     79 
     80 void reportTransactionFailed(InspectorFrontend::Database* frontend, int transactionId, SQLError* error)
     81 {
     82     if (!frontend)
     83         return;
     84     RefPtr<InspectorObject> errorObject = InspectorObject::create();
     85     errorObject->setString("message", error->message());
     86     errorObject->setNumber("code", error->code());
     87     frontend->sqlTransactionFailed(transactionId, errorObject);
     88 }
     89 
     90 class StatementCallback : public SQLStatementCallback {
     91 public:
     92     static PassRefPtr<StatementCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
     93     {
     94         return adoptRef(new StatementCallback(transactionId, frontendProvider));
     95     }
     96 
     97     virtual ~StatementCallback() { }
     98 
     99     virtual bool handleEvent(SQLTransaction*, SQLResultSet* resultSet)
    100     {
    101         if (!m_frontendProvider->frontend())
    102             return true;
    103 
    104         SQLResultSetRowList* rowList = resultSet->rows();
    105 
    106         RefPtr<InspectorArray> columnNames = InspectorArray::create();
    107         const Vector<String>& columns = rowList->columnNames();
    108         for (size_t i = 0; i < columns.size(); ++i)
    109             columnNames->pushString(columns[i]);
    110 
    111         RefPtr<InspectorArray> values = InspectorArray::create();
    112         const Vector<SQLValue>& data = rowList->values();
    113         for (size_t i = 0; i < data.size(); ++i) {
    114             const SQLValue& value = rowList->values()[i];
    115             switch (value.type()) {
    116                 case SQLValue::StringValue: values->pushString(value.string()); break;
    117                 case SQLValue::NumberValue: values->pushNumber(value.number()); break;
    118                 case SQLValue::NullValue: values->pushValue(InspectorValue::null()); break;
    119             }
    120         }
    121         m_frontendProvider->frontend()->sqlTransactionSucceeded(m_transactionId, columnNames, values);
    122         return true;
    123     }
    124 
    125 private:
    126     StatementCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    127         : m_transactionId(transactionId)
    128         , m_frontendProvider(frontendProvider) { }
    129     int m_transactionId;
    130     RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
    131 };
    132 
    133 class StatementErrorCallback : public SQLStatementErrorCallback {
    134 public:
    135     static PassRefPtr<StatementErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    136     {
    137         return adoptRef(new StatementErrorCallback(transactionId, frontendProvider));
    138     }
    139 
    140     virtual ~StatementErrorCallback() { }
    141 
    142     virtual bool handleEvent(SQLTransaction*, SQLError* error)
    143     {
    144         reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error);
    145         return true;
    146     }
    147 
    148 private:
    149     StatementErrorCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    150         : m_transactionId(transactionId)
    151         , m_frontendProvider(frontendProvider) { }
    152     int m_transactionId;
    153     RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
    154 };
    155 
    156 class TransactionCallback : public SQLTransactionCallback {
    157 public:
    158     static PassRefPtr<TransactionCallback> create(const String& sqlStatement, int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    159     {
    160         return adoptRef(new TransactionCallback(sqlStatement, transactionId, frontendProvider));
    161     }
    162 
    163     virtual ~TransactionCallback() { }
    164 
    165     virtual bool handleEvent(SQLTransaction* transaction)
    166     {
    167         if (!m_frontendProvider->frontend())
    168             return true;
    169 
    170         Vector<SQLValue> sqlValues;
    171         RefPtr<SQLStatementCallback> callback(StatementCallback::create(m_transactionId, m_frontendProvider));
    172         RefPtr<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_transactionId, m_frontendProvider));
    173         ExceptionCode ec = 0;
    174         transaction->executeSQL(m_sqlStatement, sqlValues, callback.release(), errorCallback.release(), ec);
    175         return true;
    176     }
    177 private:
    178     TransactionCallback(const String& sqlStatement, int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    179         : m_sqlStatement(sqlStatement)
    180         , m_transactionId(transactionId)
    181         , m_frontendProvider(frontendProvider) { }
    182     String m_sqlStatement;
    183     int m_transactionId;
    184     RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
    185 };
    186 
    187 class TransactionErrorCallback : public SQLTransactionErrorCallback {
    188 public:
    189     static PassRefPtr<TransactionErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    190     {
    191         return adoptRef(new TransactionErrorCallback(transactionId, frontendProvider));
    192     }
    193 
    194     virtual ~TransactionErrorCallback() { }
    195 
    196     virtual bool handleEvent(SQLError* error)
    197     {
    198         reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error);
    199         return true;
    200     }
    201 private:
    202     TransactionErrorCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
    203         : m_transactionId(transactionId)
    204         , m_frontendProvider(frontendProvider) { }
    205     int m_transactionId;
    206     RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
    207 };
    208 
    209 class TransactionSuccessCallback : public VoidCallback {
    210 public:
    211     static PassRefPtr<TransactionSuccessCallback> create()
    212     {
    213         return adoptRef(new TransactionSuccessCallback());
    214     }
    215 
    216     virtual ~TransactionSuccessCallback() { }
    217 
    218     virtual void handleEvent() { }
    219 
    220 private:
    221     TransactionSuccessCallback() { }
    222 };
    223 
    224 } // namespace
    225 
    226 void InspectorDatabaseAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
    227 {
    228     if (InspectorDatabaseResource* resource = findByFileName(database->fileName())) {
    229         resource->setDatabase(database);
    230         return;
    231     }
    232 
    233     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
    234     m_resources.set(resource->id(), resource);
    235     // Resources are only bound while visible.
    236     if (m_frontendProvider && m_enabled)
    237         resource->bind(m_frontendProvider->frontend());
    238 }
    239 
    240 void InspectorDatabaseAgent::clearResources()
    241 {
    242     m_resources.clear();
    243 }
    244 
    245 InspectorDatabaseAgent::InspectorDatabaseAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state)
    246     : m_instrumentingAgents(instrumentingAgents)
    247     , m_inspectorState(state)
    248     , m_enabled(false)
    249 {
    250     m_instrumentingAgents->setInspectorDatabaseAgent(this);
    251 }
    252 
    253 InspectorDatabaseAgent::~InspectorDatabaseAgent()
    254 {
    255     m_instrumentingAgents->setInspectorDatabaseAgent(0);
    256 }
    257 
    258 void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend)
    259 {
    260     m_frontendProvider = FrontendProvider::create(frontend);
    261 }
    262 
    263 void InspectorDatabaseAgent::clearFrontend()
    264 {
    265     m_frontendProvider->clearFrontend();
    266     m_frontendProvider.clear();
    267     disable(0);
    268 }
    269 
    270 void InspectorDatabaseAgent::enable(ErrorString*)
    271 {
    272     if (m_enabled)
    273         return;
    274     m_enabled = true;
    275     m_inspectorState->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
    276 
    277     DatabaseResourcesMap::iterator databasesEnd = m_resources.end();
    278     for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != databasesEnd; ++it)
    279         it->second->bind(m_frontendProvider->frontend());
    280 }
    281 
    282 void InspectorDatabaseAgent::disable(ErrorString*)
    283 {
    284     if (!m_enabled)
    285         return;
    286     m_enabled = false;
    287     m_inspectorState->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
    288 }
    289 
    290 void InspectorDatabaseAgent::restore()
    291 {
    292     m_enabled =  m_inspectorState->getBoolean(DatabaseAgentState::databaseAgentEnabled);
    293 }
    294 
    295 void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString* error, int databaseId, RefPtr<InspectorArray>* names)
    296 {
    297     if (!m_enabled) {
    298         *error = "Database agent is not enabled";
    299         return;
    300     }
    301 
    302     Database* database = databaseForId(databaseId);
    303     if (database) {
    304         Vector<String> tableNames = database->tableNames();
    305         unsigned length = tableNames.size();
    306         for (unsigned i = 0; i < length; ++i)
    307             (*names)->pushString(tableNames[i]);
    308     }
    309 }
    310 
    311 void InspectorDatabaseAgent::executeSQL(ErrorString* error, int databaseId, const String& query, bool* success, int* transactionId)
    312 {
    313     if (!m_enabled) {
    314         *error = "Database agent is not enabled";
    315         return;
    316     }
    317 
    318     Database* database = databaseForId(databaseId);
    319     if (!database) {
    320         *success = false;
    321         return;
    322     }
    323 
    324     *transactionId = ++lastTransactionId;
    325     RefPtr<SQLTransactionCallback> callback(TransactionCallback::create(query, *transactionId, m_frontendProvider));
    326     RefPtr<SQLTransactionErrorCallback> errorCallback(TransactionErrorCallback::create(*transactionId, m_frontendProvider));
    327     RefPtr<VoidCallback> successCallback(TransactionSuccessCallback::create());
    328     database->transaction(callback.release(), errorCallback.release(), successCallback.release());
    329     *success = true;
    330 }
    331 
    332 int InspectorDatabaseAgent::databaseId(Database* database)
    333 {
    334     for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
    335         if (it->second->database() == database)
    336             return it->first;
    337     }
    338     return 0;
    339 }
    340 
    341 InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName)
    342 {
    343     for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
    344         if (it->second->database()->fileName() == fileName)
    345             return it->second.get();
    346     }
    347     return 0;
    348 }
    349 
    350 Database* InspectorDatabaseAgent::databaseForId(int databaseId)
    351 {
    352     DatabaseResourcesMap::iterator it = m_resources.find(databaseId);
    353     if (it == m_resources.end())
    354         return 0;
    355     return it->second->database();
    356 }
    357 
    358 } // namespace WebCore
    359 
    360 #endif // ENABLE(INSPECTOR) && ENABLE(DATABASE)
    361