/*
* Copyright (c) 2006 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: Encapsulates all the clients
*
*/
// INCLUDES
#include <mpxlog.h>
#include "mpxuser.h"
#include "mpxmessagequeue.h"
#include "mpxclientlistobserver.h"
#include "mpxclientlist.h"
#include <mpxsubscription.h>
// ============================ MEMBER FUNCTIONS ==============================
// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
EXPORT_C CMPXClientList* CMPXClientList::NewL(
MMPXClientlistObserver* aObserver /*=NULL*/)
{
CMPXClientList* list=new(ELeave)CMPXClientList(aObserver);
CleanupStack::PushL(list);
list->ConstructL();
CleanupStack::Pop(list);
return list;
}
// ----------------------------------------------------------------------------
// Constructor.
// ----------------------------------------------------------------------------
//
CMPXClientList::CMPXClientList(MMPXClientlistObserver* aObserver)
: iIdentity(CMPXClientList::ClientsMatch),
iObserver(aObserver)
{}
// ----------------------------------------------------------------------------
// 2nd phase constructor.
// ----------------------------------------------------------------------------
//
void CMPXClientList::ConstructL()
{
}
// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
//
EXPORT_C CMPXClientList::~CMPXClientList()
{
iClients.ResetAndDestroy();
iClients.Close();
iClientProcesses.Close();
}
// ----------------------------------------------------------------------------
// Add a client into the client list
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::AddClientL(
TThreadId aId,
CMPXMessageQueue* aMsgQueue)
{
AddClientL(aId, KErrUnknown, aMsgQueue);
}
// ----------------------------------------------------------------------------
// Add a client into the client list
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::AddClientL(
TThreadId aId,
TInt aMode,
CMPXMessageQueue* aMsgQueue)
{
TProcessId pid=MPXUser::ProcessIdL(aId);
CClientId* newClient = new(ELeave) CClientId(aId,pid,aMode,aMsgQueue);
CleanupStack::PushL(newClient);
// add an empty subscription by default
CMPXSubscription* subscription = CMPXSubscription::NewL();
CleanupStack::PushL(subscription);
// transfer the ownership
newClient->iSubscriptions.AppendL(subscription);
CleanupStack::Pop(subscription);
iClients.AppendL(newClient);
CleanupStack::Pop(newClient);
if (iClientProcesses.Find(pid)==KErrNotFound)
{
iClientProcesses.AppendL(pid);
if (iObserver)
{
iObserver->HandleClientChange(pid, MMPXClientlistObserver::EAdd);
}
}
}
// ----------------------------------------------------------------------------
// Add a client into the client list
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::AddClientL(
TThreadId aId,
TInt aMode,
CMPXMessageQueue* aMsgQueue,
const TInt aCategory)
{
TProcessId pid=MPXUser::ProcessIdL(aId);
CClientId* newClient = new(ELeave) CClientId(aId,pid,aMode,aMsgQueue, aCategory);
CleanupStack::PushL(newClient);
// add an empty subscription by default
CMPXSubscription* subscription = CMPXSubscription::NewL();
CleanupStack::PushL(subscription);
// transfer the ownership
newClient->iSubscriptions.AppendL(subscription);
CleanupStack::Pop(subscription);
iClients.AppendL(newClient);
CleanupStack::Pop(newClient);
if (iClientProcesses.Find(pid)==KErrNotFound)
{
iClientProcesses.AppendL(pid);
if (iObserver)
{
iObserver->HandleClientChange(pid, MMPXClientlistObserver::EAdd);
}
}
}
// SK
// ----------------------------------------------------------------------------
// Remove a client from the list
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::RemoveClient(TInt aIndex)
{
// USER panic 130, if aIndex is negative or is greater than the number of
// objects currently in the array.
CClientId* id( iClients[aIndex] );
iClients.Remove(aIndex);
CClientId removeId( id->iPid );
if ( iClients.Find( &removeId, iIdentity ) == KErrNotFound )
//
// There's no other client from the same process, so
// remove it from the process list
//
{
TInt i=iClientProcesses.Find(id->iPid);
if (KErrNotFound != i)
{
if (iObserver)
{
iObserver->HandleClientChange(id->iPid, MMPXClientlistObserver::ERemove);
}
iClientProcesses.Remove(i);
}
}
delete id;
}
// -----------------------------------------------------------------------------
// Return the number of clients
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXClientList::ClientCount() const
{
return iClients.Count();
}
// -----------------------------------------------------------------------------
// Return array of client process ids
// -----------------------------------------------------------------------------
//
EXPORT_C TArray<TProcessId> CMPXClientList::ClientProcessList() const
{
return iClientProcesses.Array();
}
// -----------------------------------------------------------------------------
// Check if the client in the client list or not
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CMPXClientList::IsClient(TThreadId aId) const
{
return (KErrNotFound != Find(aId));
}
// -----------------------------------------------------------------------------
// Find a client denoted by message queue in this list.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXClientList::Find(const CMPXMessageQueue& aMsgQueue) const
{
CClientId id( const_cast<CMPXMessageQueue*>( &aMsgQueue ));
return iClients.Find( &id, iIdentity );
}
// -----------------------------------------------------------------------------
// Found a client by Id
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXClientList::Find(TThreadId aId) const
{
CClientId id( aId );
return iClients.Find( &id ,iIdentity );
}
// -----------------------------------------------------------------------------
// Return client mode
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXClientList::ClientMode(TInt aIndex) const
{
MPX_ASSERT(aIndex>=0 && aIndex<ClientCount());
return iClients[aIndex]->iMode;
}
// -----------------------------------------------------------------------------
// Return client category
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXClientList::ClientCategory(TInt aIndex) const
{
MPX_ASSERT(aIndex>=0 && aIndex<ClientCount());
TInt category = iClients[aIndex]->iCategory;
return category;
}
// -----------------------------------------------------------------------------
// Send message to all clients in the list
// -----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::SendMsg(const CMPXMessage* aMsg, TInt aError)
{
MPX_FUNC_EX("CMPXClientList::SendMsg");
for (TInt i=iClients.Count();--i>=0;)
{
SendMsg( i, aMsg, aError );
}
}
// -----------------------------------------------------------------------------
// Send message to a client
// -----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::SendMsg(
TInt aIndex,
const CMPXMessage* aMsg,
TInt aError)
{
MPX_FUNC_EX("CMPXClientList::SendMsgL(aIndex)");
MPX_ASSERT(aIndex>=0 && aIndex<iClients.Count());
MPX_ASSERT(iClients[aIndex]->iMsgQueue);
// check the subscriptions
TBool send(EFalse);
TInt err(KErrNone);
if (aMsg)
{
TRAP(err, send = IsMsgSubscribedL(aIndex, aMsg));
}
else
{
send = ETrue; // broadcast error message aError
}
// only send if the client has subscribed for it
if (send && KErrNone == err)
{
iClients[aIndex]->iMsgQueue->Add(aMsg, aError);
}
}
// -----------------------------------------------------------------------------
// CMPXClientList::AddSubscriptionL
// -----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::AddSubscriptionL(
TInt aIndex,
CMPXSubscription* aSubscription)
{
MPX_FUNC("CMPXClientList::AddSubscriptionL");
CClientId* id( iClients[aIndex] );
TInt subCount( id->iSubscriptions.Count() );
const CMPXMediaArray* items = id->iSubscriptions[0]->ItemsL();
// check if it has an empty subscription
if ( 1 == subCount && items->Count() )
{
// remove it if so
id->RemoveAllSubscriptionsL();
}
// add the new subscription
id->AddSubscriptionL(aSubscription);
}
// -----------------------------------------------------------------------------
// CMPXClientList::RemoveSubscriptionL
// -----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::RemoveSubscriptionL(
TInt aIndex,
const CMPXSubscription& aSubscription)
{
MPX_FUNC("CMPXClientList::RemoveSubscriptionL");
iClients[aIndex]->RemoveSubscriptionL(aSubscription);
}
// -----------------------------------------------------------------------------
// CMPXClientList::RemoveAllSubscriptionsL
// -----------------------------------------------------------------------------
//
EXPORT_C void CMPXClientList::RemoveAllSubscriptionsL(
TInt aIndex)
{
MPX_FUNC("CMPXClientList::RemoveAllSubscriptionsL");
iClients[aIndex]->RemoveAllSubscriptionsL();
}
// -----------------------------------------------------------------------------
// CMPXClientList::IsMsgSubscribedL
// -----------------------------------------------------------------------------
//
TBool CMPXClientList::IsMsgSubscribedL(TInt aIndex, const CMPXMessage* aMsg)
{
// check the subscriptions
TBool IsSubScribed(EFalse);
TInt subCount(iClients[aIndex]->iSubscriptions.Count());
if (subCount)
{
const CMPXMediaArray* subscriptionItems =
iClients[aIndex]->iSubscriptions[0]->ItemsL();
if (1==subCount && (0== subscriptionItems->Count()))
{// one empty subscription - send everything
IsSubScribed = ETrue;
}
else
{// have to check the message against the subscriptions.
MPX_ASSERT(aMsg);
const TArray<TMPXAttribute> msgAttrs = aMsg->Attributes();
TInt msgAttrCount(msgAttrs.Count());
// iterate subscriptions
for (TInt subIndex = 0; subIndex<subCount && !IsSubScribed; ++subIndex)
{
// iterate items for the current subscription
subscriptionItems =
iClients[aIndex]->iSubscriptions[subIndex]->ItemsL();
TInt itemCount(subscriptionItems->Count());
for (TInt itemIndex = 0; itemIndex < itemCount; ++itemIndex)
{
// check the message attributes for the current subscription item
TBool subMatch(ETrue);
TInt attrMatchCount(0);
CMPXSubscriptionItem* subItem(subscriptionItems->AtL(itemIndex));
for (TInt msgAttrIndex = 0; msgAttrIndex < msgAttrCount; ++msgAttrIndex)
{
TBool attrExists(EFalse);
TBool attrMatch(EFalse);
const TMPXAttribute& msgAttr( msgAttrs[msgAttrIndex] );
if ( subItem->IsSupported(msgAttr))
{
attrExists = ETrue;
if ( subItem->Match( *aMsg, msgAttr ))
{
attrMatch = ETrue;
attrMatchCount++;
}
}
if (attrExists && !attrMatch)
{
subMatch = EFalse;
break;
}
}
// send the message if all attributes that exist in both the message and the subscription
// have the same values and all subscription attributes match
if ( subMatch && ( attrMatchCount == subItem->Count()) )
{
IsSubScribed = ETrue;
break;
}
}
}
}
} // else subCount = 0, IsSubScribed = EFalse (default)
return IsSubScribed;
}
// ----------------------------------------------------------------------------
// Comparison function. If the names are set in the client objects, then
// that's used to test for equality. Otherwise, if the thread ids are set,
// that's used. Else, it's assumed that the equality test is based on process
// ids.
// ----------------------------------------------------------------------------
//
TBool CMPXClientList::ClientsMatch(const CClientId& aClient1,
const CClientId& aClient2)
{
TBool match=EFalse;
if (aClient1.iMsgQueue && aClient2.iMsgQueue)
{
match=aClient1.iMsgQueue==aClient2.iMsgQueue;
}
else if (aClient1.iTid.Id()!=KNullThreadId &&
aClient2.iTid.Id()!=KNullThreadId)
{
match=(aClient1.iTid==aClient2.iTid);
}
else
{
match=(aClient1.iPid==aClient2.iPid);
}
return match;
}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(
TThreadId aTid,
TProcessId aPid,
CMPXMessageQueue* aMsgQueue)
: iTid(aTid),
iPid(aPid),
iMode(KErrNotFound),
iMsgQueue(aMsgQueue)
{}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(
TThreadId aTid,
TProcessId aPid,
TInt aMode,
CMPXMessageQueue* aMsgQueue)
: iTid(aTid),
iPid(aPid),
iMode(aMode),
iMsgQueue(aMsgQueue)
{}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(
TThreadId aTid,
TProcessId aPid,
TInt aMode,
CMPXMessageQueue* aMsgQueue,
TInt aCategory)
: iTid(aTid),
iPid(aPid),
iMode(aMode),
iMsgQueue(aMsgQueue),
iCategory(aCategory)
{}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(CMPXMessageQueue* aMsgQueue)
:iTid(static_cast<TUint64>(KNullThreadId)),
iPid(static_cast<TUint64>(KNullProcessId)),
iMode(KErrUnknown),
iMsgQueue(aMsgQueue)
{}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(TThreadId aTid)
: iTid(aTid),
iPid(static_cast<TUint64>(KNullProcessId)),
iMode(KErrUnknown),
iMsgQueue(NULL)
{}
// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::CClientId(TProcessId aPid)
: iTid(static_cast<TUint64>(KNullThreadId)),
iPid(aPid),
iMode(KErrUnknown),
iMsgQueue(NULL)
{}
// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId::~CClientId()
{
iSubscriptions.ResetAndDestroy();
}
// -----------------------------------------------------------------------------
// CClientId::operator=
// -----------------------------------------------------------------------------
//
CMPXClientList::CClientId& CMPXClientList::CClientId::operator=(
const CClientId& aClient)
{
iTid = aClient.iTid;
iPid = aClient.iPid;
iMode = aClient.iMode;
iMsgQueue = aClient.iMsgQueue;
RemoveAllSubscriptionsL();
// copy the subscriptions
TInt count(aClient.iSubscriptions.Count());
for (TInt index = 0; index < count; ++index)
{
CMPXSubscription* subscription = static_cast<CMPXSubscription*>(
CMPXMedia::NewL(*(aClient.iSubscriptions[index])));
CleanupStack::PushL(subscription);
// transfer the ownership
iSubscriptions.AppendL(subscription);
CleanupStack::Pop(subscription);
}
return *this;
}
// -----------------------------------------------------------------------------
// CClientId::AddSubscriptionL
// -----------------------------------------------------------------------------
//
void CMPXClientList::CClientId::AddSubscriptionL(
CMPXSubscription* aSubscription)
{
// add the subscription
iSubscriptions.AppendL(aSubscription);
}
// -----------------------------------------------------------------------------
// CClientId::RemoveSubscriptionL
// -----------------------------------------------------------------------------
//
void CMPXClientList::CClientId::RemoveSubscriptionL(
const CMPXSubscription& aSubscription)
{
TInt count(iSubscriptions.Count());
for (TInt index = 0; index < count; ++index)
{
CMPXSubscription* subscription = iSubscriptions[index];
if (aSubscription == *subscription)
{
// found the subscription, remove it
iSubscriptions.Remove(index);
delete subscription;
break;
}
}
}
// -----------------------------------------------------------------------------
// CClientId::RemoveAllSubscriptionsL
// -----------------------------------------------------------------------------
//
void CMPXClientList::CClientId::RemoveAllSubscriptionsL()
{
iSubscriptions.ResetAndDestroy();
}
// End of File