1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/dbms/sdbms/SD_SRC.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,334 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// DBMS server: data source management and sharing classes
1.18 +//
1.19 +//
1.20 +
1.21 +#include "SD_STD.H"
1.22 +
1.23 +extern const TDbDriver KBuiltinDriver;
1.24 +
1.25 +// Class CDbsObserver::HObserver
1.26 +
1.27 +// The server side of a RDbNotifier object
1.28 +// All "observers" on the same database are held in a list on the
1.29 +// primary CDbsObserver, which tracks the single notifier object
1.30 +// on the data source.
1.31 +
1.32 +inline CDbsObserver::HObserver::HObserver()
1.33 + :iPending(0)
1.34 + {}
1.35 +
1.36 +//
1.37 +// Complete the outstanding request, and reset the observer status
1.38 +//
1.39 +void CDbsObserver::HObserver::Complete(TInt aStatus)
1.40 + {
1.41 + iPending=0;
1.42 + iMessage.Complete(aStatus);
1.43 + }
1.44 +
1.45 +//
1.46 +// Notification request from the client
1.47 +// Int0() has the notification type (CDbNotifier::TType)
1.48 +//
1.49 +void CDbsObserver::HObserver::Notify(const RMessage2& aMessage)
1.50 + {
1.51 + __ASSERT_ALWAYS(iPending>=0,Panic(EDbsObserverRequestPending));
1.52 + iMessage=aMessage;
1.53 + if (iPending>RDbNotifier::EUnlock)
1.54 + Complete(iPending); // report any missed event first
1.55 + else if (iLink.iNext==&iLink)
1.56 + Complete(RDbNotifier::EClose); // report a "closed" event
1.57 + else
1.58 + iPending=aMessage.Int0(); // wait for an event
1.59 + }
1.60 +
1.61 +//
1.62 +// Cancel the notification request (if pending)
1.63 +//
1.64 +void CDbsObserver::HObserver::Cancel()
1.65 + {
1.66 + if (iPending<0)
1.67 + Complete(KErrCancel);
1.68 + }
1.69 +
1.70 +//
1.71 +// An event occurs on the database
1.72 +//
1.73 +void CDbsObserver::HObserver::Event(TInt aEvent)
1.74 + {
1.75 + if (aEvent==RDbNotifier::EClose)
1.76 + { // detach the observer when closed
1.77 + iLink.Deque();
1.78 + iLink.iPrev=iLink.iNext=&iLink;
1.79 + }
1.80 + TInt pending=iPending;
1.81 + if (pending<0)
1.82 + { // request is pending
1.83 + if (aEvent==RDbNotifier::EUnlock && pending==CDbNotifier::EChange)
1.84 + ; // don't report unlock events to "change" requests
1.85 + else
1.86 + Complete(aEvent);
1.87 + }
1.88 + else if (aEvent>pending)
1.89 + iPending=aEvent; // store more significant event
1.90 + }
1.91 +
1.92 +//
1.93 +// Client notifer is closed
1.94 +//
1.95 +CDbsObserver::HObserver::~HObserver()
1.96 + {
1.97 + Cancel();
1.98 + iLink.Deque();
1.99 + }
1.100 +
1.101 +// Class CDbsObserver
1.102 +
1.103 +// The central server-side observer active object for the database notifiers
1.104 +// This maintains a list of all notifiers, and propogates events from the
1.105 +// database source.
1.106 +
1.107 +inline CDbsObserver::CDbsObserver(CDbsSource& aSource)
1.108 + :CActive(10),iSource(aSource),iQueue(_FOFF(HObserver,iLink))
1.109 + {}
1.110 +
1.111 +CDbsObserver* CDbsObserver::NewL(CDbsSource& aSource)
1.112 + {
1.113 + CDbsObserver* self=new(ELeave) CDbsObserver(aSource);
1.114 + CleanupStack::PushL(self);
1.115 + self->iNotifier=aSource.Source().NotifierL();
1.116 + CActiveScheduler::Add(self);
1.117 + CleanupStack::Pop(); // self
1.118 + return self;
1.119 + }
1.120 +
1.121 +//
1.122 +// Used by the source to destroy the observer only when all client
1.123 +// notifiers have been closed
1.124 +//
1.125 +CDbsObserver* CDbsObserver::Collect(CDbsObserver* aObserver)
1.126 + {
1.127 + if (!aObserver)
1.128 + return aObserver;
1.129 + if (!aObserver->iQueue.IsEmpty())
1.130 + return aObserver;
1.131 + delete aObserver;
1.132 + return 0;
1.133 + }
1.134 +
1.135 +CDbsObserver::~CDbsObserver()
1.136 + {
1.137 + __ASSERT(iQueue.IsEmpty());
1.138 + CDbObject::Destroy(iNotifier); // will cancel any request
1.139 + Cancel();
1.140 + }
1.141 +
1.142 +//
1.143 +// Create and initialise a new client-observer object
1.144 +//
1.145 +CDbsObserver::HObserver* CDbsObserver::ObserverL()
1.146 + {
1.147 + HObserver* observer=new(ELeave) HObserver;
1.148 + iQueue.AddLast(*observer);
1.149 + if (!IsActive())
1.150 + Queue(); // start receiving events
1.151 + return observer;
1.152 + }
1.153 +
1.154 +//
1.155 +// Request an event from the database
1.156 +//
1.157 +void CDbsObserver::Queue()
1.158 + {
1.159 + SetActive();
1.160 + iNotifier->Notify(CDbNotifier::EUnlock,iStatus);
1.161 + }
1.162 +
1.163 +//
1.164 +// Dispatch the event to all observers and re-queue
1.165 +//
1.166 +void CDbsObserver::RunL()
1.167 + {
1.168 + TDblQueIter<HObserver> iter(iQueue);
1.169 + for (HObserver* ob;(ob=iter++)!=0;)
1.170 + ob->Event(iStatus.Int());
1.171 + if (!iQueue.IsEmpty())
1.172 + Queue();
1.173 + else if (iStatus.Int()==RDbNotifier::EClose)
1.174 + iSource.Closed(); // disconnect and destroy on a close event
1.175 + }
1.176 +
1.177 +//
1.178 +// Provided fo CActive: should never have to do anything as called only
1.179 +// via the d'tor which destroys the notifier first, completing the message
1.180 +//
1.181 +void CDbsObserver::DoCancel()
1.182 + {
1.183 + __ASSERT(iStatus!=KRequestPending);
1.184 + }
1.185 +
1.186 +// Class CDbsDatabaseStub
1.187 +
1.188 +// This class is used as a stub object between the two phases of
1.189 +// authentication on a secure database
1.190 +
1.191 +CDbsDatabaseStub* CDbsDatabaseStub::NewL()
1.192 + {
1.193 + return new(ELeave) CDbsDatabaseStub;
1.194 + }
1.195 +
1.196 +//
1.197 +// Authenticate the access, on success destroy this object and return the
1.198 +// real database interface object
1.199 +//
1.200 +CDbDatabase* CDbsDatabaseStub::AuthenticateL()
1.201 + {
1.202 + CDbSource& src=CDbsConnection::Source(*this).Source();
1.203 + CDbDatabase* db=src.AuthenticateL();
1.204 + Attach(db);
1.205 + Destroy(this);
1.206 + return db;
1.207 + }
1.208 +
1.209 +// Class CDbsConnection
1.210 +
1.211 +// The context for all interface objects residing in the server, which
1.212 +// owns a reference on the data source.
1.213 +
1.214 +CDbsConnection::~CDbsConnection()
1.215 + {
1.216 + if (iSource)
1.217 + iSource->Close();
1.218 + }
1.219 +
1.220 +
1.221 +// Class CDbsSource
1.222 +
1.223 +// The sharing point for databases in the server, this maintains access
1.224 +// to the CDbSource interface object, allowing multiple connections to the
1.225 +// same database.
1.226 +
1.227 +//
1.228 +// Something has closed. Check if we are still needed, and delete if not
1.229 +//
1.230 +void CDbsSource::Closed()
1.231 + {
1.232 + __ASSERT(iConnections==0);
1.233 + iObserver=CDbsObserver::Collect(iObserver);
1.234 + if (!iObserver)
1.235 + delete this;
1.236 + }
1.237 +
1.238 +//
1.239 +// A connection has been removed
1.240 +//
1.241 +void CDbsSource::Close()
1.242 + {
1.243 + __ASSERT(iConnections>0);
1.244 + __ASSERT(iSource);
1.245 + if (--iConnections==0)
1.246 + { // last connection is closed
1.247 + CDbSource* s=iSource;
1.248 + iSource=0;
1.249 + CDbObject::Destroy(s);
1.250 + iLink.Deque(); // cannot connect this source again
1.251 + Closed();
1.252 + }
1.253 + }
1.254 +
1.255 +CDbsSource::~CDbsSource()
1.256 + {
1.257 + __ASSERT(!iSource);
1.258 + __ASSERT(!iObserver);
1.259 + delete iName;
1.260 + }
1.261 +
1.262 +//
1.263 +// Construct a new source object from a database using the driver discovery
1.264 +//
1.265 +CDbsSource* CDbsSource::NewL(RFs& aFs,const TDesC& aSource)
1.266 + {
1.267 + //The following two statements are here to check the file path and raise (if have to)
1.268 + //the same errors as they were raised before by the previous (DbDriver related) source code.
1.269 + ::TEntry fileEntry;
1.270 + __LEAVE_IF_ERROR(aFs.Entry(aSource, fileEntry));
1.271 +
1.272 + const TDbFormat& fmt=KBuiltinDriver.iFormats[0];
1.273 +
1.274 + CDbsSource* self=new(ELeave) CDbsSource(fmt);
1.275 + CleanupStack::PushL(self);
1.276 + self->iName=aSource.AllocL();
1.277 + self->iSource=fmt.OpenL(aFs,aSource,TDbFormat::EReadWrite);
1.278 + CleanupStack::Pop(); // self
1.279 + return self;
1.280 + }
1.281 +
1.282 +//
1.283 +// [Create and] return the active observer of the data source
1.284 +//
1.285 +CDbsObserver::HObserver* CDbsSource::ObserverL()
1.286 + {
1.287 + __ASSERT(iSource);
1.288 + CDbsObserver* observer=iObserver;
1.289 + if (!observer)
1.290 + iObserver=observer=CDbsObserver::NewL(*this);
1.291 + return observer->ObserverL();
1.292 + }
1.293 +
1.294 +//
1.295 +// Test to find an identical source, in order to share it
1.296 +//
1.297 +TBool CDbsSource::Is(const TDesC& aSource) const
1.298 + {
1.299 + if (iName->CompareF(aSource)!=0)
1.300 + return EFalse;
1.301 +
1.302 + return ETrue;
1.303 + }
1.304 +
1.305 +
1.306 +// Class RDbsSources
1.307 +
1.308 +// The collection of all shared sources in the server
1.309 +
1.310 +//
1.311 +// Open a source for sharing
1.312 +//
1.313 +CDbsConnection* RDbsSources::OpenLC(RFs& aFs,const TDesC& aSource,const TDesC& /*aFormat*/)
1.314 + {
1.315 + CDbsConnection* connect=new(ELeave) CDbsConnection;
1.316 + CleanupStack::PushL(connect);
1.317 +
1.318 + // try and find the source already open
1.319 + TIter iter(iSources);
1.320 + CDbsSource* src;
1.321 + for (;;)
1.322 + {
1.323 + src=iter++;
1.324 + if (src==0)
1.325 + { // not already open, have to open a new source
1.326 + src=CDbsSource::NewL(aFs,aSource);
1.327 + iSources.AddFirst(*src);
1.328 + break;
1.329 + }
1.330 + if (src->Is(aSource))
1.331 + break; // share this source
1.332 + }
1.333 + // we have a source
1.334 + connect->Set(*src);
1.335 + return connect;
1.336 + }
1.337 +