persistentstorage/centralrepository/cenrepnotifierhandler/src/cenrepnotifyhandler.cpp
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/centralrepository/cenrepnotifierhandler/src/cenrepnotifyhandler.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,481 @@
+// Copyright (c) 2004-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:
+// INCLUDE FILES
+//
+
+
+
+#include <e32std.h>
+#include <e32svr.h>
+#include <centralrepository.h>
+#include "cenrepnotifyhandler.h"
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+/**
+* Constructor used for single key listening.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession Reference to an existing repository session.
+* @param aKeyType  Type of the key identified by aId parameter.
+* @param aId       Id of the key that change notifications are needed for.
+* @capability      None
+*/
+CCenRepNotifyHandler::CCenRepNotifyHandler(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession, 
+    TCenRepKeyType aKeyType, 
+    TUint32 aId)
+    : CActive(EPriorityStandard), iSession(aSession), 
+    iCallback(aCallback), iKeyType(aKeyType), iId(aId), iWholeRepository(EFalse)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+/**
+* Constructor used for whole repository listening.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession Reference to an existing repository session.
+* @capability None
+*/
+CCenRepNotifyHandler::CCenRepNotifyHandler(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession)
+    : CActive(EPriorityStandard), iSession(aSession), iCallback(aCallback), 
+    iKeyType(EIntKey), iId(0), iWholeRepository(ETrue)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+/**
+* This is a two-phase constructor method that is used to
+* create a new instance for listening to the changes in a single key.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession  Reference to an existing repository session.
+*                  Do not close this session until all CCenRepNotifyHandler
+*                  instances referring to it have been deleted.
+* @param aKeyType  Type of the key identified by aId parameter. 
+* @param aId       Id of the key that change notifications are needed for.
+* @return          A pointer to a new instance of the CCenRepNotifyHandler class.
+* 
+* @leave           KErrArgument if invalid key type is passed as a parameter.
+* @capability      None
+*/
+EXPORT_C CCenRepNotifyHandler* CCenRepNotifyHandler::NewL(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession, 
+    TCenRepKeyType aKeyType, 
+    TUint32 aId)
+    {
+    CCenRepNotifyHandler* newInstance = NewLC(aCallback, aSession, aKeyType, aId);
+    CleanupStack::Pop();
+    return newInstance;
+    }
+
+/**
+* This is a two-phase constructor method that is used to create a new
+* instance for listening to the changes in all keys in the repository. 
+*
+* Type specific callback methods of MCenRepNotifyHandlerCallback will not
+* be used when notifying about changes in this case,
+* only HandleNotifyGeneric() is used.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession  Reference to an existing repository session.
+*                  Do not close this session until all CCenRepNotifyHandler
+*                  instances referring to it have been deleted.
+* @return          A pointer to a new instance of the CCenRepNotifyHandler class.
+* @capability      None
+*/
+EXPORT_C CCenRepNotifyHandler* CCenRepNotifyHandler::NewL(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession)
+    {
+    CCenRepNotifyHandler* newInstance = NewLC(aCallback, aSession);
+    CleanupStack::Pop();
+    return newInstance;
+    }
+
+/**
+* This is a two-phase constructor method that is used to create a new
+* instance for listening to the changes in a single key.
+* Leaves the constructed instance to cleanup stack.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession  Reference to an existing repository session.
+*                  Do not close this session until all CCenRepNotifyHandler
+*                  instances referring to it have been deleted.
+* @param aKeyType  Type of the key identified by aId parameter.
+* @param aId       Id of the key that change notifications are needed for.
+* @return          A pointer to a new instance of the CCenRepNotifyHandler class.
+* 
+* @leave           KErrArgument if invalid key type is passed as a parameter.
+* @capability      None
+*/
+EXPORT_C CCenRepNotifyHandler* CCenRepNotifyHandler::NewLC(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession, 
+    TCenRepKeyType aKeyType, 
+    TUint32 aId)
+    {
+    if ( aKeyType != EIntKey && 
+         aKeyType != ERealKey && 
+         aKeyType != EStringKey  && 
+         aKeyType != EBinaryKey ) 
+        { 
+        User::Leave( KErrArgument ); 
+        } 
+
+    CCenRepNotifyHandler* newInstance = new (ELeave) CCenRepNotifyHandler( aCallback, aSession, 
+                                                                           aKeyType, aId);
+    CleanupStack::PushL( newInstance );
+    return newInstance;
+    }
+
+/**
+* This is a two-phase constructor method that is used to create a new
+* instance for listening to the changes in all keys in the repository.
+* Leaves the constructed instance to cleanup stack. 
+*
+* Type specific callback methods of MCenRepNotifyHandlerCallback will
+* not be used when notifying about changes in this case,
+* only HandleNotifyGeneric() is used.
+*
+* @param aCallback Reference to a callback instance.
+* @param aSession  Reference to an existing repository session.
+*                  Do not close this session until all CCenRepNotifyHandler
+*                  instances referring to it have been deleted.
+* @return          A pointer to a new instance of the CCenRepNotifyHandler class.
+* @capability      None
+*/
+EXPORT_C CCenRepNotifyHandler* CCenRepNotifyHandler::NewLC(
+    MCenRepNotifyHandlerCallback& aCallback, 
+    CRepository& aSession)
+    {
+    CCenRepNotifyHandler* newInstance = new (ELeave) CCenRepNotifyHandler(aCallback, aSession);
+    CleanupStack::PushL( newInstance );
+
+    return newInstance;
+    }
+
+// Destructor
+EXPORT_C CCenRepNotifyHandler::~CCenRepNotifyHandler()
+    {
+    Cancel();
+    }
+
+/**
+* When this method is called, the CCenRepNotifyHandler starts
+* listening for notifications. If it is already listening, nothing happens.
+*
+* For single setting handler when there is already an existing notification
+* on the same setting and session,the HandleNotifyError will be trigerred with
+* KErrAlreadyExists error
+* @leave KErrNotFound if setting does not exist
+* 		 KErrPermissionDenied if client does not have the necessary capability
+* plus other system-wide error codes.
+* For whole settings handler, the HandleNotifyError will be trigerred with the 
+* error code
+* @capability Dependent Capability required depends on platform security of keyspace.
+*/
+EXPORT_C void CCenRepNotifyHandler::StartListeningL()
+    {
+    if(IsActive())
+        {
+        return;
+        }
+    User::LeaveIfError(OrderNotification());
+
+    SetActive();
+    }
+
+/**
+* When this method is called, the CCenRepNotifyHandler stops
+* listening for notifications. If it is already stopped, nothing happens.
+* @capability      None
+*/
+EXPORT_C void CCenRepNotifyHandler::StopListening()
+    {
+    if(IsActive())
+        {
+        Cancel();
+        }
+    }
+
+/**
+* Implements CActive
+*/    
+void CCenRepNotifyHandler::RunL()
+    {
+    // Check that notification was for correct ID or it was caused by
+    // a repository wide reset (KInvalidNotificationId).
+    TUint32 status = static_cast<TUint32>(iStatus.Int());
+    if( !iWholeRepository && status != iId && 
+        status != NCentralRepositoryConstants::KInvalidNotificationId )
+        {
+#ifdef _DEBUG
+        RDebug::Print(_L("CCenRepNotifyHandler::RunL(): Received notif about unknown key: %d"), 
+        status);
+        RDebug::Print(_L("CCenRepNotifyHandler::RunL(): Notification not renewed."));
+#endif
+        // We are not listening to key notified for us. Do not reorder notification 
+        // as there is clearly some problems in central repository.
+        iCallback.HandleNotifyError(status, KErrArgument, this);
+        return;
+        }
+
+    if (iWholeRepository && iStatus.Int() == KErrPermissionDenied)
+    	{
+
+        RArray<TUint32> allKeyList;
+        //check every single settings that we have read permission
+        TRAPD(err,iSession.FindL(0x00000000,0x00000000,allKeyList));
+        if (err==KErrNone)
+        	{
+        	TInt arrayCount=allKeyList.Count();
+        	for (TInt i=0;i<arrayCount;i++)
+        		{
+        		TUint32 dummyMeta;
+        		err=iSession.GetMeta(allKeyList[i],dummyMeta);
+        		//potential error at this stage likely to include only
+        		//KErrPermissionDenied plus other resource allocation
+        		//error such as KErrNoMemory
+        		if (err!=KErrNone)
+        			{
+        			TInt errorkey=allKeyList[i];
+        			allKeyList.Close();
+        			iCallback.HandleNotifyError(errorkey, err, this);
+					return;
+        			}
+                }
+        	}
+        else
+            {
+            iCallback.HandleNotifyError( NCentralRepositoryConstants::KUnspecifiedKey , err, this );
+            return;
+            }
+    	}
+
+    // Reorder notification
+    TInt err = OrderNotification();
+    
+    // Handle notification
+    if ( err == KErrNone )
+        {
+        SetActive();
+        if ( iWholeRepository )
+            {
+            iCallback.HandleNotifyGeneric(status);
+            }
+        else
+            {
+            switch (iKeyType)
+                {
+                case EIntKey:
+                    {
+                    TInt newValue;
+                    err=iSession.Get(iId, newValue);
+                    if (err==KErrNone)
+                    	{
+                    	iCallback.HandleNotifyInt(iId, newValue);
+                    	}
+                    }
+                    break;
+                case ERealKey:            
+                    {
+                    TReal newValue;
+                    err=iSession.Get(iId, newValue);
+                    if (err==KErrNone)
+                    	{
+                    	iCallback.HandleNotifyReal(iId, newValue);
+                    	}
+                    }
+                    break;
+                case EStringKey:
+                    {
+                    TBuf16<NCentralRepositoryConstants::KMaxUnicodeStringLength> newValue;
+                    err=iSession.Get(iId, newValue);
+                    if (err==KErrNone)
+                    	{
+                    	iCallback.HandleNotifyString(iId, newValue);
+                    	}
+                    }
+                    break;
+                case EBinaryKey:
+                    {
+                    TBuf8<NCentralRepositoryConstants::KMaxBinaryLength> newValue;
+                    err=iSession.Get(iId, newValue);
+                    if (err==KErrNone)
+                    	{
+                    	iCallback.HandleNotifyBinary(iId, newValue);
+                    	}
+                    }
+                    break;
+                default:
+                    break;
+                }
+            if (err!=KErrNone)
+            	{           	
+            	iCallback.HandleNotifyError(iId,err,this);
+            	}
+            }
+        }
+    else
+        {
+        iCallback.HandleNotifyError(status, err, this);
+        }
+    }
+    
+/**
+* Implements CActive
+* @param aError the error returned
+* @return error
+*/
+TInt CCenRepNotifyHandler::RunError(TInt aError)
+    {
+    if ( iWholeRepository )
+        {
+        iCallback.HandleNotifyError(NCentralRepositoryConstants::KInvalidNotificationId, 
+                                    aError, this);    
+        }
+    else
+        {
+        iCallback.HandleNotifyError(iId, aError, this);    
+        }
+    
+    return KErrNone;
+    }
+
+/**
+* Implements CActive
+*/    
+void CCenRepNotifyHandler::DoCancel()
+    {
+    if ( iWholeRepository )
+        {
+        iSession.NotifyCancelAll();
+        }
+    else
+        {
+        iSession.NotifyCancel(iId);
+        }
+    }
+
+/* 
+* Order notification
+* @return error code from CenRep
+*/
+TInt CCenRepNotifyHandler::OrderNotification()
+    {
+    if ( iWholeRepository )
+        {
+        // order notification for all keys in repository
+        return iSession.NotifyRequest(0x00000000, 0x00000000, iStatus);
+        }
+    else
+        {
+        return iSession.NotifyRequest(iId, iStatus);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// MCenRepNotifyHandlerCallback::HandleNotifyXXX
+// Default implementations for callback interface. 
+// In debug build these methods print trace. 
+// In release build they do nothing.
+//
+// These methods are documented in cenrepnotifierhandler.h. Don't redocument
+// here.
+// -----------------------------------------------------------------------------
+// 
+#ifdef _DEBUG
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyInt(TUint32 aId, TInt aNewValue)
+    {
+    RDebug::Print(_L("MCenRepNotifyHandlerCallback: Integer key %d changed, new value: %d"), 
+    aId, aNewValue);
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyReal(TUint32 aId, TReal aNewValue)
+    {
+    RDebug::Print(_L("MCenRepNotifyHandlerCallback: Real key %d changed, new value: %e"), 
+    aId, aNewValue);
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyString(TUint32 aId, 
+                                                               const TDesC16&  aNewValue)
+    {
+    RDebug::Print(_L("MCenRepNotifyHandlerCallback: String key %d changed, new value: %S"), 
+    aId, &aNewValue);
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyBinary(TUint32 aId, 
+                                                               const TDesC8&  aNewValue)
+    {
+    RDebug::Print(_L("MCenRepNotifyHandlerCallback: Binary key %d changed, new value: %s"), 
+    aId, aNewValue.Ptr());
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyGeneric(TUint32 aId)
+    {
+    if ( aId == NCentralRepositoryConstants::KInvalidNotificationId )
+        {
+        RDebug::Print(_L("MCenRepNotifyHandlerCallback: "));
+        RDebug::Print(_L("Repository wide reset caused generic notification"));
+        }
+    else
+        {
+        RDebug::Print(_L("MCenRepNotifyHandlerCallback: Generic key %d changed"), aId);
+        }
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyError(TUint32 aId, TInt aError, 
+                                                              CCenRepNotifyHandler* aHandler)
+    {
+    RDebug::Print(_L("MCenRepNotifyHandlerCallback %d notifies error for id: %d, error: %d"), 
+    aHandler, aId, aError);
+    }
+
+#else
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyInt(TUint32 /*aId*/, TInt /*aNewValue*/)
+    {
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyReal(TUint32 /*aId*/, TReal /*aNewValue*/)
+    {
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyString(TUint32 /*aId*/, 
+    const TDesC16&  /*aNewValue*/)
+    {
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyBinary(TUint32 /*aId*/, 
+    const TDesC8&  /*aNewValue*/)
+    {
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyGeneric(TUint32 /*aId*/)
+    {
+    }
+
+EXPORT_C void MCenRepNotifyHandlerCallback::HandleNotifyError(TUint32 /*aId*/, TInt /*aError*/, 
+    CCenRepNotifyHandler* /*aHandler*/)
+    {
+    }
+#endif // _DEBUG
+
+// End of File