# examples/Base/SemaphoreExample/src/CDatabase.cpp

    00001 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
    00002 // All rights reserved.
    00003 // This component and the accompanying materials are made available
    00004 // under the terms of "Eclipse Public License v1.0"
    00005 // which accompanies this distribution, and is available
    00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
    00007 //
    00008 // Initial Contributors:
    00009 // Nokia Corporation - initial contribution.
    00010 //
    00011 // Contributors:
    00012 //
    00013 // Description:
    00014 // This class contains methods to create a database of integers and periodically read /write integers
    00015 // from/ to the database. The macro USE_SEMAPHORE is used at various places to show thread synchronization
    00016 // using a semaphore.
    00017
    00018 #include "CDatabase.h"
    00019
    00020 //Declare a delay of 1000000 microseconds i.e. 1 sec for the periodic functions.
    00021 const int KDelay = 1000000;
    00022
    00023 //The last number in the database.
    00024 const int KLastNum = 50;
    00025
    00029 CDatabase* CDatabase::NewL()
    00030     {
    00031     CDatabase* self=new(ELeave)CDatabase();
    00032     CleanupStack::PushL(self);
    00033     self->ConstructL();
    00034     CleanupStack::Pop(self);
    00035     return self;
    00036     }
    00037
    00041 CDatabase::~CDatabase()
    00042     {
    00043     iFsSession.Close();  //close the file server session.
    00044     delete iPeriodic;    //delete the periodic object.
    00045     delete iConsole;     //delete the console.
    00046     #ifdef USE_SEMAPHORE
    00047     iSemWrite.Close();
    00048     #endif
    00049     }
    00050
    00054 void CDatabase::ConstructL()
    00055     {
    00056     iPeriodic = CPeriodic::NewL(CActive::EPriorityUserInput);
    00057
    00058     _LIT(KDbCreateDb,"exampleDatabase.db");
    00059
    00060     iFsSession.Connect();
    00061
    00062     //The database exampleDatabase.db is created as a permanent file store
    00063     //in the app's private directory.
    00064     User::LeaveIfError(iFsSession.CreatePrivatePath(RFs::GetSystemDrive()));
    00065
    00066     User::LeaveIfError(iFsSession.PrivatePath(iDbname));
    00067     iDbname.Append(KDbCreateDb);
    00068
    00069     #ifdef USE_SEMAPHORE
    00070     //Open the global semaphore which was created in CSemaphoreExample.
    00071     _LIT(KSemaphoreWrite, "WriteSemaphore");
    00072     User::LeaveIfError(iSemWrite.OpenGlobal(KSemaphoreWrite, EOwnerProcess));
    00073     #endif
    00074     }
    00075
    00079 void CDatabase::CreateDatabaseL()
    00080     {
    00081     //Construct a file store object - the file to contain the
    00082     //database replaces any existing file of the same name.
    00083     CFileStore* store = CPermanentFileStore::ReplaceLC(iFsSession, iDbname, EFileRead|EFileWrite);
    00084     //Complete file store creation.
    00085     store->SetTypeL(store->Layout());
    00086
    00087     //Create a database in the store.
    00088     TStreamId id= iDatabase.CreateL(store);
    00089
    00090     //Keep database id as root of store.
    00091     store->SetRootL(id);
    00092
    00093     //Complete database creation by commiting the store.
    00094     store->CommitL();
    00095
    00096
    00097     //Create a table definition.
    00098     CDbColSet* columns=CDbColSet::NewLC();
    00099
    00100     //Add three columns each containing Int32 values.
    00101     _LIT(KCol1, "Number1");
    00102     _LIT(KCol2, "Number2");
    00103     _LIT(KCol3, "Number3");
    00104     columns->AddL(TDbCol(KCol1,EDbColInt32));
    00105     columns->AddL(TDbCol(KCol2,EDbColInt32));
    00106     columns->AddL(TDbCol(KCol3,EDbColInt32));
    00107
    00108
    00109     //Create the table, table name is "Numbers" and add the columns to it.
    00110     _LIT(KTable, "Numbers");
    00111     User::LeaveIfError(iDatabase.CreateTable(KTable,*columns));
    00112
    00113     CDbKey* key=CDbKey::NewLC();
    00114
    00115     //Add the key columns.
    00116     TDbKeyCol number1(KCol1);
    00117     key->AddL(number1);
    00118     TDbKeyCol number2(KCol2);
    00119     key->AddL(number2);
    00120     TDbKeyCol number3(KCol3);
    00121     key->AddL(number3);
    00122     User::LeaveIfError(iDatabase.CreateIndex(KTable,KTable,*key));
    00123
    00124     iDatabase.Close();
    00125     //Cleanup the column set.
    00126     CleanupStack::PopAndDestroy(key);
    00127     CleanupStack::PopAndDestroy(columns);
    00128     CleanupStack::PopAndDestroy(store);
    00129     }
    00130
    00135 void CDatabase::WritetoDatabaseL()
    00136     {
    00137     iPeriodic->Start(0, KDelay, TCallBack(PeriodicWriteL, this));
    00138     CActiveScheduler::Start();
    00139     }
    00140
    00145 TInt CDatabase::PeriodicWriteL(TAny* aPtr)
    00146     {
    00147     CDatabase* ptr = static_cast<CDatabase*> (aPtr);
    00148     //Invoke the RThread::Resume() function on the consumer thread repeatedly.
    00149     ptr->PeriodicWriteFuncL();
    00150     return KErrNone;
    00151     }
    00152
    00157 void CDatabase::PeriodicWriteFuncL()
    00158     {
    00159     //Declare an integer which is used to fill numbers in the database.
    00160     static int num = 0 ;
    00161
    00162      //Open the file store.
    00163     _LIT(KSQLStatement,"select Number1, Number2, Number3 from Numbers order by Number1,Number2,Number3");
    00164     CFileStore* store = CFileStore::OpenLC(iFsSession,iDbname,EFileRead|EFileWrite);
    00165
    00166
    00167     //Open the database from the root stream.
    00168     iDatabase.OpenL(store,store->Root());
    00169
    00170     //Lock the database before use.
    00171     iDatabase.Begin();
    00172
    00173     //Create a view on the database view to read/write numbers into it.
    00174     RDbView view;
    00175     User::LeaveIfError(view.Prepare(iDatabase,TDbQuery(KSQLStatement,EDbCompareNormal)));
    00176     User::LeaveIfError(view.EvaluateAll());
    00177
    00178
    00179     //Insert a new row at the end of the database.
    00180     view.InsertL();
    00181
    00182     //Fill three coloumns with numbers.
    00183     view.SetColL(1, num++);
    00184     view.SetColL(2, num++);
    00185     view.SetColL(3, num++);
    00186     view.PutL();
    00187
    00188     //Close the view.
    00189     view.Close();
    00190
    00191     //Unlock the database after writing.
    00192     iDatabase.Commit();
    00193
    00194     // close the database.
    00195     iDatabase.Close();
    00196
    00197     //Do not commit store: database has taken control of commit.
    00198     CleanupStack::PopAndDestroy(store);
    00199
    00200     //Cancel the periodic function once 50 numbers have been written to the database.
    00201     if(num > KLastNum )
    00202         {
    00203         iPeriodic->Cancel();
    00204         CActiveScheduler::Stop();
    00205         }
    00206
    00207     #ifdef USE_SEMAPHORE
    00208     /*Signal the semaphore and the PeriodicReadFunc() which was
    00209       waiting on the semaphore is scheduled to run.
    00210       */
    00211     iSemWrite.Signal();
    00212     #endif
    00213     }
    00214
    00220 void CDatabase::ReadfromDatabaseL()
    00221     {
    00222     _LIT(KTextConsoleTitle, "ReaderThread");
    00223     if(!iConsole)
    00224         {
    00225          iConsole = Console::NewL(KTextConsoleTitle, TSize(KConsFullScreen,KConsFullScreen));
    00226          _LIT(KReading, "Reading the database.\n");
    00227          iConsole->Printf(KReading);
    00228         }
    00229     iPeriodic->Start(0, KDelay, TCallBack(PeriodicReadL,this));
    00230     CActiveScheduler::Start();
    00231     }
    00232
    00237 TInt CDatabase::PeriodicReadL(TAny* aPtr)
    00238     {
    00239     CDatabase* ptr = static_cast<CDatabase*> (aPtr);
    00240     ptr->PeriodicReadFuncL();
    00241     return KErrNone;
    00242     }
    00243
    00248 void CDatabase::PeriodicReadFuncL()
    00249     {
    00250     #ifdef USE_SEMAPHORE
    00251     //Semaphore waits till it gets a signal from the PeriodicWrite() function.
    00252     iSemWrite.Wait();
    00253     #endif
    00254
    00255     CFileStore* store = CFileStore::OpenLC(iFsSession,iDbname,EFileRead);
    00256
    00257     //Open the database from the root stream.
    00258     iDatabase.OpenL(store,store->Root());
    00259
    00260     //Lock the database.
    00261     iDatabase.Begin();
    00262
    00263     //Prepare an SQL query to read three numbers from the database.
    00264     _LIT(KSQLStatement,"select Number1,Number2,Number3  from Numbers order by Number1,Number2, Number3");
    00265
    00266     //Create a view on the database.
    00267     RDbView view;
    00268     User::LeaveIfError(view.Prepare(iDatabase,TDbQuery(KSQLStatement,EDbCompareNormal)));
    00269     User::LeaveIfError(view.EvaluateAll());
    00270
    00271     //Declare integers to iterate through the database rows.
    00272     static int count = 0;
    00273     TInt iter = 0;
    00274
    00275     /*Iterate through the database to read only the row which was most recently
    00276       written by the PeriodicWriteFunc.
    00277       */
    00278     view.FirstL();
    00279     while( iter < count)
    00280         {
    00281         view.NextL();
    00282         iter++;
    00283         }
    00284     count ++ ;
    00285
    00286     //Read the integers from the view and display in console.
    00287     view.GetL();
    00288     TInt number1 = view.ColInt(1);
    00289     TInt number2 = view.ColInt(2);
    00290     TInt number3 = view.ColInt(3);
    00291     //Prepare a row formatter to print the numbers to the console.
    00292     _LIT(KRowFormatter, "\n reading  %d \t%d\t%d");
    00293
    00294     iConsole->Printf(KRowFormatter,number1,number2, number3);
    00295
    00296     //Cancel the periodic function after it has read the last number in the database.
    00297     if(number3 >= KLastNum)
    00298         {
    00299         iPeriodic->Cancel();
    00300         CActiveScheduler::Stop();
    00301         _LIT(KAllRead, "\nAll the numbers in the database have been read\n");
    00302         iConsole->Printf(KAllRead);
    00303         _LIT(KExit, "Press a key to exit\n");
    00304         iConsole->Printf(KExit);
    00305         iConsole->Getch();
    00306         }
    00307     //Close the view.
    00308     view.Close();
    00309
    00310     //Unlock the database.
    00311     iDatabase.Commit();
    00312
    00313     iDatabase.Close();
    00314     CleanupStack::PopAndDestroy(store);
    00315     }