mmappcomponents/harvester/filehandler/src/mpxdbsynchronizer.cpp
changeset 0 a2952bb97e68
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmappcomponents/harvester/filehandler/src/mpxdbsynchronizer.cpp	Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,450 @@
+/*
+* Copyright (c) 2006-2007 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:  Class for synchronization collection and harvester databases
+*
+*/
+
+#include <e32base.h>
+#include <mpxlog.h>
+#include <mpxcommandgeneraldefs.h>
+#include <mpxcollectioncommanddefs.h>
+#include <mpxcollectionutility.h>
+
+#include "mpxcommand.h"
+#include "mpxharvesterdbmanager.h"
+#include "mpxharvesterdbtable.h"
+#include "mpxdbsynchronizer.h"
+#include "mpxdbsyncobserver.h"
+
+#include <mpxcollectionplugin.hrh>
+#include <centralrepository.h>            // to get podcasting cenrep key
+// CONSTANTS
+const TInt KRecStepCount = 100;
+
+// ======== LOCAL FUNCTIONS ========
+    
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXDbSynchronizer::CMPXDbSynchronizer(MMPXDbSyncObserver& aObserver,
+                                       CMPXHarvesterDatabaseManager& aDbMng,
+                                       const TUid& aMusic,
+                                       const TUid& aPodcast,
+                                       RFs& aFs,
+                                       TBool aDisablePodcast )
+        : CActive(EPriorityNull), //using the same priority as folder scanner
+        iSyncObserver(aObserver),
+        iDBManager(aDbMng),
+        iColUtil(NULL),
+        iMusicUid(aMusic),
+        iPodcastUid(aPodcast),
+        iFs(aFs),
+        iSyncState(ESyncStopped),
+        iCurDrive(-1),
+        iDbRecTotalCount(0),
+        iCurDbRecCount(0),
+        iLastID(0),
+        iDisablePodcasting( aDisablePodcast )
+    {
+    CActiveScheduler::Add(this);
+    }
+
+// ---------------------------------------------------------------------------
+// 2nd Phase Constructor
+// ---------------------------------------------------------------------------
+//
+void CMPXDbSynchronizer::ConstructL()
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Two Phased Constructor
+// ---------------------------------------------------------------------------
+//
+CMPXDbSynchronizer* CMPXDbSynchronizer::NewL(MMPXDbSyncObserver& aObserver,
+                                             CMPXHarvesterDatabaseManager& aDbMng,
+                                             const TUid& aMusic,
+                                             const TUid& aPodcast, 
+                                             RFs& aFs,
+                                             TBool aDisablePodcast )
+    {
+    CMPXDbSynchronizer* self = new(ELeave) CMPXDbSynchronizer(aObserver,aDbMng,aMusic,
+                                                              aPodcast,aFs,aDisablePodcast);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CMPXDbSynchronizer::~CMPXDbSynchronizer()
+    {
+    Cancel();
+    iDbDrives.Close();
+    }
+    
+// ---------------------------------------------------------------------------
+// Scans a list of drives for files
+// ---------------------------------------------------------------------------
+//
+void CMPXDbSynchronizer::Synchronize(RArray<TInt>& aDrives, MMPXCollectionUtility* aColUtil)
+    {
+    MPX_DEBUG1("---> CMPXDbSynchronizer::Synchronize");
+    ASSERT(aColUtil != NULL); //internal call, should be always ok
+    
+    iColUtil = aColUtil;
+    
+    //check if synchronization is already active then ignore request
+    if(iSyncState == ESyncStopped)
+        {
+        TInt dbCount(iDBManager.Count());
+        TInt count(aDrives.Count());
+        
+        if(dbCount >= count && count != 0)
+            {
+            for(TInt i=0; i<count; ++i)
+                {
+                iDbDrives.Append(aDrives[i]);
+                }
+
+            iSyncState = ESyncMusic;
+            
+            // start synchronization cycle
+            CompleteSelf();
+            }
+        else
+            {
+            iSyncObserver.HandleSynchronizationComplete(KErrArgument);
+            }
+        }
+    else
+        {
+        iSyncObserver.HandleSynchronizationComplete(KErrInUse);
+        }
+    
+    MPX_DEBUG1("<--- CMPXDbSynchronizer::Synchronize");
+    }
+
+// ---------------------------------------------------------------------------
+// Sync next portion of data
+// ---------------------------------------------------------------------------
+//
+TBool CMPXDbSynchronizer::DoSynchronizeStepL()
+    {
+    MPX_DEBUG1("---> CMPXDbSynchronizer::DoSynchronizeStepL");
+
+    TBool ret(EFalse);
+
+    if(iDbDrives.Count() != 0)
+        {
+        TBool clear(EFalse);
+        //first time for a database on this drive
+        if(iCurDrive == -1)
+            {
+            iCurDrive = iDbDrives[0];
+            clear = ETrue;
+            }
+
+        CMPXHarvesterDB& db = iDBManager.GetDatabaseL((TDriveNumber)iCurDrive);
+        CMPXHarvesterDatabaseTable* table = db.OpenAllFilesTableL();
+        CleanupStack::PushL(table);
+
+        if(clear)
+            {
+            db.RemoveAllFilesL();
+            iDbRecTotalCount = 0;
+            iCurDbRecCount = 0;
+            iLastID = 0;
+            }
+
+        switch(iSyncState)
+            {
+            case ESyncMusic: //now getting music table content from curr drive's db
+                {
+                DoMusicTableSyncL(*table);
+                break;
+                }
+            case ESyncPlaylist: //now getting playlist table content (music db)
+                {
+                DoPlaylistTableSyncL(*table);
+                break;
+                }
+            case ESyncPodcast: //now getting podcast table content (podcast db)
+                {
+                DoPodcastTableSyncL(*table);
+                break;
+                }
+            default:
+                {
+                User::Leave(KErrAbort);
+                }
+            }
+
+        CleanupStack::PopAndDestroy(table);
+        }
+    else
+        {
+        ret = ETrue; //sync complete
+        }
+    
+    MPX_DEBUG1("<--- CMPXDbSynchronizer::SetupNextDriveToScanL return");
+    return ret;
+    }
+    
+// ---------------------------------------------------------------------------
+// Handle when synchronization is complete
+// ---------------------------------------------------------------------------
+//
+void CMPXDbSynchronizer::DoSynchronizeComplete(TInt aErr)
+    {
+    MPX_DEBUG1("---> CMPXDbSynchronizer::DoSynchronizeComplete");
+    
+    iDbDrives.Reset(); // Reset drives
+    iSyncState = ESyncStopped;
+
+    iCurDrive = -1;
+    iDbRecTotalCount = 0;
+    iCurDbRecCount = 0;
+    
+    // Notify observer
+    iSyncObserver.HandleSynchronizationComplete(aErr);
+    
+    MPX_DEBUG1("<--- CMPXDbSynchronizer::DoSynchronizeComplete");
+    }
+     
+// ---------------------------------------------------------------------------
+// From CActive
+// ---------------------------------------------------------------------------
+//
+void CMPXDbSynchronizer::RunL()
+    {
+    MPX_DEBUG1("---> CMPXDbSynchronizer::RunL");
+    
+    TBool done(EFalse);
+    done = DoSynchronizeStepL();
+     
+    if(done)
+        {
+        DoSynchronizeComplete(KErrNone);
+        }
+    else // if( !done )
+        {
+        MPX_DEBUG1("CMPXDbSynchronizer::RunL -- Schedule next run");
+        CompleteSelf();
+        }
+    MPX_DEBUG1("<--- CMPXDbSynchronizer::RunL");
+    }
+
+// ---------------------------------------------------------------------------
+// From CActive
+// ---------------------------------------------------------------------------
+//
+void CMPXDbSynchronizer::DoCancel()
+    {
+    ASSERT(iSyncState != ESyncStopped);
+    DoSynchronizeComplete(KErrCancel);
+    }
+    
+// ----------------------------------------------------------------------------
+// Handles a leave occurring in the request completion event handler RunL()
+// ----------------------------------------------------------------------------
+//
+TInt CMPXDbSynchronizer::RunError(TInt aError)
+    {
+    MPX_DEBUG2("CMPXDbSynchronizer::RunError(%d)", aError );
+    
+    DoSynchronizeComplete(aError);
+    
+    return KErrNone;
+    }
+
+//Helper functions implementation
+void CMPXDbSynchronizer::DoMusicTableSyncL(CMPXHarvesterDatabaseTable& aTable)
+    {
+    if(iDbRecTotalCount == 0)
+        {
+        //get total number of records from music db for music table
+        GetTableCountL(iMusicUid.iUid,EMPXCollectionCountTrack);
+        if (iDbRecTotalCount == 0)
+            {
+            iSyncState = ESyncPlaylist;
+            }
+        }
+    else
+        {
+        //get number of records from music table
+        TInt count = CopyTableRecordsL(aTable,iMusicUid.iUid,EMPXCollectionURITrack);
+        
+        //continue with music or switch to playlist
+        if(iCurDbRecCount >= iDbRecTotalCount || count == 0)
+            {
+            iDbRecTotalCount = 0;
+            iCurDbRecCount = 0;
+            iLastID = 0;
+            iSyncState = ESyncPlaylist;
+            }
+        }
+    }
+
+void CMPXDbSynchronizer::DoPlaylistTableSyncL(CMPXHarvesterDatabaseTable& aTable)
+    {
+    if(iDbRecTotalCount == 0)
+        {
+        //get total number of records from music db for playlist table
+        GetTableCountL(iMusicUid.iUid,EMPXCollectionCountPlaylist);
+        if (iDbRecTotalCount == 0)
+            {
+            iSyncState = ESyncPodcast;
+            }
+        }
+    else
+        {
+        //get number of records from playlist table
+        TInt count = CopyTableRecordsL(aTable,iMusicUid.iUid,EMPXCollectionURIPlaylist);
+
+        //continue with music or switch to playlist
+        if(iCurDbRecCount >= iDbRecTotalCount || count == 0)
+            {
+            iDbRecTotalCount = 0;
+            iCurDbRecCount = 0;
+            iLastID = 0;
+            iSyncState = ESyncPodcast;
+            }
+        }
+    }
+
+void CMPXDbSynchronizer::DoPodcastTableSyncL(CMPXHarvesterDatabaseTable& aTable)
+    {
+    if( iDisablePodcasting )
+        {
+        iDbDrives.Remove(0);
+        iCurDrive = -1;
+        iSyncState = ESyncMusic;
+        }
+    else
+        {
+        if(iDbRecTotalCount == 0)
+            {
+            //get total number of records from podcast db for podcast table
+            GetTableCountL(iPodcastUid.iUid,EMPXCollectionCountTrack);
+            if (iDbRecTotalCount == 0)
+                {
+                iDbDrives.Remove(0);
+                iCurDrive = -1;
+                iSyncState = ESyncMusic;
+                }
+            }
+        else
+            {
+            //get number of records from podcast table
+            TInt count = CopyTableRecordsL(aTable,iPodcastUid.iUid,EMPXCollectionURITrack);
+        
+            //continue with music or switch to playlist
+            if(iCurDbRecCount >= iDbRecTotalCount || count == 0)
+                {
+                iDbDrives.Remove(0);
+                iCurDrive = -1;
+                iSyncState = ESyncMusic;
+                }
+            }
+        }
+    }
+
+void CMPXDbSynchronizer::CompleteSelf()
+    {
+    iStatus = KRequestPending;
+    SetActive();
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, KErrNone );        
+    }
+
+void CMPXDbSynchronizer::GetTableCountL(TInt aDbId, TInt aTable)
+    {
+    //get total number of records from given Db for a given table
+    CMPXCommand* cmdCount = CMPXMedia::NewL();
+    CleanupStack::PushL(cmdCount);
+    cmdCount->SetTObjectValueL<TMPXCommandId>(KMPXCommandGeneralId, KMPXCommandCollectionGetCount);
+    cmdCount->SetTObjectValueL<TBool>(KMPXCommandGeneralDoSync, ETrue);
+    cmdCount->SetTObjectValueL<TInt>(KMPXCommandGeneralCollectionId, aDbId);
+    cmdCount->SetTObjectValueL<TInt>(KMPXCommandCollectionCountTable, aTable);
+    cmdCount->SetTObjectValueL<TInt>(KMPXCommandCollectionCountDrive, iCurDrive);
+    
+    iColUtil->Collection().CommandL(*cmdCount);
+
+    // returned command should contain count
+    if (!cmdCount->IsSupported(KMPXCommandCollectionCountValue))
+        {
+        User::Leave(KErrAbort);
+        }
+
+    iDbRecTotalCount = cmdCount->ValueTObjectL<TInt>(KMPXCommandCollectionCountValue);
+    
+    CleanupStack::PopAndDestroy(cmdCount);
+    }
+
+TInt CMPXDbSynchronizer::CopyTableRecordsL(CMPXHarvesterDatabaseTable& aTable,
+                                           TInt aColDbId, TInt aColTable)
+    {
+    //get number of records from given db and table
+    CMPXCommand* cmdUri = CMPXMedia::NewL();
+    CleanupStack::PushL(cmdUri);
+    cmdUri->SetTObjectValueL<TMPXCommandId>(KMPXCommandGeneralId, KMPXCommandCollectionGetURIs);
+    cmdUri->SetTObjectValueL<TBool>(KMPXCommandGeneralDoSync, ETrue);
+    cmdUri->SetTObjectValueL<TInt>(KMPXCommandGeneralCollectionId, aColDbId);
+    cmdUri->SetTObjectValueL<TInt>(KMPXCommandCollectionURIDrive, iCurDrive);
+    cmdUri->SetTObjectValueL<TInt>(KMPXCommandCollectionURITable, aColTable);
+    cmdUri->SetTObjectValueL<TInt>(KMPXCommandCollectionURIRecords, KRecStepCount); //number of records
+    cmdUri->SetTObjectValueL<TInt>(KMPXCommandCollectionURIFromID, iLastID); //from last record
+
+    // send sync retrieve count command
+    iColUtil->Collection().CommandL(*cmdUri);
+
+    // return command should contain Uri list and last item ID
+    if (!cmdUri->IsSupported(KMPXCommandCollectionURIList) && 
+        !cmdUri->IsSupported(KMPXCommandCollectionURILastID) )
+        {
+        User::Leave(KErrAbort);
+        }
+
+    //populate harvester db using received values;
+    // retrieve the list of URIs
+    CDesCArray* files = cmdUri->ValueNoNewLCObjectL<CDesCArray>(KMPXCommandCollectionURIList);
+    CleanupStack::PushL(files);
+
+    TInt uriCount = files->Count();
+    for(TInt j=0; j<uriCount; ++j)
+        {
+        TTime lastModTime(0);
+        TPtrC file((*files)[j]);
+        //we need to add all files to harvester db to be able to remove non-existing later
+        iFs.Modified(file, lastModTime);
+        TParsePtrC parse(file);
+        //if we leave here we it's ok to keep in harvester db what we managed to add
+        aTable.AddItemL(parse.DriveAndPath(), parse.NameAndExt(),
+                        lastModTime, aColDbId, 0); //drm is ok to be 0 here
+        }
+
+    iCurDbRecCount += uriCount;
+    CleanupStack::PopAndDestroy(files);
+    iLastID = cmdUri->ValueTObjectL<TInt>(KMPXCommandCollectionURILastID);
+    CleanupStack::PopAndDestroy(cmdUri);
+    
+    return uriCount;
+    }