remotestoragefw/remotefileengine/src/rsfwlockmanager.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:07:59 +0200
changeset 0 3ad9d5175a89
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Lock manager for locked remote files
*
*/


#include "rsfwfileentry.h"
#include "rsfwrfestatemachine.h"
#include "rsfwlockmanager.h"
#include "rsfwfileentry.h"
#include "rsfwconfig.h"
#include "mdebug.h"

// ----------------------------------------------------------------------------

// ============================ MEMBER FUNCTIONS ==============================

// ----------------------------------------------------------------------------
// CRsfwLockManager::NewL
// ----------------------------------------------------------------------------
//
CRsfwLockManager* CRsfwLockManager::NewL(CRsfwRemoteAccess* aRemoteAccess)
    {
    CRsfwLockManager* self = CRsfwLockManager::NewLC(aRemoteAccess);
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::NewLC
// ----------------------------------------------------------------------------
//
CRsfwLockManager* CRsfwLockManager::NewLC(CRsfwRemoteAccess* aRemoteAccess)
    {
    DEBUGSTRING(("CRsfwLockManager::NewLC"));
    CRsfwLockManager* self = new (ELeave) CRsfwLockManager();
    CleanupStack::PushL(self);
    self->ConstructL(aRemoteAccess);
    return self;
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::ConstructL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::ConstructL(CRsfwRemoteAccess* aRemoteAccess)
    {
    iRemoteAccess = aRemoteAccess;
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::~CRsfwLockManager
// ----------------------------------------------------------------------------
//
CRsfwLockManager::~CRsfwLockManager()
    {
    iLockRefreshContexts.Close();

    // set unlock flag for all the entries locked
    while (iLockedEntries.Count() > 0)
        {
        CRsfwFileEntry* entry = iLockedEntries[0];
        iLockedEntries.Remove(0);
        // note that RemoveLocked will call CRsfwLockManager::RemoveLockedEntry
        entry->RemoveLocked();
        }
    iLockedEntries.Close();    
    }


// ----------------------------------------------------------------------------
// CRsfwLockManager::HandleRemoteAccessResponse
// For handling the response from RefreshLockL().
// If the lock refresh is successful we restart the timer
// as the server may have changed the timeout.
// If the refresh request returns an error we remove the lock
// We assume that server does not hold the lock anymore,
// so we cannot re-acquire it simply by trying to refresh it again.
// Instead, we should do a fresh lock operation
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::HandleRemoteAccessResponse(TUint aId,
                                              TInt aStatus)
    {
    DEBUGSTRING(("CRsfwLockManager::HandleRemoteAccessResponse id: %d, status: %d", aId, aStatus));
    TPendingLockRefreshContext lockRefresh;
    lockRefresh.iId = aId;
    TInt index = iLockRefreshContexts.Find(lockRefresh);
    if (index != KErrNotFound) 
        {
        lockRefresh = iLockRefreshContexts[index];
        if (aStatus == KErrNone) 
            {
            // Note that this can leave only when creating the timer
            // so it shouldn't really leave anymore at this point.
            // Also resetting the timer and calling Start() do not even
            // return an error, so there is no need to examine err or ret value
            TRAP_IGNORE(lockRefresh.iFileEntry->SetLockedL(this, NULL));
            }
        else 
            {
            lockRefresh.iFileEntry->RemoveLocked();
            }
        iLockRefreshContexts.Remove(index);
        }
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::ObtainLockL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::ObtainLockL(CRsfwFileEntry *aFileEntry,
                               TUint aLockFlags,
                               TDesC8*& aLockToken,
                               CRsfwRfeStateMachine* aOperation)
    {
    DEBUGSTRING(("CRsfwLockManager::ObtainLockL"));
    if (aFileEntry->iLockTimeout == 0)
        {
        // No locking wanted,
        // we use notsupported as a return code in this case too....
        DEBUGSTRING(("lock timeout in CFileEntry is 0, no locking"));
        aOperation->HandleRemoteAccessResponse(0, KErrNotSupported); 
        }
    else 
        {
        HBufC* fullName = aFileEntry->FullNameLC();
         if (!iRemoteAccess) 
            {
            DEBUGSTRING(("iRemoteAccess NULL"));
            User::Leave(KErrNotReady);
            }
        else 
            {
            DEBUGSTRING(("calling iRemoteAccess::ObtainLockL()"));
            iRemoteAccess->ObtainLockL(*fullName,
                                   aLockFlags,
                                   aFileEntry->iLockTimeout,
                                   aLockToken,
                                   aOperation);
            }

        CleanupStack::PopAndDestroy(fullName); // fullname  
        }
    
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::ReleaseLockL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::ReleaseLockL(CRsfwFileEntry* aFileEntry,
                                CRsfwRfeStateMachine* aOperation)
    {
    DEBUGSTRING(("CRsfwLockManager::ReleaseLockL"));
    if (aFileEntry->iLockTimeout == 0)
        {
        // No locking
        User::Leave(KErrNotFound);
        }
    

    if (!iRemoteAccess) 
        {
        User::Leave(KErrNotReady);
        }
    else 
        {
        HBufC* fullName = aFileEntry->FullNameLC();
#ifdef _DEBUG
        TInt err;
        err = iRemoteAccess->ReleaseLockL(*fullName, aOperation);
        TPtrC p = fullName->Des();
        DEBUGSTRING16(("ReleaseLockL(): returned %d for file '%S'", err, &p));     



#else        
        iRemoteAccess->ReleaseLockL(*fullName, aOperation);
#endif
        CleanupStack::PopAndDestroy(fullName); // fullname
        }
    
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::RefreshLockL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::RefreshLockL(CRsfwFileEntry* aFileEntry)
    {
   DEBUGSTRING(("CRsfwLockManager::RefreshLockL"));
    TInt id = 0;
    if (aFileEntry->iLockTimeout > 0) // timeout = 0 indicates no locking
        {
        aFileEntry->iLockTimer->Cancel(); // cancel the old timer
        HBufC* fullName = aFileEntry->FullNameLC();
        TRAPD(err, id = iRemoteAccess->RefreshLockL(*fullName,
                                                    aFileEntry->iLockTimeout,
                                                    this)); 
        if (err == KErrNone) 
            {
            TPendingLockRefreshContext lockRefresh;
            lockRefresh.iId = id;
            lockRefresh.iFileEntry = aFileEntry;
            iLockRefreshContexts.AppendL(lockRefresh);
            } 
        else 
            {
            // This error would come from the lower layers of the communication
            // stack, not from the server.
            // We use the timer mechanism to try again
            // but set the timeout to smaller.
            // Note that we don't touch aFileEntry->iLockTimer, 
            // which will be used to set the timeout requested from the server
            TInt lockTimeout =
                Min((aFileEntry->iLockTimeout / KLockRefreshAdjustment) / 2,
                    KMinLockRefreshAttempt);
            TCallBack callBack(CRsfwFileEntry::LockTimerExpiredL, this);
            aFileEntry->iLockTimer->Start(1000000 * lockTimeout,
                                          1000000 * lockTimeout,
                                          callBack);
            }
        CleanupStack::PopAndDestroy(fullName); // fullname
        }
    }
  
// ----------------------------------------------------------------------------
// CRsfwLockManager::LockedCount
// ----------------------------------------------------------------------------
//  
TInt CRsfwLockManager::LockedCount()
    {
    return iLockedEntries.Count();
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::AddLockedEntryL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::AddLockedEntryL(CRsfwFileEntry* aEntry)
    {
    // prevent from adding the same item twice
    if (iLockedEntries.Find(aEntry) != KErrNotFound)
        {
        return;
        }
    
    iLockedEntries.AppendL(aEntry);
    DEBUGSTRING(("Update locked count %d -> %d",
                 iLockedEntries.Count() - 1,
                 iLockedEntries.Count()));
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::RemoveLockedEntry
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::RemoveLockedEntry(CRsfwFileEntry* aEntry)
    {
    TInt index = iLockedEntries.Find(aEntry);
    if (index != KErrNotFound)
        {
        iLockedEntries.Remove(index);        
        DEBUGSTRING(("Update locked count %d -> %d",
                 iLockedEntries.Count() + 1,
                 iLockedEntries.Count()));

        }
    }

// ----------------------------------------------------------------------------
// CRsfwLockManager::PopulateExternalLockTokenCacheL
// ----------------------------------------------------------------------------
//
void CRsfwLockManager::PopulateExternalLockTokenCacheL(CRsfwFileEntry* aRoot)
    {
    if (aRoot)
        {
        const TDesC8* lockToken = aRoot->LockToken();
        if (lockToken)
            {
            HBufC* path = aRoot->FullNameLC();
            TPtr pathPtr = path->Des();
            if (aRoot->Type() == KNodeTypeDir)
                {
                // the MaxLength() of path is KMaxPath, so we can append
            if (pathPtr.Length() && (pathPtr[pathPtr.Length() - 1] != '/'))
                {
                pathPtr.Append('/');
                }
                }
            iRemoteAccess->SetLockToken(pathPtr, *lockToken);
            CleanupStack::PopAndDestroy(path);
            }
        
        RPointerArray<CRsfwFileEntry>* kids = aRoot->Kids();
        TInt i;
        for (i = 0; i < kids->Count(); i++)
            {
            PopulateExternalLockTokenCacheL((*kids)[i]);
            }
        }
    }

//  End of File