metadataengine/server/src/mdsnotifier.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:34:07 +0200
changeset 0 c53acadfccc6
child 1 acef663c1218
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* Copyright (c) 2002-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:  Notifier engine / server side*
*/

#include "mdsnotifier.h"

#include "mdcresult.h"
#include "mdcitem.h"
#include "mdsserversession.h"
#include "mdsnotifycomparator.h"
#include "mdslogger.h"
#include "mdcserializationbuffer.h"
#include "mdccommon.pan"

__USES_LOGGER

// ------------------------------------------------
// NewL
// ------------------------------------------------
//
CMdSNotifier* CMdSNotifier::NewL()
    {
    CMdSNotifier* that = CMdSNotifier::NewLC();
    CleanupStack::Pop( that );
    return that;
    }


// ------------------------------------------------
// NewLC
// ------------------------------------------------
//
CMdSNotifier* CMdSNotifier::NewLC()
    {
    CMdSNotifier* that = new(ELeave) CMdSNotifier();
    CleanupStack::PushL( that );
    that->ConstructL();
    return that;
    }


// ------------------------------------------------
// Constructor
// ------------------------------------------------
//
CMdSNotifier::CMdSNotifier()
    {
    
    }

// ------------------------------------------------
// ConstructL
// ------------------------------------------------
//
void CMdSNotifier::ConstructL()
    {
    iComparator = CMdSNotifyComparator::NewL();
    }

// ------------------------------------------------
// Destructor
// ------------------------------------------------
//
CMdSNotifier::~CMdSNotifier()
    {
    delete iComparator;
    iEntries.Close();
    }

// ------------------------------------------------
// Constructor
// ------------------------------------------------
//
CMdSNotifier::TEntry::TEntry( TInt aId,
    TConditionType aType,
    CMdCSerializationBuffer* aSerializedBuffer,
    TDefId aNamespaceDefId, 
    CMdSServerSession& aSession, 
    TBool aConfidential)
    : iId( aId )
    , iType( aType )
    , iNamespaceDefId(aNamespaceDefId)
    , iSerializedCondition( aSerializedBuffer )
    , iSession( aSession )
    , iConfidential(aConfidential)    
    {
    iDataBuffer = NULL;
    iRemoteSizeMsgSlot = KErrNotFound;
    }

// ------------------------------------------------
// TriggerL completes the client message and sends the data size
// ------------------------------------------------
//
void CMdSNotifier::TEntry::TriggerL(
	TUint32 aCompleteCode,
    const RArray<TItemId>& aIdArray )
    {
    TInt remoteSizeMsgSlot = iRemoteSizeMsgSlot;
    iRemoteSizeMsgSlot = KErrNotFound;

    __ASSERT_DEBUG( !iDataBuffer, MMdCCommon::Panic( KErrCorrupt ) );

    if(aIdArray.Count())
		{
		iDataBuffer = CopyToBufferL( aIdArray );
	    iSession.SizeToRemoteL( iMessage, remoteSizeMsgSlot, iDataBuffer->Size());
		}
	else
		{
	    iSession.SizeToRemoteL( iMessage, remoteSizeMsgSlot, 0);
		}

    __LOG2( ELogServer, "<- Notify trigger %d (%d)", iId, aCompleteCode );
    iMessage.Complete( aCompleteCode );
    }

// ------------------------------------------------
// TriggerRelationItemsL completes the client
//                  message and sends the data size
// ------------------------------------------------
//
void CMdSNotifier::TEntry::TriggerRelationItemsL(
	TUint32 aCompleteCode,
	CMdCSerializationBuffer& aBuffer,
	const RArray<TItemId>& aRelationIdArray)
    {
    TInt remoteSizeMsgSlot = iRemoteSizeMsgSlot;
    iRemoteSizeMsgSlot = KErrNotFound;

    __ASSERT_DEBUG( !iDataBuffer, MMdCCommon::Panic( KErrCorrupt ) );

    if(aRelationIdArray.Count())
		{
		iDataBuffer = CopyItemsToBufferL( aBuffer, aRelationIdArray );
	    iSession.SizeToRemoteL( iMessage, remoteSizeMsgSlot, iDataBuffer->Size());
		}
	else
		{
	    iSession.SizeToRemoteL( iMessage, remoteSizeMsgSlot, 0);
		}

    __LOG2( ELogServer, "<- Notify trigger %d (%d)", iId, aCompleteCode );
    iMessage.Complete( aCompleteCode );
    }

