diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/server/src/drmmeteringdb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/server/src/drmmeteringdb.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,655 @@ +/* +* 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: Implementation of the Metering database +* +*/ + + +// INCLUDE FILES + +#include +#include +#include +#include "drmlog.h" +#include "drmmeteringdb.h" +#ifdef RD_DRM_METERING +#include "drmmeteringdbdata.h" +#endif +#include "DRMTypes.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +#ifdef RD_DRM_METERING + +_LIT( KCIDColName, "cid" ); +_LIT( KRightIssuerColName, "riid" ); +_LIT( KCountColName, "count" ); +_LIT( KAccumulatedTimeColName, "time" ); +_LIT( KMeteringDataTable, "metering" ); +_LIT( KParentUIDColName, "parent" ); +_LIT( KViewInitQuery, "SELECT * FROM metering ORDER BY riid" ); + +LOCAL_C const TUint8 KDbViewCIDOrdinal = 1; +LOCAL_C const TUint8 KDbViewRIIDOrdinal = 2; +LOCAL_C const TUint8 KDbViewCountOrdinal = 3; +LOCAL_C const TUint8 KDbViewAccumulatedTimeOrdinal = 4; +LOCAL_C const TUint8 KDbViewParentUIDOrdinal = 5; + +// MODULE DATA STRUCTURES +NONSHARABLE_STRUCT( TDoDeleteFile ) + { + RFs* iFs; + const TDesC* iFile; + }; + +// LOCAL FUNCTION PROTOTYPES +LOCAL_C void DoRollBack( TAny* aAny ); +LOCAL_C void DoDeleteFile( TAny* aAny ); + +// FORWARD DECLARATIONS + +// ============================= LOCAL FUNCTIONS =============================== +// ----------------------------------------------------------------------------- +// DoRollBack +// +// Do a rollback operation to the RDbDatabase* +// ----------------------------------------------------------------------------- +// +LOCAL_C void DoRollBack( TAny* aAny ) + { + reinterpret_cast< RDbDatabase* >( aAny )->Rollback(); + } + +// ----------------------------------------------------------------------------- +// DoDeleteFile +// +// Delete the file presented by TDoDeleteFile* +// ----------------------------------------------------------------------------- +// +LOCAL_C void DoDeleteFile( TAny* aAny ) + { + TDoDeleteFile* s = reinterpret_cast< TDoDeleteFile* >( aAny ); + + s->iFs->Delete( *( s->iFile ) ); + } + +#endif + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::RDrmMeteringDb +// +// Default constructor +// ----------------------------------------------------------------------------- +// +RDrmMeteringDb::RDrmMeteringDb(): +iFs( NULL ), +iDb() + { + // Nothing + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::~RDrmMeteringDb +// +// Destructor +// ----------------------------------------------------------------------------- +// +RDrmMeteringDb::~RDrmMeteringDb() + { + } + +// ----------------------------------------------------------------------------- +// RDRMMeteringDb::Close +// +// Closes the databases. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::Close() + { + // Atomic operations only at the moment, but what about the future. + iDb.Close(); + } + +#ifdef RD_DRM_METERING + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::RDrmMeteringDb +// +// Constructor +// ----------------------------------------------------------------------------- +// +RDrmMeteringDb::RDrmMeteringDb( RFs& aFs ) : +iFs( &aFs ), +iDb() + { + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::Set +// +// Set iFs to given aFs. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::Set( RFs& aFs ) + { + iFs = &aFs; + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::InitL +// +// Initialize the databases. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::InitL( const TDesC& aFileName ) + { + + DRMLOG( _L( "RDrmMeteringDb::InitL" ) ); + TInt error = KErrNone; + TBool exists = BaflUtils::FileExists( *iFs, aFileName ); + + if ( exists ) + { + TRAP( error, OpenDbL( iDb, aFileName ) ); + } + if ( error || !exists ) + { + ReplaceDbL( iDb, aFileName ); + } + DRMLOG( _L( "RDrmMeteringDb::InitL ok" ) ); + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::AddL +// +// Add an entry to the database. The method checks whether an entry matching +// the given Content Id and Rights Issuer Id already exists or not. A new row +// is added to the database if one does not already exist. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::AddL( const CDrmMeteringDbData* aMeteringData ) + { + + DRMLOG( _L( "RDrmMeteringDb::AddL" ) ); + + __ASSERT_DEBUG( aMeteringData, User::Invariant() ); + + RDbView view; + TBool res = EFalse; + + PushL( iDb ); + + InitViewLC( view ); + + User::LeaveIfError( iDb.Begin() ); + + for ( view.FirstL(); view.AtRow() && !res ; view.NextL() ) + { + view.GetL(); + + // Check whether an entry already exists or not. + if ( CompareIDL( view, *( aMeteringData->iContentId ), + aMeteringData->iRiId ) ) + { + + view.UpdateL(); // Update count and accumulated time of the rowset + + // Get the structure of rowset + CDbColSet* colset = view.ColSetL(); + CleanupStack::PushL( colset ); + + TInt count = 0; + TTimeIntervalSeconds accumulatedTime = + aMeteringData->iAccumulatedTime.Int(); + + count = aMeteringData->iCount + + view.ColUint32( KDbViewCountOrdinal ); + + view.SetColL( colset->ColNo( KCountColName ), count ); + + accumulatedTime = accumulatedTime.Int() + + view.ColInt32( KDbViewAccumulatedTimeOrdinal ); + + view.SetColL( colset->ColNo( KAccumulatedTimeColName ), + accumulatedTime.Int() ); + + if ( aMeteringData->iParentUid ) + { + view.SetColL( KDbViewParentUIDOrdinal, + *( aMeteringData->iParentUid ) ); + } + + view.PutL(); + iDb.Compact(); + + res = ETrue; + CleanupStack::PopAndDestroy( colset ); + } + + } + + // No existing entry was found. Make a new entry to the database. + if ( !res ) + { + view.InsertL(); // Add new row to the database + + view.SetColL( KDbViewCIDOrdinal, *( aMeteringData->iContentId ) ); + view.SetColL( KDbViewRIIDOrdinal, aMeteringData->iRiId ); + view.SetColL( KDbViewCountOrdinal, aMeteringData->iCount ); + view.SetColL( KDbViewAccumulatedTimeOrdinal, + aMeteringData->iAccumulatedTime.Int() ); + + if ( aMeteringData->iParentUid ) + { + view.SetColL( KDbViewParentUIDOrdinal, + *( aMeteringData->iParentUid ) ); + } + + view.PutL(); + } + + CleanupStack::PopAndDestroy(); // view + + User::LeaveIfError( iDb.Commit() ); + + Pop(); // iDb + DRMLOG( _L( "RDrmMeteringDb::AddL ok" ) ); + + } + + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::GetL +// +// Get the metering data list of a Rights Issuer from the database. Return value +// is ETrue if at least one entry was found. return value is EFalse if no entry +// was found. Function will leave if an error happens when accessing the +// database or if the given Rights Issuer Id is either empty or too long. +// ----------------------------------------------------------------------------- +// + +TBool RDrmMeteringDb::GetL( const TDesC8& aRiId, + CDRMPointerArray< CDrmMeteringDbData >& + aMeteringDataList ) + { + + DRMLOG( _L( "RDrmMeteringDb::GetL" ) ); + + // If Rights Issuer Id not available or is too long + if ( ( aRiId.Length() == 0 ) || ( aRiId.Length() > KRiIdSize ) ) + { + User::Leave( KErrArgument ); + } + + TBool found = EFalse; + + RDbView view; + + PushL( iDb ); + + InitViewLC( view ); + + User::LeaveIfError( iDb.Begin() ); + + // Examine the whole database for possible entries matching the Rights + // Issuer Id + for ( view.FirstL(); view.AtRow(); view.NextL() ) + { + + view.GetL(); + + // Check whether the Rights Issuer Id in the current row matches + // the given Rights Issuer Id or not. + if ( CompareIDL( view, aRiId ) ) + { + + found = ETrue; + + CDbColSet* colset = view.ColSetL(); + CleanupStack::PushL( colset ); + + // Create a new instance of the Metering information storage + // class to be included in the given Metering data pointer + // array + CDrmMeteringDbData* meteringdata = CDrmMeteringDbData::NewLC(); + TPtrC8 cid = view.ColDes8( colset->ColNo( KCIDColName ) ); + + meteringdata->iContentId = cid.AllocL(); + meteringdata->iRiId.Copy( aRiId ); + meteringdata->iCount = view.ColUint32( KDbViewCountOrdinal ); + + meteringdata->iAccumulatedTime = + static_cast< TTimeIntervalSeconds >\ + ( view.ColInt32( KDbViewAccumulatedTimeOrdinal ) ); + + TPtrC8 parentuid = + view.ColDes8( colset->ColNo( KParentUIDColName ) ); + + // Alloc has been used instead of AllocL in order not to leave + // if an error happens in the memory allocation. + meteringdata->iParentUid = parentuid.Alloc(); + + // Insert the instance to the Metering data pointer array + aMeteringDataList.AppendL( meteringdata ); + + CleanupStack::Pop( meteringdata ); + CleanupStack::PopAndDestroy( colset ); + } + + } + + User::LeaveIfError( iDb.Commit() ); + + CleanupStack::PopAndDestroy(); // view + + Pop(); // iDb + + DRMLOG( _L( "RDrmMeteringDb::GetL ok" ) ); + + return found; + + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::DeleteL +// +// Delete all the metering data associated to a Rights Issuer from the database. +// Return value is ETrue if at least one entry was found. Return value is EFalse +// if no entry was found. Function will leave if an error happens when accessing +// the database or if the given Rights Issuer Id is either empty or too long. +// ----------------------------------------------------------------------------- +// +TBool RDrmMeteringDb::DeleteL( const TDesC8& aRiId ) + { + + DRMLOG( _L( "RDrmMeteringDb::DeleteL" ) ); + + // If Rights Issuer Id is empty or is not available + if ( ( aRiId.Length() == 0 ) || ( aRiId.Length() > KRiIdSize ) ) + { + User::Leave( KErrArgument ); + } + + TBool found = EFalse; + + RDbView view; + + PushL( iDb ); + + InitViewLC( view ); + + User::LeaveIfError( iDb.Begin() ); + + for ( view.FirstL(); view.AtRow(); view.NextL() ) + { + + view.GetL(); + + if ( CompareIDL( view, aRiId ) ) + { + found = ETrue; + view.DeleteL(); + } + + } + + if ( found ) + { + iDb.Compact(); + } + + User::LeaveIfError( iDb.Commit() ); + + CleanupStack::PopAndDestroy(); // view + + Pop(); // iDb + + DRMLOG( _L( "RDrmMeteringDb::DeleteL ok" ) ); + + return found; + + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::OpenDbL +// +// Open the database. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::OpenDbL( RDbNamedDatabase& aDb, + const TDesC& aFileName ) + { + + DRMLOG( _L( "RDrmMeteringDb::OpenDbL" ) ); + CDbTableNames* tables = NULL; + + User::LeaveIfError( aDb.Open( *iFs, aFileName ) ); + CleanupClosePushL( aDb ); + + if ( aDb.IsDamaged() ) + { + User::LeaveIfError( aDb.Recover() ); + } + + // Sanity check + tables = aDb.TableNamesL(); + CleanupStack::PushL( tables ); + + if ( tables->Count() != 1 || + ( *tables )[ 0 ].Compare( KMeteringDataTable ) ) + { + User::Leave( KErrCorrupt ); + } + + CleanupStack::PopAndDestroy( tables ); + CleanupStack::Pop(); // aDb + DRMLOG( _L( "RDrmMeteringDb::OpenDbL ok" ) ); + + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::ReplaceDbL +// +// Replace the database. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::ReplaceDbL( RDbNamedDatabase& aDb, + const TDesC& aFileName ) + { + DRMLOG( _L( "RDrmMeteringDb::ReplaceDbL" ) ); + + CDbColSet* colSet = NULL; + + // Define column names and their data types + TDbCol cidCol( KCIDColName, EDbColText8 ); + TDbCol riidCol( KRightIssuerColName, EDbColText8 ); + TDbCol countCol( KCountColName, EDbColUint32 ); + TDbCol accumulatedTimeCol( KAccumulatedTimeColName, EDbColInt32 ); + TDbCol parentUIDCol( KParentUIDColName, EDbColText8 ); + + TDoDeleteFile deletefile = { iFs, &aFileName }; + + TCleanupItem item( DoDeleteFile, &deletefile ); + CleanupStack::PushL( item ); + + User::LeaveIfError( aDb.Replace( *iFs, aFileName ) ); + CleanupClosePushL( aDb ); + + // Add columns + colSet = CDbColSet::NewLC(); + colSet->AddL( cidCol ); + colSet->AddL( riidCol ); + colSet->AddL( countCol ); + colSet->AddL( accumulatedTimeCol ); + colSet->AddL( parentUIDCol); + + // Create indices + TDbKeyCol cidKeyCol( KCIDColName ); + TDbKeyCol riidKeyCol( KRightIssuerColName ); + + CDbKey* key = CDbKey::NewLC(); + key->AddL( cidKeyCol ); + key->AddL( riidKeyCol ); + key->MakeUnique(); + + User::LeaveIfError( aDb.Begin() ); + User::LeaveIfError( aDb.CreateTable( KMeteringDataTable, *colSet ) ); + + User::LeaveIfError( aDb.CreateIndex( KMeteringDataTable, + KMeteringDataTable, + *key ) ); + + User::LeaveIfError( aDb.Commit() ); + + CleanupStack::PopAndDestroy( 2, colSet ); // key, colset + CleanupStack::Pop(); // aDb + CleanupStack::Pop(); // item + + DRMLOG( _L( "RDrmMeteringDb::ReplaceDbL ok" ) ); + + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::InitViewLC +// +// Initialize the view. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::InitViewLC( RDbView& aView ) + { + + DRMLOG( _L( "RDrmMeteringDb::InitViewLC" ) ); + + User::LeaveIfError( + aView.Prepare( iDb, + TDbQuery( KViewInitQuery, EDbCompareCollated ), + RDbRowSet::EUpdatable ) ); + + CleanupClosePushL( aView ); + + User::LeaveIfError( aView.EvaluateAll() ); + + DRMLOG( _L( "RDrmMeteringDb::InitViewLC ok" ) ); + + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::CompareIDL +// +// Compare the Rights Issuer Id and Content Id to their counterparts in the current +// row of the view. Return value is ETrue only if both the Content Id and the Rights +// Issuer Id match their counterpart Ids in the view. +// ----------------------------------------------------------------------------- +// +TBool RDrmMeteringDb::CompareIDL( RDbRowSet& aView, + const TDesC8& aCID, + const TDesC8& aRiId ) + { + + DRMLOG( _L( "RDrmMeteringDb::CompareIDL" ) ); + + TBool res = EFalse; + + CDbColSet* colset = aView.ColSetL(); + CleanupStack::PushL( colset ); + + TPtrC8 riid = aView.ColDes8( colset->ColNo( KRightIssuerColName ) ); + TBuf8< KRiIdSize > buf = riid; + + TPtrC8 cid = aView.ColDes8( colset->ColNo( KCIDColName ) ); + HBufC8* des = cid.AllocLC(); + + if ( ( aRiId.CompareC( buf ) == 0 ) && ( aCID.CompareC( *des ) == 0 ) ) + { + res = ETrue; + } + + CleanupStack::PopAndDestroy( des ); + CleanupStack::PopAndDestroy( colset ); + + DRMLOG( _L( "RDrmMeteringDb::CompareIDL ok" ) ); + + return res; + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::CompareIDL +// +// Compare whether the rowset's ID matches the given ID. For comparison of +// Rights Issuer ID. Overloaded. +// ----------------------------------------------------------------------------- +// +TBool RDrmMeteringDb::CompareIDL( RDbRowSet& aView, + const TDesC8& aRiId ) + { + + DRMLOG( _L( "RDrmMeteringDb::CompareIDL" ) ); + + TBool res = EFalse; + + CDbColSet* colset = aView.ColSetL(); + CleanupStack::PushL( colset ); + + TPtrC8 riid = aView.ColDes8( colset->ColNo( KRightIssuerColName ) ); + TBuf8< KRiIdSize > buf = riid; + + if ( aRiId.CompareC( buf ) == 0 ) + { + res = ETrue; + } + + CleanupStack::PopAndDestroy( colset ); + + DRMLOG( _L( "RDrmMeteringDb::CompareIDL ok" ) ); + + return res; + } + + +// ----------------------------------------------------------------------------- +// RDrmMeteringDb::PushL +// +// Push a cleanup item to cleanup stack. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::PushL( RDbDatabase& aDb ) + { + TCleanupItem item( DoRollBack, &aDb ); + CleanupStack::PushL( item ); + } + +// ----------------------------------------------------------------------------- +// RDrmMeteringDB::Pop +// +// Pop a cleanup item pushed in by PushL. +// ----------------------------------------------------------------------------- +// +void RDrmMeteringDb::Pop() + { + CleanupStack::Pop(); + } + +#endif + +// End of File