|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // DBMS server: data source management and sharing classes |
|
15 // |
|
16 // |
|
17 |
|
18 #include "SD_STD.H" |
|
19 |
|
20 extern const TDbDriver KBuiltinDriver; |
|
21 |
|
22 // Class CDbsObserver::HObserver |
|
23 |
|
24 // The server side of a RDbNotifier object |
|
25 // All "observers" on the same database are held in a list on the |
|
26 // primary CDbsObserver, which tracks the single notifier object |
|
27 // on the data source. |
|
28 |
|
29 inline CDbsObserver::HObserver::HObserver() |
|
30 :iPending(0) |
|
31 {} |
|
32 |
|
33 // |
|
34 // Complete the outstanding request, and reset the observer status |
|
35 // |
|
36 void CDbsObserver::HObserver::Complete(TInt aStatus) |
|
37 { |
|
38 iPending=0; |
|
39 iMessage.Complete(aStatus); |
|
40 } |
|
41 |
|
42 // |
|
43 // Notification request from the client |
|
44 // Int0() has the notification type (CDbNotifier::TType) |
|
45 // |
|
46 void CDbsObserver::HObserver::Notify(const RMessage2& aMessage) |
|
47 { |
|
48 __ASSERT_ALWAYS(iPending>=0,Panic(EDbsObserverRequestPending)); |
|
49 iMessage=aMessage; |
|
50 if (iPending>RDbNotifier::EUnlock) |
|
51 Complete(iPending); // report any missed event first |
|
52 else if (iLink.iNext==&iLink) |
|
53 Complete(RDbNotifier::EClose); // report a "closed" event |
|
54 else |
|
55 iPending=aMessage.Int0(); // wait for an event |
|
56 } |
|
57 |
|
58 // |
|
59 // Cancel the notification request (if pending) |
|
60 // |
|
61 void CDbsObserver::HObserver::Cancel() |
|
62 { |
|
63 if (iPending<0) |
|
64 Complete(KErrCancel); |
|
65 } |
|
66 |
|
67 // |
|
68 // An event occurs on the database |
|
69 // |
|
70 void CDbsObserver::HObserver::Event(TInt aEvent) |
|
71 { |
|
72 if (aEvent==RDbNotifier::EClose) |
|
73 { // detach the observer when closed |
|
74 iLink.Deque(); |
|
75 iLink.iPrev=iLink.iNext=&iLink; |
|
76 } |
|
77 TInt pending=iPending; |
|
78 if (pending<0) |
|
79 { // request is pending |
|
80 if (aEvent==RDbNotifier::EUnlock && pending==CDbNotifier::EChange) |
|
81 ; // don't report unlock events to "change" requests |
|
82 else |
|
83 Complete(aEvent); |
|
84 } |
|
85 else if (aEvent>pending) |
|
86 iPending=aEvent; // store more significant event |
|
87 } |
|
88 |
|
89 // |
|
90 // Client notifer is closed |
|
91 // |
|
92 CDbsObserver::HObserver::~HObserver() |
|
93 { |
|
94 Cancel(); |
|
95 iLink.Deque(); |
|
96 } |
|
97 |
|
98 // Class CDbsObserver |
|
99 |
|
100 // The central server-side observer active object for the database notifiers |
|
101 // This maintains a list of all notifiers, and propogates events from the |
|
102 // database source. |
|
103 |
|
104 inline CDbsObserver::CDbsObserver(CDbsSource& aSource) |
|
105 :CActive(10),iSource(aSource),iQueue(_FOFF(HObserver,iLink)) |
|
106 {} |
|
107 |
|
108 CDbsObserver* CDbsObserver::NewL(CDbsSource& aSource) |
|
109 { |
|
110 CDbsObserver* self=new(ELeave) CDbsObserver(aSource); |
|
111 CleanupStack::PushL(self); |
|
112 self->iNotifier=aSource.Source().NotifierL(); |
|
113 CActiveScheduler::Add(self); |
|
114 CleanupStack::Pop(); // self |
|
115 return self; |
|
116 } |
|
117 |
|
118 // |
|
119 // Used by the source to destroy the observer only when all client |
|
120 // notifiers have been closed |
|
121 // |
|
122 CDbsObserver* CDbsObserver::Collect(CDbsObserver* aObserver) |
|
123 { |
|
124 if (!aObserver) |
|
125 return aObserver; |
|
126 if (!aObserver->iQueue.IsEmpty()) |
|
127 return aObserver; |
|
128 delete aObserver; |
|
129 return 0; |
|
130 } |
|
131 |
|
132 CDbsObserver::~CDbsObserver() |
|
133 { |
|
134 __ASSERT(iQueue.IsEmpty()); |
|
135 CDbObject::Destroy(iNotifier); // will cancel any request |
|
136 Cancel(); |
|
137 } |
|
138 |
|
139 // |
|
140 // Create and initialise a new client-observer object |
|
141 // |
|
142 CDbsObserver::HObserver* CDbsObserver::ObserverL() |
|
143 { |
|
144 HObserver* observer=new(ELeave) HObserver; |
|
145 iQueue.AddLast(*observer); |
|
146 if (!IsActive()) |
|
147 Queue(); // start receiving events |
|
148 return observer; |
|
149 } |
|
150 |
|
151 // |
|
152 // Request an event from the database |
|
153 // |
|
154 void CDbsObserver::Queue() |
|
155 { |
|
156 SetActive(); |
|
157 iNotifier->Notify(CDbNotifier::EUnlock,iStatus); |
|
158 } |
|
159 |
|
160 // |
|
161 // Dispatch the event to all observers and re-queue |
|
162 // |
|
163 void CDbsObserver::RunL() |
|
164 { |
|
165 TDblQueIter<HObserver> iter(iQueue); |
|
166 for (HObserver* ob;(ob=iter++)!=0;) |
|
167 ob->Event(iStatus.Int()); |
|
168 if (!iQueue.IsEmpty()) |
|
169 Queue(); |
|
170 else if (iStatus.Int()==RDbNotifier::EClose) |
|
171 iSource.Closed(); // disconnect and destroy on a close event |
|
172 } |
|
173 |
|
174 // |
|
175 // Provided fo CActive: should never have to do anything as called only |
|
176 // via the d'tor which destroys the notifier first, completing the message |
|
177 // |
|
178 void CDbsObserver::DoCancel() |
|
179 { |
|
180 __ASSERT(iStatus!=KRequestPending); |
|
181 } |
|
182 |
|
183 // Class CDbsDatabaseStub |
|
184 |
|
185 // This class is used as a stub object between the two phases of |
|
186 // authentication on a secure database |
|
187 |
|
188 CDbsDatabaseStub* CDbsDatabaseStub::NewL() |
|
189 { |
|
190 return new(ELeave) CDbsDatabaseStub; |
|
191 } |
|
192 |
|
193 // |
|
194 // Authenticate the access, on success destroy this object and return the |
|
195 // real database interface object |
|
196 // |
|
197 CDbDatabase* CDbsDatabaseStub::AuthenticateL() |
|
198 { |
|
199 CDbSource& src=CDbsConnection::Source(*this).Source(); |
|
200 CDbDatabase* db=src.AuthenticateL(); |
|
201 Attach(db); |
|
202 Destroy(this); |
|
203 return db; |
|
204 } |
|
205 |
|
206 // Class CDbsConnection |
|
207 |
|
208 // The context for all interface objects residing in the server, which |
|
209 // owns a reference on the data source. |
|
210 |
|
211 CDbsConnection::~CDbsConnection() |
|
212 { |
|
213 if (iSource) |
|
214 iSource->Close(); |
|
215 } |
|
216 |
|
217 |
|
218 // Class CDbsSource |
|
219 |
|
220 // The sharing point for databases in the server, this maintains access |
|
221 // to the CDbSource interface object, allowing multiple connections to the |
|
222 // same database. |
|
223 |
|
224 // |
|
225 // Something has closed. Check if we are still needed, and delete if not |
|
226 // |
|
227 void CDbsSource::Closed() |
|
228 { |
|
229 __ASSERT(iConnections==0); |
|
230 iObserver=CDbsObserver::Collect(iObserver); |
|
231 if (!iObserver) |
|
232 delete this; |
|
233 } |
|
234 |
|
235 // |
|
236 // A connection has been removed |
|
237 // |
|
238 void CDbsSource::Close() |
|
239 { |
|
240 __ASSERT(iConnections>0); |
|
241 __ASSERT(iSource); |
|
242 if (--iConnections==0) |
|
243 { // last connection is closed |
|
244 CDbSource* s=iSource; |
|
245 iSource=0; |
|
246 CDbObject::Destroy(s); |
|
247 iLink.Deque(); // cannot connect this source again |
|
248 Closed(); |
|
249 } |
|
250 } |
|
251 |
|
252 CDbsSource::~CDbsSource() |
|
253 { |
|
254 __ASSERT(!iSource); |
|
255 __ASSERT(!iObserver); |
|
256 delete iName; |
|
257 } |
|
258 |
|
259 // |
|
260 // Construct a new source object from a database using the driver discovery |
|
261 // |
|
262 CDbsSource* CDbsSource::NewL(RFs& aFs,const TDesC& aSource) |
|
263 { |
|
264 //The following two statements are here to check the file path and raise (if have to) |
|
265 //the same errors as they were raised before by the previous (DbDriver related) source code. |
|
266 ::TEntry fileEntry; |
|
267 __LEAVE_IF_ERROR(aFs.Entry(aSource, fileEntry)); |
|
268 |
|
269 const TDbFormat& fmt=KBuiltinDriver.iFormats[0]; |
|
270 |
|
271 CDbsSource* self=new(ELeave) CDbsSource(fmt); |
|
272 CleanupStack::PushL(self); |
|
273 self->iName=aSource.AllocL(); |
|
274 self->iSource=fmt.OpenL(aFs,aSource,TDbFormat::EReadWrite); |
|
275 CleanupStack::Pop(); // self |
|
276 return self; |
|
277 } |
|
278 |
|
279 // |
|
280 // [Create and] return the active observer of the data source |
|
281 // |
|
282 CDbsObserver::HObserver* CDbsSource::ObserverL() |
|
283 { |
|
284 __ASSERT(iSource); |
|
285 CDbsObserver* observer=iObserver; |
|
286 if (!observer) |
|
287 iObserver=observer=CDbsObserver::NewL(*this); |
|
288 return observer->ObserverL(); |
|
289 } |
|
290 |
|
291 // |
|
292 // Test to find an identical source, in order to share it |
|
293 // |
|
294 TBool CDbsSource::Is(const TDesC& aSource) const |
|
295 { |
|
296 if (iName->CompareF(aSource)!=0) |
|
297 return EFalse; |
|
298 |
|
299 return ETrue; |
|
300 } |
|
301 |
|
302 |
|
303 // Class RDbsSources |
|
304 |
|
305 // The collection of all shared sources in the server |
|
306 |
|
307 // |
|
308 // Open a source for sharing |
|
309 // |
|
310 CDbsConnection* RDbsSources::OpenLC(RFs& aFs,const TDesC& aSource,const TDesC& /*aFormat*/) |
|
311 { |
|
312 CDbsConnection* connect=new(ELeave) CDbsConnection; |
|
313 CleanupStack::PushL(connect); |
|
314 |
|
315 // try and find the source already open |
|
316 TIter iter(iSources); |
|
317 CDbsSource* src; |
|
318 for (;;) |
|
319 { |
|
320 src=iter++; |
|
321 if (src==0) |
|
322 { // not already open, have to open a new source |
|
323 src=CDbsSource::NewL(aFs,aSource); |
|
324 iSources.AddFirst(*src); |
|
325 break; |
|
326 } |
|
327 if (src->Is(aSource)) |
|
328 break; // share this source |
|
329 } |
|
330 // we have a source |
|
331 connect->Set(*src); |
|
332 return connect; |
|
333 } |
|
334 |