// ------------------------------------------------
// TriggerSchemaL sends a schema notification
// ------------------------------------------------
//
void CMdSNotifier::TEntry::TriggerSchema()
    {
    iRemoteSizeMsgSlot = KErrNotFound;
    iMessage.Complete( ESchemaModify );
    }

// ------------------------------------------------
// TriggerError send a error message to the client
// ------------------------------------------------
//
void CMdSNotifier::TEntry::TriggerError( TInt aErrorCode )
    {
    iRemoteSizeMsgSlot = KErrNotFound;
	delete iDataBuffer;
    iDataBuffer = NULL;
    __LOG2( ELogServer, "<- Notify trigger %d (%d)", iId, aErrorCode );

    if( !iMessage.IsNull() )
    	{
    	iMessage.Complete( aErrorCode );
    	}
    }

// ------------------------------------------------
// CopyToBufferL copies id to buffer
// ------------------------------------------------
//
CMdCSerializationBuffer* CMdSNotifier::TEntry::CopyToBufferL(const RArray<TItemId>& aIdArray)
	{
	// IDs are always stored in object ID, 
	// even if those are actually relation or event IDs

	const TUint32 count = aIdArray.Count();

	CMdCSerializationBuffer* buffer = CMdCSerializationBuffer::NewLC(
			sizeof( TMdCItemIds )
			+ count * CMdCSerializationBuffer::KRequiredSizeForTItemId );

	TMdCItemIds itemIds;
	itemIds.iNamespaceDefId = NamespaceDefId();
	itemIds.iObjectIds.iPtr.iCount = count;
	itemIds.iObjectIds.iPtr.iOffset = sizeof(TMdCItemIds);
	itemIds.SerializeL( *buffer );

	for( TInt i = 0; i < count; ++i )
		{
		buffer->InsertL( aIdArray[i] );
		}

	CleanupStack::Pop( buffer );
	return buffer;	
	}

// ------------------------------------------------
// CopyItemsToBufferL copies relation items to buffer
// ------------------------------------------------
//
CMdCSerializationBuffer* CMdSNotifier::TEntry::CopyItemsToBufferL(
		CMdCSerializationBuffer& aRelationItemsBuffer, 
		const RArray<TItemId>& aIdArray)
	{
	const TUint32 count = aIdArray.Count();
	aRelationItemsBuffer.PositionL( KNoOffset );
	const TMdCItems& items = TMdCItems::GetFromBufferL( aRelationItemsBuffer );

	CMdCSerializationBuffer* buffer = NULL;
	if ( items.iRelations.iPtr.iCount == count )
		{
		buffer = CMdCSerializationBuffer::NewLC( aRelationItemsBuffer );
		}
	else
		{
		buffer = CMdCSerializationBuffer::NewLC( sizeof(TMdCItems)
				+ count * sizeof(TMdCRelation) );

		TMdCItems returnItems;
		returnItems.iNamespaceDefId = items.iNamespaceDefId;
		returnItems.iRelations.iPtr.iCount = count;
		returnItems.iRelations.iPtr.iOffset = sizeof(TMdCItems);
		buffer->PositionL( sizeof(TMdCItems) );

		for( TInt i = 0; i < items.iRelations.iPtr.iCount; ++i )
			{
			TMdCRelation relation;
			relation.DeserializeL( aRelationItemsBuffer );

			if ( aIdArray.Find( relation.iId ) >= 0 )
				{
				relation.SerializeL( *buffer );
				}
			}
		buffer->PositionL( KNoOffset );
		returnItems.SerializeL( *buffer );
		}
	
	CleanupStack::Pop( buffer );
	return buffer;
	}

// ------------------------------------------------
// CacheL caches the notification
// ------------------------------------------------
//
void CMdSNotifier::TEntry::CacheL(TUint32 aCompleteCode, const RArray<TItemId>& aIdArray )
    {
    if ( aIdArray.Count() <= 0 )
    	{
    	return;
    	}

    CMdCSerializationBuffer* data = CopyToBufferL( aIdArray );
    iSession.CacheNotificationL( iId, aCompleteCode, data );
    }

