summaryrefslogtreecommitdiffstats
path: root/plugins/contacts/symbian/contactsmodel/cntsrv/inc/ccntstatemachine.h
blob: 1e02a96f412fd6e6a338f4a8358c7b3b8fb432d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/*
* Copyright (c) 2006-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: 
*
*/




/**
 @file
 @internalComponent
 @released
*/


#ifndef __CCNTSTATEMACHINE_H__
#define __CCNTSTATEMACHINE_H__

#include "cactiveloop.h" // for mactiveloopcallback.
#include <cntdef.h>  	 // for tcontactitemid.
#include "ccntrequest.h"

namespace nsState 
	{			  
	const TInt KLastStep    = 0;
	const TInt KNoSessionId = 0;
	
	enum TStates
		{
		EStateClosed 	    = 0,
		EStateTablesClosed,
		EStateWritable,
		EStateOpening,
		EStateTransaction,
		EStateBackupRestore
		};
	}


// Forward class references.	
class CCntStateMachine;
class CTransactionTimer;
class CCntRequest;
class CPersistenceLayer;
class CCntDbManager;
class MLplContactsFile;


/**
This class is the base class for each State object held in the State Machine.
*/
class CState : public CBase, public MContactDbObserverV2
	{
public:
	~CState();

	virtual TAccept AcceptRequestL(CReqAsyncOpen*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqUpdateCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCommitCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqReadCnt*			 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqOpenCnt*			 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDeleteCnt*		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCloseCnt* 		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCreateCnt*		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCancelAsyncOpen*  aRequest); //visitor pattern
  	virtual TAccept AcceptRequestL(CReqCloseTables*  	 aRequest); //visitor pattern	
	virtual TAccept AcceptRequestL(CReqReOpen*  	  	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbBeginTrans*     aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbCommitTrans*    aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbRollbackTrans*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqBackupRestoreBegin* aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqBackupRestoreEnd* aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDiskSpaceLow*     aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDiskSpaceNormal*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqAsyncActivity*	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqNoAsyncActivity*	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetSpeedDial* 	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetOwnCard* 	 	 aRequest); //visitor pattern 
	virtual TAccept AcceptRequestL(CReqInternalSessionUnlock* aRequest); //visitor pattern
	
	// Implementation of the MContactDbObserver interface
	void HandleDatabaseEventV2L(TContactDbObserverEventV2 aEvent);

protected:
	CState(CCntStateMachine& aStateMachine, CPersistenceLayer&	iPersistenceLayer);

	void TransactionStartLC(TUint aSessionId);
	void TransactionCommitLP();
	virtual void RollbackTransAndRecoverL(const TBool aNotification);

	TAccept DeferRequest(CCntRequest* aRequest);
	TAccept DeferWithTimeOutError(CCntRequest* aRequest);

	// derived state classes use different error codes and implement a derived TimeOutErrorCode()
	virtual TInt TimeOutErrorCode();
	
private:
	static void CleanupTransactionRollback(TAny* aState);
	
protected:
	CCntStateMachine&	iStateMachine;
	CPersistenceLayer&	iPersistenceLayer;
	TUint iCurrentTransactionSessionId;
	};


class CStateClosed : public CState
	{
public:
	static CStateClosed* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	~CStateClosed();

	virtual TAccept AcceptRequestL(CReqAsyncOpen* 		aRequest);
	virtual TAccept AcceptRequestL(CReqReOpen*    		aRequest);

	// Overridden read-only operations from base class: can't read from the
	// database while in the Closed state so defer these requests.
	virtual TAccept AcceptRequestL(CReqReadCnt*			aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqOpenCnt*			aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDeleteCnt*		aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqUpdateCnt*    	aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCommitCnt*    	aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCreateCnt*		aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCloseTables*  	aRequest); //visitor pattern	
	virtual TAccept AcceptRequestL(CReqDbBeginTrans*     aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbCommitTrans*    aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbRollbackTrans*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetSpeedDial* 	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetOwnCard* 	 	 aRequest); //visitor pattern 
		
	// Overridden Backup/Restore operations from base class.
	virtual TAccept AcceptRequestL(CReqBackupRestoreBegin* aRequest); //visitor pattern
	
protected:
	CStateClosed(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);	
	}; 
		


/**
CStateTablesClosed is a special case of the CStateClosed.  It allows requests
that don't use the tables, such as compression.
*/

class CStateTablesClosed : public CStateClosed	
  	{
public:
  	static CStateTablesClosed* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
  	~CStateTablesClosed();
  	
	// Do not allow AsyncOpen requests - return deferred. 
  	// The CStateClosed parent class processes CReqAsyncOpen requests.
  	virtual TAccept AcceptRequestL(CReqAsyncOpen* 		 aRequest); //visitor pattern  	
  	virtual TAccept AcceptRequestL(CReqReOpen*    	 	 aRequest); //visitor pattern
  	
private:
 	CStateTablesClosed(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);	
  	};	


