iaupdate/IAD/engine/controller/src/iaupdateloader.cpp
changeset 0 ba25891c3a9e
child 1 c42dffbd5b4f
--- /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 <ncdprovider.h>
+#include <ncdnode.h>
+#include <ncdnodecontainer.h>
+#include <ncdloadnodeoperation.h>
+#include <ncdquery.h>
+#include <ncdnodechildoftransparent.h>
+
+#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");
+    }
+