// ------------------------------------------------
// CacheRelationItemsL caches the notification
// ------------------------------------------------
//
void CMdSNotifier::TEntry::CacheRelationItemsL(TUint32 aCompleteCode,
		CMdCSerializationBuffer& aBuffer, 
		const RArray<TItemId>& aRelationIdArray )
    {
    CMdCSerializationBuffer* data = CopyItemsToBufferL( aBuffer, 
    		aRelationIdArray );
    iSession.CacheNotificationL(iId, aCompleteCode, data);
    }

// ------------------------------------------------
// CacheL for schema mods
// ------------------------------------------------
//
void CMdSNotifier::TEntry::CacheL(TUint32 aCompleteCode)
    {
    iSession.CacheNotificationL(iId, aCompleteCode, NULL);
    }
    
// ------------------------------------------------
// TriggerCachedL triggers a previously cached notification
// ------------------------------------------------
//
void CMdSNotifier::TEntry::TriggerCachedL(TUint32 aCompleteCode, 
		CMdCSerializationBuffer* aData)
    {
    TInt remoteSizeMsgSlot = iRemoteSizeMsgSlot;
    iRemoteSizeMsgSlot = KErrNotFound;

    __ASSERT_DEBUG( !iDataBuffer, MMdCCommon::Panic( KErrCorrupt ) );

    if( aData )
    	{
    	iSession.SizeToRemoteL( iMessage, remoteSizeMsgSlot, aData->Size());
    	}

	iDataBuffer = aData;

    __LOG2( ELogServer, "<- Notify trigger %d (%d)", iId, aCompleteCode );
    iMessage.Complete( aCompleteCode );
    }

// ------------------------------------------------
// SetupForCallback
// ------------------------------------------------
//
void CMdSNotifier::TEntry::SetupForCallback(
    RMessage2 aMessage, TInt aRemoteSizeMsgSlot )
    {
    __ASSERT_DEBUG( !IsPending(), MMdCCommon::Panic( KErrCorrupt ) );
    iMessage = aMessage;
    iRemoteSizeMsgSlot = aRemoteSizeMsgSlot;
    }

// ------------------------------------------------
// GetDataBuffer
// ------------------------------------------------
//
CMdCSerializationBuffer* CMdSNotifier::TEntry::GetDataBuffer()
    {
    CMdCSerializationBuffer* data = iDataBuffer;
    iDataBuffer = NULL;
    return data;
    }

// ------------------------------------------------
// CreateEntry creates a new notifier entry
// ------------------------------------------------
//
CMdSNotifier::TEntry& CMdSNotifier::CreateEntryL( TInt aId,
    TConditionType aType, CMdCSerializationBuffer* aSerializedBuffer,
    TDefId aNamespaceDefId, CMdSServerSession& aSession, TBool aConfidential )
    {

    User::LeaveIfError( iEntries.Append(
        TEntry( aId, aType, aSerializedBuffer, aNamespaceDefId, aSession, aConfidential ) ) );
    return iEntries[ iEntries.Count() - 1 ];
    }

// ------------------------------------------------
// FindEntry
// ------------------------------------------------
//
CMdSNotifier::TEntry& CMdSNotifier::FindEntryL( TInt aId )
    {
    CMdSNotifier::TEntry* entry = NULL;
    
    const TInt count = iEntries.Count();
    
    for ( TInt i = 0; i < count; ++i )
        {
        if ( iEntries[i].iId == aId )
            {
            entry = &iEntries[i];
            break;
            }
        }

    if( !entry )
    	{
    	User::Leave( KErrNotFound );
    	}
    
    return *entry;
    }

// ------------------------------------------------
// RemoveEntryL
// ------------------------------------------------
//
void CMdSNotifier::RemoveEntryL( TInt aId )
    {
    const TInt count = iEntries.Count();
    
    for ( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];
        if ( e.iId == aId )
            {
            if ( e.IsPending() )
                {
                e.TriggerError( KErrCancel );
                }
            
            if ( e.iSerializedCondition )
            	{
            	delete e.iSerializedCondition;
            	e.iSerializedCondition = NULL;
            	}
            if ( e.iDataBuffer )
            	{
            	delete e.iDataBuffer;
            	e.iDataBuffer = NULL;
            	}
            iEntries.Remove( i );
            return;
            }
        }
    User::Leave( KErrNotFound );
    }

