--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/sdbms/SD_SRC.CPP Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,334 @@
+// Copyright (c) 1998-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:
+// DBMS server: data source management and sharing classes
+//
+//
+
+#include "SD_STD.H"
+
+extern const TDbDriver KBuiltinDriver;
+
+// Class CDbsObserver::HObserver
+
+// The server side of a RDbNotifier object
+// All "observers" on the same database are held in a list on the
+// primary CDbsObserver, which tracks the single notifier object
+// on the data source.
+
+inline CDbsObserver::HObserver::HObserver()
+ :iPending(0)
+ {}
+
+//
+// Complete the outstanding request, and reset the observer status
+//
+void CDbsObserver::HObserver::Complete(TInt aStatus)
+ {
+ iPending=0;
+ iMessage.Complete(aStatus);
+ }
+
+//
+// Notification request from the client
+// Int0() has the notification type (CDbNotifier::TType)
+//
+void CDbsObserver::HObserver::Notify(const RMessage2& aMessage)
+ {
+ __ASSERT_ALWAYS(iPending>=0,Panic(EDbsObserverRequestPending));
+ iMessage=aMessage;
+ if (iPending>RDbNotifier::EUnlock)
+ Complete(iPending); // report any missed event first
+ else if (iLink.iNext==&iLink)
+ Complete(RDbNotifier::EClose); // report a "closed" event
+ else
+ iPending=aMessage.Int0(); // wait for an event
+ }
+
+//
+// Cancel the notification request (if pending)
+//
+void CDbsObserver::HObserver::Cancel()
+ {
+ if (iPending<0)
+ Complete(KErrCancel);
+ }
+
+//
+// An event occurs on the database
+//
+void CDbsObserver::HObserver::Event(TInt aEvent)
+ {
+ if (aEvent==RDbNotifier::EClose)
+ { // detach the observer when closed
+ iLink.Deque();
+ iLink.iPrev=iLink.iNext=&iLink;
+ }
+ TInt pending=iPending;
+ if (pending<0)
+ { // request is pending
+ if (aEvent==RDbNotifier::EUnlock && pending==CDbNotifier::EChange)
+ ; // don't report unlock events to "change" requests
+ else
+ Complete(aEvent);
+ }
+ else if (aEvent>pending)
+ iPending=aEvent; // store more significant event
+ }
+
+//
+// Client notifer is closed
+//
+CDbsObserver::HObserver::~HObserver()
+ {
+ Cancel();
+ iLink.Deque();
+ }
+
+// Class CDbsObserver
+
+// The central server-side observer active object for the database notifiers
+// This maintains a list of all notifiers, and propogates events from the
+// database source.
+
+inline CDbsObserver::CDbsObserver(CDbsSource& aSource)
+ :CActive(10),iSource(aSource),iQueue(_FOFF(HObserver,iLink))
+ {}
+
+CDbsObserver* CDbsObserver::NewL(CDbsSource& aSource)
+ {
+ CDbsObserver* self=new(ELeave) CDbsObserver(aSource);
+ CleanupStack::PushL(self);
+ self->iNotifier=aSource.Source().NotifierL();
+ CActiveScheduler::Add(self);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+//
+// Used by the source to destroy the observer only when all client
+// notifiers have been closed
+//
+CDbsObserver* CDbsObserver::Collect(CDbsObserver* aObserver)
+ {
+ if (!aObserver)
+ return aObserver;
+ if (!aObserver->iQueue.IsEmpty())
+ return aObserver;
+ delete aObserver;
+ return 0;
+ }
+
+CDbsObserver::~CDbsObserver()
+ {
+ __ASSERT(iQueue.IsEmpty());
+ CDbObject::Destroy(iNotifier); // will cancel any request
+ Cancel();
+ }
+
+//
+// Create and initialise a new client-observer object
+//
+CDbsObserver::HObserver* CDbsObserver::ObserverL()
+ {
+ HObserver* observer=new(ELeave) HObserver;
+ iQueue.AddLast(*observer);
+ if (!IsActive())
+ Queue(); // start receiving events
+ return observer;
+ }
+
+//
+// Request an event from the database
+//
+void CDbsObserver::Queue()
+ {
+ SetActive();
+ iNotifier->Notify(CDbNotifier::EUnlock,iStatus);
+ }
+
+//
+// Dispatch the event to all observers and re-queue
+//
+void CDbsObserver::RunL()
+ {
+ TDblQueIter<HObserver> iter(iQueue);
+ for (HObserver* ob;(ob=iter++)!=0;)
+ ob->Event(iStatus.Int());
+ if (!iQueue.IsEmpty())
+ Queue();
+ else if (iStatus.Int()==RDbNotifier::EClose)
+ iSource.Closed(); // disconnect and destroy on a close event
+ }
+
+//
+// Provided fo CActive: should never have to do anything as called only
+// via the d'tor which destroys the notifier first, completing the message
+//
+void CDbsObserver::DoCancel()
+ {
+ __ASSERT(iStatus!=KRequestPending);
+ }
+
+// Class CDbsDatabaseStub
+
+// This class is used as a stub object between the two phases of
+// authentication on a secure database
+
+CDbsDatabaseStub* CDbsDatabaseStub::NewL()
+ {
+ return new(ELeave) CDbsDatabaseStub;
+ }
+
+//
+// Authenticate the access, on success destroy this object and return the
+// real database interface object
+//
+CDbDatabase* CDbsDatabaseStub::AuthenticateL()
+ {
+ CDbSource& src=CDbsConnection::Source(*this).Source();
+ CDbDatabase* db=src.AuthenticateL();
+ Attach(db);
+ Destroy(this);
+ return db;
+ }
+
+// Class CDbsConnection
+
+// The context for all interface objects residing in the server, which
+// owns a reference on the data source.
+
+CDbsConnection::~CDbsConnection()
+ {
+ if (iSource)
+ iSource->Close();
+ }
+
+
+// Class CDbsSource
+
+// The sharing point for databases in the server, this maintains access
+// to the CDbSource interface object, allowing multiple connections to the
+// same database.
+
+//
+// Something has closed. Check if we are still needed, and delete if not
+//
+void CDbsSource::Closed()
+ {
+ __ASSERT(iConnections==0);
+ iObserver=CDbsObserver::Collect(iObserver);
+ if (!iObserver)
+ delete this;
+ }
+
+//
+// A connection has been removed
+//
+void CDbsSource::Close()
+ {
+ __ASSERT(iConnections>0);
+ __ASSERT(iSource);
+ if (--iConnections==0)
+ { // last connection is closed
+ CDbSource* s=iSource;
+ iSource=0;
+ CDbObject::Destroy(s);
+ iLink.Deque(); // cannot connect this source again
+ Closed();
+ }
+ }
+
+CDbsSource::~CDbsSource()
+ {
+ __ASSERT(!iSource);
+ __ASSERT(!iObserver);
+ delete iName;
+ }
+
+//
+// Construct a new source object from a database using the driver discovery
+//
+CDbsSource* CDbsSource::NewL(RFs& aFs,const TDesC& aSource)
+ {
+ //The following two statements are here to check the file path and raise (if have to)
+ //the same errors as they were raised before by the previous (DbDriver related) source code.
+ ::TEntry fileEntry;
+ __LEAVE_IF_ERROR(aFs.Entry(aSource, fileEntry));
+
+ const TDbFormat& fmt=KBuiltinDriver.iFormats[0];
+
+ CDbsSource* self=new(ELeave) CDbsSource(fmt);
+ CleanupStack::PushL(self);
+ self->iName=aSource.AllocL();
+ self->iSource=fmt.OpenL(aFs,aSource,TDbFormat::EReadWrite);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+//
+// [Create and] return the active observer of the data source
+//
+CDbsObserver::HObserver* CDbsSource::ObserverL()
+ {
+ __ASSERT(iSource);
+ CDbsObserver* observer=iObserver;
+ if (!observer)
+ iObserver=observer=CDbsObserver::NewL(*this);
+ return observer->ObserverL();
+ }
+
+//
+// Test to find an identical source, in order to share it
+//
+TBool CDbsSource::Is(const TDesC& aSource) const
+ {
+ if (iName->CompareF(aSource)!=0)
+ return EFalse;
+
+ return ETrue;
+ }
+
+
+// Class RDbsSources
+
+// The collection of all shared sources in the server
+
+//
+// Open a source for sharing
+//
+CDbsConnection* RDbsSources::OpenLC(RFs& aFs,const TDesC& aSource,const TDesC& /*aFormat*/)
+ {
+ CDbsConnection* connect=new(ELeave) CDbsConnection;
+ CleanupStack::PushL(connect);
+
+ // try and find the source already open
+ TIter iter(iSources);
+ CDbsSource* src;
+ for (;;)
+ {
+ src=iter++;
+ if (src==0)
+ { // not already open, have to open a new source
+ src=CDbsSource::NewL(aFs,aSource);
+ iSources.AddFirst(*src);
+ break;
+ }
+ if (src->Is(aSource))
+ break; // share this source
+ }
+ // we have a source
+ connect->Set(*src);
+ return connect;
+ }
+