diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdreportmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/provider/server/src/ncdreportmanager.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,1543 @@ +/* +* Copyright (c) 2007-2008 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: CNcdReportManager implementation +* +*/ + + +#include "ncdreportmanager.h" + +#include "ncdoperationobserver.h" + +// Supported reports +#include "ncdreportdownload.h" +#include "ncdreportomadownload.h" +#include "ncdreportinstall.h" + +#include "ncdproviderdefines.h" +#include "ncdproviderutils.h" +#include "ncdpanics.h" +#include "ncdnodeidentifier.h" +#include "ncdconfigurationmanager.h" +#include "ncdserverdetails.h" +#include "ncdgeneralmanager.h" + +// Protocol +#include "ncdprotocol.h" +#include "ncdrequestgenerator.h" +#include "ncdrequestinstallation.h" +#include "ncdcapabilities.h" +#include "ncdprotocol.h" + +// Storage +#include "ncdstorage.h" +#include "ncddatabasestorage.h" +#include "ncdstoragemanager.h" +#include "ncdstorageitem.h" +#include "ncdstoragedataitem.h" + +#include "catalogscontext.h" +#include "catalogsutils.h" + +// HTTP +#include "catalogshttpincludes.h" +#include "catalogshttptransaction.h" +#include "catalogshttpsessionmanagerimpl.h" +#include "catalogsnetworkmanager.h" +#include "catalogshttpconnectionmanager.h" + +#include "catalogsdebug.h" + + +void CNcdReportManager::ReportIdToDescriptor( + const TNcdReportId& aId, TDes& aTarget ) + { + aTarget.Num( aId ); + } + + +// --------------------------------------------------------------------------- +// NewL +// --------------------------------------------------------------------------- +CNcdReportManager* CNcdReportManager::NewL( + const MCatalogsContext& aContext, + CNcdGeneralManager& aGeneralManager, + MCatalogsHttpSession& aHttpSession, + TBool aClientCrashed ) + { + CNcdReportManager* self = new(ELeave) CNcdReportManager( + aContext, + aGeneralManager, + aHttpSession, + aClientCrashed ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +CNcdReportManager::~CNcdReportManager() + { + DLTRACEIN(("")); + CancelReportSending(); + Cancel(); + + iReports.ResetAndDestroy(); + if ( iNetworkManager ) + { + iNetworkManager->RemoveObserver( *this ); + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CNcdReportManager::SetReportingMethod( const MNcdServerReportManager::TReportingMethod& aMethod ) + { + DLTRACEIN(("")); + // Here we create a copy of the member variable for later comparison. Notice, that + // we crete a copy instead of a reference because if reference was used then the value of the + // variable would change when iReporting is changed. + MNcdServerReportManager::TReportingMethod tmpMethod( iReportingMethod ); + iReportingMethod = aMethod; + + if ( tmpMethod != iReportingMethod + && iReportingMethod == MNcdServerReportManager::EReportingBackground + && iManagerState == ENcdReportManagerIdle + && iTransactions.Count() == 0 ) + { + // If reporting method was changed to background method, + // then try one loop to send the reports now, instead of waiting for the next report setting. + // Also, transactions are checked to be sure that no pending transactions exist and + // to check if all HTTP operations are completed yet. + // Probably there is not anything to send, but just in case. + // This setting will also start the RunL loop for the sending. + TRAP_IGNORE( SetManagerStateL( ENcdReportManagerPreparing ) ); + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +const MNcdServerReportManager::TReportingMethod& CNcdReportManager::ReportingMethod() const + { + DLTRACEIN(("")); + return iReportingMethod; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CNcdReportManager::SetReportingStyle( const MNcdServerReportManager::TReportingStyle& aStyle ) + { + DLTRACEIN(("")); + iReportingStyle = aStyle; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +const MNcdServerReportManager::TReportingStyle& CNcdReportManager::ReportingStyle() const + { + DLTRACEIN(("")); + return iReportingStyle; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CNcdReportManager::StartSendReportsL( MNcdOperationObserver& aObserver ) + { + DLTRACEIN(("")); + + if ( iObserver != NULL ) + { + // Operation is already going on and observer is set. + User::Leave( KErrInUse ); + } + else if ( iReportingMethod != MNcdServerReportManager::EReportingManaged ) + { + // This function should be called only for managed reports. + User::Leave( KErrArgument ); + } + else if ( iManagerState != ENcdReportManagerIdle + || iTransactions.Count() > 0 ) + { + // This case may occur if the reporting method has just been changed and + // there was still an automated operation pending when sending was asked + // by the manager. + // Because observer was not set, then set it here. + // Observers are set only when reporting is managed. + // For automated reporting observers are not used. + // Also, transactions are checked to be sure that no pending transactions exist and + // to check if all HTTP operations are completed yet. + // Notice, that ownership is not transferred here. + iObserver = &aObserver; + return; + } + else + { + // We are having a managed report and operation is in idle state. + // So, start the action. + SetManagerStateL( ENcdReportManagerPreparing ); + // Notice, that ownership is not transferred here. + iObserver = &aObserver; + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TNcdReportId CNcdReportManager::RegisterDownloadL( + const TDesC& aUri, + const CNcdNodeIdentifier& aMetadataId, + const TNcdReportStatusInfo& aStatus, + const TDesC& aReportUri, + const TDesC& aReportNamespace ) + { + DLTRACEIN(( _L("aUri: %S, aStatus: %d"), &aUri, aStatus.iStatus )); + + // Check if the download has already been registered + CNcdReport* report = FindReport( + aUri, + aMetadataId, + aReportUri, + ENcdReportDownload, + iReports ); + + // Use old report only if it can still be updated with a new + // status before sending. We don't want to overwrite any pending + // cancellation/failure/success reports + if ( report && !report->StatusIsFinal() ) + { + DLTRACEOUT(("Download has already been registered")); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + return report->ReportId(); + } + + report = NULL; + + TBool serverSupports = ServerSupportsReports( + ENcdReportDownload, + aReportUri, + aReportNamespace ); + + if ( serverSupports ) + { + DLTRACE(("Server supports download reports")); + report = CNcdReportDownload::NewLC( + *this, + aUri, + aMetadataId, + aStatus, + aReportUri, + aReportNamespace ); + + iReports.InsertInOrderAllowRepeatsL( + report, + TLinearOrder( CNcdReport::Compare ) ); + + CleanupStack::Pop( report ); + report->SetReportId( GenerateReportId() ); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + DLTRACEOUT(("Report added")); + return report->ReportId(); + } + + return KNcdReportNotSupported; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TNcdReportId CNcdReportManager::RegisterOmaDownloadL( + const TDesC& aUri, + const CNcdNodeIdentifier& aMetadataId, + const TNcdReportStatusInfo& aStatus, + const TDesC& aReportUri ) + { + DLTRACEIN(( _L("aUri: %S, aStatus: %d"), &aUri, aStatus.iStatus )); + + // Check if the download has already been registered + CNcdReport* report = FindReport( + aUri, + aMetadataId, + aReportUri, + ENcdReportOmaDownload, + iReports ); + + // Use old report only if it can still be updated with a new + // status before sending + if ( report && !report->StatusIsFinal() ) + { + + DLTRACEOUT(("Download has already been registered")); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + return report->ReportId(); + } + + report = NULL; + + DLTRACE(("Server supports download reports")); + report = CNcdReportOmaDownload::NewLC( + *this, + aUri, + aMetadataId, + aStatus, + aReportUri ); + + iReports.InsertInOrderAllowRepeatsL( + report, + TLinearOrder( CNcdReport::Compare ) ); + + CleanupStack::Pop( report ); + report->SetReportId( GenerateReportId() ); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + DLTRACEOUT(("Report added")); + return report->ReportId(); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TInt CNcdReportManager::SetDownloadReportAccessPoint( + const TNcdReportId& aReportId, + const TCatalogsConnectionMethod& aAccessPoint ) + { + DLTRACEIN(("aAccessPoint: %d", aAccessPoint.iId )); + + CNcdReport* report = FindReport( + aReportId, + iReports ); + + if ( !report ) + { + DLERROR(("Download has not been been registered")); + return KErrNotFound; + } + + report->SetAccessPoint( aAccessPoint ); + + DLTRACEOUT(("Access point set successfully")); + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::ReportDownloadStatusL( + const TNcdReportId& aReportId, + const TNcdReportStatusInfo& aStatus, + TBool aSendable ) + { + DLTRACEIN(("aStatus: %d", aStatus.iStatus )); + + CNcdReport* report = FindReport( + aReportId, + iReports ); + + if ( !report ) + { + DLERROR(("Report not found")); + return; + } + + SetReportStatusL( *report, aStatus, aSendable ); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TNcdReportId CNcdReportManager::RegisterInstallL( + const TDesC& aContentIdentifier, + const CNcdNodeIdentifier& aMetadataId, + const TNcdReportStatusInfo& aStatus, + const TDesC& aReportUri, + const TDesC& aReportNamespace ) + { + DLTRACEIN(( _L("aReportUri: %S, aStatus: %d"), &aReportUri, aStatus.iStatus )); + + // Check if the install has already been registered. + CNcdReport* report = FindReport( + aContentIdentifier, + aMetadataId, + aReportUri, + ENcdReportInstall, + iReports ); + + if ( report && !report->StatusIsFinal() ) + { + DLTRACEOUT(("Install has already been registered")); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + return report->ReportId(); + } + + TBool serverSupports = ServerSupportsReports( + ENcdReportInstall, + aReportUri, + aReportNamespace ); + + if ( serverSupports ) + { + DLTRACE(("Server supports install reports")); + report = CNcdReportInstall::NewLC( + *this, + aContentIdentifier, + aMetadataId, + aStatus, + aReportUri, + aReportNamespace ); + + iReports.InsertInOrderAllowRepeatsL( + report, + TLinearOrder( CNcdReport::Compare ) ); + + CleanupStack::Pop( report ); + report->SetReportId( GenerateReportId() ); + report->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + + DLTRACEOUT(("Report added")); + return report->ReportId(); + } + + return KNcdReportNotSupported; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TInt CNcdReportManager::SetInstallReportAccessPoint( + const TNcdReportId& aReportId, + const TCatalogsConnectionMethod& aAccessPoint ) + { + DLTRACEIN(("aAccessPoint: %d", aAccessPoint.iId )); + + // Same implementation with download and install. + TInt error( SetDownloadReportAccessPoint( aReportId, aAccessPoint ) ); + + DLTRACEOUT(("Access point set successfully")); + return error; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::ReportInstallStatusL( + const TNcdReportId& aReportId, + const TNcdReportStatusInfo& aStatus ) + { + DLTRACEIN(("aStatus: %d", aStatus.iStatus)); + + // Same implementation with download and install + TBool sendable( EFalse ); + if ( aStatus.iStatus == ENcdReportSuccess + || aStatus.iStatus == ENcdReportCancel + || aStatus.iStatus == ENcdReportFail ) + { + sendable = ETrue; + } + ReportDownloadStatusL( aReportId, aStatus, sendable ); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::SetReportsAsUsedL( + const CNcdNodeIdentifier& aMetadataId ) + { + DLTRACEIN(("")); + for ( TInt i = 0; i < iReports.Count(); ++i ) + { + if ( iReports[i]->MetadataId().Equals( aMetadataId ) ) + { + DLINFO(("Setting report as used")); + iReports[i]->Attributes().SetAttributeL( + ENcdReportAttributeIsUsed, ETrue ); + // No break since there may be other reports with + // the same metadata id + } + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::RemoveUnusedReportsL() + { + DLTRACEIN(("")); + for ( TInt i = 0; i < iReports.Count(); ++i ) + { + if ( !iReports[i]->Attributes().AttributeInt32( + ENcdReportAttributeIsUsed ) ) + { + TNcdReportStatusInfo info( ENcdReportCancel, KErrCancel ); + SetReportStatusL( *iReports[i], info, ETrue ); + } + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::OpenStorageL() + { + DLTRACEIN(("")); + iDb = NULL; + + HBufC* clientUid = iContext.FamilyId().Name().AllocLC(); + + // Recreate necessary storage objects. Nothing is created if not necessary + MNcdStorage& storage = iStorageManager.CreateOrGetStorageL( + *clientUid, NcdProviderDefines::KDownloadNamespace ); + + CleanupStack::PopAndDestroy( clientUid ); + + iDb = &storage.DatabaseStorageL( + NcdProviderDefines::KReportDatabaseUid ); + DLTRACEOUT(("Storage opened, iDb: %x", iDb)); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::CloseStorage() + { + DLTRACEIN(("")); + + iDb = NULL; + } + + +// --------------------------------------------------------------------------- +// Loads unfinished reports +// --------------------------------------------------------------------------- +void CNcdReportManager::LoadReportsL() + { + DLTRACEIN(("")); + + OpenStorageL(); + + DASSERT( iDb ); + + // Get all items from the db + RPointerArray items; + iDb->StorageItemsL( items ); + CleanupClosePushL( items ); + + for ( TInt i = 0; i < items.Count(); ++i ) + { + items[i]->SetDataItem( this ); + + // This will cause a call to report manager's InternalizeL + items[i]->ReadDataL(); + } + + CleanupStack::PopAndDestroy( &items ); + + DLTRACEOUT(("Reports loaded")); + } + + +// --------------------------------------------------------------------------- +// Saves an individual report to disk +// --------------------------------------------------------------------------- +void CNcdReportManager::SaveReportL( CNcdReport& aReport ) + { + DLTRACEIN(("")); + + MNcdStorageItem& item( StorageItemForReportL( aReport.ReportId() ) ); + + // Save new item to database + item.SetDataItem( &aReport ); + item.OpenL(); + + // Calls ExternalizeL for the item + item.WriteDataL(); + + // Save the item to the database. + item.SaveL(); + + DLTRACEOUT(("")); + } + + +// --------------------------------------------------------------------------- +// Remove report from db +// --------------------------------------------------------------------------- +void CNcdReportManager::RemoveReportL( const TNcdReportId& aId ) + { + DLTRACEIN(("")); + + MNcdStorageItem& item( StorageItemForReportL( aId ) ); + item.RemoveFromStorageL(); + } + + +// --------------------------------------------------------------------------- +// Get a storage item that matches the report id +// --------------------------------------------------------------------------- +MNcdStorageItem& CNcdReportManager::StorageItemForReportL( + const TNcdReportId& aId ) + { + DLTRACEIN(("")); + OpenStorageL(); + + DASSERT( iDb ); + + TBuf id; + ReportIdToDescriptor( aId, id ); + DLTRACE(( _L("Id: %S"), &id )); + DLTRACE(("Getting storage item, iDb: %x", iDb )); + // Get/create the storage item where the data is saved + // Note: database has the ownership of the item + MNcdStorageItem* item = iDb->StorageItemL( id, KNcdReportDataType ); + return *item; + } + + +// --------------------------------------------------------------------------- +// MCatalogsAccessPointObserver +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::HandleAccessPointEventL( + const TCatalogsConnectionMethod& aAp, + const TCatalogsAccessPointEvent& aEvent ) + { + DLTRACEIN(("")); + (void) aAp; // suppress warning + + // Just try to send reports when an AP is opened. + if ( aEvent == ECatalogsAccessPointOpened && + iManagerState == ENcdReportManagerIdle && + iReportingMethod == MNcdServerReportManager::EReportingBackground ) + { + DLTRACE(("Ap: %d opened", aAp.iId )); + // Notice, that the manager state is set to ENcdReportManagerPreparing + // only if the reporting method should work in the background. + // This setting will also start the RunL loop for the sending. + SetManagerStateL( ENcdReportManagerPreparing ); + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::HandleHttpEventL( + MCatalogsHttpOperation& aOperation, + TCatalogsHttpEvent aEvent ) + { + DLTRACEIN(("")); + + switch( aEvent.iOperationState ) + { + // Handle completed operation + case ECatalogsHttpOpCompleted: + { + DLTRACE(("Operation complete")); + // Finish report releases the transaction + FinishReportL( aOperation, KErrNone ); + break; + } + + // Handle operation in progress + case ECatalogsHttpOpInProgress: + { + if ( aEvent.iProgressState == + ECatalogsHttpResponseBodyReceived ) + { + DLINFO(("response body=%S", &aOperation.Body() )); + // send received data to parser + } + break; + } + + default: + { + break; + } + } + + DLTRACEOUT(("")); + + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TBool CNcdReportManager::HandleHttpError( + MCatalogsHttpOperation& aOperation, + TCatalogsHttpError aError ) + { + DLTRACEIN(("Error type: %d, code: %d", aError.iType, aError.iError )); + + // Can't do anything for the error anyway + // Finish report releases the transaction + TRAP_IGNORE( FinishReportL( aOperation, aError.iError ) ); + DLTRACEOUT(("")); + return ETrue; + + } + + +// --------------------------------------------------------------------------- +// Context getter +// --------------------------------------------------------------------------- +const MCatalogsContext& CNcdReportManager::Context() const + { + return iContext; + } + + +// --------------------------------------------------------------------------- +// Cancel ongoing report transactions +// --------------------------------------------------------------------------- +void CNcdReportManager::CancelReportSending() + { + DLTRACEIN(("")); + + for ( TInt i = 0; i < iTransactions.Count(); ++i ) + { + iTransactions[i]->Cancel(); + } + iTransactions.Reset(); + + for ( TInt i = 0; i < iReports.Count(); ++i ) + { + iReports[i]->SetReportTransaction( NULL ); + } + + if ( iObserver != NULL ) + { + // Inform the observer about the cancellation. + iObserver->OperationComplete( NULL, KErrCancel ); + iObserver = NULL; + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TCatalogsConnectionMethod CNcdReportManager::DefaultConnectionMethod() + { + DLTRACEIN(("")); + // APN ID of the current/last opened default accesspoint + TUint32 apn = iHttpSession.ConnectionManager().CurrentAccessPoint(); + + // This ensures that reports use the latest connected default accesspoint + // or the AP that is set to them. + // Issue: DLEB-140 + TCatalogsConnectionMethod method( + apn, + ECatalogsConnectionMethodTypeAccessPoint ); + method.iApnId = apn; + + return method; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +CNcdGeneralManager& CNcdReportManager::GeneralManager() const + { + return iGeneralManager; + } + + +// --------------------------------------------------------------------------- +// From MNcdStorageDataItem +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::ExternalizeL( RWriteStream& /*aStream*/ ) + { + DLTRACEIN(("")); + // nothing to do + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::InternalizeL( RReadStream& aStream ) + { + DLTRACEIN(("")); + + TNcdReportType type; + InternalizeEnumL( type, aStream ); + + CNcdReport* report( NULL ); + + switch( type ) + { + case ENcdReportDownload: + { + report = CNcdReportDownload::NewLC( *this, aStream ); + break; + } + + case ENcdReportOmaDownload: + { + report = CNcdReportOmaDownload::NewLC( *this, aStream ); + break; + } + + case ENcdReportInstall: + { + report = CNcdReportInstall::NewLC( *this, aStream ); + break; + } + + default: + { + NCD_ASSERT_ALWAYS( 0, ENcdPanicIndexOutOfRange ); + } + } + + CNcdAttributes& att( report->Attributes() ); + + if ( !iClientCrashed ) + { + + // Set as unused, flag is set to used if a download registers + // to this report + att.SetAttributeL( + ENcdReportAttributeIsUsed, EFalse ); + + // Check if the report sending was canceled and + // set as sendable if it was + if ( att.AttributeInt32( + ENcdReportAttributeReportBeingSent ) != ENcdReportNone && + att.AttributeInt32( + ENcdReportAttributeLatestSentReport ) == ENcdReportNone ) + { + DLTRACE(("Set as sendable because previous attempt was canceled")); + att.SetAttributeL( ENcdReportAttributeSendable, ETrue ); + } + } + else + { + DLTRACE(("Set report as failed because engine crashed")); + TNcdReportStatusInfo info( ENcdReportFail, KErrUnknown ); + report->SetStatus( info ); + att.SetAttributeL( + ENcdReportAttributeIsUsed, EFalse ); + + // Check if the report sending was canceled and + // set as sendable if it was + att.SetAttributeL( ENcdReportAttributeSendable, ETrue ); + + } + + iReports.InsertInOrderAllowRepeatsL( + report, + TLinearOrder( CNcdReport::Compare ) ); + + CleanupStack::Pop( report ); // report, + + // ensure that iNewReportId is higher than any current report id + if ( report->ReportId() >= iNewReportId ) + { + iNewReportId = report->ReportId() + 1; + } + + DLTRACEOUT(("Report internalized")); + } + + + +// --------------------------------------------------------------------------- +// From CActive +// --------------------------------------------------------------------------- + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::RunL() + { + DLTRACEIN(("")); + if ( iStatus.Int() == KErrNone ) + { + switch ( iManagerState ) + { + case ENcdReportManagerPreparing: + { + SendReportsL(); + break; + }; + + default: + { + DLTRACE(("Default")); + break; + } + } + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::DoCancel() + { + DLTRACEIN(("")); + + // No requests to cancel + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TInt CNcdReportManager::RunError( TInt aError ) + { + DLTRACEIN(("aError: %d", aError)); + + if ( iObserver != NULL ) + { + iObserver->OperationComplete( NULL, aError ); + iObserver = NULL; + } + + // Return KErrNone so that CActiveScheduler doesn't panic + // with E32USER-CBase 47. Would call an observer if there was any. + + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::FinishReportL( MCatalogsHttpOperation& aOperation, TInt aErrorCode ) + { + DLTRACEIN(("")); + + // This function will insert the information into the reports after the + // report sending operation has been finished. So, all the reports that have + // been handled by the operation are removed from the list. + + MCatalogsHttpOperation* operationPtr = &aOperation; + + // Remove the transaction before any leaving code so that if a leave + // occurs, we don't have any hanging transactions in the array + TInt index = iTransactions.FindInAddressOrder( &aOperation ); + DASSERT( index != KErrNotFound ); + + iTransactions.Remove( index ); + aOperation.Release(); + + TInt i = iReports.Count(); + while ( i-- ) + { + if ( iReports[i]->ReportTransaction() == operationPtr ) + { + iReports[i]->SetReportTransaction( NULL ); + + CNcdAttributes& att( iReports[i]->Attributes() ); + + // Update latest sent report status + att.SetAttributeL( + ENcdReportAttributeLatestSentReport, + att.AttributeInt32( + ENcdReportAttributeReportBeingSent ) ); + + if ( iReports[i]->CanBeRemoved() ) + { + DLTRACE(("Deleting report")); + RemoveReportL( iReports[i]->ReportId() ); + delete iReports[i]; + iReports.Remove( i ); + } + else // save info that report was sent + { + SaveReportL( *iReports[i] ); + } + } + } + + + DLTRACE(("Committing report changes")); + iDb->CommitL(); + + + // Check if all the transactions have been handled. If they are, then no more + // http operations are going on and the reporting is finished. + if ( iTransactions.Count() == 0 ) + { + DLTRACE(("No more pending reports.")); + if ( iReportingMethod == MNcdServerReportManager::EReportingBackground ) + { + DLINFO(("Start handling next patch")); + // Notice, that by calling this, we continue to the next round in the RunL. + // So, then new reports will be sent if they exist then. If there is already new + // items available, then they will be sent. Otherwise the operation + // will end after RunL is called next time. + SetManagerStateL( ENcdReportManagerPreparing ); + } + else + { + DLINFO(("Set to idle because sending is managed by hand.")); + // This will set the state and the RunL loop will not be continued. + SetManagerStateL( ENcdReportManagerIdle ); + } + + // Notice, that observer is set only for the managed reporting. But, in some cases + // the reporting may have been changed to background before the requested managed send + // was finished. So, instead of waiting for the background action to finish in next + // RunL loop, inform the observer already here about the completion. If only background + // operations have been occurring, then the observer is NULL here. + if ( iObserver != NULL ) + { + // Because observer was set for manager to know when managed operation + // was finished, inform the observer. + iObserver->OperationComplete( NULL, aErrorCode ); + iObserver = NULL; + } + } + } + + +// --------------------------------------------------------------------------- +// Server capability check +// --------------------------------------------------------------------------- +TBool CNcdReportManager::ServerSupportsReports( + TNcdReportType aType, + const TDesC& aServerUri, + const TDesC& aServerNamespace ) const + { + DLTRACEIN(("")); + const MNcdServerDetails* serverDetails = + iConfigurationManager.ServerDetails( + iContext, + aServerUri, + aServerNamespace ); + + // No server details so we don't know whether server supports them + // or not + if ( !serverDetails ) + { + DLTRACEOUT(("Server details not found")); + return EFalse; + } + + // Notice, that install capability support is already checked here. + TBool supports = + serverDetails->IsCapabilitySupported( + NcdCapabilities::KInstallationReport() ); + + // Download report requires install capability and also download capability + if ( aType == ENcdReportDownload ) + { + DLTRACE(("Checking for downloadReport capability")); + + supports = supports && + serverDetails->IsCapabilitySupported( + NcdCapabilities::KDownloadReport() ); + } + + DLTRACEOUT(("Required caps supported: %d", supports )); + return supports; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +CNcdReportManager::CNcdReportManager( + const MCatalogsContext& aContext, + CNcdGeneralManager& aGeneralManager, + MCatalogsHttpSession& aHttpSession, + TBool aClientCrashed ) : + CActive( EPriorityStandard ), + iContext( aContext ), + iGeneralManager( aGeneralManager ), + iConfigurationManager( aGeneralManager.ConfigurationManager() ), + iStorageManager( aGeneralManager.StorageManager() ), + iHttpSession( aHttpSession ), + iReportingMethod( MNcdServerReportManager::EReportingBackground ), + iReportingStyle( MNcdServerReportManager::EReportingStyleGeneral ), + iClientCrashed( aClientCrashed ) + { + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::ConstructL() + { + CActiveScheduler::Add( this ); + + iNetworkManager = &CCatalogsHttpSessionManager::NetworkManagerL(); + // observe changes in access points + iNetworkManager->AddObserverL( *this ); + LoadReportsL(); + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +CNcdReport* CNcdReportManager::FindReport( + const TNcdReportId& aReportId, + RNcdReportArray& aArray ) const + { + DLTRACEIN(("aReportId: %d", aReportId)); + for ( TInt i = 0; i < aArray.Count(); ++i ) + { + if ( aArray[i]->ReportId() == aReportId ) + { + return aArray[i]; + } + } + DLTRACEOUT(("Not found")); + return NULL; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +CNcdReport* CNcdReportManager::FindReport( + const TDesC& aId, + const CNcdNodeIdentifier& aNodeId, + const TDesC& aReportUri, + const TNcdReportType& aReportType, + RNcdReportArray& aArray ) const + { + DLTRACEIN(( _L("aId: %S, report URI: %S"), &aId, &aReportUri )); + // Search backwards so that the newest & changeable report is found + TInt count = aArray.Count(); + while( count-- ) + { + if ( aArray[ count ]->Match( aNodeId, aId, aReportUri, aReportType ) ) + { + return aArray[ count ]; + } + } + DLTRACEOUT(("Not found")); + return NULL; + } + + +// --------------------------------------------------------------------------- +// State setter +// --------------------------------------------------------------------------- +void CNcdReportManager::SetManagerStateL( TNcdReportManagerState aState ) + { + DLTRACEIN(("aState: %d", aState)); + + iManagerState = aState; + switch ( iManagerState ) + { + case ENcdReportManagerPreparing: + { + ExecuteRunL( KErrNone ); + break; + } + + case ENcdReportManagerSending: + { + break; + } + + default: + { + break; + } + } + } + + +// --------------------------------------------------------------------------- +// Initiate report sending +// --------------------------------------------------------------------------- +void CNcdReportManager::SendReportsL() + { + DLTRACEIN(("")); + + DASSERT( !iTransactions.Count() ); + + // Update open connections so that IsAccessPointOpen is up-to-date + iNetworkManager->UpdateConnectionsL(); + + TBool defaultApIsOpen = iNetworkManager->IsAccessPointOpen( + DefaultConnectionMethod() ); + + for ( TInt i = 0; i < iReports.Count(); ++i ) + { + CNcdReport& report = *iReports[i]; + + if ( report.IsSendable() && ( + // either report has no AP set -> use default which has to be open + // or its AP needs to be open + ( defaultApIsOpen ) || + ( iNetworkManager->IsAccessPointOpen( report.ConnectionMethod() ) ) ) ) + { + if ( !iNetworkManager->IsAccessPointOpen( report.ConnectionMethod() ) ) + { + DLTRACE(("Using default ap for reporting")); + report.SetAccessPoint( DefaultConnectionMethod() ); + } + + MCatalogsHttpOperation* transaction = + iHttpSession.CreateTransactionL( + report.Attributes().AttributeString16( + ENcdReportAttributeReportUri ), this ); + + CleanupReleasePushL( *transaction ); + + if ( report.CanBundle() ) + { + BundleReportsL( i, *transaction ); + } + else + { + PrepareReportL( report, *transaction ); + } + + report.UpdateTransactionConfigL( *transaction ); + User::LeaveIfError( transaction->Start() ); + + iTransactions.InsertInAddressOrderL( transaction ); + CleanupStack::Pop( transaction ); + } + } + + // The operations that were created above, will call http callback functions + // of this class and the operation will be finished in FinishReportL function. + + // Check if the manager state should be set to idle or if we should + // let the state to be something else and wait for the HTTP operations + // that were created above to complete.. + if ( iTransactions.Count() == 0 ) + { + DLTRACE(("Nothing to send anymore.")); + // This will set the state and operation will not continue RunL loop + // any more. + SetManagerStateL( ENcdReportManagerIdle ); + + if ( iObserver != NULL ) + { + // Because observer was set for manager to know when managed operation + // was finished, inform the observer. + iObserver->OperationComplete( NULL, KErrNone ); + iObserver = NULL; + } + } + } + + +// --------------------------------------------------------------------------- +// Bundle reports +// --------------------------------------------------------------------------- +void CNcdReportManager::BundleReportsL( + TInt aIndex, + MCatalogsHttpOperation& aTransaction ) + { + DLTRACEIN(("Bundling reports from index %d onwards", aIndex )); + DASSERT( aIndex < iReports.Count() ); + + CNcdRequestInstallation* report = + NcdRequestGenerator::CreateInstallationReportRequestLC(); + + + CNcdReport& currentReport( *iReports[ aIndex ] ); + CNcdAttributes& att( currentReport.Attributes() ); + + report->SetNamespaceL( + att.AttributeString16( ENcdReportAttributeReportNamespace ) ); + + currentReport.AddReportDataL( *report ); + currentReport.SetReportTransaction( &aTransaction ); + + // Update report flags: beingSent = current status, + // latestSentReport = none, so we can identify cases were the same + // status is sent multiple times in a row (pause, pause...) + UpdateReportAttributesForSendingL( currentReport ); + + DLTRACE(("Start bundling, report count: %d", iReports.Count() )); + for ( TInt i = aIndex + 1; i < iReports.Count(); ++i ) + { + + TNcdReportBundleMatch bundle = CanBundleWithL( + currentReport, + *iReports[i] ); + + if ( bundle == ENcdReportBundleMatch && + iReports[i]->IsSendable() ) + { + DLTRACE(("Bundling report %d", i )); + iReports[i]->AddReportDataL( *report ); + iReports[i]->SetReportTransaction( &aTransaction ); + + // Update report status + UpdateReportAttributesForSendingL( *iReports[i] ); + } + else if ( bundle == ENcdReportBundleNoMatch ) + { + DLTRACE(("Nothing more to bundle, exit loop")); + break; + } + } + + DLTRACE(("Process report")); + HBufC8* body = + iGeneralManager.ProtocolManager().ProcessPreminetRequestL( + Context(), + *report, + att.AttributeString16( ENcdReportAttributeReportUri ), + ETrue ); + CleanupStack::PopAndDestroy( report ); + + CleanupStack::PushL( body ); + aTransaction.SetBodyL( *body ); + CleanupStack::PopAndDestroy( body ); + } + + +// --------------------------------------------------------------------------- +// Updates common attributes of the report for sending +// --------------------------------------------------------------------------- +void CNcdReportManager::UpdateReportAttributesForSendingL( + CNcdReport& aReport ) + { + DLTRACEIN(("")); + CNcdAttributes& att( aReport.Attributes() ); + + att.SetAttributeL( + ENcdReportAttributeReportBeingSent, + aReport.Status().iStatus ); + + att.SetAttributeL( + ENcdReportAttributeLatestSentReport, + ENcdReportNone ); + + att.SetAttributeL( + ENcdReportAttributeSendable, + EFalse ); + } + +// --------------------------------------------------------------------------- +// Check if reports can be bundled together +// --------------------------------------------------------------------------- +TNcdReportBundleMatch CNcdReportManager::CanBundleWithL( + const CNcdReport& aReport, + const CNcdReport& aReport2 ) const + { + DLTRACEIN(("")); + // Report URIs must match + if ( ( aReport.Attributes().AttributeString16( + ENcdReportAttributeReportUri ).Compare( + aReport2.Attributes().AttributeString16( + ENcdReportAttributeReportUri ) ) != 0 ) ) + { + DLTRACEOUT(("Can stop")); + return ENcdReportBundleNoMatch; + } + + if ( + // Report namespaces must match + ( aReport.Attributes().AttributeString16( + ENcdReportAttributeReportNamespace ).Compare( + aReport2.Attributes().AttributeString16( + ENcdReportAttributeReportNamespace ) ) == 0 ) + + && + // Report access points must match + ( CompareConnectionMethods( aReport, aReport2 ) ) ) + { + return ENcdReportBundleMatch; + } + + DLTRACEOUT(("")); + return ENcdReportBundleUriMatch; + } + + +// --------------------------------------------------------------------------- +// Prepare report for sending +// --------------------------------------------------------------------------- +void CNcdReportManager::PrepareReportL( + CNcdReport& aReport, + MCatalogsHttpOperation& aTransaction ) + { + DLTRACEIN(("")); + + aReport.SetReportTransaction( &aTransaction ); + + UpdateReportAttributesForSendingL( aReport ); + + HBufC8* body = aReport.CreateReportL(); + CleanupStack::PushL( body ); + DLINFO(( "body= %S", body )); + + aTransaction.SetBodyL( *body ); + CleanupStack::PopAndDestroy( body ); + } + + +// --------------------------------------------------------------------------- +// Complete request +// --------------------------------------------------------------------------- +void CNcdReportManager::ExecuteRunL( TInt aError ) + { + DLTRACEIN(("aError: %d", aError)); + + if ( !IsActive() ) + { + iStatus = KRequestPending; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete( status, aError ); + } + } + + +// --------------------------------------------------------------------------- +// Generate a new report id +// --------------------------------------------------------------------------- +TNcdReportId CNcdReportManager::GenerateReportId() + { + DLTRACEIN(("")); + return iNewReportId++; + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +void CNcdReportManager::SetReportStatusL( + CNcdReport& aReport, + const TNcdReportStatusInfo& aStatus, + TBool aSendable ) + { + DLTRACEIN(("")); + aReport.SetStatus( aStatus ); + aReport.Attributes().SetAttributeL( + ENcdReportAttributeSendable, + aSendable ); + + SaveReportL( aReport ); + + // Start sending if the report is sendable and the manager isn't already + // sending. Also if the operation is not done in the background then do not + // do sending here. But, later when it is separately asked. + if ( aReport.IsSendable() && + iManagerState == ENcdReportManagerIdle && + iReportingMethod == MNcdServerReportManager::EReportingBackground ) + { + SetManagerStateL( ENcdReportManagerPreparing ); + } + } + + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +TBool CNcdReportManager::CompareConnectionMethods( + const CNcdReport& aFirstReport, + const CNcdReport& aSecondReport ) const + { + DLTRACEIN(("")); + const TCatalogsConnectionMethod& first = aFirstReport.ConnectionMethod(); + const TCatalogsConnectionMethod& second = aSecondReport.ConnectionMethod(); + + switch( first.iType ) + { + case ECatalogsConnectionMethodTypeAlwaysAsk: + case ECatalogsConnectionMethodTypeDeviceDefault: // flow-through + { + if ( second.iType == first.iType ) + { + return ETrue; + } + break; + } + + case ECatalogsConnectionMethodTypeDestination: + { + if ( second.iType == ECatalogsConnectionMethodTypeDestination ) + { + return ( first.iId != 0 && first.iId == second.iId ) || + ( first.iApnId != 0 && first.iApnId == second.iApnId ); + } + break; + } + + case ECatalogsConnectionMethodTypeAccessPoint: + { + if ( second.iType == ECatalogsConnectionMethodTypeAccessPoint ) + { + return ( first.iId != 0 && first.iId == second.iId ); + } + break; + } + + default: + { + DASSERT( 0 ); + } + } + + return ( first.iApnId != 0 && first.iApnId == second.iApnId ); + }