class CStateBackupRestore : public CStateClosed
	{
public:
	static CStateBackupRestore* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	~CStateBackupRestore();

	// Do not allow AsyncOpen requests
	virtual TAccept AcceptRequestL(CReqAsyncOpen* 		 aRequest); //visitor pattern

	virtual TAccept AcceptRequestL(CReqBackupRestoreBegin* aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqBackupRestoreEnd* aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqNoAsyncActivity*	 aRequest); //visitor pattern
		
	// Does not use the CStateClosed Timeout error code
	virtual TInt TimeOutErrorCode();

private:
	CStateBackupRestore(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	};


/**
The CStateOpening state is where the opening and possibly recovery and upgrade
of the Contacts database takes place.
*/
class CStateOpening : public CState, public MActiveLoopCallBack 
	{
public:
	static CStateOpening* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	~CStateOpening();

	virtual TAccept AcceptRequestL(CReqAsyncOpen*   	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCancelAsyncOpen*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqReOpen*      	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqBackupRestoreEnd* aRequest); //visitor pattern

	// Overridden read-only operations from base class: can't read from the
	// database while in the Opening state so defer these requests.
	virtual TAccept AcceptRequestL(CReqReadCnt*			 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqOpenCnt*			 aRequest); //visitor pattern
	
	TBool DoStepL();
	void  DoError(TInt aError);

private:
	CStateOpening(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	void 	SetFileNameL (const TDes& aFileName);
	void 	ConstructL  ();
	void 	InitialStep();
	TAccept OpenDatabaseFileL(CCntRequest* aRequest, TBool aNoftify = EFalse);
	void 	DoCompletion(TInt aError);
private:	
	CActiveLoop* 				iActive;
	MLplContactsFile*	 		iCntFile;
	HBufC* 						iFileName;
	RPointerArray<CCntRequest>  iOpenReqsStore;
	// When opening the database a notification event is propogated for some requests
	// however, the Persistence layer knows nothing of requests, so this flag is set for
	// those requests that require notification to be propagated to the client.
	TBool 						iNotify;  
	}; 


/**
The CStateWritable state is the "normal" state for a Contacts database.  In this
state CRUD operations can be carried out.
*/
class CStateWritable : public CState
	{
public:
	static CStateWritable* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	~CStateWritable();

	// Locking methods.
	virtual TAccept AcceptRequestL(CReqUpdateCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCommitCnt*     	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDeleteCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCreateCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCancelAsyncOpen*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbBeginTrans* 	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqBackupRestoreBegin* aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetSpeedDial* 	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqSetOwnCard* 	 	 aRequest); //visitor pattern
    virtual TAccept AcceptRequestL(CReqCloseTables* aRequest); //visitor pattern	
	
	virtual TInt TimeOutErrorCode();
	
private:
	CStateWritable(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	}; 


/**
The CStateTransaction state prevents all other sessions performing changes to
the Contacts database.

This state contains a CTransactionTimer which is reset after all requests are
processed when the CStateTransaction is the current active state.  If the
CTransactionTimer timer object times out, the session is deemed to have died
since it has not been in touch, and the transaction is rolled back.
*/
class CStateTransaction : public CState
	{
public:
	static CStateTransaction* NewL(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	~CStateTransaction();

	// Overloaded Visitor Pattern methods
	virtual TAccept AcceptRequestL(CReqDbBeginTrans*     aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbCommitTrans*    aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDbRollbackTrans*  aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCreateCnt* 		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqReadCnt* 		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqUpdateCnt* 		 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqDeleteCnt* 	  	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCommitCnt*    	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqOpenCnt*		 	 aRequest); //visitor pattern
	virtual TAccept AcceptRequestL(CReqCloseCnt* 		 aRequest); //visitor pattern

	virtual void CancelTransactionL();

	void HandleDatabaseEventV2L(TContactDbObserverEventV2 aEvent);
private:
	CStateTransaction(CCntStateMachine& aStateMachine, CPersistenceLayer& aPersistenceLayer);
	void ConstructL();
	void StrayRequestL(CCntRequest* aRequest);
	void PropagateDatabaseEventsL();
	TBool CheckInternalCompressL();

protected:
	virtual TInt TimeOutErrorCode();	
	
private:
	// Only one session is allowed to perform a transaction
	TUint 				iSessionId; 
	CTransactionTimer*  iTimeOut;
	// Holds all events until the a commit transaction has been called
	RArray<TContactDbObserverEventV2> iEventQ;
	};


class CTransactionTimer : public CTimer
	{
public:
	static CTransactionTimer* NewL(CStateTransaction& aTransState);
	~CTransactionTimer();
	void Start();
	void Stop ();
	void Reset();

private:
	CTransactionTimer(CStateTransaction& aTransState);
	void RunL();
	void ConstructL();

private:
	CStateTransaction& iTransState;
	};


/**
The transaction lock is NOT directly related to the CStateTransaction state.
The CTransactionLock holds all the IDs of locked contact items - locked by a
session for updating.  No other session can perform a write operation on a
locked contact item.  There is one instance of the transaction lock owned by the
CStateMachine class.
*/ 
class CTransactionLock : public CBase
	{
public:
	static CTransactionLock* NewL(CCntStateMachine& aStateMachine);
	inline ~CTransactionLock(){ iLockedIds.Close();}
	
	TInt  LockLX (const TUint aSessionId, const TContactItemId aCntId);
	TInt  UnLockL (const TUint aSessionId, const TContactItemId aCntId);
	
	// Used with TCleanupItem when a method leaves & cleanup stack pop by the client
	void UnlockLastLockedContactL(TUint aSessionId = nsState::KNoSessionId);
	static void CleanupUnlockRecord(TAny* aTransLock);
		
	// Used for the session close - removes all contact items that remain locked by the session
	void  UnLockAllL(const TUint aSessionId);
	TBool IsLocked  (const TUint aSessionId, const TContactItemId aCntId) const;

	// Overridden IsLocked is used by CStateWritable::AcceptRequestL()
	// which ignore the session id when checking for locked contact ids - original implementation
	TBool IsLocked(const TContactItemId aCntId) const;

	TBool AnyLocked() const;

private:
	inline CTransactionLock(CCntStateMachine& aStateMachine) : iStateMachine(aStateMachine){};
	void ProcessLockedContactsL();

private:
	struct TLockData
		{
		TContactItemId	iCntItemId;
		const TUint 	iSessionId;
		TLockData (TContactItemId aCntId, const TUint aSessionId);
		};
		
	// The iLockIds array works like a stack. On the client side, the lock
	// can be popped via the CleanUpStack, this generates an IPC close request
	// which pops the last LockID 
	RArray<TLockData> iLockedIds;
	CCntStateMachine& iStateMachine;
	};



/**
The CCntStateMachine class contains all states, sets the current state and is
the point of entry for processing requests.  It does none of the request
processing, this is done within the state objects.

It also contains all generic helper objects used by more than one state such as
the request store where all deferred requests (requests that can not be 
processed) by the current active state are queued until the state changed.

Another helper object is the transaction lock which holds the IDds of locked
contact item.  No state can  modify a locked contact item.  The states call into
the state machine to ascertain if a contact item has been locked before
modifying it.

The CCntStateMachine class also implements the MContactDbObserver interface
which propagates events back to the client session.  All events originating in
the Persistence Layer are routed through the State Machine. The reason for this
is that within the Transaction State, the operations which trigger these events 
are only committed via an explicit commit request and therefore these events
should only be propagated to the sessions after the operations have been
committed to the Contacts database.

Finally, each CCntStateMachine instance is owned by an associated CCntDbManager
instance.  This means one State Machine exists for each open Contacts database
file which is shared among many sessions - hence the need for states.
*/
class CCntStateMachine : public CBase, public MContactDbObserverV2
	{
public:
	static	 CCntStateMachine* NewL(CPersistenceLayer& aPersistenceLayer, CCntDbManager& aDbManager);
	virtual ~CCntStateMachine();

	CState&  CurrentState(); 
	void 	 SetCurrentStateL  (CState& aState);
	
	void 	 ProcessRequestL  (CCntRequest* aRequest); 
	inline TBool DatabaseReady() { return iState == &StateWritable(); };
	
	// Implementation of the MContactDbObserverV2 interface
	void HandleDatabaseEventV2L(TContactDbObserverEventV2 aEvent);
	
	CTransactionLock& TransactionLockL();
		
	CCntDbManager& DbManager();
	CRequestStore& ReqStoreL();

	inline void SetLowDisk(TBool aLowDisk) { iLowDisk = aLowDisk; };
	inline TBool LowDisk() { return iLowDisk; };

	inline void SetAsyncActivity(TBool aAsyncActivity) { iAsyncActivity = aAsyncActivity; };
	inline TBool AsyncActivity() { return iAsyncActivity; };

	inline CStateClosed& 		StateClosed()		{ return static_cast<CStateClosed&> 	  (*iStateArray[nsState::EStateClosed]);};
    inline CStateTablesClosed&  StateTablesClosed() { return static_cast<CStateTablesClosed&> (*iStateArray[nsState::EStateTablesClosed]);};  
	inline CStateWritable&      StateWritable()  	{ return static_cast<CStateWritable&> 	  (*iStateArray[nsState::EStateWritable]);};
	inline CStateOpening& 		StateOpening()		{ return static_cast<CStateOpening&> 	  (*iStateArray[nsState::EStateOpening]);};
	inline CStateTransaction&	StateTransaction()	{ return static_cast<CStateTransaction&>  (*iStateArray[nsState::EStateTransaction]);};
	inline CStateBackupRestore&	StateBackupRestore(){ return static_cast<CStateBackupRestore&>(*iStateArray[nsState::EStateBackupRestore]);};

private:
	CCntStateMachine(CCntDbManager& aDbManager);
	void ConstructL(CPersistenceLayer& aPersistenceLayer);

#ifdef __STATE_MACHINE_DEBUG__
	const TDesC& StateName(CState& aState);
#endif
	
private:
	CState* 				iState;
	RPointerArray <CState>	iStateArray;
	CRequestStore* 			iReqStore;
	CTransactionLock* 		iTransLock;
	CCntDbManager&			iDbManager;
	TBool					iLowDisk;
	TBool					iAsyncActivity;
	};


#endif