// ------------------------------------------------
// RemoveEntriesBySession
// ------------------------------------------------
//
void CMdSNotifier::RemoveEntriesBySession(
    const CMdSServerSession& aSession )
    {
    const TInt count = iEntries.Count();
    
    for ( TInt i = count; --i >= 0; )
        {
        TEntry& e = iEntries[i];
        if ( &e.iSession == &aSession ) // pointer comparision
            {
            if ( e.IsPending() )
                {
                e.TriggerError( KErrCancel );
                }
            
            delete e.iSerializedCondition;
            delete e.iDataBuffer;
            iEntries.Remove( i );
            }
        }
    }

// ------------------------------------------------
// NotifyAdded
// ------------------------------------------------
//
void CMdSNotifier::NotifyAddedL(CMdCSerializationBuffer& aSerializedItems, 
							    CMdCSerializationBuffer& aSerializedItemIds)
    {
    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        if ( ! (e.iType & ( EObjectNotifyAdd | ERelationNotifyAdd | EEventNotifyAdd ) ) )
        	{
        	continue;
        	}
        
        RArray<TItemId> matchingItemIdArray;
   		CleanupClosePushL( matchingItemIdArray );

		aSerializedItems.PositionL( KNoOffset );
		aSerializedItemIds.PositionL( KNoOffset );

		TBool someMatches = iComparator->MatchL( e.NamespaceDefId(), e.iType, e.Condition(), 
												 aSerializedItems, aSerializedItemIds, 
												 matchingItemIdArray,
												 e.AllowConfidential() );

        if( someMatches ) // check if there is some matches
            {
            if( e.IsPending() )
            	{
            	// match found. trigger notifier entry !
	            TRAPD( err, e.TriggerL( EObjectNotifyAdd | ERelationNotifyAdd | EEventNotifyAdd,
	            		matchingItemIdArray ) );
	            if( err != KErrNone )
	            	{
	            	e.TriggerError( err );
	            	}
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( EObjectNotifyAdd | ERelationNotifyAdd | EEventNotifyAdd,
            			matchingItemIdArray ) );
            	}
            }

   		CleanupStack::PopAndDestroy( &matchingItemIdArray );
        }
    }

