diff -r 000000000000 -r ba25891c3a9e iaupdate/IAD/engine/controller/src/iaupdateloader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iaupdate/IAD/engine/controller/src/iaupdateloader.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,878 @@ +/* +* Copyright (c) 2007-2009 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: This module contains the implementation of +* CIAUpdateLoader class member functions. +* +*/ + + + + +#include +#include +#include +#include +#include +#include + +#include "iaupdateloader.h" +#include "iaupdateloaderobserver.h" +#include "iaupdatectrlconsts.h" +#include "iaupdateversion.h" +#include "iaupdateutils.h" +#include "iaupdatedebug.h" + + +// Use KMaxTInt value for the child count. +// Then, all the children will be downloaded +// even if the parent does not have the correct +// information about its child count. +const TInt KChildCountLoadAll( KMaxTInt ); + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::NewLC +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CIAUpdateLoader* CIAUpdateLoader::NewLC( + MNcdProvider& aProvider, + MIAUpdateLoaderObserver& aObserver ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::NewLC() begin"); + + CIAUpdateLoader* self = + new( ELeave ) CIAUpdateLoader( aProvider, aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::NewLC() end"); + + return self; + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CIAUpdateLoader* CIAUpdateLoader::NewL( + MNcdProvider& aProvider, + MIAUpdateLoaderObserver& aObserver ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::NewL() begin"); + + CIAUpdateLoader* self = + CIAUpdateLoader::NewLC( aProvider, aObserver ); + CleanupStack::Pop( self ); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::NewL() end"); + + return self; + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::CIAUpdateLoader +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CIAUpdateLoader::CIAUpdateLoader( + MNcdProvider& aProvider, + MIAUpdateLoaderObserver& aObserver ) +: CBase(), + iProvider( aProvider ), + iObserver( aObserver ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::CIAUpdateLoader()"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::ConstructL() + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::ConstructL() begin"); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::ConstructL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::~CIAUpdateLoader +// Destructor +// ----------------------------------------------------------------------------- +// +CIAUpdateLoader::~CIAUpdateLoader() + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::~CIAUpdateLoader() begin"); + + // Call just to be sure. + Cancel(); + + iOperations.Close(); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::~CIAUpdateLoader() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::RootExpiredL +// +// ----------------------------------------------------------------------------- +// +TBool CIAUpdateLoader::RootExpiredL() const + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::RootExpiredL() begin"); + + TBool rootExpired( EFalse ); + + // Remember to release this node when it is not needed. + MNcdNode* rootNode( iProvider.RootNodeL() ); + + // Get the state of the root. + MNcdNode::TState rootState( rootNode->State() ); + + IAUPDATE_TRACE_1("[IAUPDATE] Root state: %d", + rootState); + + // Check if the root is expired or not. + if ( rootState == MNcdNode::EStateExpired ) + { + IAUPDATE_TRACE("[IAUPDATE] Root is expired"); + rootExpired = ETrue; + } + + MNcdNodeContainer* container( rootNode->QueryInterfaceLC< MNcdNodeContainer >() ); + TInt childCount( container->ChildCount() ); + CleanupStack::PopAndDestroy( container ); + + IAUPDATE_TRACE_1("[IAUPDATE] count of children: %d", childCount ); + + //2 here means arrow CGW and firmware CGW. If one of them failed last time, + //refresh from CDB again + if ( childCount != 2 && rootState == MNcdNode::EStateInitialized ) + { + IAUPDATE_TRACE("[IAUPDATE] Root is expired. update from phase 1 to phase 2 or previous CGW load failed"); + rootExpired = ETrue; + } + // Release root because it is not needed any more. + rootNode->Release(); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::RootExpiredL() end"); + + return rootExpired; + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadNodesL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadNodesL() + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadNodesL() begin"); + + if ( iOperations.Count() > 0 ) + { + // + IAUPDATE_TRACE("[IAUPDATE] ERROR: Refresh already going on."); + User::Leave( KErrInUse ); + } + + // Reset this value for new round. + iErrorCode = KErrNone; + + // Root refresh will handle everything. + LoadRootL(); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadNodesL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::Cancel +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::Cancel() + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::Cancel() begin"); + + // Cancel asynchronous operations. + + // Use this flag to inform that operation complete callback function + // that cancellation is going on. Cancel related things are handled + // here. + iCancelling = ETrue; + + // Operations will use callback functions to inform + // when the operation is completed. + TInt count( iOperations.Count() ); + IAUPDATE_TRACE_1("[IAUPDATE] Cancel array count: %d", count); + + for ( TInt i = count - 1; i >= 0; --i ) + { + TIAUpdateOperationInfo info( iOperations[ i ] ); + MNcdOperation* operation( info.iOperation ); + + // Notice, that OperationCompleteL callback is called when + // cancellation finishes + operation->CancelOperation(); + + } + + // Now, that the array elements were released, reset the array. + iOperations.Reset(); + + // Release the flag now, that all the cancellations have been handled. + iCancelling = EFalse; + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::CancelOperation() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::SetSkipChildCountRefresh +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::SetSkipChildCountRefresh( TBool aSkip ) + { + IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateLoader::SetSkipChildCountRefresh(): %d", + aSkip); + iSkipChildCountRefresh = aSkip; + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::NodesUpdated +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::NodesUpdated( + MNcdLoadNodeOperation& /*aOperation*/, + RCatalogsArray< MNcdNode >& /*aNodes*/ ) + { + // No need to inform the observer about single updates. + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::QueryReceived +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::QueryReceived( + MNcdLoadNodeOperation& aOperation, + MNcdQuery* aQuery ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::QueryReceived() begin"); + + // Operation query received. Always accept queries. + // Queries should not be requested from this client. + TInt trapError( KErrNone ); + if ( aQuery ) + { + TRAP ( trapError, + aQuery->SetResponseL( MNcdQuery::EAccepted ); + aOperation.CompleteQueryL( *aQuery ); ); + // Release needs to be called to the query after it is not used. + aQuery->Release(); + } + + if ( ( trapError != KErrNone ) || ( !aQuery ) ) + { + // Error occurred when query was handled. + // So, operation can not continue. + // Cancel operation. Notice, that OperationComplete will be called + // by the operation when cancel is called. + aOperation.CancelOperation(); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::QueryReceived() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::OperationComplete +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::OperationComplete( + MNcdLoadNodeOperation& aOperation, + TInt aError ) + { + IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateLoader::OperationComplete() begin: %d", + aError); + + MNcdNode* operationNode( NULL ); + TIAUpdateOperationInfo::TOperationType operationType( + TIAUpdateOperationInfo::EIdle ); + + // Remember to release the operation, + // because its reference count was increased + // when the operation was inserted into the array. + for ( TInt i = 0; i < iOperations.Count(); ++i ) + { + TIAUpdateOperationInfo tmpInfo( iOperations[ i ] ); + MNcdOperation* operation( tmpInfo.iOperation ); + MNcdOperation* paramOperation( &aOperation ); + if ( paramOperation == operation ) + { + IAUPDATE_TRACE_1("[IAUPDATE] Completed operation was found from the list %d", + i); + + // Get the operation type info. + // Then, we can later decide how to continue. + operationType = tmpInfo.iOperationType; + + // Get the node of the operation. + // Notice, this needs to be released. + operationNode = operation->Node(); + + // Release the operation here because its reference count + // was increased before it was added into the array. + operation->Release(); + + // Remove completed operation from the array. + iOperations.Remove( i ); + + // No need to continue the for loop anymore. + break; + } + } + + if ( operationNode ) + { + if ( aError != KErrNone ) + { + // Get the latest error code, if error has occurred. + // We handle here only error codes that have been + // directed to the operations that we recognized from the + // operation array. + + //Continue next round to load the children. + //This is to make sure when one CGW loading failed, the updates from the other CGW will + //still be shown in mainview. + TRAP_IGNORE( NextLoadLoopL( *operationNode, operationType ) ); + IAUPDATE_TRACE_1("[IAUPDATE] New iErrorCode value: %d", aError); + + if ( iErrorCode == KErrNone ) + { + iErrorCode = aError; + } + } + else + { + // Continue to the next loop only if an error did not occur + // during this round. + TRAPD( trapError, + NextLoadLoopL( *operationNode, operationType ) ); + if ( trapError != KErrNone ) + { + IAUPDATE_TRACE_1("[IAUPDATE] ERROR: Next round error: %d", trapError); + // Something went wrong when children load was started. + // Update error code. + iErrorCode = trapError; + } + } + + // No need for the node anymore. + operationNode->Release(); + operationNode = NULL; + } + + if ( iOperations.Count() == 0 ) + { + IAUPDATE_TRACE("[IAUPDATE] The operation as whole completed"); + // No more operations left. So, inform observer. + if ( iErrorCode == KErrNone ) + { + // Because of workaround needed for handling firmware updates. + // Refresh from network was completed succesfully. + // Current firmware version is stored to private folder. + TRAP_IGNORE( IAUpdateUtils::SaveCurrentFwVersionIfNeededL() ); + } + iObserver.LoadComplete( iErrorCode ); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::OperationComplete() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadRootL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadRootL() + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadRootL() begin"); + + MNcdNode* rootNode( iProvider.RootNodeL() ); + CleanupReleasePushL( *rootNode ); + + MNcdNodeContainer* rootContainer( + rootNode->QueryInterfaceLC< MNcdNodeContainer >() ); + + if ( !rootContainer ) + { + User::Leave( KErrNotFound ); + } + + MNcdNode::TState rootState( rootNode->State() ); + if ( rootState == MNcdNode::EStateInitialized ) + { + IAUPDATE_TRACE("[IAUPDATE] Root already initialized."); + + // CDB connections should be avoided if possible. So, if the + // root node is initialized and not expired, then do not update it + // from the net. Just continue directly to its children. + + if ( iSkipChildCountRefresh ) + { + IAUPDATE_TRACE("[IAUPDATE] Root, load all children and skip child count refresh."); + // Because child count refresh should be skipped. Try to load children + // of the children directly without requesting the child count first. + LoadChildrenOfChildrenL( + *rootContainer, TIAUpdateOperationInfo::ELoadAllChildren ); + } + else + { + IAUPDATE_TRACE("[IAUPDATE] Root, load child containers."); + // At the moment, NCD Engine does not load root children nodes + // when MNcdContainer::LoadChildrenL is called. So, we have to + // load the children one by one here. + LoadChildContainersL( *rootContainer ); + } + } + else + { + IAUPDATE_TRACE_1("[IAUPDATE] Refresh root. State: %d", rootState); + + // Start loading root. + StartLoadOperationL( *rootContainer, TIAUpdateOperationInfo::ELoadRoot ); + } + + // No use for the node objects any more. Release them. + CleanupStack::PopAndDestroy( rootContainer ); + CleanupStack::PopAndDestroy( rootNode ); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadRootL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadChildContainersL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadChildContainersL( MNcdNodeContainer& aParentContainer ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildContainersL() begin"); + + // LoadL is used to update the children of the parent container here + // instead of updating them by calling LoadChildrenL function. + + TInt childCount( aParentContainer.ChildCount() ); + IAUPDATE_TRACE_1("[IAUPDATE] Parent container child count: %d", childCount); + + for ( TInt i = 0; i < childCount; ++i ) + { + IAUPDATE_TRACE_1("[IAUPDATE] Container child: %d", i); + + MNcdNode* node( aParentContainer.ChildL( i ) ); + CleanupReleasePushL( *node ); + + MNcdNodeContainer* container( + node->QueryInterfaceLC< MNcdNodeContainer >() ); + if ( container ) + { + IAUPDATE_TRACE("[IAUPDATE] Container child had container interface"); + LoadContainerL( *container ); + CleanupStack::PopAndDestroy( container ); + } + + CleanupStack::PopAndDestroy( node ); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildContainersL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadContainerL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadContainerL( MNcdNodeContainer& aContainer ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadContainerL() begin"); + + StartLoadOperationL( + aContainer, TIAUpdateOperationInfo::ELoadContainer ); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadContainerL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadChildrenL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadChildrenL( MNcdNodeContainer& aContainer ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildrenL() begin"); + + if ( aContainer.ChildCount() > 0 ) + { + StartLoadOperationL( + aContainer, TIAUpdateOperationInfo::ELoadChildren ); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildrenL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadAllChildrenL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadAllChildrenL( MNcdNodeContainer& aContainer ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadAllChildrenL() begin"); + + if ( !iSkipChildCountRefresh ) + { + // Child count skip flag has been set to EFalse in previous round. + // Most likely NCD Engine does not support load all children functionality. + // So, just load children using normal flow from now on. + // Notice, that now we need to first load the child count + // for the child containers. So, even if children were + // already updated by LoadChildrenL, a new request for + // containers needs . Otherwise, the child count + // will not be up-to-date. When the child containers are + // loaded, the flow will continue to load the children. + IAUPDATE_TRACE("[IAUPDATE] Child count should not be skipped"); + LoadContainerL( aContainer ); + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadAllChildrenL() end"); + return; + } + + TRAPD ( trapError, + StartLoadOperationL( + aContainer, TIAUpdateOperationInfo::ELoadAllChildren ); ); + + IAUPDATE_TRACE_1("[IAUPDATE] trapError: %d", trapError); + + // Only acceptable error is KErrArgument. + // Then it is possible that an old NCD Engine is used + // and it does not allow too big page size. So, in that + // case try one more time below by not skipping child count + // refresh. Else, leave if error occurred. + + if ( trapError == KErrArgument ) + { + IAUPDATE_TRACE("[IAUPDATE] Try to change child load method"); + // Notice, that now we need to first load the child count + // for the child containers. So, even if children were + // already updated by LoadChildrenL, a new request for + // containers needs . Otherwise, the child count + // will not be up-to-date. When the child containers are + // loaded, the flow will continue to load the children. + LoadContainerL( aContainer ); + IAUPDATE_TRACE("[IAUPDATE] Child load method changed and container load started"); + // If we come here, it means that support for all children is + // not available in NCD Engine. So, do not try it after this. + SetSkipChildCountRefresh( EFalse ); + } + else if ( trapError != KErrNone ) + { + IAUPDATE_TRACE_1("[IAUPDATE] Error: %d", trapError); + User::Leave( trapError ); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadAllChildrenL() end"); + } + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::LoadChildrenOfChildrenL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::LoadChildrenOfChildrenL( + MNcdNodeContainer& aContainer, + TIAUpdateOperationInfo::TOperationType aPreviousOperationType ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildrenOfChildrenL() begin"); + + TInt childCount( aContainer.ChildCount() ); + IAUPDATE_TRACE_1("[IAUPDATE] Container child count: %d", childCount); + + for ( TInt i = 0; i < childCount; ++i ) + { + MNcdNode* node( aContainer.ChildL( i ) ); + CleanupReleasePushL( *node ); + + MNcdNodeContainer* container( + node->QueryInterfaceLC< MNcdNodeContainer >() ); + if ( container ) + { + IAUPDATE_TRACE_1("[IAUPDATE] Container child: %d had container interface", i); + + switch ( aPreviousOperationType ) + { + case TIAUpdateOperationInfo::ELoadRoot: + IAUPDATE_TRACE("[IAUPDATE] Load children of the root child"); + // When root is loaded, also its children are loaded + // and they have now their child count. So, no need to + // reload children of the root. Load their children + // directly now. + LoadChildrenL( *container ); + break; + + case TIAUpdateOperationInfo::ELoadChildren: + IAUPDATE_TRACE("[IAUPDATE] Load children of a container"); + // Notice, that now we need to first load the child count + // for the child containers. So, even if children were + // already updated by LoadChildrenL, a new request for + // containers needs . Otherwise, the child count + // will not be up-to-date. When the child containers are + // loaded, the flow will continue to load the children. + LoadContainerL( *container ); + break; + + case TIAUpdateOperationInfo::ELoadAllChildren: + IAUPDATE_TRACE("[IAUPDATE] Load all children of a container"); + // Notice, here we will try to skip the loading of the child + // count of the container. So, all the children are tried to + // be loaded directly even if the child count may not be + // up-to-date. + LoadAllChildrenL( *container ); + break; + + default: + IAUPDATE_TRACE("[IAUPDATE] ERROR: Wrong operation type"); + User::Leave( KErrArgument ); + break; + } + + CleanupStack::PopAndDestroy( container ); + } + + CleanupStack::PopAndDestroy( node ); + } + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::LoadChildrenOfChildrenL() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::StartLoadOperationL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::StartLoadOperationL( + MNcdNodeContainer& aContainer, + TIAUpdateOperationInfo::TOperationType aOperationType ) + { + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::StartLoadOperation() begin"); + + MNcdOperation* operation( NULL ); + + // Create a new operation based on the operation type information. + switch ( aOperationType ) + { + case TIAUpdateOperationInfo::ELoadRoot: + case TIAUpdateOperationInfo::ELoadContainer: + { + // Container itself should be loaded. + IAUPDATE_TRACE("[IAUPDATE] LoadL requested as operation"); + MNcdNode* node( aContainer.QueryInterfaceLC< MNcdNode >() ); + if ( !node ) + { + IAUPDATE_TRACE("[IAUPDATE] Container did not have node interface."); + User::Leave( KErrNotFound ); + } + operation = node->LoadL( *this ); + // No need for the node anymore + CleanupStack::PopAndDestroy( node ); + } + break; + + case TIAUpdateOperationInfo::ELoadChildren: + { + // Children of the container should be loaded. + IAUPDATE_TRACE("[IAUPDATE] LoadChildrenL requested as operation"); + TInt childCount( aContainer.ChildCount() ); + IAUPDATE_TRACE_1("[IAUPDATE] Child count: %d", childCount); + operation = + aContainer.LoadChildrenL( + 0, childCount, ELoadMetadata, *this ); + } + break; + + case TIAUpdateOperationInfo::ELoadAllChildren: + { + // All children of the container should be loaded. + IAUPDATE_TRACE("[IAUPDATE] LoadAllChildren requested as operation"); + // Because we can not be sure about the container child count, + // use the really big value. Then we will surely get all the + // children. + operation = + aContainer.LoadChildrenL( + 0, KChildCountLoadAll, ELoadMetadata, *this ); + } + break; + + default: + IAUPDATE_TRACE_1("[IAUPDATE] ERROR: Operation type: %d", aOperationType); + User::Leave( KErrArgument ); + break; + } + + // Insert the operation to the cleanupstack. So, it will be released + // if leave occurs. + CleanupReleasePushL( *operation ); + + // Insert the operation into the array first. By doing this before starting + // the operation, we do not need to Cancel just started operation if leave + // occurs. + TIAUpdateOperationInfo info( aOperationType, operation ); + iOperations.AppendL( info ); + + TRAPD( trapError, operation->StartOperationL() ); + if ( trapError != KErrNone ) + { + IAUPDATE_TRACE_1("[IAUPDATE] ERROR: Operation Start failed: %d", trapError); + // Operation start failed. + // Remove operation from the array because it was appended + // above. + iOperations.Remove( iOperations.Count() - 1 ); + + // Now, we can leave. + // Notice, this leave will pop and destroy the operation. So, + // it will be released then. + User::Leave( trapError ); + } + + // Operation was started. + // Do not release it now but remove only from the stack. + // Operation will be released when it completes. + CleanupStack::Pop( operation ); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::StartLoadOperation() end"); + } + + +// ----------------------------------------------------------------------------- +// CIAUpdateLoader::NextLoadLoopL +// +// ----------------------------------------------------------------------------- +// +void CIAUpdateLoader::NextLoadLoopL( + MNcdNode& aNode, + TIAUpdateOperationInfo::TOperationType aPreviousOperationType ) + { + IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateLoader::NextLoadLoopL() begin: %d", + aPreviousOperationType); + + MNcdNodeContainer* container( + aNode.QueryInterfaceLC< MNcdNodeContainer >() ); + if ( !container ) + { + IAUPDATE_TRACE("[IAUPDATE] Container interface was not found"); + // Container interface should always exist in these cases. + User::Leave( KErrNotFound ); + } + + // Check if the operation should be continued to its children. + switch ( aPreviousOperationType ) + { + case TIAUpdateOperationInfo::ELoadRoot: + IAUPDATE_TRACE("[IAUPDATE] Previously loaded root"); + // When root is loaded, also its children are loaded + // and they have now their child count. So, no need to + // reload children of the root. Load their children + // directly now. + LoadChildrenOfChildrenL( + *container, + TIAUpdateOperationInfo::ELoadRoot ); + break; + + case TIAUpdateOperationInfo::ELoadContainer: + IAUPDATE_TRACE("[IAUPDATE] Previously loaded container"); + // After normal container has been loaded, + // its children can be loaded. + LoadChildrenL( *container ); + break; + + case TIAUpdateOperationInfo::ELoadChildren: + IAUPDATE_TRACE("[IAUPDATE] Previously loaded children"); + // Because children of the container have been loaded here, + // maybe we need to start a new loop for their children. + // If this container does not contain any new containers, + // then there is nothing to do anymore. + if ( iSkipChildCountRefresh ) + { + // We should come here only after root has been loaded + // and its children of children have been loaded after that. + // After that, skip child count refreshes in the + // next levels. + IAUPDATE_TRACE("[IAUPDATE] Start to load all children"); + LoadChildrenOfChildrenL( + *container, + TIAUpdateOperationInfo::ELoadAllChildren ); + } + else + { + IAUPDATE_TRACE("[IAUPDATE] Continue load children of children"); + LoadChildrenOfChildrenL( + *container, + TIAUpdateOperationInfo::ELoadChildren ); + } + break; + + case TIAUpdateOperationInfo::ELoadAllChildren: + IAUPDATE_TRACE("[IAUPDATE] Previously loaded all children"); + // Notice, here we will try to skip the loading of the child + // count of the container. So, all the children are tried to + // be loaded directly even if the child count may not be + // up-to-date. + LoadChildrenOfChildrenL( + *container, + TIAUpdateOperationInfo::ELoadAllChildren ); + break; + + default: + IAUPDATE_TRACE("[IAUPDATE] No need for next loop"); + // No need to load anything else anymore. + break; + } + + // No need for the interface anymore. Release it. + CleanupStack::PopAndDestroy( container ); + + IAUPDATE_TRACE("[IAUPDATE] CIAUpdateLoader::NextLoadLoopL() end"); + } +