/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "IDBRequest.h"
#if ENABLE(INDEXED_DATABASE)
#include "Event.h"
#include "EventException.h"
#include "EventListener.h"
#include "EventNames.h"
#include "IDBDatabaseRequest.h"
#include "IDBIndexRequest.h"
#include "IDBErrorEvent.h"
#include "IDBObjectStoreRequest.h"
#include "IDBSuccessEvent.h"
#include "ScriptExecutionContext.h"
namespace WebCore {
IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> source)
: ActiveDOMObject(context, this)
, m_source(source)
, m_result(IDBAny::create())
, m_timer(this, &IDBRequest::timerFired)
, m_stopped(false)
, m_aborted(false)
, m_readyState(INITIAL)
{
}
IDBRequest::~IDBRequest()
{
if (m_readyState != DONE)
abort();
}
void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
{
onEventCommon();
m_error = error;
}
void IDBRequest::onSuccess()
{
onEventCommon();
m_result->set();
}
void IDBRequest::onSuccess(PassRefPtr<IDBDatabase> idbDatabase)
{
onEventCommon();
m_result->set(IDBDatabaseRequest::create(idbDatabase));
}
void IDBRequest::onSuccess(PassRefPtr<IDBIndex> idbIndex)
{
onEventCommon();
m_result->set(IDBIndexRequest::create(idbIndex));
}
void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
{
onEventCommon();
m_result->set(idbKey);
}
void IDBRequest::onSuccess(PassRefPtr<IDBObjectStore> idbObjectStore)
{
onEventCommon();
m_result->set(IDBObjectStoreRequest::create(idbObjectStore));
}
void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
{
onEventCommon();
m_result->set(serializedScriptValue);
}
void IDBRequest::abort()
{
m_timer.stop();
m_aborted = true;
// FIXME: This should cancel any pending work being done in the backend.
}
ScriptExecutionContext* IDBRequest::scriptExecutionContext() const
{
return ActiveDOMObject::scriptExecutionContext();
}
void IDBRequest::stop()
{
abort();
m_selfRef = 0; // Could trigger a delete.
}
void IDBRequest::suspend()
{
m_timer.stop();
m_stopped = true;
}
void IDBRequest::resume()
{
m_stopped = false;
// We only hold our self ref when we're waiting to dispatch an event.
if (m_selfRef && !m_aborted)
m_timer.startOneShot(0);
}
EventTargetData* IDBRequest::eventTargetData()
{
return &m_eventTargetData;
}
EventTargetData* IDBRequest::ensureEventTargetData()
{
return &m_eventTargetData;
}
void IDBRequest::timerFired(Timer<IDBRequest>*)
{
ASSERT(m_readyState == DONE);
ASSERT(m_selfRef);
ASSERT(!m_stopped);
ASSERT(!m_aborted);
// We need to keep self-referencing ourself, otherwise it's possible we'll be deleted.
// But in some cases, suspend() could be called while we're dispatching an event, so we
// need to make sure that resume() doesn't re-start the timer based on m_selfRef being set.
RefPtr<IDBRequest> selfRef = m_selfRef.release();
if (m_error) {
ASSERT(m_result->type() == IDBAny::UndefinedType);
dispatchEvent(IDBErrorEvent::create(m_source, *m_error));
} else {
ASSERT(m_result->type() != IDBAny::UndefinedType);
dispatchEvent(IDBSuccessEvent::create(m_source, m_result));
}
}
void IDBRequest::onEventCommon()
{
ASSERT(m_readyState < DONE);
ASSERT(m_result->type() == IDBAny::UndefinedType);
ASSERT(!m_error);
ASSERT(!m_selfRef);
ASSERT(!m_timer.isActive());
if (m_aborted)
return;
m_readyState = DONE;
m_selfRef = this;
if (!m_stopped)
m_timer.startOneShot(0);
}
} // namespace WebCore
#endif