// ------------------------------------------------
// NotifyRemoved
// ------------------------------------------------
//
void CMdSNotifier::NotifyRemovedL(CMdCSerializationBuffer& aSerializedItemIds, 
								  TBool aItemIsConfidential)
    {
	aSerializedItemIds.PositionL( KNoOffset );

	const TMdCItemIds& itemIds = TMdCItemIds::GetFromBufferL( aSerializedItemIds );

    RArray<TItemId> objectIdArray;
	CleanupClosePushL( objectIdArray );
    RArray<TItemId> eventIdArray;
	CleanupClosePushL( eventIdArray );
    RArray<TItemId> relationIdArray;
	CleanupClosePushL( relationIdArray );

    //get removed item IDs
	if( itemIds.iObjectIds.iPtr.iCount > 0 )
		{
		aSerializedItemIds.PositionL( itemIds.iObjectIds.iPtr.iOffset );

    	objectIdArray.ReserveL( itemIds.iObjectIds.iPtr.iCount );
    	for( TUint32 i = 0; i < itemIds.iObjectIds.iPtr.iCount; i++ )
    		{
    		TItemId objectId;
    		aSerializedItemIds.ReceiveL( objectId );
    		if ( objectId != KNoId )
    			{
    			objectIdArray.Append( objectId );
    			}
    		}
		}
	if( itemIds.iEventIds.iPtr.iCount > 0 )
		{
		aSerializedItemIds.PositionL( itemIds.iEventIds.iPtr.iOffset );

    	eventIdArray.ReserveL( itemIds.iEventIds.iPtr.iCount );
    	for( TUint32 i = 0; i < itemIds.iEventIds.iPtr.iCount; i++ )
    		{
    		TItemId eventId;
    		aSerializedItemIds.ReceiveL( eventId );
    		if ( eventId != KNoId )
    			{
    			eventIdArray.Append( eventId );
    			}
    		}
		}
	if( itemIds.iRelationIds.iPtr.iCount > 0 )
		{
		aSerializedItemIds.PositionL( itemIds.iRelationIds.iPtr.iOffset );

    	relationIdArray.ReserveL( itemIds.iRelationIds.iPtr.iCount );
    	for( TUint32 i = 0; i < itemIds.iRelationIds.iPtr.iCount; i++ )
    		{
    		TItemId relationId;
    		aSerializedItemIds.ReceiveL( relationId );
    		if ( relationId != KNoId )
    			{
    			relationIdArray.Append( relationId );
    			}
    		}
		}

	if( objectIdArray.Count() != 0 
			|| eventIdArray.Count() != 0 
			|| relationIdArray.Count() != 0 )
		{
		const TInt entriesCount = iEntries.Count();
	    for( TInt i=0; i < entriesCount; ++i )
	        {
	        TEntry& e = iEntries[i];
	        
	        // if namespace definition IDs don't match skip listener entry
	        if( e.NamespaceDefId() != itemIds.iNamespaceDefId )
	        	{
	        	continue;
	        	}

	        if(aItemIsConfidential && !e.AllowConfidential())
	        	{
	        	continue;	
	        	}

	        if( e.iType & EObjectNotifyRemove && objectIdArray.Count() > 0 )
	            {
	            // collect matching object IDs
	            RArray<TItemId> matchingObjectIdArray;
				CleanupClosePushL( matchingObjectIdArray );
	
	            TBool allMatches = iComparator->MatchObjectIdsL( e.Condition(),
	            		objectIdArray, matchingObjectIdArray );
	
				// check is there any matches
				if( allMatches || matchingObjectIdArray.Count() > 0 )
	            	{
	            	if(e.IsPending())
	            		{
		            	// Match found. Trigger notifier entry.
		            	TInt err;
		            	
		            	if( allMatches )
		            		{
		            		// all matches so send whole object ID array
		            		TRAP( err, e.TriggerL( EObjectNotifyRemove, 
		            				objectIdArray ) );
		            		}
		            	else
		            		{
		            		TRAP( err, e.TriggerL( EObjectNotifyRemove, 
		            				matchingObjectIdArray ) );
		            		}
	
		            	if( err != KErrNone )
			            	{
			            	e.TriggerError( err );
		    	        	}
	            		}
	            	else
	            		{
						if( allMatches )
		            		{
		            		// all matches so send whole object ID array
	            			TRAP_IGNORE( e.CacheL( EObjectNotifyRemove, 
	            					objectIdArray ) );
		            		}
		            	else
		            		{
		            		TRAP_IGNORE( e.CacheL( EObjectNotifyRemove, 
		            				matchingObjectIdArray ) );
		            		}
	            		}
	            	}
	
				CleanupStack::PopAndDestroy( &matchingObjectIdArray );
				}
	        else if( ( e.iType & EEventNotifyRemove ) 
	        		&& eventIdArray.Count() > 0 )
            	{
				// event condition can't contain ID conditions, 
            	// so get all IDs
	        	if(e.IsPending())
	        		{
	            	// Match found. Trigger notifier entry.
	            	TRAPD( err, e.TriggerL( EEventNotifyRemove, 
	            			eventIdArray ) );
	            	if( err != KErrNone )
		            	{
		            	e.TriggerError( err );
	    	        	}
	        		}
	        	else
	        		{
	        		TRAP_IGNORE( e.CacheL( EEventNotifyRemove, 
	        				eventIdArray ) );
	        		}
            	}
	        else if( ( e.iType & ERelationNotifyRemove ) 
	        		&& relationIdArray.Count() > 0 )
            	{
	            // relation condition can't contain ID conditions, 
            	// so get all IDs
	        	if(e.IsPending())
	        		{
	            	// Match found. Trigger notifier entry.
	            	TRAPD( err, e.TriggerL( ERelationNotifyRemove, 
	            			relationIdArray ) );
	            	if( err != KErrNone )
		            	{
		            	e.TriggerError( err );
	    	        	}
	        		}
	        	else
	        		{
	        		TRAP_IGNORE( e.CacheL( ERelationNotifyRemove, 
	        				relationIdArray ) );
	        		}
            	}
	        }
		}

	CleanupStack::PopAndDestroy( 3, &objectIdArray ); // relationIdArray, eventIdArray, objectIdArray
    }

