219 lines
10 KiB
C++
219 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <framework/transactionmanager.hxx>
|
|
|
|
#include <com/sun/star/lang/DisposedException.hpp>
|
|
|
|
namespace framework{
|
|
|
|
/*-************************************************************************************************************
|
|
@short standard ctor
|
|
@descr Initialize instance with right start values for correct working.
|
|
*//*-*************************************************************************************************************/
|
|
TransactionManager::TransactionManager()
|
|
: m_eWorkingMode ( E_INIT )
|
|
, m_nTransactionCount ( 0 )
|
|
{
|
|
m_aBarrier.open();
|
|
}
|
|
|
|
/*-************************************************************************************************************
|
|
@short standard dtor
|
|
*//*-*************************************************************************************************************/
|
|
TransactionManager::~TransactionManager()
|
|
{
|
|
}
|
|
|
|
/*-****************************************************************************************************
|
|
@short set new working mode
|
|
@descr These implementation knows for states of working: E_INIT, E_WORK, E_BEFORECLOSE, E_CLOSE
|
|
You can step during this ones only from the left to the right side and start at left side again!
|
|
(This is necessary e.g. for refcounted objects!)
|
|
This call will block till all current existing transactions was finished.
|
|
Following results can occur:
|
|
E_INIT : All requests on this implementation are refused.
|
|
It's your decision to react in a right way.
|
|
|
|
E_WORK : The object can work now. The full functionality is available.
|
|
|
|
E_BEFORECLOSE : The object start the closing mechanism ... but sometimes
|
|
e.g. the dispose() method need to call some private methods.
|
|
These some special methods should use E_SOFTEXCEPTIONS
|
|
to detect this special case!
|
|
|
|
E_CLOSE : Object is already dead! All further requests will be refused.
|
|
It's your decision to react in a right way.
|
|
@param "eMode", is the new mode - but we don't accept setting mode in wrong order!
|
|
@onerror We do nothing.
|
|
*//*-*****************************************************************************************************/
|
|
void TransactionManager::setWorkingMode( EWorkingMode eMode )
|
|
{
|
|
// Safe member access.
|
|
bool bWaitFor = false;
|
|
{
|
|
std::unique_lock aAccessGuard(m_aAccessLock);
|
|
// Change working mode first!
|
|
if (
|
|
(m_eWorkingMode == E_INIT && eMode == E_WORK) ||
|
|
((m_eWorkingMode == E_WORK || m_eWorkingMode == E_INIT) && eMode == E_BEFORECLOSE) ||
|
|
(m_eWorkingMode == E_BEFORECLOSE && eMode == E_CLOSE) ||
|
|
(m_eWorkingMode == E_CLOSE && eMode == E_INIT)
|
|
)
|
|
{
|
|
m_eWorkingMode = eMode;
|
|
if (m_eWorkingMode == E_BEFORECLOSE || m_eWorkingMode == E_CLOSE)
|
|
{
|
|
bWaitFor = true;
|
|
}
|
|
}
|
|
}
|
|
// Wait for current existing transactions then!
|
|
// (Only necessary for changing to E_BEFORECLOSE or E_CLOSE!...
|
|
// otherwise; if you wait at setting E_WORK another thread could finish an acquire-call during our unlock() and wait() call
|
|
// ... and we will wait forever here!!!)
|
|
// Don't forget to release access mutex before.
|
|
if( bWaitFor )
|
|
{
|
|
m_aBarrier.wait();
|
|
}
|
|
}
|
|
|
|
/*-****************************************************************************************************
|
|
@short get current working mode
|
|
@descr If you stand in your close() or init() method ... but don't know
|
|
if you called more than ones(!) ... you can use this function to get
|
|
right information.
|
|
e.g: You have a method init() which is used to change working mode from
|
|
E_INIT to E_WORK and should be used to initialize some member too ...
|
|
What should you do:
|
|
|
|
void init( sal_Int32 nValue )
|
|
{
|
|
// Reject this call if our transaction manager say: "Object already initialized!"
|
|
// Otherwise initialize your member.
|
|
if( m_aTransactionManager.getWorkingMode() == E_INIT )
|
|
{
|
|
// Object is uninitialized ...
|
|
// Make member access threadsafe!
|
|
Guard aGuard( m_aMutex );
|
|
|
|
// Check working mode again .. because another instance could be faster.
|
|
// (It's possible to set this guard at first of this method too!)
|
|
if( m_aTransactionManager.getWorkingMode() == E_INIT )
|
|
{
|
|
m_aMember = nValue;
|
|
|
|
// Object is initialized now ... set working mode to E_WORK!
|
|
m_aTransactionManager.setWorkingMode( E_WORK );
|
|
}
|
|
}
|
|
}
|
|
|
|
@seealso method setWorkingMode()
|
|
@return Current set mode.
|
|
|
|
@onerror No error should occur.
|
|
*//*-*****************************************************************************************************/
|
|
EWorkingMode TransactionManager::getWorkingMode() const
|
|
{
|
|
// Synchronize access to internal member!
|
|
std::unique_lock aAccessLock( m_aAccessLock );
|
|
return m_eWorkingMode;
|
|
}
|
|
|
|
/*-****************************************************************************************************
|
|
@short start new transaction
|
|
@descr A guard should use this method to start a new transaction. He should look for rejected
|
|
calls to by using parameter eMode and eReason.
|
|
If call was not rejected your transaction will be non breakable during releasing your transaction
|
|
guard! BUT ... your code isn't threadsafe then! It's a transaction manager only...
|
|
|
|
@seealso method unregisterTransaction()
|
|
|
|
@param "eMode" ,used to enable/disable throwing exceptions automatically for rejected calls
|
|
*//*-*****************************************************************************************************/
|
|
void TransactionManager::registerTransaction( EExceptionMode eMode )
|
|
{
|
|
std::unique_lock aAccessGuard( m_aAccessLock );
|
|
switch( m_eWorkingMode )
|
|
{
|
|
case E_INIT:
|
|
if( eMode == E_HARDEXCEPTIONS )
|
|
{
|
|
// Help programmer to find out, why this exception is thrown!
|
|
SAL_WARN( "fwk", "TransactionManager...: Owner instance not correctly initialized yet. Call was rejected! Normally it's an algorithm error ... wrong use of class!" );
|
|
//ATTENTION: temp. disabled - till all bad code positions are detected and changed! */
|
|
// throw css::uno::RuntimeException( "TransactionManager.: Owner instance not right initialized yet. Call was rejected! Normally it's an algorithm error... wrong using of class!\n", css::uno::Reference< css::uno::XInterface >() );
|
|
}
|
|
break;
|
|
case E_WORK:
|
|
break;
|
|
case E_BEFORECLOSE:
|
|
if( eMode == E_HARDEXCEPTIONS )
|
|
{
|
|
// Help programmer to find out, why this exception is thrown!
|
|
SAL_WARN( "fwk", "TransactionManager...: Owner instance stand in close method. Call was rejected!" );
|
|
throw css::lang::DisposedException( u"TransactionManager: Owner instance stand in close method. Call was rejected!"_ustr );
|
|
}
|
|
break;
|
|
case E_CLOSE:
|
|
// Help programmer to find out, why this exception is thrown!
|
|
SAL_WARN( "fwk", "TransactionManager...: Owner instance already closed. Call was rejected!" );
|
|
throw css::lang::DisposedException( u"TransactionManager: Owner instance already closed. Call was rejected!"_ustr );
|
|
}
|
|
|
|
// Register this new transaction.
|
|
// If it is the first one .. close gate to disable changing of working mode.
|
|
++m_nTransactionCount;
|
|
if( m_nTransactionCount == 1 )
|
|
{
|
|
m_aBarrier.close();
|
|
}
|
|
}
|
|
|
|
/*-****************************************************************************************************
|
|
@short finish transaction
|
|
@descr A guard should call this method to release current transaction.
|
|
|
|
@seealso method registerTransaction()
|
|
*//*-*****************************************************************************************************/
|
|
void TransactionManager::unregisterTransaction()
|
|
{
|
|
// This call could not rejected!
|
|
// Safe access to internal member.
|
|
std::unique_lock aAccessGuard( m_aAccessLock );
|
|
|
|
// Deregister this transaction.
|
|
// If it was the last one ... open gate to enable changing of working mode!
|
|
// (see setWorkingMode())
|
|
|
|
--m_nTransactionCount;
|
|
if( m_nTransactionCount == 0 )
|
|
{
|
|
m_aBarrier.open();
|
|
}
|
|
}
|
|
|
|
} // namespace framework
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|