diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdloadrootnodeoperationimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/provider/server/src/ncdloadrootnodeoperationimpl.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,1828 @@ +/* +* 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 +#include + +#include "ncdloadrootnodeoperationimpl.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 "ncdchildentity.h" +#include "ncdprotocolstrings.h" +#include "ncdnodeseeninfo.h" +#include "ncdchildentitymap.h" +#include "ncdproviderutils.h" +#include "ncdhttputils.h" +#include "ncdgeneralmanager.h" + +#include "catalogsdebug.h" + +// --------------------------------------------------------------------------- +// ?description_if_needed +// --------------------------------------------------------------------------- +// +CNcdLoadRootNodeOperation* CNcdLoadRootNodeOperation::NewL( + TInt aClientUid, + CNcdGeneralManager& aGeneralManager, + MCatalogsHttpSession& aHttpSession, + MNcdOperationRemoveHandler* aRemoveHandler, + MCatalogsSession& aSession ) + { + CNcdLoadRootNodeOperation* self = CNcdLoadRootNodeOperation::NewLC( + aClientUid, + aGeneralManager, + aHttpSession, + aRemoveHandler, + aSession ); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// ?description_if_needed +// --------------------------------------------------------------------------- +// +CNcdLoadRootNodeOperation* CNcdLoadRootNodeOperation::NewLC( + TInt aClientUid, + CNcdGeneralManager& aGeneralManager, + MCatalogsHttpSession& aHttpSession, + MNcdOperationRemoveHandler* aRemoveHandler, + MCatalogsSession& aSession ) + { + CNcdLoadRootNodeOperation* self = + new( ELeave ) CNcdLoadRootNodeOperation( + aClientUid, + aGeneralManager, + aHttpSession, + aRemoveHandler, + aSession ); + CleanupClosePushL( *self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// ?description_if_needed +// --------------------------------------------------------------------------- +// +CNcdLoadRootNodeOperation::~CNcdLoadRootNodeOperation() + { + DLTRACEIN(("")); + DASSERT( !iNodeDbLocked ); + iConfigManager.RemoveObserver( *this ); + + iLoadedNodes.ResetAndDestroy(); + + DLTRACE(("Delete id, buffer")); + delete iRootNodeIdentifier; + + 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& CNcdLoadRootNodeOperation::NodeIdentifier() const + { + return *iRootNodeIdentifier; + } + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CNcdLoadRootNodeOperation::HandleCancelMessage( MCatalogsBaseMessage* aMessage ) + { + DLTRACEIN(("")); + Cancel(); + CNcdBaseOperation::HandleCancelMessage( aMessage ); + } + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CNcdLoadRootNodeOperation::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( TUid::Uid( iClientUid ) ); + iNodeDbLocked = EFalse; + TRAP_IGNORE( iNodeManager->RevertNodeCacheL( *iRootNodeIdentifier ) ); + } + } + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CNcdLoadRootNodeOperation::HandleHttpEventL( + MCatalogsHttpOperation& aOperation, + TCatalogsHttpEvent aEvent ) + { + DLTRACEIN(("")); + DASSERT( &aOperation == iTransaction ); + DASSERT( aOperation.OperationType() == ECatalogsHttpTransaction ); + + TCatalogsTransportProgress progress( iTransaction->Progress() ); + + // Are state and id needed? + iProgress = TNcdSendableProgress( iRootNodeState, + 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 ( iRootNodeState == EReceiveConf ) + { + iConfigResponseBuf->InsertL( + iConfigResponseBuf->Size(), aOperation.Body() ); + } + + // send received data to parser + iParser->ParseL( aOperation.Body() ); + } + break; + } + + default: + { + break; + } + } + } + + +TBool CNcdLoadRootNodeOperation::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; + iRootNodeState = EFailed; + } + else + { + iMasterServerRedirectionState = EReverted; + iRootNodeState = EConfRequest; + } + } + else + { + iError = aError.iError; + iRootNodeState = EFailed; + } + RunOperation(); + return ETrue; + } + +void CNcdLoadRootNodeOperation::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; + iRootNodeState = EFailed; + } + else + { + iMasterServerRedirectionState = EReverted; + iRootNodeState = EConfRequest; + } + } + else + { + iRootNodeState = EFailed; + iError = aErrorCode; + } + + if ( iTransaction ) + { + iTransaction->Cancel(); + iTransaction = NULL; + } + if ( iParser ) + { + iParser->CancelParsing(); + } + + RunOperation(); + } + } + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +void CNcdLoadRootNodeOperation::ParseCompleteL( TInt aError ) + { + DLTRACEIN((_L("error:%d"), aError )); + + if ( iParser ) + { + delete iParser; + iParser = NULL; + } + if ( aError != KErrNone ) + { + DLTRACE(("Parsing error, stop operation!")) + iError = aError; + iRootNodeState = EFailed; + RunOperation(); + } + else + { + DASSERT( iRootNodeState == EReceiveConf || iRootNodeState == EConfRequest ); + if ( iConfQuery ) + { + DLTRACE(("Query received, let base op handle it")); + iRootNodeState = EConfQuery; + // let base op handle the query + TRAPD( err, CNcdBaseOperation::QueryReceivedL( iConfQuery ) ); + if ( err != KErrNone ) + { + iError = err; + iRootNodeState = EFailed; + RunOperation(); + } + } + else if ( iRootNodeState == EConfRequest ) + { + DASSERT( iMasterServerRedirectionState == ERedirecting ); + RunOperation(); + } + else if ( iContentSourceMap->ContentSourceCount() < 1 && + iContentSourceMap->BundleFolderCount() < 1 ) + { + iError = KNcdErrorNoContentSources; + iRootNodeState = EFailed; + DLINFO(("No content sources received, stop operation!")) + RunOperation(); + } + else + { + iRootNodeState = EBrowseRequest; + RunOperation(); + } + } + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationBeginL( const TDesC& aVersion, + TInt aExpirationDelta ) + { + DLTRACEIN(("")); + // set expiration delta for root node + // No need to set metadata value for root, because it does not have one. + iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ). + CreateAndSetLinkL().SetValidUntilDelta( aExpirationDelta ); + // Pass to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ConfigurationBeginL( aVersion, aExpirationDelta ); + + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationQueryL( + MNcdConfigurationProtocolQuery* aQuery ) + { + DLTRACEIN(("")); + 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 CNcdLoadRootNodeOperation::ClientConfigurationL( + MNcdConfigurationProtocolClientConfiguration* aConfiguration ) + { + DLTRACEIN(("")); + + CleanupDeletePushL( aConfiguration ); + if ( !iNodeDbLocked ) + { + iNodeManager->LockNodeDbL( TUid::Uid( iClientUid ) ); + iNodeDbLocked = ETrue; + } + DLINFO(("detail count:%d", aConfiguration->DetailCount())); + + // Parse access point data from client configuration response. + iAccessPointManager.ParseAccessPointDataFromClientConfL( + *aConfiguration, iPendingMessage->Session().Context().FamilyId() ); + + iBundleInsertIndex = 0; + + 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& 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; + } + + // create a content source + // The parameter is the parent node identifier. + CNcdContentSource* contentSource = + CNcdContentSource::NewLC( *iRootNodeIdentifier ); + contentSource->SetNameSpaceL( csDetail->Value() ); + + // get details + const RPointerArray& nsDetails = + csDetail->Details(); + DLINFO(("nsDetails count=%d", nsDetails.Count())); + for ( TInt k = 0 ; k < nsDetails.Count() ; k++ ) + { + MNcdConfigurationProtocolDetail* nsDetail = nsDetails[k]; + DLINFO((_L("nsDetail: id=%S value=%S"), &nsDetail->Id(), &nsDetail->Value() )); + if ( nsDetail->Id() == KUri ) + { + contentSource->SetUriL( nsDetail->Value() ); + } + } + + // get contents + const RPointerArray& nsContents = + csDetail->Contents(); + DLINFO(("nsContents count=%d", nsContents.Count())); + for ( TInt l = 0 ; l < nsContents.Count() ; l++ ) + { + MNcdConfigurationProtocolContent* nsContent = nsContents[l]; + DLINFO((_L("nsContent: key=%S value=%S"), &nsContent->Key(), &nsContent->Value() )); + if ( nsContent->Key() == KProvider ) + { + contentSource->SetProviderL( nsContent->Value() ); + } + else if ( nsContent->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(), + nsContent->Value(), + iRootNodeIdentifier->ClientUid() ); + CNcdNodeIdentifier* actualNodeIdentifier = + NcdNodeIdentifierEditor::CreateNodeIdentifierLC( *iRootNodeIdentifier, + *contentIdentifier ); + DLINFO((_L("Actual nodeidentifier for content source: %S"), + &actualNodeIdentifier->NodeId())); + contentSource->SetNodeIdL( actualNodeIdentifier->NodeId() ); + CleanupStack::PopAndDestroy( actualNodeIdentifier ); + CleanupStack::PopAndDestroy( contentIdentifier ); + } + else if ( nsContent->Key() == KAlwaysVisible ) + { + TBool visible = EFalse; + NcdProtocolUtils::DesToBool( visible, nsContent->Value() ); + contentSource->SetAlwaysVisible( visible ); + } + else if ( nsContent->Key() == KTransparent ) + { + TBool transparent = EFalse; + NcdProtocolUtils::DesToBool( transparent, nsContent->Value() ); + contentSource->SetTransparent( transparent ); + } + } + + DLINFO((_L("content source: namespace=%S, uri=%S, provider=%S, nodeid=%S"), + &contentSource->NameSpace(), + &contentSource->Uri(), + &contentSource->Provider(), + &contentSource->NodeId())); + iContentSourceMap->AppendContentSourceL( contentSource ); + CleanupStack::Pop( contentSource ); + iBundleInsertIndex++; + } + } + + CleanupStack::Pop( aConfiguration ); + // Pass ownership to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ClientConfigurationL( aConfiguration ); + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationDetailsL( + CArrayPtr* aDetails ) + { + DLTRACEIN(("")); + + // Pass ownership to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ConfigurationDetailsL( aDetails ); + + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationActionRequestL( + MNcdConfigurationProtocolActionRequest* aActionRequest ) + { + DLTRACEIN(("")); + // Pass ownership to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ConfigurationActionRequestL( aActionRequest ); + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationServerDetailsL( MNcdConfigurationProtocolServerDetails* aServerDetails ) + { + DLTRACEIN(("")); + // Pass ownership to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ConfigurationServerDetailsL( aServerDetails ); + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationErrorL( MNcdConfigurationProtocolError* aError ) + { + DLTRACEIN(("")); + iRootNodeState = EFailed; + iError = aError->Code(); + + // Pass ownership to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + // Operation already failed, ignore possible error here + TRAP_IGNORE(iDefaultConfigurationProtocolObserver->ConfigurationErrorL( aError )); + + RunOperation(); + + DLTRACEOUT(("")); + } + +void CNcdLoadRootNodeOperation::ConfigurationEndL() + { + DLTRACEIN(("")); + // Pass to default observer. + DASSERT( iDefaultConfigurationProtocolObserver != NULL ); + iDefaultConfigurationProtocolObserver->ConfigurationEndL(); + DLTRACEOUT(("")); + } + + +void CNcdLoadRootNodeOperation::Progress( CNcdBaseOperation& aOperation ) + { + (void) aOperation; // suppresses compiler warning + DASSERT( iRootNodeState == EReceiveBrowse ) + DASSERT( aOperation.Type() == ELoadNodeOperation ) + //CNcdLoadNodeOperationImpl& loadOp = + // static_cast( aOperation ); + + /*for ( TInt i = 0 ; i < loadOp.LoadedNodes().Count() ; i++ ) + { + iLoadedNodes.AppendL( loadOp.LoadedNodes()[i] ); + }*/ + } + +void CNcdLoadRootNodeOperation::QueryReceived( CNcdBaseOperation& /*aOperation*/, + CNcdQuery* aQuery ) + { + DASSERT( iRootNodeState == EReceiveBrowse ) + TRAPD( err, iSubOpQuerys.AppendL( aQuery ) ); + aQuery->InternalAddRef(); + if( err != KErrNone ) + { + iError = err; + iRootNodeState = EFailed; + } + RunOperation(); + } + +void CNcdLoadRootNodeOperation::OperationComplete( CNcdBaseOperation* aOperation, + TInt aError ) + { + DLTRACEIN(("error=%d", aError)); + DLINFO((("iRootNodeState = %d"), iRootNodeState )); + (void) aError; // suppresses compiler warning + + DASSERT( iRootNodeState == EReceiveBrowse || + iRootNodeState == 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( 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& loadedNodes = loadOp->LoadedNodes(); + CNcdRootNode& rootNode = + iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ); + CNcdNodeLink& rootLink = rootNode.NodeLinkL(); + TTime currentTime; + currentTime.HomeTime(); + + // 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 ( iRootNodeState == 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; + iRootNodeState = EFailed; + RunOperation(); + } + } + +void CNcdLoadRootNodeOperation::ConfigurationChangedL() + { + DLTRACEIN((( "iRootNodeState: %d"), iRootNodeState )); + DASSERT( iRootNodeState == EReceiveConf ) + // Master server address changed. Restart operation. + iRootNodeState = EConfRequest; + iMasterServerRedirectionState = ERedirecting; + } + +void CNcdLoadRootNodeOperation::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 CNcdLoadRootNodeOperation::ErrorL( MNcdPreminetProtocolError* aData ) + { + DLTRACEIN(("")); + // Default observer deletes aData + iParser->DefaultObserver().ErrorL( aData ); + } + +// --------------------------------------------------------------------------- +// ?description_if_needed +// --------------------------------------------------------------------------- +// +CNcdLoadRootNodeOperation::CNcdLoadRootNodeOperation( + TInt aClientUid, + CNcdGeneralManager& aGeneralManager, + MCatalogsHttpSession& aHttpSession, + MNcdOperationRemoveHandler* aRemoveHandler, + MCatalogsSession& aSession ) + : CNcdBaseOperation( aGeneralManager, aRemoveHandler, ELoadRootNodeOperation, + aSession ), + iAccessPointManager( aGeneralManager.AccessPointManager() ), + iHttpSession( aHttpSession ), + iProtocol( aGeneralManager.ProtocolManager() ), + iConfigManager( aGeneralManager.ConfigurationManager() ), + iClientUid( aClientUid ), + iNodeDbLocked( EFalse ) + { + iRootNodeState = EConfRequest; + iMasterServerRedirectionState = EBegin; + iProgress.iState = 0; + iProgress.iOperationId = 0; + iProgress.iProgress = 0; + iProgress.iMaxProgress = 100; + } + + +// --------------------------------------------------------------------------- +// ?description_if_needed +// --------------------------------------------------------------------------- +// +void CNcdLoadRootNodeOperation::ConstructL() + { + DLTRACEIN(("")); + CNcdBaseOperation::ConstructL(); + + iConfigResponseBuf = CBufFlat::NewL( 100 ); + } + +// --------------------------------------------------------------------------- +// ?implementation_description +// --------------------------------------------------------------------------- +// +HBufC8* CNcdLoadRootNodeOperation::CreateConfRequestLC( CNcdQuery* aQuery ) + { + DLTRACEIN(("")); + CNcdRequestConfiguration* req = + NcdRequestGenerator::CreateConfigurationRequestLC(); + + 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 CNcdLoadRootNodeOperation::RevertNodesOfBrokenSourcesToCacheL() + { + DLTRACEIN(("")); + // Revert the nodes from broken content sources + CNcdRootNode& rootNode = + iNodeManager->RootNodeL( iRootNodeIdentifier->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& 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 + DLINFO(("Source was broken, revert %d nodes", oldNodes.Count())); + for ( TInt i = 0; i < oldNodes.Count(); i++ ) + { + RevertNodeL( *oldNodes[i], source ); + // Add the node to the new content source map also since the root node's old + // content source map is replaced with the new one. + CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( *oldNodes[i] ); + iContentSourceMap->AddNodeToContentSourceL( identifier, source ); + CleanupStack::Pop( identifier ); + } + + + } + } + } + } + + +void CNcdLoadRootNodeOperation::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 ); + + // The node is root'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( *iRootNodeIdentifier ) ) + { + DLINFO(("Child of root")); + CNcdRootNode& rootNode = + iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ); + CNcdNodeIdentifier* metaOfChild = + NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( aNodeIdentifier ); + iNodeManager->AddToParentL( + *parentId, *metaOfChild, CNcdNodeFactory::ENcdNodeRoot, CNcdNodeFactory::ENcdNormalNode, + CNcdNodeFactory::NodePurposeL( *node ), CNcdNodeManager::EInsert, + iContentSourceMap->GetInsertIndexL( aContentSource, *parentId ) ); + CleanupStack::PopAndDestroy( metaOfChild ); + } + CleanupStack::PopAndDestroy( parentId ); + } + + +void CNcdLoadRootNodeOperation::AddNodesToDifferentParentsL() + { + DLTRACEIN(("")); + + // Move nodes from iBundleFolders to iLoadedNodes to update the bundle folders in proxy + // side. + User::LeaveIfError( + iLoadedNodes.Reserve( iLoadedNodes.Count() + iContentSourceMap->BundleFolderCount() ) ); + + for ( TInt i = 0; i < iContentSourceMap->BundleFolderCount(); i++ ) + { + // Append node ids to the loaded nodes list. These identifiers are + // returned to the proxy side when the operation is completed. + // Note that the content sources contain node identifiers, + // not metadata identifiers. + CNcdNodeIdentifier* bundle = CNcdNodeIdentifier::NewLC( + iContentSourceMap->BundleFolder( i ) ); + + DLINFO((_L("Root Bundle ns: %S, id_: %S"), + &bundle->NodeNameSpace(), + &bundle->NodeId())); + + iLoadedNodes.AppendL( bundle ); + + // Do not delete because array takes ownership. + CleanupStack::Pop( bundle ); + } + + DLTRACEOUT(("Ok")); + } + +void CNcdLoadRootNodeOperation::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& 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 CNcdLoadRootNodeOperation::ParseCatalogBundleL( + const MNcdConfigurationProtocolDetail& aDetail ) + { + DLTRACEIN(("")); + DASSERT( aDetail.GroupId() == KCatalogBundle ); + DASSERT( aDetail.Id() == KNameSpace ); + + const RPointerArray& bundleContents = + aDetail.Contents(); + + 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; + } + } + + // Create folder for catalog bundle. + DASSERT( bundleId ); + + CNcdNodeIdentifier* metaDataId = CNcdNodeIdentifier::NewLC( + aDetail.Value(), *bundleId, iPendingMessage->Session().Context().FamilyId() ); + DLINFO((_L("Bundle metaid ns: %S, id: %S"), + &metaDataId->NodeNameSpace(), + &metaDataId->NodeId())); + + // The id has been gotten from the net server. So, it is same as + // the metadata id that should be used here. Note that the creation of bundle requires the + // metadataid (instead actual nodeid) for the parameter, and that we have here :) + // Because the bundle folder is always the child of the root, the function can automatically + // create the correct node id for the folder. + CNcdNodeFolder& bundleFolder = + iNodeManager->CreateBundleFolderL( *metaDataId ); + + // Create the link for the bundle + CNcdNodeLink& link = bundleFolder.CreateAndSetLinkL(); + + // 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( bundleFolder ).SetViewTypeL( + content->Value() ); + } + } + + const RPointerArray& 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 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() ); + } + } + } + + iNodeManager->DbSaveNodeMetaDataL( bundleMetaData ); + + // Set the metadata to the bundle folder because it was not set during creation. + bundleFolder.SetNodeMetaDataL( bundleMetaData ); + + // Set the bundle folder as child of root node. + // Bundle folders are always children of the root. + iNodeManager->AddToParentL( *iRootNodeIdentifier, *metaDataId, + CNcdNodeFactory::ENcdNodeRoot, + CNcdNodeFactory::ENcdNormalNode, + CNcdNodeFactory::ENcdBundleNode, + CNcdNodeManager::EReplace, iBundleInsertIndex ); + CleanupStack::PopAndDestroy( metaDataId ); + metaDataId = NULL; + + // Because AddToParentL only saves the parent information after child is added to it + // we should always save the bundle node here. So, it will be usable after client is + // restarted. + iNodeManager->DbSaveNodeL( bundleFolder ); + + // Disabled bundle handling temporarily because of NCDALTCI-667 + // Bundles are now loaded explicitly with CNcdLoadBundleNodeOperation because + // otherwise transparent folders are not refreshed when they are supposed to +/* + // Parse sub catalogs. + for ( TInt i = 0; i < subCatalogs.Count(); i++ ) + { + MNcdConfigurationProtocolDetail* subCatalog = subCatalogs[i]; + if ( subCatalog->GroupId() != KSubCatalogs ) + { + continue; + } + + // Get namespace + DASSERT( subCatalog->Id() == KNameSpace ); + const TDesC& nameSpace = subCatalog->Value(); + DLINFO((_L("Bundle subcatalog ns(/value): %S"), + &subCatalog->Value())); + + //Get uri + const TDesC* uri = NULL; + const RPointerArray& subCatalogDetails = + subCatalog->Details(); + for ( TInt i = 0; i < subCatalogDetails.Count(); i++ ) + { + const MNcdConfigurationProtocolDetail* detail = subCatalogDetails[i]; + if ( detail->Id() == KUri ) + { + uri = &detail->Value(); + DLINFO((_L("Bundle subcatalog detail uri(/value): %S"), + &detail->Value())); + } + } + if( uri == NULL ) + { + DLTRACE(("Uri not found -> incomplete, skip")); + continue; + } + + CNcdNodeIdentifier* subCatalogIdentifier = NULL; + const TDesC* provider = NULL; + TBool transparent = EFalse; + const RPointerArray& 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( nameSpace, + content->Value(), + *uri, + bundleFolder.Identifier().ClientUid() ); + + subCatalogIdentifier = + NcdNodeIdentifierEditor::CreateNodeIdentifierLC( bundleFolder.Identifier(), + *contentIdentifier ); + CleanupStack::Pop( subCatalogIdentifier ); + CleanupStack::PopAndDestroy( contentIdentifier ); + CleanupStack::PushL( subCatalogIdentifier ); + DLINFO((_L("Bundle subcatalog content set node id(/value): %S"), + &subCatalogIdentifier->NodeId())); + } + else if ( content->Key() == KProvider ) + { + provider = &content->Value(); + DLINFO((_L("Bundle subcatalog content set provider (/value): %S"), + provider)); + } + else if ( content->Key() == KTransparent ) + { + NcdProtocolUtils::DesToBool( transparent, content->Value() ); + } + } + + if( subCatalogIdentifier == NULL ) + { + DLTRACE(("Id not found -> incomplete, skip")); + continue; + } + + // Create the actual child folder + CNcdNodeFolder* bundleChild = NULL; + if( transparent ) + { + bundleChild = &iNodeManager->CreateNodeFolderL( + CNcdNodeFactory::ENcdTransparentNode, *subCatalogIdentifier ); + } + else + { + bundleChild = &iNodeManager->CreateNodeFolderL( + CNcdNodeFactory::ENcdNormalNode, *subCatalogIdentifier ); + } + CleanupStack::PopAndDestroy( subCatalogIdentifier ); + + // Create a link for the child + CNcdNodeLink& bundleChildLink = bundleChild->CreateAndSetLinkL(); + + if ( provider ) + { + bundleChildLink.SetCatalogsSourceNameL( *provider ); + } + + // Also, notice that it is essential to insert the metadata identifier into the + // link info. So, the right metadata will be found when the node is opened + // from the database. For example when application has been started. + CNcdNodeIdentifier* bundleChildMeta = + NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( bundleChild->Identifier() ); + bundleChildLink.SetMetaDataIdentifierL( *bundleChildMeta ); + CleanupStack::PopAndDestroy( bundleChildMeta ); + + // Set uri for the child + bundleChildLink.SetServerUriL( *uri ); + + // Add the child to the bundle. + if ( transparent ) + { + iNodeManager->AddToParentL( bundleFolder.Identifier(), + bundleChildLink.MetaDataIdentifier(), + CNcdNodeFactory::ENcdNodeFolder, + CNcdNodeFactory::ENcdBundleNode, + CNcdNodeFactory::ENcdTransparentNode, + CNcdNodeManager::EAppend, + 0, + transparent ); + } + else + { + iNodeManager->AddToParentL( bundleFolder.Identifier(), + bundleChildLink.MetaDataIdentifier(), + CNcdNodeFactory::ENcdNodeFolder, + CNcdNodeFactory::ENcdBundleNode, + CNcdNodeFactory::ENcdNormalNode, + CNcdNodeManager::EAppend, + 0, + transparent ); + } + iNodeManager->DbSaveNodeL( *bundleChild ); + } + */ + iContentSourceMap->AppendFolderL( bundleFolder.Identifier(), iBundleInsertIndex ); + + // increment insert index for next bundle + iBundleInsertIndex++; + + // Because AddToParentL only saves the parent information after child is added to it + // we should always save the bundle node here. So, it will be usable after client is + // restarted. + + // Unnecessary while bundle handling is disabled + //iNodeManager->DbSaveNodeL( bundleFolder ); + } + + +TBool CNcdLoadRootNodeOperation::ContainsNode( + const RPointerArray& 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 CNcdLoadRootNodeOperation::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 CNcdLoadRootNodeOperation::RunOperation() + { + DLTRACEIN((("this-ptr: %x"), this )); + + TInt err( KErrNone ); + TRAP( err, DoRunOperationL() ); + + if ( err != KErrNone ) + { + DLTRACE(("error: %d", err)); + Cancel(); + iRootNodeState = EFailed; + iError = err; + if ( iPendingMessage ) + { + // ignoring error because operation already failed + CNcdBaseOperation::CompleteMessage( iPendingMessage, + ENCDOperationMessageCompletionError, iError ); + } + } + + DLTRACEOUT(("err: %d", err)); + return err; + } + + +void CNcdLoadRootNodeOperation::DoRunOperationL() + { + DLTRACEIN(("")); + switch ( iRootNodeState ) + { + case EConfRequest: + { + DLTRACE((_L("->EConfRequest"))); + DASSERT ( iPendingMessage ); + + CNcdRootNode& root = + iNodeManager->CreateRootL( iPendingMessage->Session().Context() ); + root.CreateAndSetLinkL(); + + if ( !iRootNodeIdentifier ) + { + // create identifier for root node + iRootNodeIdentifier = CNcdNodeIdentifier::NewL( root.Identifier() ); + + // Store previous list only if some children have been previously loaded. + if( root.ChildrenPreviouslyLoaded() ) + { + root.StoreChildrenToPreviousListL(); + } + + // Create previous lists of children for new checking. + iChildEntityMaps.ResetAndDestroy(); + iNodeManager->SeenInfo().CreatePreviousListsForChildrenL( root, iChildEntityMaps ); + + iNodeManager->BackupAndClearCacheL( *iRootNodeIdentifier ); + iNodeManager->LockNodeDbL( TUid::Uid( iClientUid ) ); + iNodeDbLocked = ETrue; + } + + // remove old content sources + delete iContentSourceMap; + iContentSourceMap = NULL; + iContentSourceMap = CNcdContentSourceMap::NewL(); + + delete iServerUri; + iServerUri = NULL; + iServerUri = iConfigManager.MasterServerAddressL( + iPendingMessage->Session().Context() ).AllocL(); + + 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 ); + + + iRootNodeState = EReceiveConf; + DLTRACE(( "->EConfRequest done" )); + break; + } + + case EReceiveConf: + { + DLTRACE((_L("->EReceiveConf"))); + // Should send progress only if progress is made + + if ( iPendingMessage && iSendProgress ) + { + User::LeaveIfError( CNcdBaseOperation::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 + iRootNodeState = 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; + iRootNodeState = 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 + iRootNodeState = EComplete; + } + } + else + { + // NORMAL CASE: + // Respond to the query in a new request + iRootNodeState = 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 + iRootNodeState = 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; + iRootNodeState = EConfRequest; + } + else + { + DLTRACE(("No sources received!")); + // no content sources received with an optional query + // this should never happen! + iError = KNcdErrorNoContentSources; + iRootNodeState = EFailed; + } + } + else + { + DLTRACE(("Query not optional, operation will stop!")); + iRootNodeState = 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())); + + // The parent identifier should be root here. + // So, no need to change that parent identifier info. It does not + // differ from the metadataid because root does not have metadata. + 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(); + } + + iRootNodeState = 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 + iRootNodeState = 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] ); + // release own reference and remove + iSubOpQuerys[0]->InternalRelease(); + 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 + iRootNodeState = EComplete; + if ( iFailedSubOps.Count() > 0 ) + { + DLINFO(("Some catalogs failed to load")); + iError = KNcdErrorSomeCatalogsFailedToLoad; + } + RunOperation(); + } + + DLTRACE((_L("->EReceiveBrowse done"))); + break; + } + + case EComplete: + { + DLTRACE((_L("->EComplete"))); + + CNcdRootNode& rootNode = + iNodeManager->RootNodeL( iRootNodeIdentifier->ClientUid() ); + // 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 || + iContentSourceMap->BundleFolderCount() > 0 ) ) + { + DLINFO(("Content source map count")); + RevertNodesOfBrokenSourcesToCacheL(); + AddNodesToDifferentParentsL(); + SetAlwaysVisibleFlagsL(); + + // Give the new content source map to root node to be used in the next + // root node load + rootNode.SetContentSourceMap( iContentSourceMap ); + // Root node takes the ownership. + // So, set NULL here. So this class will not delete this. + iContentSourceMap = NULL; + // Now the RAM node cache should be updated correctly, save it to database. + iNodeManager->UnlockNodeDb( TUid::Uid( iClientUid ) ); + iNodeDbLocked = EFalse; + iNodeManager->DbSaveNodesL( *iRootNodeIdentifier ); + } + + if( iNodeDbLocked ) + { + iNodeManager->UnlockNodeDb( TUid::Uid( iClientUid ) ); + iNodeDbLocked = EFalse; + } + + iNodeManager->ClearTempCacheL( *iRootNodeIdentifier ); + + // Set the children loaded flag so that next refresh stores + // previous child list (needed for new checking) + if( rootNode.ChildCount() ) + { + rootNode.SetChildrenPreviouslyLoaded(); + iNodeManager->DbSaveNodeL( rootNode ); + } + // Check new status + iNodeManager->SeenInfo().StorePreviousListsToExistingChildrenL( + rootNode, + iChildEntityMaps ); + + iChildEntityMaps.ResetAndDestroy(); + + // Check new status for transparent folders (transparent folders are + // loaded during root op so they need to be checked here) + iNodeManager->SeenInfo().DoNewCheckForTransparentChildrenL( + rootNode ); + + iNodeManager->SeenInfo().RefreshFolderSeenStatusL( *iRootNodeIdentifier ); + + 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( CNcdBaseOperation::CompleteMessage( iPendingMessage, + ENCDOperationMessageCompletionComplete, + iProgress, + KErrNone ) ); + + iOperationState = EStateComplete; + } + else + { + iRootNodeState = 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 + CNcdBaseOperation::CompleteMessage( iPendingMessage, + ENCDOperationMessageCompletionError, iError ); + } + DLTRACE((_L("->EFailed done"))); + break; + } + default: + { + DLTRACE(("default")); + DASSERT(0); + break; + } + } + } + +void CNcdLoadRootNodeOperation::ChangeToPreviousStateL() + { + DLTRACEIN(("no implementation needed")); + } + +TBool CNcdLoadRootNodeOperation::QueryCompletedL( CNcdQuery* aQuery ) + { + DLTRACEIN(("")); + TBool handled = EFalse; + if ( aQuery == iConfQuery ) + { + // handle conf query + DASSERT( iRootNodeState == EConfQuery ); + //RunOperation(); + // Query has been handled, release it + /*iConfQuery->Release(); + iConfQuery = NULL;*/ + 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; + }