ncdengine/provider/server/src/ncdloadbundlenodeoperationimpl.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdloadbundlenodeoperationimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1868 @@
+/*
+* Copyright (c) 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:  
+*
+*/
+
+
+#include "ncdloadbundlenodeoperationimpl.h"
+#include "ncdoperationfunctionids.h"
+#include "catalogsbasemessage.h"
+#include "catalogshttpsession.h"
+#include "catalogshttpoperation.h"
+#include "catalogshttpconfig.h"
+#include "catalogsbigdes.h"
+#include "catalogsaccesspointmanagerimpl.h"
+#include "ncdrequestgenerator.h"
+
+#include "ncdrequestbase.h"
+#include "ncdrequestbrowsesearch.h"
+#include "ncdrequestconfiguration.h"
+#include "ncd_pp_itemref.h"
+#include "ncd_pp_folderref.h"
+#include "ncd_pp_dataentity.h"
+#include "ncd_cp_query.h"
+#include "ncd_cp_queryelement.h"
+#include "ncd_cp_queryoption.h"
+
+#include "ncdprotocolutils.h"
+#include "ncdprotocol.h"
+#include "ncdprotocolimpl.h"
+#include "ncdparser.h"
+#include "ncdnodemanager.h"
+#include "ncdproviderdefines.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodefolder.h"
+#include "ncdrootnode.h"
+#include "ncdbundlefolder.h"
+#include "ncdloadnodeoperationimpl.h"
+#include "ncd_cp_detail.h"
+#include "ncd_cp_clientconfiguration.h"
+#include "ncd_cp_error.h"
+#include "catalogscontext.h"
+#include "ncd_cp_serverdetails.h"
+#include "ncdqueryimpl.h"
+#include "ncdnodelink.h"
+#include "ncd_cp_queryresponseimpl.h"
+#include "catalogsutils.h"
+#include "ncderrors.h"
+#include "ncdconfigurationmanager.h"
+#include "ncdoperationremovehandler.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncdnodeiconimpl.h"
+#include "ncdsessionhandler.h"
+#include "ncd_pp_error.h"
+#include "ncdconfigurationkeys.h"
+#include "ncdutils.h"
+#include "ncdnodeidentifiereditor.h"
+#include "ncdnodeidentifier.h"
+#include "ncdprotocolstrings.h"
+#include "ncdnodeseeninfo.h"
+#include "ncdchildentitymap.h"
+#include "ncdproviderutils.h"
+#include "ncdhttputils.h"
+#include "ncdoperationqueue.h"
+#include "ncdgeneralmanager.h"
+#include "ncd_cp_queryimpl.h"
+#include "ncdstring.h"
+#include "ncdnodedisclaimer.h"
+
+#include "catalogsdebug.h"
+
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdLoadBundleNodeOperation* CNcdLoadBundleNodeOperation::NewL(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    CNcdGeneralManager& aGeneralManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue& aOperationQueue,
+    MCatalogsSession& aSession )
+    {
+    CNcdLoadBundleNodeOperation* self = CNcdLoadBundleNodeOperation::NewLC(
+        aNodeIdentifier,
+        aGeneralManager,
+        aHttpSession,
+        aRemoveHandler,
+        aOperationQueue,
+        aSession );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdLoadBundleNodeOperation* CNcdLoadBundleNodeOperation::NewLC(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    CNcdGeneralManager& aGeneralManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue& aOperationQueue,
+    MCatalogsSession& aSession )
+    {
+    CNcdLoadBundleNodeOperation* self =
+        new( ELeave ) CNcdLoadBundleNodeOperation( 
+            aGeneralManager,
+            aHttpSession, 
+            aRemoveHandler, 
+            aOperationQueue, 
+            aSession );
+    CleanupClosePushL( *self );
+    self->ConstructL( aNodeIdentifier );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdLoadBundleNodeOperation::~CNcdLoadBundleNodeOperation()
+    {
+    DLTRACEIN((""));
+    DASSERT( !iNodeDbLocked );
+    iConfigManager.RemoveObserver( *this );
+    
+    iLoadedNodes.ResetAndDestroy();
+    
+    DLTRACE(("Delete id, buffer"));
+    delete iNodeIdentifier;
+    
+    DLTRACE(("Delete parser"));
+    delete iParser;
+    if ( iTransaction )
+        {
+        DLTRACE(("Releasing transaction"));
+        iTransaction->Release();
+        }
+    DLTRACE(("Delete loaded nodes"));
+    iLoadedNodes.ResetAndDestroy();
+        
+    DLTRACE(("Closing suboperations"));
+    // Close operations
+    for ( TInt i = 0; i < iSubOps.Count(); ++i )
+        {
+        iSubOps[i]->Close();        
+        }
+    DLTRACE(("Suboperations closed"));
+    iSubOps.Reset();
+    iFailedSubOps.Reset();
+    iCompletedSubOps.Reset();
+    
+    DLTRACE(("Deleting content sources"));
+    delete iContentSourceMap;
+    
+    DLTRACE(("Delete conf response buffer"));
+    delete iConfigResponseBuf;
+        
+    if( iConfQuery )
+        {
+        iConfQuery->InternalRelease();
+        }
+
+    iSubOpQuerys.Close();
+    
+    delete iServerUri;
+    
+    iChildEntityMaps.ResetAndDestroy();
+    
+    DLTRACEOUT((""));
+    }
+
+const CNcdNodeIdentifier& CNcdLoadBundleNodeOperation::NodeIdentifier() const
+    {
+    return *iNodeIdentifier;
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdLoadBundleNodeOperation::HandleCancelMessage( MCatalogsBaseMessage* aMessage ) 
+    {
+    DLTRACEIN((""));
+    Cancel();
+    CNcdBaseOperation::HandleCancelMessage( aMessage );
+    iOperationQueue.QueuedOperationComplete( *this );
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//    
+TInt CNcdLoadBundleNodeOperation::CompleteMessage(
+    MCatalogsBaseMessage* & aMessage,
+    TNcdOperationMessageCompletionId aId,
+    const MNcdSendable& aSendableObject,
+    TInt aStatus ) 
+    {
+    DLTRACEIN((""));    
+    NotifyCompletionOfQueuedOperation( aId );
+    return CNcdBaseOperation::CompleteMessage( aMessage, aId, aSendableObject, aStatus );
+    }
+    
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//    
+TInt CNcdLoadBundleNodeOperation::CompleteMessage(
+    MCatalogsBaseMessage* & aMessage,
+    TNcdOperationMessageCompletionId aId,
+    TInt aStatus )
+    {
+    DLTRACEIN((""));
+    NotifyCompletionOfQueuedOperation( aId );
+    return CNcdBaseOperation::CompleteMessage( aMessage, aId, aStatus );
+    }
+    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//    
+TInt CNcdLoadBundleNodeOperation::CompleteMessage(
+    MCatalogsBaseMessage*& aMessage,
+    TNcdOperationMessageCompletionId aId,
+    const MNcdSendable& aSendableObject,
+    RPointerArray<CNcdNodeIdentifier>& aNodes,
+    TInt aStatus )
+    {
+    DLTRACEIN((""));
+    NotifyCompletionOfQueuedOperation( aId );
+    return CNcdBaseOperation::CompleteMessage( aMessage, aId, aSendableObject, aNodes, aStatus );
+    }
+    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//    
+TInt CNcdLoadBundleNodeOperation::CompleteMessage(
+    MCatalogsBaseMessage*& aMessage,
+    TNcdOperationMessageCompletionId aId,
+    RPointerArray<CNcdExpiredNode>& aExpiredNodes,
+    TInt aStatus )
+    {
+    DLTRACEIN((""));
+    NotifyCompletionOfQueuedOperation( aId );
+    return CNcdBaseOperation::CompleteMessage( aMessage, aId, aExpiredNodes, aStatus );
+    }
+    
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TInt CNcdLoadBundleNodeOperation::Start()
+    {
+    DLTRACEIN((""));
+    if ( iOperationState == EStateStopped )
+        {
+        // Op not yet running, queue it
+        iOperationState = EStateRunning;                
+        TRAPD( err, iOperationQueue.QueueOperationL( *this ) );        
+        return err;
+        }
+    else
+        {
+        return KErrInUse;
+        }
+    }    
+    
+    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdLoadBundleNodeOperation::Cancel()
+    {
+    DLTRACEIN( ( "" ) );
+    if ( iTransaction )
+        {
+        iTransaction->Cancel();        
+        iTransaction = NULL;
+        }
+    if ( iParser )
+        {
+        iParser->CancelParsing();
+        }    
+    for ( TInt i = 0 ; i < iSubOps.Count() ; i++ )
+        {
+        iSubOps[i]->Cancel();
+        iSubOps[i]->Close();
+        }
+    iSubOps.Reset();
+    if ( iNodeDbLocked ) 
+        {        
+        iNodeManager->UnlockNodeDb( iNodeIdentifier->ClientUid() );
+        iNodeDbLocked = EFalse;
+        TRAP_IGNORE( iNodeManager->RevertNodeCacheL( *iNodeIdentifier ) );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdLoadBundleNodeOperation::HandleHttpEventL( 
+        MCatalogsHttpOperation& aOperation, 
+        TCatalogsHttpEvent aEvent )
+    {
+    DLTRACEIN((""));
+    DASSERT( &aOperation == iTransaction );
+    DASSERT( aOperation.OperationType() == ECatalogsHttpTransaction );
+
+    TCatalogsTransportProgress progress( iTransaction->Progress() );
+    
+    // Are state and id needed?
+    iProgress = TNcdSendableProgress( iBundleNodeState,
+        iTransaction->OperationId().Id(), progress.iProgress,
+        progress.iMaxProgress );
+
+    switch( aEvent.iOperationState ) 
+        {
+        // Handle completed operation
+        case ECatalogsHttpOpCompleted:
+            {
+            
+            iTransaction->Release();
+            iTransaction = NULL;
+            // Inform parser that no more data will be sent
+            iParser->EndL();
+            break;
+            }     
+               
+        // Handle operation in progress
+        case ECatalogsHttpOpInProgress:
+            {
+            if( aEvent.iProgressState == ECatalogsHttpResponseBodyReceived )
+                {
+                // If config response, append the contents to the buffer.
+                if ( iBundleNodeState == EReceiveConf ) 
+                    {
+                    iConfigResponseBuf->InsertL(
+                        iConfigResponseBuf->Size(), aOperation.Body() );                        
+                    }               
+
+                // send received data to parser
+                iParser->ParseL( aOperation.Body() );
+                }
+            break;
+            }
+                    
+        default:
+            {
+            break;
+            }
+        }
+    }
+    
+    
+TBool CNcdLoadBundleNodeOperation::HandleHttpError( 
+    MCatalogsHttpOperation& aOperation, 
+    TCatalogsHttpError aError )    
+    {
+    DLTRACEIN(("Error type: %d, code: %d", aError.iType, aError.iError ));    
+    DASSERT( &aOperation == iTransaction );
+    
+    aOperation.Release();
+    iTransaction = NULL;
+
+    if ( iMasterServerRedirectionState == ERedirecting ) 
+        {
+        // Return back to original master server uri.
+        iConfigManager.RemoveObserver( *this );
+        TRAPD(err, iConfigManager.ResetMasterServerAddressL(
+            iPendingMessage->Session().Context() ));
+        if( err != KErrNone )
+            {
+            iError = err;
+            iBundleNodeState = EFailed;
+            }
+        else
+            {
+            iMasterServerRedirectionState = EReverted;
+            iBundleNodeState = EConfRequest;
+            }
+        }
+    else
+        {
+        iError = aError.iError;
+        iBundleNodeState = EFailed;
+        }
+    RunOperation();
+    return ETrue;
+    }
+
+void CNcdLoadBundleNodeOperation::ParseError( TInt aErrorCode )
+    {
+    DLTRACEIN(("error:%d", aErrorCode ));
+    
+    // Handle error only if not handling an error already
+    // (cancellation of parsing may cause an unnecessary call to this function).
+    if ( iError == KErrNone )
+        {
+        if ( iMasterServerRedirectionState == ERedirecting ) 
+            {
+            // Return back to original master server uri.
+            iConfigManager.RemoveObserver( *this );
+            TRAPD(err, iConfigManager.ResetMasterServerAddressL(
+                iPendingMessage->Session().Context() ));
+            if( err != KErrNone )
+                {
+                iError = err;
+                iBundleNodeState = EFailed;
+                }
+            else
+                {
+                iMasterServerRedirectionState = EReverted;
+                iBundleNodeState = EConfRequest;
+                }
+            }
+        else 
+            {            
+            iBundleNodeState = EFailed;
+            iError = aErrorCode;
+            }
+            
+        if ( iTransaction )
+            {
+            iTransaction->Cancel();
+            iTransaction = NULL;
+            }
+        if ( iParser )
+            {
+            iParser->CancelParsing();
+            }
+        
+        RunOperation();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdLoadBundleNodeOperation::ParseCompleteL( TInt aError )
+    {
+    DLTRACEIN((_L("error:%d"), aError ));
+    
+    if ( iParser )
+        {
+        delete iParser;
+        iParser = NULL;
+        }
+    if ( aError != KErrNone )
+        {
+        DLTRACE(("Parsing error, stop operation!"))
+        iError = aError;
+        iBundleNodeState = EFailed;
+        RunOperation();
+        }
+    else
+        {
+        DASSERT( iBundleNodeState == EReceiveConf || iBundleNodeState == EConfRequest );
+        if ( iConfQuery )
+            {
+            DLTRACE(("Query received, let base op handle it"));
+            iBundleNodeState = EConfQuery;
+            // let base op handle the query
+            TRAPD( err, CNcdBaseOperation::QueryReceivedL( iConfQuery ) );
+            if ( err != KErrNone ) 
+                {
+                iError = err;
+                iBundleNodeState = EFailed;
+                RunOperation();
+                }
+            }
+        else if ( iBundleNodeState == EConfRequest )
+            {
+            DASSERT( iMasterServerRedirectionState == ERedirecting );
+            RunOperation();
+            }
+        else if ( iContentSourceMap->ContentSourceCount() < 1 ) 
+            {
+            iError = KNcdErrorNoContentSources;
+            iBundleNodeState = EFailed;
+            DLINFO(("No content sources received, stop operation!"))
+            RunOperation();
+            }
+        else
+            {            
+            iBundleNodeState = EBrowseRequest;
+            RunOperation();
+            }
+        }
+    DLTRACEOUT((""));
+    }
+
+void CNcdLoadBundleNodeOperation::ConfigurationBeginL( const TDesC& aVersion, 
+                                                     TInt aExpirationDelta )
+    {
+    DLTRACEIN((""));
+
+    // set expiration delta for the bundle node
+    iNodeManager->NodeL( *iNodeIdentifier ).
+        CreateAndSetLinkL().SetValidUntilDelta( aExpirationDelta );
+    // Pass to default observer.
+    DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationBeginL( aVersion, aExpirationDelta );
+    DLTRACEOUT((""));
+    }
+    
+void CNcdLoadBundleNodeOperation::ConfigurationQueryL(
+    MNcdConfigurationProtocolQuery* aQuery )
+    {
+    DLTRACEIN(("Query received"));
+    DASSERT( !iConfQuery );
+    CleanupDeletePushL( aQuery );
+    // create a query object form the protocol entity
+    iConfQuery = CNcdQuery::NewL( *aQuery, IsHttpsUri( *iServerUri ) );
+    CleanupStack::Pop( aQuery );    
+    
+	// Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationQueryL( aQuery );
+    DLTRACEOUT((""));
+    }
+
+void CNcdLoadBundleNodeOperation::ClientConfigurationL(
+    MNcdConfigurationProtocolClientConfiguration* aConfiguration )
+    {
+    DLTRACEIN((""));
+    
+    CleanupDeletePushL( aConfiguration );
+    if ( !iNodeDbLocked )
+        {        
+        iNodeManager->LockNodeDbL( iNodeIdentifier->ClientUid() );
+        iNodeDbLocked = ETrue;
+        }
+    DLINFO(("detail count:%d", aConfiguration->DetailCount()));
+
+    // Parse access point data from client configuration response.
+    iAccessPointManager.ParseAccessPointDataFromClientConfL(
+        *aConfiguration, iPendingMessage->Session().Context().FamilyId() );
+    
+    for( TInt i = 0 ; i < aConfiguration->DetailCount() ; i++ )
+        {
+        const MNcdConfigurationProtocolDetail& detail = aConfiguration->DetailL( i );
+        DLINFO((_L("detail: id=%S value=%S"), &detail.Id(), &detail.Value() ));
+        
+        if ( detail.Id() != KContentSources )
+            {
+            continue;
+            }
+        const RPointerArray<MNcdConfigurationProtocolDetail>& csDetails =
+            detail.Details();
+        DLINFO(("csDetails count=%d", csDetails.Count()));
+        for ( TInt j = 0 ; j < csDetails.Count() ; j++ )
+            {            
+            MNcdConfigurationProtocolDetail* csDetail = csDetails[j];
+            DLINFO((_L("csDetail: id=%S value=%S"), &csDetail->Id(), &csDetail->Value() ));
+            if ( csDetail->Id() != KNameSpace )
+                {
+                continue;
+                }
+            
+            if ( csDetail->GroupId() == KCatalogBundle ) 
+                {
+                ParseCatalogBundleL( *csDetail );
+                continue;
+                }
+
+            }           
+        }
+    if ( iContentSourceMap->ContentSourceCount() < 1 &&
+              iMasterServerRedirectionState == EReverted )
+        {
+        iError = KNcdErrorNoContentSources;
+        iBundleNodeState = EFailed;
+        DLINFO(("No content sources received, stop operation!"))
+        RunOperation();
+        // Leave so that parsing is not continued.
+        User::Leave( iError );
+        }
+    CleanupStack::Pop( aConfiguration );
+	// Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ClientConfigurationL( aConfiguration );
+    DLTRACEOUT((""));
+    }
+    
+void CNcdLoadBundleNodeOperation::ConfigurationDetailsL(
+    CArrayPtr<MNcdConfigurationProtocolDetail>* aDetails )
+    {
+    DLTRACEIN((""));
+    
+    // Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+	iDefaultConfigurationProtocolObserver->ConfigurationDetailsL( aDetails );
+	
+	DLTRACEOUT((""));
+    }
+    
+void CNcdLoadBundleNodeOperation::ConfigurationActionRequestL(
+    MNcdConfigurationProtocolActionRequest* aActionRequest )
+    {
+    DLTRACEIN((""));
+	// Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationActionRequestL( aActionRequest );
+    DLTRACEOUT((""));
+    }
+
+void CNcdLoadBundleNodeOperation::ConfigurationServerDetailsL( MNcdConfigurationProtocolServerDetails* aServerDetails )
+    {
+    DLTRACEIN((""));
+	// Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationServerDetailsL( aServerDetails );
+    DLTRACEOUT((""));
+    }
+
+void CNcdLoadBundleNodeOperation::ConfigurationErrorL( MNcdConfigurationProtocolError* aError )
+    {
+    DLTRACEIN((""));
+    iBundleNodeState = EFailed;
+    iError = aError->Code();
+
+	// Pass ownership to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationErrorL( aError );
+   
+    RunOperation();
+
+    DLTRACEOUT((""));
+    }
+    
+void CNcdLoadBundleNodeOperation::ConfigurationEndL()
+    {
+    DLTRACEIN((""));
+	// Pass to default observer.
+	DASSERT( iDefaultConfigurationProtocolObserver != NULL );
+    iDefaultConfigurationProtocolObserver->ConfigurationEndL();
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdLoadBundleNodeOperation::Progress( CNcdBaseOperation& aOperation )
+    {
+    (void) aOperation; // suppresses compiler warning
+    DASSERT( iBundleNodeState == EReceiveBrowse )
+    DASSERT( aOperation.Type() == ELoadNodeOperation )
+    }
+    
+void CNcdLoadBundleNodeOperation::QueryReceived( CNcdBaseOperation& /*aOperation*/,
+    CNcdQuery* aQuery )
+    {
+    DASSERT( iBundleNodeState == EReceiveBrowse )
+    TRAPD( err, iSubOpQuerys.AppendL( aQuery ) );
+    aQuery->InternalAddRef();
+    if( err != KErrNone )
+        {
+        iError = err;
+        iBundleNodeState = EFailed;
+        }
+    RunOperation();
+    }
+    
+void CNcdLoadBundleNodeOperation::OperationComplete( CNcdBaseOperation* aOperation,
+                                                   TInt aError )
+    {
+    DLTRACEIN(("error=%d", aError));
+    DLINFO((("iBundleNodeState = %d"), iBundleNodeState ));
+    (void) aError; // suppresses compiler warning
+
+    DASSERT( iBundleNodeState == EReceiveBrowse || 
+             iBundleNodeState == EBrowseRequest )
+    DASSERT( aOperation->Type() == ELoadNodeOperation )
+    
+    DLINFO(("subop count: failed:%d completed:%d total:%d",
+                iFailedSubOps.Count(), iCompletedSubOps.Count(), iSubOps.Count() ));
+    
+    TRAPD(err, 
+    CNcdLoadNodeOperationImpl* loadOp =
+        static_cast<CNcdLoadNodeOperationImpl*>( aOperation );
+    DASSERT( loadOp->State() == CNcdLoadNodeOperationImpl::EFailed ||
+        loadOp->State() == CNcdLoadNodeOperationImpl::EComplete )
+    if ( loadOp->State() == CNcdLoadNodeOperationImpl::EFailed )
+        {
+        iFailedSubOps.AppendL( loadOp );
+        }
+    else if ( loadOp->State() == CNcdLoadNodeOperationImpl::EComplete )
+        {
+        iCompletedSubOps.AppendL( loadOp );
+        const RPointerArray<CNcdNodeIdentifier>& loadedNodes = loadOp->LoadedNodes();
+
+        // add loaded nodes from child op to our own array
+        for ( TInt i = 0 ; i < loadedNodes.Count() ; i++ )
+            {
+            CNcdNodeIdentifier* id = CNcdNodeIdentifier::NewLC( *loadedNodes[i] );
+            iLoadedNodes.AppendL( id );
+            CleanupStack::Pop( id );
+            }
+        }
+    
+    if ( iBundleNodeState ==  EReceiveBrowse )
+        {
+        // call RunOperation only in this state,
+        // otherwise RunOperation could call itself immediately
+        // after starting a sub op
+        // (sub-op start -> error -> complete callback -> run op )
+        RunOperation();
+        }); //TRAPD    
+    if ( err != KErrNone )
+        {
+        iError = err;
+        iBundleNodeState = EFailed;
+        RunOperation();
+        }
+    }
+    
+void CNcdLoadBundleNodeOperation::ConfigurationChangedL() 
+    {
+    DLTRACEIN((( "iBundleNodeState: %d"), iBundleNodeState ));
+    DASSERT( iBundleNodeState == EReceiveConf )    
+    // Master server address changed. Restart operation.
+    iBundleNodeState = EConfRequest;
+    iMasterServerRedirectionState = ERedirecting;    
+    }
+    
+void CNcdLoadBundleNodeOperation::ReceiveMessage(
+    MCatalogsBaseMessage* aMessage,
+    TInt aFunctionNumber ) 
+    {    
+    DLTRACEIN((_L("Handle: %i, aFunctionNumber=%d"), aMessage->Handle(),
+    aFunctionNumber));
+
+    switch ( aFunctionNumber ) 
+        {
+        case ENCDOperationFunctionGetData:
+            {
+            HandleConfigurationDataRequestMessage( *aMessage );
+            break;
+            }
+        default:
+            {
+            CNcdBaseOperation::ReceiveMessage( aMessage, aFunctionNumber );
+            break;
+            }
+        }
+    }
+
+void CNcdLoadBundleNodeOperation::ErrorL( MNcdPreminetProtocolError* aData )
+    {
+    DLTRACEIN((""));    
+    // Default observer deletes aData
+    iParser->DefaultObserver().ErrorL( aData );
+    }
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdLoadBundleNodeOperation::CNcdLoadBundleNodeOperation(
+    CNcdGeneralManager& aGeneralManager, 
+    MCatalogsHttpSession& aHttpSession,  
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue& aOperationQueue,
+    MCatalogsSession& aSession )
+    : CNcdBaseOperation( aGeneralManager, aRemoveHandler, ELoadBundleNodeOperation,
+        aSession ), 
+      iAccessPointManager( aGeneralManager.AccessPointManager() ),
+      iHttpSession( aHttpSession ),
+      iProtocol( aGeneralManager.ProtocolManager() ),
+      iConfigManager( aGeneralManager.ConfigurationManager() ),
+      iNodeDbLocked( EFalse ),
+      iOperationQueue( aOperationQueue ),
+      iFirstConfRequest( ETrue )
+    {
+    iBundleNodeState = EConfRequest;
+    iMasterServerRedirectionState = EBegin;
+    iProgress.iState = 0;
+    iProgress.iOperationId = 0;
+    iProgress.iProgress = 0;
+    iProgress.iMaxProgress = 100;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+void CNcdLoadBundleNodeOperation::ConstructL(
+    const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((""));
+    CNcdBaseOperation::ConstructL();
+    
+    iConfigResponseBuf = CBufFlat::NewL( 100 );
+    iNodeIdentifier = CNcdNodeIdentifier::NewL( aNodeIdentifier );
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNcdLoadBundleNodeOperation::CreateConfRequestLC( CNcdQuery* aQuery )
+    {
+    DLTRACEIN((""));
+    CNcdRequestConfiguration* req =
+        NcdRequestGenerator::CreateConfigurationRequestLC();
+    CNcdNode& bundleNode = iNodeManager->NodeL( *iNodeIdentifier );
+    
+    CNcdNodeIdentifier* metadataIdentifier = 
+        NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( *iNodeIdentifier );
+            
+    RBuf8 buf;
+    CleanupClosePushL( buf );
+    buf.CreateL( metadataIdentifier->NodeId().Length() );
+    buf.Copy( metadataIdentifier->NodeId() );
+    
+    req->AddCatalogBundleRequestL( buf );
+    CleanupStack::PopAndDestroy( &buf );
+    
+    CleanupStack::PopAndDestroy( metadataIdentifier );
+    
+    if( aQuery )
+        {
+        DASSERT(( aQuery->Response() == MNcdQuery::EAccepted ));
+        
+        MNcdConfigurationProtocolQueryResponse* queryResponse =
+            CreateResponseL( *aQuery );
+        CleanupStack::PushL( queryResponse );
+        req->AddQueryResponseL( queryResponse );
+        CleanupStack::Pop( queryResponse );
+        }
+        
+    HBufC8* data = iProtocol.ProcessConfigurationRequestL(
+        iPendingMessage->Session().Context(), *req );
+    CleanupStack::PopAndDestroy( req );
+    CleanupStack::PushL( data );    
+    return data;
+    }
+
+
+void CNcdLoadBundleNodeOperation::RevertNodesOfBrokenSourcesToCacheL() 
+    {
+    DLTRACEIN((""));
+    // Revert the nodes from broken content sources
+    CNcdRootNode* rootNode( NULL );
+    TRAPD( err, rootNode = &iNodeManager->RootNodeL( iNodeIdentifier->ClientUid() ) );
+    
+    if ( err != KErrNone )
+        {
+        // Root node has not been created, so there is no old content source map.
+        // There is no need to revert anything.
+        return;
+        }
+        
+    DASSERT( rootNode );
+    
+    CNcdContentSourceMap& oldContentSourceMap = rootNode->ContentSourceMap();
+    DLINFO(("old content source count=%d", oldContentSourceMap.ContentSourceCount() ));
+    for ( TInt i = 0; i < oldContentSourceMap.ContentSourceCount(); i++ ) 
+        {
+        CNcdContentSource& oldSource = oldContentSourceMap.ContentSource( i );
+
+        // Note that the content sources contain node identifiers, 
+        // not metadata identifiers.        
+        RPointerArray<CNcdNodeIdentifier>& oldNodes = 
+            oldContentSourceMap.NodesL( oldSource );
+            
+        if ( iContentSourceMap->HasContentSource( oldSource ) )
+            {           
+            DLINFO(("same content source")); 
+            CNcdContentSource& source = 
+                iContentSourceMap->ContentSourceL( oldSource );
+            if ( source.IsBroken() ) 
+                {
+                // Broken content source, revert the nodes belonging to this source                                             
+                for ( TInt i = 0; i < oldNodes.Count(); i++ ) 
+                    {
+                    RevertNodeL( *oldNodes[i], source );
+                    }
+                }
+            }
+        else if ( oldSource.ParentIdentifier().Equals( *iNodeIdentifier ) )
+            {
+            DLINFO(("content source disappeared"));
+            for ( TInt i = 0; i < oldNodes.Count(); i++ ) 
+                {                
+                iNodeManager->RemoveNodeL( *oldNodes[i] );
+                }
+            }            
+        }
+    }
+        
+    
+void CNcdLoadBundleNodeOperation::RevertNodeL(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    const CNcdContentSource& aContentSource ) 
+    {
+    DLTRACEIN((_L("node ns: %S, id: %S"), 
+        &aNodeIdentifier.NodeNameSpace(), 
+        &aNodeIdentifier.NodeId() ));
+        
+    iNodeManager->RevertNodeFromTempCacheL( aNodeIdentifier );
+    CNcdNode* node = iNodeManager->NodePtrL( aNodeIdentifier );
+    DASSERT( node );
+    
+    // If the node is bundle's child, it must be added as a child since it was removed from the 
+    // child list as it was moved to temp cache.
+    CNcdNodeIdentifier* parentId = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier );
+    if ( parentId->Equals( *iNodeIdentifier ) ) 
+        {
+        DLINFO(("Child of bundle"));
+        CNcdNode& bundleNode = 
+            iNodeManager->NodeL( *iNodeIdentifier );
+        CNcdNodeIdentifier* metaOfChild = 
+            NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( aNodeIdentifier );
+        iNodeManager->AddToParentL(
+            *parentId, *metaOfChild, CNcdNodeFactory::ENcdNodeFolder, CNcdNodeFactory::ENcdBundleNode,
+            CNcdNodeFactory::NodePurposeL( *node ), CNcdNodeManager::EInsert,
+            iContentSourceMap->GetInsertIndexL( aContentSource, *parentId ) );
+        CleanupStack::PopAndDestroy( metaOfChild );
+        }
+    CleanupStack::PopAndDestroy( parentId );        
+    }
+    
+    
+void CNcdLoadBundleNodeOperation::RemoveOldNodesL() 
+    {
+    DLTRACEIN((""));
+    CNcdRootNode& rootNode = 
+        iNodeManager->RootNodeL( iNodeIdentifier->ClientUid() );
+    CNcdContentSourceMap& oldContentSourceMap = rootNode.ContentSourceMap();
+    DLINFO(("old content source count=%d", oldContentSourceMap.ContentSourceCount() ));
+    for ( TInt i = 0; i < oldContentSourceMap.ContentSourceCount(); i++ ) 
+        {
+        CNcdContentSource& oldSource = oldContentSourceMap.ContentSource( i );
+
+        // Note that the content sources contain node identifiers, 
+        // not metadata identifiers.        
+        RPointerArray<CNcdNodeIdentifier>& oldNodes = 
+            oldContentSourceMap.NodesL( oldSource );
+            
+        if ( iContentSourceMap->HasContentSource( oldSource ) )
+            {           
+            DLINFO(("same content source")); 
+            CNcdContentSource& source = 
+                iContentSourceMap->ContentSourceL( oldSource );
+            if ( !source.IsBroken() ) 
+                {                
+                RPointerArray<CNcdNodeIdentifier>& nodes = 
+                    iContentSourceMap->NodesL( source );
+                for ( TInt i = 0; i < oldNodes.Count(); i++ ) 
+                    {
+                    if ( !ContainsNode( nodes, *oldNodes[i] ) ) 
+                        {                        
+                        // Note that the content sources contain node identifiers, 
+                        // not metadata identifiers.
+                        iNodeManager->RemoveNodeL( *oldNodes[i] );
+                        }
+                    }
+                }
+            }
+        else if ( oldSource.ParentIdentifier().Equals( *iNodeIdentifier ) )
+            {
+            DLINFO(("content source disappeared"));
+            for ( TInt i = 0; i < oldNodes.Count(); i++ ) 
+                {                
+                iNodeManager->RemoveNodeL( *oldNodes[i] );
+                }
+            }
+        }
+    }
+    
+void CNcdLoadBundleNodeOperation::AddBundleToLoadedNodesL() 
+    {
+    DLTRACEIN((""));
+    CNcdNodeIdentifier* bundleId = CNcdNodeIdentifier::NewLC( *iNodeIdentifier );
+    iLoadedNodes.AppendL( bundleId );
+    CleanupStack::Pop( bundleId );    
+    }
+    
+void CNcdLoadBundleNodeOperation::SetAlwaysVisibleFlagsL() 
+    {
+    DLTRACEIN((""));
+    for ( TInt i = 0; i < iContentSourceMap->ContentSourceCount(); i++ ) 
+        {
+        CNcdContentSource& contentSource = iContentSourceMap->ContentSource( i );
+        if ( !contentSource.AlwaysVisible() ) 
+            {
+            continue;
+            }
+        // Get the reference. So, no need to close this array.
+        RPointerArray<CNcdNodeIdentifier>& nodes = iContentSourceMap->NodesL( contentSource );
+        TRAPD( err, 
+            {            
+            for ( TInt i = 0; i < nodes.Count(); i++ ) 
+                {
+                // Because content sources use node id 
+                CNcdNodeIdentifier* nodeId = nodes[i];
+                
+                // Check whether the node is loaded completely
+                for ( TInt i = 0; i < iLoadedNodes.Count(); i++ ) 
+                    {
+                    if ( iLoadedNodes[i]->Equals( *nodeId ) ) 
+                        {                        
+                        CNcdNode& node = iNodeManager->NodeL( *nodeId );
+                        CNcdNodeMetaData& metadata = node.NodeMetaDataL();                
+                        metadata.SetAlwaysVisible( ETrue );
+                        
+                        // DLMAIN-523, "Always visible information is not 
+                        // persisted to disk"
+                        iNodeManager->DbSaveNodeMetaDataL( metadata );
+                        break;
+                        }
+                    }
+                }
+            }); // TRAP
+
+
+        if ( err == KErrNotFound ) 
+            {
+            DASSERT( EFalse );
+            }
+        else if ( err != KErrNone )
+            {
+            User::Leave( err );
+            }
+
+        }
+    DLTRACEOUT(("Ok."));
+    }
+    
+void CNcdLoadBundleNodeOperation::UpdateCsMapToRootNodeL() 
+    {
+    DLTRACEIN((""));
+    CNcdRootNode& rootNode = iNodeManager->CreateRootL( iNodeIdentifier->ClientUid() );
+    CNcdContentSourceMap& oldMap = rootNode.ContentSourceMap();
+    
+    // Find the bundle from old map
+    TInt folderIndex = oldMap.FindFolder( *iNodeIdentifier );
+    if ( folderIndex == KErrNotFound ) 
+        {
+        // This bundle folder is not in root node's content source map.
+        // Can happen for example when cache has been cleared and favorite view opened
+        // if there is a bundle folder in favorites.
+        for ( TInt i = 0; i < iContentSourceMap->ContentSourceCount(); i++ ) 
+            {
+            CNcdContentSource& cs = iContentSourceMap->ContentSource( i );
+            CNcdContentSource* copy = cs.CopyL();
+            CleanupStack::PushL( copy );
+            oldMap.AppendContentSourceL( copy );
+            CleanupStack::Pop( copy );
+            }
+        }
+    else 
+        {
+        // Root node's content source map contains this bundle folder already. Clear
+        // the old content sources from the bundle and add the new ones.
+        CNcdFolderContent& content = oldMap.FolderContent( folderIndex );
+        content.ClearContentSources();
+        for ( TInt i = 0; i < iContentSourceMap->ContentSourceCount(); i++ ) 
+            {
+            CNcdContentSource& cs = iContentSourceMap->ContentSource( i );
+            CNcdContentSource* copy = cs.CopyL();
+            CleanupStack::PushL( copy );
+            content.AppendContentSourceL( copy );    
+            CleanupStack::Pop( copy );
+            }
+        }
+        
+    DASSERT( !iNodeDbLocked );        
+    // Root node's content source map updated, save root node to db
+    iNodeManager->DbSaveNodeL( rootNode );
+    }
+
+     
+void CNcdLoadBundleNodeOperation::ParseCatalogBundleL(
+    const MNcdConfigurationProtocolDetail& aDetail ) 
+    {  
+    DLTRACEIN((""));
+    DASSERT( aDetail.GroupId() == KCatalogBundle );
+    DASSERT( aDetail.Id() == KNameSpace );
+    
+    // The bundle node should already exist.
+    CNcdNode& bundleFolder = iNodeManager->NodeL( *iNodeIdentifier );
+    CNcdNodeLink& link = bundleFolder.NodeLinkL();
+
+    CNcdNodeIdentifier* metaDataId =
+        NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( *iNodeIdentifier );
+    
+    const RPointerArray<MNcdConfigurationProtocolContent>& bundleContents = 
+        aDetail.Contents();
+
+#ifdef CATALOGS_BUILD_CONFIG_DEBUG    
+    const TDesC* bundleId = NULL;
+    for ( TInt i = 0; i < bundleContents.Count(); i++ ) 
+        {
+        const MNcdConfigurationProtocolContent* content = bundleContents[i];
+        if ( content->Key() == KId ) 
+            {
+            bundleId = &content->Value();
+            break;
+            }
+        }
+        
+    DASSERT( bundleId );
+    DASSERT( *bundleId == metaDataId->NodeId() );
+    DASSERT( aDetail.Value() == metaDataId->NodeNameSpace() );    
+#endif  
+    
+    // Also, notice that it is essential to insert the metadata identifier into the
+    // link info. So, the right metadata will be found when the bundle is opened
+    // from the database. For example when application has been started.
+    link.SetMetaDataIdentifierL( *metaDataId );
+    
+    // Create meta data for bundle folder.
+    CNcdNodeMetaData& bundleMetaData = 
+        iNodeManager->CreateNodeMetaDataL( *metaDataId, CNcdNodeFactory::ENcdNodeFolder );
+    
+    for ( TInt i = 0; i < bundleContents.Count(); i++ )
+        {
+        const MNcdConfigurationProtocolContent* content = bundleContents[i];
+        if ( content->Key() == KName ) 
+            {
+            bundleMetaData.SetNodeNameL( content->Value() );
+            }
+        else if ( content->Key() == KDescription ) 
+            {
+            bundleMetaData.SetDescriptionL( content->Value() );
+            }
+        else if ( content->Key() == KValidUntil ) 
+            {
+            link.SetValidUntilDelta(
+                NcdProtocolUtils::DesDecToIntL( content->Value() ) );
+            }
+        else if ( content->Key() == KViewType ) 
+            {
+            static_cast<CNcdBundleFolder&>( bundleFolder ).SetViewTypeL( 
+                content->Value() );
+            }
+        else if ( content->Key() == KDisclaimer )
+            {
+            HandleBundleDisclaimerL( bundleMetaData, content->Value() );
+            }
+        }
+            
+    const RPointerArray<MNcdConfigurationProtocolDetail>& subCatalogs = 
+        aDetail.Details();
+
+    // Parse icon data.
+    for ( TInt i = 0; i < subCatalogs.Count(); i++ ) 
+        {
+        MNcdConfigurationProtocolDetail* detail = subCatalogs[i];
+        if ( detail->Id() != KIcon ) 
+            {
+            continue;
+            }
+        const RPointerArray<MNcdConfigurationProtocolContent> iconContents = 
+            detail->Contents();
+        CNcdNodeIcon* icon = CNcdNodeIcon::NewL( *iNodeManager, bundleMetaData );
+        bundleMetaData.SetIcon( icon );
+        
+        for ( TInt i = 0; i < iconContents.Count(); i++ ) 
+            {
+            MNcdConfigurationProtocolContent* content = iconContents[i];
+            if ( content->Key() == KId ) 
+                {
+                icon->SetIconIdL( content->Value() );
+                }
+            else if ( content->Key() == KData ) 
+                {
+                const TDesC& iconData = content->Content();
+                HBufC8* iconData8 = HBufC8::NewLC( iconData.Length() );
+                iconData8->Des().Copy( iconData );
+                HBufC8* decodedData = 
+                    NcdProtocolUtils::DecodeBase64LC( *iconData8 );
+                
+                // Save the icon data to database.
+                CNcdNodeIdentifier* iconId = CNcdNodeIdentifier::NewLC(
+                    metaDataId->NodeNameSpace(), icon->IconId(), 
+                    icon->Uri(), metaDataId->ClientUid() );
+                iNodeManager->DbSaveIconDataL( *iconId, *decodedData );
+                CleanupStack::PopAndDestroy( iconId );
+                CleanupStack::PopAndDestroy( decodedData );
+                CleanupStack::PopAndDestroy( iconData8 );
+                }
+            else if ( content->Key() == KUri && content->Value() != KNullDesC )
+                {
+                DLTRACE((_L("Setting bundle icon uri: %S"), &content->Value() ));
+                icon->SetUriL( content->Value() );
+                }
+            }
+        }
+        
+    CleanupStack::PopAndDestroy( metaDataId );
+    
+    iNodeManager->DbSaveNodeMetaDataL( bundleMetaData );          
+
+    // Set the metadata to the bundle folder because it was not set during creation.
+    bundleFolder.SetNodeMetaDataL( bundleMetaData );
+    
+    iNodeManager->DbSaveNodeL( bundleFolder );        
+
+    // Parse sub catalogs.            
+    for ( TInt i = 0; i < subCatalogs.Count(); i++ ) 
+        {
+        MNcdConfigurationProtocolDetail* subCatalog = subCatalogs[i];
+        if ( subCatalog->GroupId() != KSubCatalogs ) 
+            {
+            continue;
+            }
+            
+        DASSERT( subCatalog->Id() == KNameSpace );
+        // The parameter is the parent node identifier.
+        CNcdContentSource* contentSource = CNcdContentSource::NewLC( bundleFolder.Identifier() );
+        contentSource->SetNameSpaceL( subCatalog->Value() );
+
+        DLINFO((_L("Bundle subcatalog ns(/value): %S"), 
+                &subCatalog->Value()));
+        
+        const RPointerArray<MNcdConfigurationProtocolDetail>& subCatalogDetails =
+            subCatalog->Details();
+        for ( TInt i = 0; i < subCatalogDetails.Count(); i++ ) 
+            {
+            const MNcdConfigurationProtocolDetail* detail = subCatalogDetails[i];
+            if ( detail->Id() == KUri ) 
+                {
+                contentSource->SetUriL( detail->Value() );
+                DLINFO((_L("Bundle subcatalog detail uri(/value): %S"), 
+                        &detail->Value()));
+                }
+            }
+        
+        const RPointerArray<MNcdConfigurationProtocolContent>& subCatalogContents =
+            subCatalog->Contents();
+        for ( TInt i = 0; i < subCatalogContents.Count(); i++ ) 
+            {
+            const MNcdConfigurationProtocolContent* content = subCatalogContents[i];
+            if ( content->Key() == KId ) 
+                {
+                // Notice that the the content source ids should be node identifiers.
+                // Not the actual metadata identifiers. So, append the root info
+                // in front of the value gotten from the server.
+                CNcdNodeIdentifier* contentIdentifier =
+                    CNcdNodeIdentifier::NewLC( contentSource->NameSpace(),
+                                               content->Value(),
+                                               contentSource->Uri(),
+                                               bundleFolder.Identifier().ClientUid() );
+
+                CNcdNodeIdentifier* actualNodeIdentifier =
+                    NcdNodeIdentifierEditor::CreateNodeIdentifierLC( bundleFolder.Identifier(),
+                                                                      *contentIdentifier );
+                                                              
+                contentSource->SetNodeIdL( actualNodeIdentifier->NodeId() );
+                
+                DLINFO((_L("Bundle subcatalog content set node id(/value): %S"), 
+                        &actualNodeIdentifier->NodeId()));
+                        
+                CleanupStack::PopAndDestroy( actualNodeIdentifier );
+                CleanupStack::PopAndDestroy( contentIdentifier );
+                }
+            else if ( content->Key() == KProvider ) 
+                {
+                contentSource->SetProviderL( content->Value() );
+                DLINFO((_L("Bundle subcatalog content set provider (/value): %S"), 
+                        &content->Value()));
+                }
+            else if ( content->Key() == KTransparent ) 
+                {
+                TBool transparent = EFalse;
+                NcdProtocolUtils::DesToBool( transparent, content->Value() );
+                contentSource->SetTransparent( transparent );
+                }
+            }
+            
+        // add the content source to content source map
+        iContentSourceMap->AppendContentSourceL( contentSource );
+        CleanupStack::Pop( contentSource );
+        }
+    }
+    
+    
+void CNcdLoadBundleNodeOperation::NotifyCompletionOfQueuedOperation(
+    TNcdOperationMessageCompletionId aId )
+    {
+    DLTRACEIN((""));
+    if ( aId == ENCDOperationMessageCompletionComplete ||
+         aId == ENCDOperationMessageCompletionError )
+        {
+        iOperationQueue.QueuedOperationComplete( *this );
+        }
+    }
+    
+    
+TBool CNcdLoadBundleNodeOperation::ContainsNode(
+    const RPointerArray<CNcdNodeIdentifier>& aNodes,
+    const CNcdNodeIdentifier& aNode) 
+    {
+    for ( TInt i = 0; i < aNodes.Count(); i++ ) 
+        {
+        CNcdNodeIdentifier* nodeId = aNodes[i];
+        DASSERT( nodeId->ClientUid() == aNode.ClientUid() );
+        if ( nodeId->Equals( aNode ) ) 
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+
+void CNcdLoadBundleNodeOperation::HandleBundleDisclaimerL(
+    CNcdNodeMetaData& aMetadata, 
+    const TDesC& aDisclaimer )
+    {
+    DLTRACEIN((""));
+    // Create a temp query that is initialized with the disclaimer data
+    // and internalize the disclaimer-object with the query. This
+    // way we don't have to add new setters to CNcdNodeDisclaimer
+    CNcdConfigurationProtocolQueryImpl* tempQuery = 
+        CNcdConfigurationProtocolQueryImpl::NewLC();
+    tempQuery->iBodyText->SetDataL( aDisclaimer );
+    tempQuery->iSemantics = MNcdQuery::ESemanticsDisclaimer;
+    
+    CNcdNodeDisclaimer* disclaimer = CNcdNodeDisclaimer::NewLC();
+    disclaimer->InternalizeL( *tempQuery );
+    aMetadata.SetDisclaimer( disclaimer );
+    
+    CleanupStack::Pop( disclaimer );
+    CleanupStack::PopAndDestroy( tempQuery );
+    }
+
+    
+void CNcdLoadBundleNodeOperation::HandleConfigurationDataRequestMessage(
+    MCatalogsBaseMessage& aMessage ) 
+    {
+    DLTRACEIN((""));
+    TPtr8 data = iConfigResponseBuf->Ptr( 0 );
+    
+    TRAPD( err, aMessage.CompleteAndReleaseL( data, KErrNone ) );
+    if ( err != KErrNone ) 
+        {
+        aMessage.CompleteAndRelease( err );
+        }        
+    }    
+// ---------------------------------------------------------------------------
+// From class CNcdBaseOperation.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TInt CNcdLoadBundleNodeOperation::RunOperation()
+    {
+    DLTRACEIN((("this-ptr: %x"), this ));
+  
+    TRAPD( err, DoRunOperationL() ); 
+     
+     if ( err != KErrNone )
+        {
+        DLTRACE(("error: %d", err));
+        Cancel();
+        iBundleNodeState = EFailed;
+        iError = err;
+        if ( iPendingMessage )
+            {
+            // ignoring error because operation already failed
+            CompleteMessage( iPendingMessage,
+                ENCDOperationMessageCompletionError, iError );
+            }
+        }
+
+    DLTRACEOUT(("err: %d", err));
+    return err;    
+    }
+
+void CNcdLoadBundleNodeOperation::DoRunOperationL()
+    {
+    DLTRACEIN((""));
+    switch ( iBundleNodeState )
+        {
+        case EConfRequest:
+            {            
+            DLTRACE((_L("->EConfRequest")));
+            DASSERT ( iPendingMessage );
+                                    
+            // remove old content sources
+            delete iContentSourceMap;
+            iContentSourceMap = NULL;
+            iContentSourceMap = CNcdContentSourceMap::NewL();
+            
+            delete iServerUri;
+            iServerUri = NULL;
+            
+            // Use the server uri from bundle node's node link, if it exists.
+            // This way we use the correct uri in case of scheme bundle folder.
+            CNcdNodeFolder& bundleNode = iNodeManager->FolderL( *iNodeIdentifier );
+            if ( bundleNode.CreateAndSetLinkL().ServerUri() != KNullDesC ) 
+                {
+                iServerUri = bundleNode.NodeLinkL().ServerUri().AllocL();
+                }
+            else 
+                {
+                iServerUri = iConfigManager.MasterServerAddressL(
+                    iPendingMessage->Session().Context() ).AllocL();
+                }
+            DLINFO((_L("server uri: %S"), iServerUri ));
+                        
+            
+            if ( iFirstConfRequest )
+                {
+                // Store previous list only if some children have been previously loaded.
+                if( bundleNode.ChildrenPreviouslyLoaded() )
+                    {
+                    bundleNode.StoreChildrenToPreviousListL();
+                    }
+                
+                // Create previous lists of children for new checking.
+                iChildEntityMaps.ResetAndDestroy();
+                iNodeManager->SeenInfo().CreatePreviousListsForChildrenL( bundleNode, iChildEntityMaps );
+
+                // Backup node RAM cache to temp cache.
+                iNodeManager->BackupAndClearCacheL( *iNodeIdentifier );
+                iNodeManager->LockNodeDbL( iNodeIdentifier->ClientUid() );
+                iNodeDbLocked = ETrue;                                  
+                }
+            
+            HBufC8* request = CreateConfRequestLC( iConfQuery );
+            
+            if ( iConfQuery )
+                {
+                iConfQuery->InternalRelease();
+                iConfQuery = NULL;
+                }
+                        
+            DLINFO(( "request= %S", request ));
+            
+            // create transaction
+            iGeneralManager.HttpUtils().CreateTransactionL( 
+                iHttpSession,
+                iTransaction,
+                *iServerUri,
+                *this,
+                *request );
+
+            
+            // create parser
+            delete iParser;
+            iParser = NULL;
+            iParser = iProtocol.CreateParserL( 
+                iPendingMessage->Session().Context(), *iServerUri );
+            MNcdParserObserverBundle& observers = iParser->Observers();
+            observers.SetParserObserver( this );
+            iDefaultConfigurationProtocolObserver =
+                observers.ConfigurationProtocolObserver();
+            observers.SetConfigurationProtocolObserver( this );
+            observers.SetInformationObserver( this );
+            
+            iConfigManager.AddObserverL( *this, iPendingMessage->Session().Context() );
+            
+            iParser->BeginAsyncL();
+  
+            // start transaction
+            User::LeaveIfError( iTransaction->Start() );            
+            CleanupStack::PopAndDestroy( request );
+            
+            iFirstConfRequest = EFalse;
+            iBundleNodeState = EReceiveConf;
+            DLTRACE((_L("->EConfRequest done")));
+            break;
+            }
+            
+        case EReceiveConf:
+            {
+            DLTRACE((_L("->EReceiveConf")));
+            // Should send progress only if progress is made
+            
+            if ( iPendingMessage && iSendProgress )
+                {
+                User::LeaveIfError( CompleteMessage( iPendingMessage,
+                    ENCDOperationMessageCompletionProgress,
+                    iProgress, KErrNone ) );
+                iSendProgress = EFalse;
+                }
+            DLTRACE((_L("->EReceiveConf done")));
+            break;
+            }
+            
+        case EConfQuery:
+            {
+            DLTRACE(("->EConfQuery"));
+            DASSERT( iConfQuery );
+            DASSERT( iConfQuery->Response() == MNcdQuery::EAccepted ||
+                iConfQuery->Response() == MNcdQuery::ERejected )
+            if ( iConfQuery->Response() == MNcdQuery::EAccepted)
+                {
+                DLTRACE(("Query accepted"));
+                if ( iConfQuery->ItemCount() == 0 )
+                    {
+                    // SPECIAL CASE:
+                    // querys with no items don't need responding to
+                    // e.g. a server message
+                    if( iContentSourceMap->ContentSourceCount() > 0 )
+                        {
+                        // content sources received in the earlier response,
+                        // start loading them
+                        iBundleNodeState = EBrowseRequest;
+                        }
+                    else if ( iMasterServerRedirectionState == ERedirecting )
+                        {
+                        // Redirect. Delete conf query since it does not need
+                        // responding to new master server.
+                        DLINFO(("Redirect"));
+                        iConfQuery->InternalRelease();
+                        iConfQuery = NULL;                       
+                        iBundleNodeState = EConfRequest;
+                        }                        
+                    else
+                        {
+                        // no content sources received
+                        // e.g. server didn't give any content sources 
+                        // with the set provisioning, only a 
+                        // "service not available..." message is received
+                        iBundleNodeState = EComplete;
+                        }                                
+                    }
+                else
+                    {
+                    // NORMAL CASE:
+                    // Respond to the query in a new request
+                    iBundleNodeState = EConfRequest;
+                    }            
+                }            
+            else
+                {
+                DLTRACE(("Query rejected"));
+                if ( iConfQuery->IsOptional() )
+                    {
+                    DLTRACE(("Query is optional"));
+                    if( iContentSourceMap->ContentSourceCount() > 0 )
+                        {
+                        DLTRACE(("Content sources received previously, start loading"));
+                        // content sources received in the earlier response,
+                        // start loading them
+                        iBundleNodeState = EBrowseRequest;
+                        }
+                    else if ( iMasterServerRedirectionState == ERedirecting )
+                        {
+                        // Redirect. Delete conf query since it does not need
+                        // responding to new master server.
+                        DLINFO(("Redirect"));
+                        iConfQuery->InternalRelease();
+                        iConfQuery = NULL;                       
+                        iBundleNodeState = EConfRequest;
+                        }                                                
+                    else
+                        {
+                        DLTRACE(("No sources received!"));
+                        // no content sources received with an optional query
+                        // this should never happen!                        
+                        iError = KNcdErrorNoContentSources;
+                        iBundleNodeState = EFailed;
+                        }                            
+                    }
+                else
+                    {
+                    DLTRACE(("Query not optional, operation will stop!"));
+                    iBundleNodeState = EComplete;
+                    }
+                }
+                            
+            RunOperation();            
+            DLTRACE(("->EConfQuery done"));
+            break;
+            }
+            
+        case EBrowseRequest:
+            {
+            DLTRACE((_L("->EBrowseRequest")));
+                        
+            iSubOps.ResetAndDestroy();
+
+            // Create load node op for each content source.
+            DLINFO((("Content source count=%d"), iContentSourceMap->ContentSourceCount()));
+            for ( TInt i = 0 ; i < iContentSourceMap->ContentSourceCount() ; i++ )
+                {
+                CNcdContentSource& contentSource =
+                    iContentSourceMap->ContentSource( i );
+                DLINFO((_L("content source: namespace=%S, uri=%S, id=%S"),
+                    &contentSource.NameSpace(), &contentSource.Uri(), &contentSource.NodeId()));
+                
+                CNcdLoadNodeOperationImpl* loadOp =
+                    CNcdLoadNodeOperationImpl::NewLC(
+                        contentSource,
+                        iContentSourceMap,
+                        contentSource.ParentIdentifier(),
+                        iGeneralManager,                        
+                        iHttpSession,                        
+                        iRemoveHandler,
+                        iSession );
+                
+                loadOp->AddObserverL( this );
+                iSubOps.AppendL( loadOp );
+                CleanupStack::Pop( loadOp );
+                // error code ignored, errors handled via callback
+                loadOp->Start();
+                }
+            
+            iBundleNodeState = EReceiveBrowse;
+            DLINFO(("subop count: failed:%d completed:%d total:%d",
+                iFailedSubOps.Count(), iCompletedSubOps.Count(), iSubOps.Count() ));
+            if ( iFailedSubOps.Count() + iCompletedSubOps.Count() ==
+                 iSubOps.Count() )
+                {
+                // all sub ops have either completed or failed
+                // -> this operation is now complete
+                iBundleNodeState = EComplete;
+                if ( iFailedSubOps.Count() > 0 ) 
+                    {
+                    DLINFO(("Some catalogs failed to load"));
+                    iError = KNcdErrorSomeCatalogsFailedToLoad;
+                    }
+                RunOperation();
+                }
+                
+            DLTRACE((_L("->EBrowseRequest done")));
+            
+            break;
+            }
+            
+        case EReceiveBrowse:
+            {
+            DLTRACE((_L("->EReceiveBrowse")));
+            if( iSubOpQuerys.Count() > 0 )
+                {
+                // send sub op query to proxy
+                CNcdBaseOperation::QueryReceivedL( iSubOpQuerys[0] );
+                iSubOpQuerys.Remove( 0 );
+                }                
+            else if ( iPendingMessage && iLoadedNodes.Count() > 0 )
+                {
+                SetAlwaysVisibleFlagsL();
+                
+                // send updated nodes identifiers to proxy
+                User::LeaveIfError( CompleteMessage( iPendingMessage,
+                    ENCDOperationMessageCompletionNodesUpdated,
+                    iProgress,
+                    iLoadedNodes,
+                    KErrNone ) );
+                
+                iLoadedNodes.ResetAndDestroy();
+                }
+            else if ( iFailedSubOps.Count() + iCompletedSubOps.Count() ==
+                 iSubOps.Count() )
+                {
+                // all sub ops have either completed or failed
+                // -> this operation is now complete
+                iBundleNodeState = EComplete;
+                if ( iFailedSubOps.Count() > 0 ) 
+                    {
+                    DLINFO(("Some catalogs failed to load"));
+                    iError = KNcdErrorSomeCatalogsFailedToLoad;
+                    }
+                RunOperation();
+                }
+                
+            DLTRACE((_L("->EReceiveBrowse done")));
+            break;
+            }
+            
+        case EComplete:
+            {
+            DLTRACE((_L("->EComplete")));
+            
+            // Compare the ContentSourceMaps of previous root node load and this
+            // load and delete the nodes that were removed from server.
+            if ( iContentSourceMap && iContentSourceMap->ContentSourceCount() > 0 ) 
+                {
+                DLINFO(("Content source map count"));
+                RevertNodesOfBrokenSourcesToCacheL();                                            
+                AddBundleToLoadedNodesL();
+                SetAlwaysVisibleFlagsL();
+
+                // Now the RAM node cache should be updated correctly, save it to database.
+                iNodeManager->UnlockNodeDb( iNodeIdentifier->ClientUid() );
+                iNodeDbLocked = EFalse;
+
+                UpdateCsMapToRootNodeL();
+                
+                delete iContentSourceMap;
+                iContentSourceMap = NULL;
+
+                iNodeManager->DbSaveNodesL( *iNodeIdentifier );                                
+                }
+                
+            if( iNodeDbLocked )
+                {
+                iNodeManager->UnlockNodeDb( iNodeIdentifier->ClientUid() );
+                iNodeDbLocked = EFalse;
+                }
+            
+            iNodeManager->ClearTempCacheL( *iNodeIdentifier );
+                            
+            CNcdNodeFolder& bundleNode = 
+                iNodeManager->FolderL( *iNodeIdentifier );
+                
+            // Set the children loaded flag so that next refresh stores
+            // previous child list (needed for new checking)
+            if( bundleNode.ChildCount() )
+                {
+                bundleNode.SetChildrenPreviouslyLoaded();
+                iNodeManager->DbSaveNodeL( bundleNode );
+                }
+                
+            // Check new status
+            iNodeManager->SeenInfo().StorePreviousListsToExistingChildrenL(
+                bundleNode,
+                iChildEntityMaps );
+                
+            iChildEntityMaps.ResetAndDestroy();
+            
+            // Check new status for transparent folders (transparent folders are
+            // loaded during bundle op so they need to be checked here)
+            iNodeManager->SeenInfo().DoNewCheckForTransparentChildrenL(
+                bundleNode );
+            
+            iNodeManager->SeenInfo().RefreshFolderSeenStatusL( *iNodeIdentifier );
+            
+            if ( iPendingMessage && iLoadedNodes.Count() > 0 )
+                {
+                DLINFO(("Pending message loaded nodes"));
+                // send updated nodes identifiers to proxy
+                User::LeaveIfError( CompleteMessage( iPendingMessage,
+                    ENCDOperationMessageCompletionNodesUpdated,
+                    iProgress,
+                    iLoadedNodes,
+                    KErrNone ) );
+                
+                iLoadedNodes.ResetAndDestroy();                
+                }
+            else if ( iPendingMessage )
+                {
+                DLINFO(("Pending message"));
+                if ( iError == KErrNone ) 
+                    {                    
+                    // Send complete message to proxy.
+                    User::LeaveIfError( CompleteMessage( iPendingMessage,
+                        ENCDOperationMessageCompletionComplete,
+                        iProgress,
+                        KErrNone ) );
+                                        
+                    iOperationState = EStateComplete;
+                    }
+                else 
+                    {
+                    iBundleNodeState = EFailed;
+                    RunOperation();
+                    }
+                }
+            DLTRACE((_L("->EComplete done")));
+            break;
+            }
+            
+        case EFailed:
+            {
+            DLTRACE((_L("->EFailed")));
+            Cancel();
+            // Send error message in case didn't have any pending
+            // messages when the operation actually failed
+            if( iPendingMessage )
+                {
+                DLINFO(("Pending"));
+                // ignoring error because operation already failed
+                CompleteMessage( iPendingMessage,
+                    ENCDOperationMessageCompletionError, iError );
+                }
+            DLTRACE((_L("->EFailed done")));
+            break;
+            }
+            
+        default:
+            {
+            DLTRACE(("default"));
+            DASSERT(0);
+            break;
+            }
+        }
+    }
+    
+void CNcdLoadBundleNodeOperation::ChangeToPreviousStateL()
+    {
+    DLTRACEIN(("no implementation needed"));
+    }
+
+TBool CNcdLoadBundleNodeOperation::QueryCompletedL( CNcdQuery* aQuery )
+    {    
+    DLTRACEIN((""));
+    TBool handled = EFalse;
+ 
+    if ( aQuery == iConfQuery )
+        {
+        // handle conf query
+        DASSERT( iBundleNodeState == EConfQuery );
+        if ( aQuery->Response() == MNcdQuery::ERejected )
+            {
+            Cancel();
+            }
+        handled = ETrue;
+        }
+    else
+        {
+        // handle child ops's querys
+        TBool found = EFalse;
+        for( TInt i = 0 ; i < iSubOps.Count() ; i++ )
+            {
+            CNcdQuery* query = iSubOps[i]->ActiveQuery();
+            if ( aQuery == query )
+                {
+                iSubOps[i]->QueryHandledL( aQuery );
+                TInt index = iSubOpQuerys.Find( aQuery );
+                if ( index != KErrNotFound )
+                    {
+                    // remove reference
+                    iSubOpQuerys[index]->InternalRelease();
+                    iSubOpQuerys.Remove( index );
+                    }
+                query->InternalRelease();
+                query = NULL;
+                found = ETrue;
+                break;
+                }
+            if ( query )
+                {
+                query->InternalRelease();
+                }
+            }
+        if ( !found )
+            {
+            DLINFO(("Query doesn't belong to any sub op! ERROR!"))
+            DASSERT( 0 );
+            User::Leave( KErrArgument );
+            }
+        else
+            {
+            handled = ETrue;
+            }
+        }
+
+    return handled;
+    }