persistentstorage/dbms/sdbms/SD_SRC.CPP
changeset 0 08ec8eefde2f
--- /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;
+	}
+