diff -r 000000000000 -r e686773b3f54 phonebookengines/contactsmodel/cntsrv/src/CCntDbManagerController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines/contactsmodel/cntsrv/src/CCntDbManagerController.cpp Tue Feb 02 10:12:17 2010 +0200 @@ -0,0 +1,593 @@ +// Copyright (c) 2005-2009 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: +// + +/** + @file + @internalComponent + @released +*/ + + +#include +#include + +#include "persistencelayer.h" +#include "CCntDbManagerController.h" +#include "CCntRequest.h" +#include "CCntIpcCodes.h" // For KCntMaxFilePath. +#include "CCntBackupRestoreAgent.h" +#include "CIniFileManager.h" +#include "CCntPermanentData.h" + +_LIT(KSqLiteFilePrefix, "SQLite__"); + +/** +Object factory method. + +@param aServerType ETransientServer if the Server is transient, +ENonTransientServer if the Server is not transient. + +@return CCntDbManagerController instance. +*/ +CCntDbManagerController* CCntDbManagerController::NewLC(TCntServerType aServerType) + { + CCntDbManagerController* ctrl = new (ELeave) CCntDbManagerController(); + CleanupStack::PushL(ctrl); + ctrl->ConstructL(aServerType); + return ctrl; + } + +/** +Second phase constructor. + +@param aServerType ETransientServer if the Server is transient, +ENonTransientServer if the Server is not transient. +*/ +void CCntDbManagerController::ConstructL(TCntServerType aServerType) + { + User::LeaveIfError(iFs.Connect()); + iBackupRestoreAgent = CCntBackupRestoreAgent::NewL(iFs, *this); + iIniFileManager = CIniFileManager::NewL(iFs, *this); + + // Controller requires one Persistence Layer instance. + iPersistenceLayer = CPersistenceLayer::NewLC(iFs); + CleanupStack::Pop(iPersistenceLayer); + + // Create a backup registration file for the Contacts Model initialisation + // file. + TFileName iniFile; + iIniFileManager->GetIniFileNameL(iniFile, EFalse); + iBackupRestoreAgent->CreateBackupRegistrationFileL(iniFile); + + // Only now safe to start the Backup/Restore Agent since it relies on the + // iIniFileManager object being fully constructed in the case where, within + // the StartL() method, the value of the Backup/Restore property indicates + // either a Backup or Restore is in progress. + iBackupRestoreAgent->StartL(); + + // Start the pre-creation of the default application data: + // Open the default file and create the default remote + // view(s) so they are ready for use by client applications. + if (aServerType == ENonTransientServer) + { + iPermanentData = CCntPermanentData::NewL(*this); + // If the permanent data creation step leaves, it should not + // cause the server to panic. Instead, TRAP it and ignore + // it - it is not fatal to normal server operation anyway. + TRAP_IGNORE(iPermanentData->StartDataCreationL()); + } + + // Retrieve the list of contact databases on the C: drive. + MLplContactsFile& contactsFile = iPersistenceLayer->ContactsFileL(); + TDriveUnit cDrive(EDriveC); + CDesCArray* list(contactsFile.ListL(&cDrive)); + CleanupStack::PushL(list); + + // Check that each database has a back up registration XML file. + // If not, create one. + const TInt KListLen(list->Count()); + for (TInt i = 0; i < KListLen; ++i) + { + TFileName dbName((*list)[i]); + HBufC* backupFileNameBuf = iBackupRestoreAgent-> + CreateBackupRegistrationFileNameLC(dbName.Mid(cDrive.Name().Length())); + TFileName backupFileName; + backupFileName.Append(cDrive.Name()); + backupFileName.Append(*backupFileNameBuf); + CleanupStack::PopAndDestroy(backupFileNameBuf); + if (!BaflUtils::FileExists(iFs, backupFileName)) + { + TRAP_IGNORE(iBackupRestoreAgent->CreateBackupRegistrationFileL(dbName)); + } + } + CleanupStack::PopAndDestroy(list); + } + + +CCntDbManagerController::CCntDbManagerController() + : iDefaultDriveUnit(EDriveC) + { + } + + +CCntDbManagerController::~CCntDbManagerController() + { + delete iPermanentData; + iManagers.ResetAndDestroy(); + delete iPersistenceLayer; + delete iIniFileManager; + delete iBackupRestoreAgent; + iFs.Close(); + } + + +/** +Return a CCntDbManager for an existing Contacts database. Creates a +CCntDbManager if no session has the file open. The Contacts database must +exist. + +@param aCntFile Contacts database filename. +@param aMode Indicates whether Contacts database is to be opened, created or +replaced. + +@return CCntDbManager instance. +*/ +CCntDbManager* CCntDbManagerController::GetDbManagerL(TDes& aCntFile, TCntFileMode aMode) + { +#ifdef __PROFILE__ + TTime now; + now.UniversalTime(); +#endif + + // If a Backup or Restore is in progress disallow creation of manager and + // hence any access to database. This is replicated behaviour from Contacts + // Model 1. + if (iBackupRestoreAgent->RestoreInProgress() || iBackupRestoreAgent->BackupInProgress()) + { + User::Leave(KErrLocked); + } + + // Deal with default Contacts database file (indicated by empty descriptor). + if(aCntFile.Length() == 0) + { + DefaultDatabaseL(aCntFile); + } + + // Free it up for a replace/create operation if + // permanent data is only thing holding it open. + if (iPermanentData && (aMode == ECntFileReplace)) + { + CCntDbManager* manager = DbManagerL(aCntFile); + if (manager && iPermanentData->IsOnlyClientOfDbManager(manager)) + { + iPermanentData->ReleaseDbManagerL(manager); + } + } + + CCntDbManager* theManager = DbManagerL(aCntFile); + + if (theManager != NULL) // Existing DbManager is found. + { + // If creating the file, leave because it is already exists. + if (aMode == ECntFileCreate) + { + User::Leave(KErrAlreadyExists); + } + // If replacing the file, leave because it is currently in use. + if (aMode == ECntFileReplace) + { + User::Leave(KErrInUse); + } + } + else // The file is not opened and DbManager doesn't exist. + { + // Create new CCntDbManager. + theManager = CCntDbManager::NewLC(iFs, aCntFile, aMode, *iBackupRestoreAgent, *iIniFileManager); + // Add to the list of managers. + iManagers.AppendL(theManager); + CleanupStack::Pop(theManager); + } + + // Increase the session count. + theManager->AddSession(); + +#ifdef __PROFILE__ + TTime now2; + now2.UniversalTime(); + + RDebug::Print(_L("[CNTMODEL] Spend %d microseconds in CCntDbManagerController::GetDbManagerL \n"), now2.MicroSecondsFrom(now).Int64()); +#endif + + return theManager; + } + + +/** +Find an existing manager for an opened Contacts database file. + +@param aCntFile Contacts database filename. + +@return CCntDbManager instance if the manager exists for aCntFile otherwise +returns NULL. +*/ +CCntDbManager* CCntDbManagerController::DbManagerL(const TDesC& aCntFile) const + { + CCntDbManager* manager = NULL; + const TInt index = FindExistingFileManager(aCntFile); + if (index != KErrNotFound) + { + manager = iManagers[index]; + } + return manager; + } + + +/** +Delete an existing Contacts database file. + +@param aCntFile Contacts database filename. +*/ +void CCntDbManagerController::DeleteDatabaseL(TDes& aCntFile) const + { + // Deal with default Contacts database file (indicated by empty descriptor). + if(aCntFile.Length() == 0) + { + DefaultDatabaseL(aCntFile); // Get the default database name. + } + + // Release the internal reference to the manager if the internal + // permanent data is the only object holding it open. + if (iPermanentData) + { + CCntDbManager* manager = DbManagerL(aCntFile); + if (manager && iPermanentData->IsOnlyClientOfDbManager(manager)) + { + iPermanentData->ReleaseDbManagerL(manager); + } + } + + // Make sure there is not an existing CCntDbManager session. + if(FindExistingFileManager(aCntFile) != KErrNotFound) + { + User::Leave(KErrInUse); + } + else + { + // Delete the backup registration file associated with the Contacts + // database file. + iBackupRestoreAgent->DeleteBackupRegistrationFileL(aCntFile); + // Call the Persistence Layer to delete the Contacts database file. + iPersistenceLayer->ContactsFileL().DeleteL(aCntFile); + } + } + + +/** +Return the filename of the current default Contact database file. + +@param aCntFile On return holds current default Contacts database filename. +*/ +void CCntDbManagerController::DefaultDatabaseL(TDes& aCntFile) const + { + + if ((iDefaultDriveUnit.Name().Length() + KContactsBaseFilename().Length()) > aCntFile.MaxLength()) + { + User::Leave(KErrOverflow); + } + aCntFile.Copy(iDefaultDriveUnit.Name()); + aCntFile.Append(KContactsBaseFilename); + } + + +/** +Return the current default Contacts database drive. + +@param aDrive On return holds the current default Contacts database drive. +*/ +void CCntDbManagerController::DatabaseDrive(TDriveUnit& aDrive) const + { + aDrive = iDefaultDriveUnit; + } + + +/** +Set the current default Contacts database drive and optionally moves the +default Contacts database from the current default drive to the new drive. + +@param aDriveUnit New current default Contacts database drive. +@param aCopy ETrue if default Contacts database should be moved to new drive. +*/ +void CCntDbManagerController::SetDatabaseDriveL(TDriveUnit aDriveUnit, TBool aCopy) + { + if (aDriveUnit == iDefaultDriveUnit) // Same drive? + { + aCopy = EFalse; + if (iIniFileManager->DatabaseDriveSet()) + { + return; + } + } + + // Old drive name. + TDriveName oldDrv = iDefaultDriveUnit.Name(); + // New drive name. + TDriveName newDrv = aDriveUnit.Name(); + TBuf oldPath; + User::LeaveIfError(iFs.PrivatePath(oldPath)); + // Drive name goes before the path. + oldPath.Insert(0,oldDrv); + // Filename goes after the path. + oldPath.Append(KSqLiteFilePrefix); + oldPath.Append(KContactsBaseFilename); + + TBuf newPath; + User::LeaveIfError(iFs.PrivatePath(newPath)); + // Drive name goes before the path. + newPath.Insert(0,newDrv); + // Filename goes after the path. + newPath.Append(KSqLiteFilePrefix); + newPath.Append(KContactsBaseFilename); + + // Move the old file to the new drive location. + CFileMan* fileManager = CFileMan::NewL(iFs); + CleanupStack::PushL(fileManager); + // The new file will be overwritten if it exists. If the file or the path + // doesn't exist then it will be created. + if (aCopy) + { + User::LeaveIfError(fileManager->Copy(oldPath, newPath, CFileMan::ERecurse | CFileMan::EOverWrite )); + } + + // Change the default drive to the specified drive. + iDefaultDriveUnit = aDriveUnit; + + // Save to Contacts initialisation file. + iIniFileManager->SetDefaultDatabaseDrive(iDefaultDriveUnit, ETrue); + iIniFileManager->ScheduleSaveIniFileSettings(CIniFileManager::ESaveDefaultDbDrive); + + // Remove the old file. + if (aCopy) + { + (void)fileManager->Delete(oldPath); + } + CleanupStack::PopAndDestroy(fileManager); + } + +/** +Return the restored Contacts database drive. + +@param aDrive On return holds the Contacts database drive restored from CntModel.ini. +*/ +void CCntDbManagerController::RestoreDatabaseDrive(TDriveUnit& aDrive) + { + iDefaultDriveUnit = aDrive; + } + +/** +Return whether or not the named or default (empty descriptor) Contacts database +exists. + +@param aCntFile Contacts database filename. + +@return ETrue if Contacts database exists, EFalse otherwise. +*/ +TBool CCntDbManagerController::DatabaseExistsL(const TDesC& aCntFile) const + { + if(aCntFile==KNullDesC) + { + TBuf path; + DefaultDatabaseL(path); + return (iPersistenceLayer->ContactsFileL().DatabaseExistsL(path)); + } + return (iPersistenceLayer->ContactsFileL().DatabaseExistsL(aCntFile)); + } + + +/** +Return a list of Contacts databases found on drive aDriveUnit. + +@param aListBuffer Client supplied flat buffer to be filled with a serialized +CDesCArray of Contacts databases found on drive aDriveUnit. +@param aDriveUnit Drive to list Contacts databases for. If defaulted then a +list of Contacts databases on all drives will be returned. +*/ +void CCntDbManagerController::ListDatabasesL(CBufFlat*& aListBuffer, TDriveUnit* aDriveUnit) const + { + const TInt KInitialBufferSize = 200; + aListBuffer = CBufFlat::NewL(KInitialBufferSize); + CleanupStack::PushL(aListBuffer); + + // Create a write stream for this buffer. + RBufWriteStream bufStream; + CleanupClosePushL(bufStream); + bufStream.Open(*aListBuffer); + + // Use Persistence Layer to get list of Contacts databases. Note that the + // ListL() method always returns a list even if empty so no NULL check for + // list is required. + MLplContactsFile& pl = iPersistenceLayer->ContactsFileL(); + CDesCArray* list =NULL; + if(aDriveUnit == NULL) + { + list = pl.ListL(); // Retrieve Contacts databases on all drives. + } + else + { + list = pl.ListL(aDriveUnit); // Retrieve Contacts databases on named drive. + } + + // Externalize the CDesCArray. + CleanupStack::PushL(list); + TInt count = list->Count(); + bufStream.WriteUint32L(count); + + for (TInt i=0; iMdcaPoint(i)).Length(); + bufStream.WriteUint8L(length); + bufStream.WriteL(list->MdcaPoint(i),length); + } + bufStream.CommitL(); + + CleanupStack::PopAndDestroy(2, &bufStream); // list + CleanupStack::Pop(aListBuffer); + } + + +/** +Return the index of the CCntDbManager instance which has a Contacts database +filename equal to aCntFile. If no CCntDbManager instance has this filename then +KErrNotFound is returned. + +@param aCntFile Contacts database filename. + +@return Index of CCntDbManager instance which has a Contacts database filename +equal to aCntFile or KErrNotFound if no match. +*/ +TInt CCntDbManagerController::FindExistingFileManager(const TDesC& aCntFile) const + { + for(TInt i=iManagers.Count()-1; i>=0; --i) + { + if(aCntFile.CompareF(iManagers[i]->CntFile()) == 0) + { + return i; + } + } + return KErrNotFound; + } + + +/** +Close a session for the given CCntDbManager instance. If no more session are +open for this CCntDbManager instance (i.e. last client session for this Contacts +database has closed) then the instance is destroyed. + +@param aManager CCntDbManager instance to close session on. +*/ +void CCntDbManagerController::CloseDatabase(CCntDbManager& aManager) + { + aManager.RemoveSession(); + if(aManager.SessionCount() == 0) + { + for(TInt i=0;iCurrentDb(); + } + + +/** +Set the "system wide" current Contacts database. Also notify all CCntDbManager +instances of the change of current Contacts database. + +@param aNewCurrentDb New current Contacts database. +@param aSessionId Session ID of the client making the change. + +@leave KErrNoMemory Out of memory. +@leave KErrNotFound +@leave KErrGeneral +*/ +void CCntDbManagerController::SetCurrentDbL(const TDesC& aNewCurrentDb, TUint aSessionId) + { + iIniFileManager->SetCurrentDb(aNewCurrentDb); + iIniFileManager->ScheduleSaveIniFileSettings(CIniFileManager::ESaveCurrentDatabase); + TContactDbObserverEvent event; + event.iType = EContactDbObserverEventCurrentDatabaseChanged; + event.iContactId = KNullContactId; + event.iConnectionId = aSessionId; + NotifyDbManagersL(event); + } + + +/** +Process a Backup/Restore event generated by the Backup/Restore Agent. Simply +notfiy all CCntDbManager instances of the event which they will process in +turn. + +@param aEvent Backup/Restore event. +*/ +void CCntDbManagerController::HandleBackupRestoreEventL(TContactDbObserverEvent aEvent) + { + TInt count = iManagers.Count(); + for (TInt i = 0 ; i < count ; ++i) + { + iManagers[i]->HandleBackupRestoreEventL(aEvent); + } + } + + +/** +Notify all CCntDbManager instances of the database event aEvent. The +CCntDbManager instances will in turn notify all registered observers of the +event. + +@param aEvent Database event. +*/ +void CCntDbManagerController::NotifyDbManagersL(TContactDbObserverEvent aEvent) + { + TInt count = iManagers.Count(); + for (TInt i = 0 ; i < count ; ++i) + { + iManagers[i]->NotifyObserversL(aEvent); + } + } + + +/** +Schedule a save of the initialisation file. +*/ +void CCntDbManagerController::ScheduleSaveIniFileSettings(TInt aSaveFlags, TBool aReplace) + { + iIniFileManager->ScheduleSaveIniFileSettings(aSaveFlags, aReplace); + } + + +/** +Get the Backup/Restore Agent instance owned by CCntDbManagerController. + +@return CCntBackupRestoreAgent instance owned by CCntDbManagerController. +*/ +CCntBackupRestoreAgent& CCntDbManagerController::BackupRestoreAgent() const + { + return *iBackupRestoreAgent; + } + + +/** +Get the Initialisation File Manager instance owned by CCntDbManagerController. + +@return CIniFileManager instance owned by CCntDbManagerController. +*/ +CIniFileManager& CCntDbManagerController::IniFileManager() const + { + return *iIniFileManager; + }