srsf/sisrscontrollerplugin/src/sidatabase.cpp
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srsf/sisrscontrollerplugin/src/sidatabase.cpp	Wed Sep 01 12:29:17 2010 +0100
@@ -0,0 +1,514 @@
+/*
+* Copyright (c) 2004-2006 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:  This class implements the SI Controller Plugin database.
+*
+*/
+
+
+// INCLUDE FILES
+#include "sidatabase.h"
+#include "rubydebug.h"
+#include "nssbackupobserver.h"
+
+
+// CONSTANTS
+// Estimate size in bytes for an empty database
+// const TInt KSizeEstimateDb = 650;
+
+// Plugin database format string for secure DBMS
+_LIT( KPluginDatabaseFormatString, "SECURE[10201AFF]" );
+
+// Name of the DB lock mutex
+_LIT( KLockMutex, "SIDATABASE" );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CSIDatabase
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CSIDatabase::CSIDatabase( TFileName aDatabaseFileName )
+                        : iOpenTransaction( EFalse ),
+                          iDatabaseFileName( aDatabaseFileName ),
+                          iDatabaseOpen( EFalse )
+    {
+    // Nothing
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::ConstructL()
+    {
+    RUBY_DEBUG_BLOCKL( "CSIDatabase::ConstructL" );
+    // Checks to see if the Database already exists.  If not, it creates one.
+    User::LeaveIfError( iDbSession.Connect() );
+    CreateDatabaseL();
+    OpenDatabaseL();
+    
+    TInt err = iMutex.OpenGlobal( KLockMutex );
+    if ( err != KErrNone )
+        {
+        RUBY_DEBUG0( "CSIDatabase::ConstructL Creating new global mutex" );
+        iMutex.CreateGlobal( KLockMutex );
+        }
+    else
+        {
+        RUBY_DEBUG0( "CSIDatabase::ConstructL Using existing global mutex" );
+        }
+        
+    iCriticalSection.CreateLocal();
+    iBackupObserver = CNssBackupObserver::NewL( *this );
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CSIDatabase* CSIDatabase::NewL( TFileName aSDDatabaseFileName )
+    {
+    RUBY_DEBUG_BLOCKL( "CSIDatabase::NewL" );
+    
+    CSIDatabase* self = new( ELeave ) CSIDatabase( aSDDatabaseFileName );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::Rollback
+// Rollback all changes to the database. 
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::Rollback()
+    {
+    RUBY_DEBUG0( "CSIDatabase::Rollback" );
+    if ( iOpenTransaction )
+        {
+        iDb.Rollback();
+        // Try to recover the database, if it is damaged
+        if( iDb.IsDamaged() )
+            {
+            iDb.Recover();
+            }
+        iMutex.Signal();
+        iCriticalSection.Signal();
+        iOpenTransaction = EFalse;
+        }
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::~CSIDatabase
+// Destructor 
+// -----------------------------------------------------------------------------
+//
+CSIDatabase::~CSIDatabase()
+    {
+    // Rollback if there are any changes not commited
+    if ( iOpenTransaction )
+        {
+        iDb.Rollback();
+        // Try to recover the database, if it is damaged
+        if( iDb.IsDamaged() )
+            {
+            iDb.Recover();
+            }
+        // Signal mutex if somebody happens to be waiting in BeginTransactionL()
+        iMutex.Signal();
+        }
+        
+    delete iBackupObserver;
+    iCriticalSection.Close();
+
+    iDb.Close();
+    iDbSession.Close();
+    iDatabaseOpen = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::BeginTransactionL
+// Begins a database transaction if not already. Waits until exclusive write lock
+// has been gained.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::BeginTransactionL()
+    {
+   
+
+    if ( iOpenTransaction )
+        {
+        // If we already have the lock, no need to take it again
+        RUBY_DEBUG0( "CSIDatabase::BeginTransactionL DB is already locked by current process" );
+        return;
+        }
+    
+    // Take mutex to ensure that only one process tries to gain the lock
+    iMutex.Wait();
+    iCriticalSection.Wait();
+    
+    // Taking the global mutex makes it sure that this should succeed every time
+    TInt readLockErr = iDb.Begin();
+
+    if ( readLockErr == KErrNone )
+        {
+        iOpenTransaction = ETrue;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CommitChangesL
+// Commits all changes to the database.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CommitChangesL( TBool aCompact )
+    {
+    if ( iOpenTransaction )
+        {
+        TInt err = iDb.Commit();
+        
+        RUBY_DEBUG1( "CSIDatabase::CommitChangesL iDb.Commit() [%d]", err );
+        
+        if ( err != KErrNone )
+            {
+            iDb.Rollback();
+            // Try to recover the database, if it is damaged
+            if( iDb.IsDamaged() )
+                {
+                iDb.Recover();
+                }
+                
+            iMutex.Signal();
+            iCriticalSection.Signal();  
+            iOpenTransaction = EFalse;
+            User::Leave( err );
+            }
+        
+        if ( aCompact )
+            {
+            RUBY_DEBUG0( "CSIDatabase::CommitChangesL compacting DB" );
+            TInt error = iDb.Compact();
+            if ( error != KErrNone )
+                {
+                RUBY_DEBUG1( "CSIDatabase::CommitChangesL compact error: [%d]", error );
+                }
+            }
+        
+        // Signal waiting BeginTransactionL()
+        iMutex.Signal();
+        iCriticalSection.Signal();  
+        iOpenTransaction = EFalse;
+        
+        User::LeaveIfError( err );
+        }
+        
+          
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoIDTablesExistL
+// Checks to see if ID tables exist.
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoIDTablesExistL()
+    {
+    // Get db table names list
+    CDbTableNames* table_names = iDb.TableNamesL();
+    TInt count = table_names->Count();
+    delete table_names;
+    // 1 is for the lock table!
+    return ( count > 1 );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesLockTableExistL
+// Checks to see if lock table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesLockTableExistL()
+    {
+    // Get db table names list
+    CDbTableNames* table_names = iDb.TableNamesL();
+    TInt count = table_names->Count();
+
+    for ( TInt counter = 0 ; counter < count ; counter++ )
+        {
+        if ( (*table_names)[counter] == _L( "writelocktable" ) )
+            {
+            delete table_names;
+            return ETrue;
+            }
+        }
+
+    delete table_names;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesModelBankTableExistL
+// Checks to see if model bank table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesModelBankTableExistL()
+    {
+    // Get db table names list
+    CDbTableNames* table_names = iDb.TableNamesL();
+    TInt count = table_names->Count();
+
+    for ( TInt counter = 0 ; counter < count ; counter++ )
+        {
+        if ( (*table_names)[counter] == _L( "siModelBankIdTable" ) )
+            {
+            delete table_names;
+            return ETrue;
+            }
+        }
+
+    delete table_names;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesLexiconTableExistL
+// Checks if lexicon table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesLexiconTableExistL()
+    {
+    // Get db table names list
+    CDbTableNames* table_names = iDb.TableNamesL();
+    TInt count = table_names->Count();
+
+    for ( TInt counter = 0 ; counter < count ; counter++ )
+        {
+        if ( (*table_names)[counter] == _L( "siLexiconIdTable" ) )
+            {
+            delete table_names;
+            return ETrue;
+            }
+        }
+
+    delete table_names;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DoesGrammarTableExistL
+// Checks if grammar table exists
+// -----------------------------------------------------------------------------
+//
+TBool CSIDatabase::DoesGrammarTableExistL()
+    {
+    // Get db table names list
+    CDbTableNames* table_names = iDb.TableNamesL();
+    TInt count = table_names->Count();
+
+    for ( TInt counter = 0 ; counter < count ; counter++ )
+        {
+        if ( (*table_names)[counter] == _L( "siGrammarIdTable" ) )
+            {
+            delete table_names;
+            return ETrue;
+            }
+        }
+
+    delete table_names;
+    return EFalse;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::SIDatabase
+// Returns a reference to the database.
+// -----------------------------------------------------------------------------
+//
+RDbNamedDatabase& CSIDatabase::SIDatabase()
+    {
+    return iDb;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CreateDatabaseL
+// Creates a database file if one does not exist yet.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CreateDatabaseL()
+    {
+    RUBY_DEBUG_BLOCKL( "CSIDatabase::CreateDatabaseL" );
+    
+    // Get the drive of the database file
+    iDatabaseDrive = EDriveC;
+    if ( iDatabaseFileName.Locate( 'c' ) == 0 || iDatabaseFileName.Locate( 'C' ) == 0 )
+        {
+        iDatabaseDrive = EDriveC;
+        }
+    else if ( iDatabaseFileName.Locate( 'd' ) == 0 || iDatabaseFileName.Locate( 'D' ) == 0 )
+        {
+        iDatabaseDrive = EDriveD;
+        }
+    else if ( iDatabaseFileName.Locate( 'z' ) == 0 || iDatabaseFileName.Locate( 'Z' ) == 0 )
+        {
+        iDatabaseDrive = EDriveZ;
+        }
+    
+    else if ( iDatabaseFileName.Locate( 'e' ) == 0 || iDatabaseFileName.Locate( 'E' ) == 0 )
+        {
+        iDatabaseDrive = EDriveE;
+        }
+    else
+        {
+        User::Leave( KErrPathNotFound );
+        }
+    
+    RDbNamedDatabase database;
+    TInt ret = database.Create( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString );
+    if ( ret == KErrAlreadyExists )
+        {
+        // Ignore KErrAlreadyExists, we will use the existing one if it is there
+        ret = KErrNone;
+        }
+    database.Close();
+    User::LeaveIfError( ret );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::OpenDatabaseL
+// Opens the database.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::OpenDatabaseL()
+    {
+    if ( !iDatabaseOpen )
+        {
+        
+        User::LeaveIfError( iDb.Open( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString ) );
+        
+        // Try to recover the database, if it is damaged
+        if( iDb.IsDamaged() )
+            {
+            RUBY_DEBUG0( "CSIDatabase::OpenDatabaseL - Db is damaged. Attempt to recover." );
+            
+            User::LeaveIfError( iDb.Recover() );
+            }
+        
+        iDatabaseOpen = ETrue;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIDatabase::CloseDatabase
+// Closes the database.
+// -----------------------------------------------------------------------------
+//
+TInt CSIDatabase::CloseDatabase()
+    {
+    RUBY_DEBUG0( "CSIDatabase::CloseDatabase" ); 
+  
+    iDb.Close();
+    iDatabaseOpen = EFalse;
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DbSession
+// Return reference to DB session.
+// -----------------------------------------------------------------------------
+//
+RDbs& CSIDatabase::DbSession()
+    {
+    return iDbSession;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::DbDrive
+// Returns a drive for DB file.
+// -----------------------------------------------------------------------------
+//
+TInt CSIDatabase::DbDrive()
+    {
+    return iDatabaseDrive;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::CreateLockTableL
+// Creates a dummy table to gain write-lock at the beginning of each transaction.
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::CreateLockTableL()
+    {
+    // Create writelocktable
+    // This table is accessed every time when transaction starts to gain
+    // exclusive locking of the DB
+    _LIT( KWriteLockTable, "writelocktable" );
+    
+    _LIT( KCol1, "temporary" );
+    
+    OpenDatabaseL();
+    
+    // Create the rrd tables definition (columnset).
+    CDbColSet* columns = CDbColSet::NewLC();
+    
+    // The tag id 
+    TDbCol dbCol1( KCol1, EDbColUint32 );
+    columns->AddL( dbCol1 );
+    
+    User::LeaveIfError( iDb.CreateTable( KWriteLockTable, *columns ) );
+    
+    // Cleanup columns
+    CleanupStack::PopAndDestroy( columns ); 
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIDatabase::LockTransactionsL
+// Permit transactions and release database
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::LockTransactionsL()
+    {
+    // lock transactions
+    RUBY_DEBUG_BLOCK( "CSIDatabase::LockTransactionsL" );
+    
+    iCriticalSection.Wait(); // wait until a possible transaction ends
+            
+    // release a database
+    CloseDatabase();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIDatabase::UnlockTransactionsL
+// Allow transactions and reserve database
+// -----------------------------------------------------------------------------
+//
+void CSIDatabase::UnlockTransactionsL()
+    {
+    // unlock transactions
+    RUBY_DEBUG_BLOCK( "CSIDatabase::UnlockTransactionsL" );
+    OpenDatabaseL(); // open database
+    
+    if ( iCriticalSection.IsBlocked() )
+        {        
+        iCriticalSection.Signal(); // allow to do transactions
+        }
+    }
+
+//  End of File