// ------------------------------------------------
// NotifyModified
// ------------------------------------------------
//
void CMdSNotifier::NotifyModifiedL(CMdCSerializationBuffer& aSerializedItems, 
							       CMdCSerializationBuffer& aSerializedItemIds)
    {
    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        if ( ! (e.iType & ( EObjectNotifyModify | ERelationNotifyModify /*| ERelationItemNotifyModify*/ ) ) )
        	{
        	continue;
        	}
  
        RArray<TItemId> matchingObjectIdArray;
		CleanupClosePushL( matchingObjectIdArray );

		aSerializedItems.PositionL( KNoOffset );
		aSerializedItemIds.PositionL( KNoOffset );

		TBool someMatches = iComparator->MatchL( e.NamespaceDefId(), 
				e.iType, e.Condition(), aSerializedItems, aSerializedItemIds, 
				matchingObjectIdArray, e.AllowConfidential() );

        if( someMatches ) // check if there is some matches
            {
            if( e.IsPending() )
            	{
            	// match found. trigger notifier entry !
	            TRAPD( err, e.TriggerL( EObjectNotifyModify | ERelationNotifyModify /*| ERelationItemNotifyModify*/,
	            		matchingObjectIdArray ) );
	            if( err != KErrNone )
	            	{
	            	e.TriggerError( err );
	            	}
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( EObjectNotifyModify | ERelationNotifyModify /*| ERelationItemNotifyModify*/,
            			matchingObjectIdArray ) );
            	}
            }

		CleanupStack::PopAndDestroy( &matchingObjectIdArray );
        }
    }

// ------------------------------------------------
// NotifyModified
// ------------------------------------------------
//
void CMdSNotifier::NotifyModifiedL(const RArray<TItemId>& aObjectIds)
	{
	if (aObjectIds.Count() == 0)
    	{
    	return;
    	}

    const TInt count = iEntries.Count();

    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        if( e.iType & EObjectNotifyModify )
            {
            // collect matching object IDs
            RArray<TItemId> matchingObjectIdArray;
			CleanupClosePushL( matchingObjectIdArray );

            TBool allMatches = iComparator->MatchObjectIdsL( e.Condition(), 
            		aObjectIds, matchingObjectIdArray );

			// check is there any matches
			if( allMatches || matchingObjectIdArray.Count() > 0 )
            	{
            	if(e.IsPending())
            		{
	            	// Match found. Trigger notifier entry.
	            	TInt err;

	            	if( allMatches )
	            		{
	            		// all matches so send whole object ID array
	            		TRAP( err, e.TriggerL( EObjectNotifyModify, 
	            				aObjectIds ) );
	            		}
	            	else
	            		{
	            		TRAP( err, e.TriggerL( EObjectNotifyModify, 
	            				matchingObjectIdArray ) );
	            		}

	            	if( err != KErrNone )
		            	{
		            	e.TriggerError( err );
	    	        	}
            		}
            	else
            		{
					if( allMatches )
	            		{
	            		// all matches so send whole object ID array
            			TRAP_IGNORE( e.CacheL( EObjectNotifyModify, 
            					aObjectIds ) );
	            		}
	            	else
	            		{
	            		TRAP_IGNORE( e.CacheL( EObjectNotifyModify, 
	            				matchingObjectIdArray ) );
	            		}
            		}
            	}

			CleanupStack::PopAndDestroy( &matchingObjectIdArray );
            }
        }
	}

// ------------------------------------------------
// NotifyRemoved
// ------------------------------------------------
//
void CMdSNotifier::NotifyRemovedL(const RArray<TItemId>& aItemIdArray)
	{
    for( TInt i=0; i<iEntries.Count(); ++i )
        {
        TEntry& e = iEntries[i];

        if( e.iType & EObjectNotifyRemove )
        	{
            if( e.IsPending() )
            	{
	            TRAPD( err, e.TriggerL( EObjectNotifyRemove, aItemIdArray ) );
	            if( err != KErrNone )
	            	{
	            	e.TriggerError( err );
	            	}
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( EObjectNotifyRemove, aItemIdArray ) );
            	}
        	}
        }
	}

