omadrm/drmengine/server/src/drmmeteringdb.cpp
changeset 0 95b198f216e5
child 18 8a03a285ab14
--- /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 <f32file.h>
+#include <S32FILE.H>
+#include <BAUTILS.H>
+#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