// ------------------------------------------------
// NotifyObjectPresent
// ------------------------------------------------
//
void CMdSNotifier::NotifyObjectPresent(TBool aPresent, const RArray<TItemId>& aObjectIds)
    {
    if (aObjectIds.Count() == 0)
    	{
    	return;
    	}

    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        // No condition matching, object present changes
        // are always notified to object present observers
        if( e.iType & ( EObjectNotifyPresent | EObjectNotifyNotPresent )  )
            {
            const TMdSObserverNotificationType objectState = 
            	aPresent ? EObjectNotifyPresent : EObjectNotifyNotPresent;

            if( e.IsPending() )
            	{
            	// match found. trigger notifier entry !
	            TRAPD( err, e.TriggerL( objectState, aObjectIds ) );
	            if( err != KErrNone )
	            	{
	            	e.TriggerError( err );
	            	}
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( objectState, aObjectIds ) );
            	}
            }
        }
    }

// ------------------------------------------------
// NotifyRelationPresent
// ------------------------------------------------
//
void CMdSNotifier::NotifyRelationPresent(TBool aPresent, const RArray<TItemId>& aRelationIds)
    {
    if (aRelationIds.Count() == 0)
    	{
    	return;
    	}

    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        // No condition matching, relation present changes
        // are always notified to relation present observers
        if( e.iType & ( ERelationNotifyPresent | ERelationNotifyNotPresent ) )
            {
            const TMdSObserverNotificationType relationState = 
            	aPresent ? ERelationNotifyPresent : ERelationNotifyNotPresent;

            if( e.IsPending() )
            	{
            	// match found. trigger notifier entry !
	            TRAPD( err, e.TriggerL( relationState, aRelationIds ) );
	            if( err != KErrNone )
	            	{
	            	e.TriggerError( err );
	            	}
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( relationState, aRelationIds ) );
            	}
            }
        }
    }


// ------------------------------------------------
// NotifySchemaAdded
// ------------------------------------------------
//
void CMdSNotifier::NotifySchemaAddedL()
    {
    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        TEntry& e = iEntries[i];

        // No condition matching, schema additions 
        // are always notified to schema observers
        if( e.iType == ESchemaModify )
            {
            if( e.IsPending() )
            	{
	            // match found. trigger notifier entry
	            e.TriggerSchema();
            	}
            else
            	{
            	TRAP_IGNORE( e.CacheL( ESchemaModify ) );
            	}
            }
        }
    }


// ------------------------------------------------
// CheckForNotifier
// ------------------------------------------------
//
TBool CMdSNotifier::CheckForNotifier( TUint32 aNotifyTypes )
    {
    const TInt count = iEntries.Count();
    
    for( TInt i = 0; i < count; ++i )
        {
        if ( iEntries[i].iType & aNotifyTypes )
        	{
        	return ETrue;
        	}
        }
    return EFalse;
    }

void CMdSNotifier::NotifyRemovedRelationItemsL( 
		CMdCSerializationBuffer& aBuffer )
	{
	aBuffer.PositionL( KNoOffset );

	const TMdCItems& items = TMdCItems::GetFromBufferL( aBuffer );

	if( items.iRelations.iPtr.iCount )
		{
		const TInt entriesCount = iEntries.Count();
	    for( TInt i = 0; i < entriesCount; ++i )
	        {
	        TEntry& e = iEntries[i];
	        
	        // if namespace definition IDs don't match skip listener entry
	        if( e.NamespaceDefId() != items.iNamespaceDefId )
	        	{
	        	continue;
	        	}
	        
	        if( e.iType & ERelationItemNotifyRemove )
            	{
            	aBuffer.PositionL( items.iRelations.iPtr.iOffset );
	            // check relations condition
            	RArray<TItemId> matchedRelations;
            	CleanupClosePushL( matchedRelations );
            	TBool matches = iComparator->MatchRelationItemsL( 
            			e.Condition(), aBuffer, matchedRelations );

            	if ( matches )
	        		{
	        		if(e.IsPending())
	        			{
		            	// Match found. Trigger notifier entry.
		            	TRAPD( err, e.TriggerRelationItemsL( 
		            			ERelationItemNotifyRemove, aBuffer, 
		            			matchedRelations ) );
		            	if( err != KErrNone )
			            	{
			            	e.TriggerError( err );
		    	        	}
		        		}
		        	else
		        		{
		        		TRAP_IGNORE( e.CacheRelationItemsL( 
		        				ERelationItemNotifyRemove, aBuffer, 
		        				matchedRelations ) );
		        		}
	        		}
            	CleanupStack::PopAndDestroy( &matchedRelations );
            	}
	        }
		}

	}