landmarks/locationlandmarks/server/src/EPos_CPosLmEventHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 17:05:00 +0300
branchRCL_3
changeset 10 d6e4203b7ebe
parent 0 667063e416a2
permissions -rw-r--r--
Revision: 201015 Kit: 201017

/*
* Copyright (c) 2005 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: class to handle event notification to subscribers.
*
*
*/


// INCLUDE FILES
#include "EPos_CPosLmEventHandler.h"
#include "EPos_LandmarksServerPanics.h"
#include "EPos_PosLmServerCommon.h"
#include "EPos_LmServerGlobal.h"

// CONSTANTS
const TInt KEventQueueMaxSize = 5;

// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// CPosLmEventHandler::CPosLmEventHandler
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPosLmEventHandler::CPosLmEventHandler()
    {
    }

// Two-phased constructor.
CPosLmEventHandler* CPosLmEventHandler::NewL()
    {
    CPosLmEventHandler* self = new (ELeave) CPosLmEventHandler();
    return self;
    }

// Destructor
CPosLmEventHandler::~CPosLmEventHandler()
    {
    LmServerGlobal::Complete(iHoldingMessage, KErrCancel);
    iEventQueue.Close();
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::HandleRequestForEventL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::HandleRequestForEventL(
    const RMessagePtr2& aMessage)
    {
    TPckgBuf<TPosLmEvent> event;
    TInt desMaxLength = aMessage.GetDesMaxLength(KPosLmServerEventArg);
    if (desMaxLength != event.Length())
        {
        PanicClient(aMessage, EPosUnableToReadOrWriteDataToClient);
        return;
        }

    if (iEventQueue.Count() > 0)
        {
        // Send the first event in the queue to the client.
        WriteEventAndComplete(aMessage, iEventQueue[0]);
        iEventQueue.Remove(0);
        }
    else
        {
        // No events in queue. Put the message on hold.
        if (!iHoldingMessage.IsNull())
            {
            PanicClient(aMessage,
                EPosEventNotifierAlreadyHasOutstandingRequest);
            }
        else
            {
            iHoldingMessage = aMessage;
            }
        }
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::HandleIncomingEventL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::HandleIncomingEventL(
    TPosLmEvent aEvent)
    {
    if (!iHoldingMessage.IsNull())
        {
        // There is a message on hold. Send response immediately.
        WriteEventAndComplete(iHoldingMessage, aEvent);
        }
    else
        {
        // Subscriber is not waiting. Add event to queue.
        AddToEventQueueL(aEvent);
        }
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::CompleteAnyOutStandingRequest
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::CompleteAnyOutStandingRequest(
    TInt aError)
    {
    LmServerGlobal::Complete(iHoldingMessage, aError);
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::WriteEventAndComplete
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::WriteEventAndComplete(
    const RMessagePtr2& aMessage,
    TPosLmEvent aEvent)
    {
    TPckgBuf<TPosLmEvent> event(aEvent);
    if (LmServerGlobal::Write(
        aMessage, KPosLmServerEventArg, event) == KErrNone)
        {
        LmServerGlobal::Complete(aMessage, KErrNone);
        }
    // Client will be panicked if write fails.
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::AddToEventQueueL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::AddToEventQueueL(
    TPosLmEvent aEvent)
    {
    if (aEvent.iEventType == EPosLmEventMediaRemoved)
        {
        // Media is removed. All other events are removed. They are unnecessary.
        iEventQueue.Reset();
        }
    else if (aEvent.iEventType == EPosLmEventNewDefaultDatabaseLocation)
        {
        // Remove all other equal events, if found.
        TInt queuePosition;
        RemoveEvents(ENewDefaultDbs, queuePosition);
        }
    else if (!MergeEventsIfPossibleL(aEvent))
        {
        // Incoming event should not be added to queue.
        return;
        }

    User::LeaveIfError(iEventQueue.Append(aEvent));
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::MergeEventsIfPossibleL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmEventHandler::MergeEventsIfPossibleL(
    TPosLmEvent aEvent)
    {
    TPosLmEventType incoming = aEvent.iEventType;
    TBool addEvent = ETrue;
    TInt noOfSpecificLms = 0;
    TInt noOfSpecificCats = 0;

    for (TInt i = 0; i < iEventQueue.Count(); i++)
        {
        TPosLmEventType eventInQueue = iEventQueue[i].iEventType;

        // EPosLmEventMediaRemoved and EPosLmEventNewDefaultDatabaseLocation
        // should not be removed from the queue, no matter what.
        // See also AddToEventQueue.
        if (eventInQueue != EPosLmEventMediaRemoved &&
            eventInQueue != EPosLmEventNewDefaultDatabaseLocation)
            {
            if (incoming == EPosLmEventUnknownChanges)
                {
                // Unknown changes. All old events are removed.
                iEventQueue.Remove(i--);
                }
            else if (incoming == EPosLmEventCategoryUnknownChanges)
                {
                // Unknown category changes.
                HandleUnknownEvent(eventInQueue,
                    IsSpecificCategory(eventInQueue) ||
                    eventInQueue == EPosLmEventCategoryUnknownChanges,
                    addEvent, i);
                }
            else if (incoming == EPosLmEventLandmarkUnknownChanges)
                {
                // Unknown landmark changes.
                HandleUnknownEvent(eventInQueue,
                    IsSpecificLandmark(eventInQueue) ||
                    eventInQueue == EPosLmEventLandmarkUnknownChanges,
                    addEvent, i);
                }
            else if (IsSpecificCategory(incoming))
                {
                // Specific category
                HandleSpecificEvent(eventInQueue,
                    EPosLmEventCategoryUnknownChanges,
                    addEvent, noOfSpecificCats, noOfSpecificLms);
                }
            else
                {
                // Specific landmark
                HandleSpecificEvent(eventInQueue,
                    EPosLmEventLandmarkUnknownChanges,
                    addEvent, noOfSpecificCats, noOfSpecificLms);
                }
            }
        }

    // If adding a specific landmark or category and queue is full,
    // either specific landmarks or categories are merged into a
    // corresponding EPosLmEventLandmarkUnknownChanges or
    // EPosLmEventCategoryUnknownChanges.
    if ((noOfSpecificLms > 0 || noOfSpecificCats > 0) &&
        iEventQueue.Count() == KEventQueueMaxSize)
        {
        TPosLmEvent event;
        event.iLandmarkItemId = KPosLmNullItemId;
        TInt queuePositionOfFirstSpecific;

        if (noOfSpecificCats > noOfSpecificLms)
            {
            RemoveEvents(ESpecificCategories, queuePositionOfFirstSpecific);
            event.iEventType = EPosLmEventCategoryUnknownChanges;
            addEvent = IsSpecificLandmark(incoming);
            }
        else
            {
            RemoveEvents(ESpecificLandmarks, queuePositionOfFirstSpecific);
            event.iEventType = EPosLmEventLandmarkUnknownChanges;
            addEvent = IsSpecificCategory(incoming);
            }

        // This should not happen, because when calling RemoveEvents above,
        // there will always be either categories or landmarks in the queue
        // (see if-statement above).
        __ASSERT_DEBUG(queuePositionOfFirstSpecific != KErrNotFound,
            PanicServer(KErrGeneral));

        User::LeaveIfError(iEventQueue.Insert(event,
            queuePositionOfFirstSpecific));
        }

    return addEvent;
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::HandleUnknownEvent
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::HandleUnknownEvent(
    TPosLmEventType aEventInQueue,
    TBool aExpression,
    TBool& aAddEvent,
    TInt& aIndex)
    {
    if (aEventInQueue == EPosLmEventUnknownChanges)
        {
        // Unknown changes found in queue. Incoming event should not
        // be added to queue.
        aAddEvent = EFalse;
        }
    else if (aExpression)
        {
        // Remove any specific events or
        // EPosLmEventCategoryUnknownChanges/EPosLmEventLandmarkUnknownChanges.
        iEventQueue.Remove(aIndex--);
        }
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::HandleSpecificEvent
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::HandleSpecificEvent(
    TPosLmEventType aEventInQueue,
    TPosLmEventType aCompareEventType,
    TBool& aAddEvent,
    TInt& aNoOfSpecificCats,
    TInt& aNoOfSpecificLms)
    {
    if (aEventInQueue == EPosLmEventUnknownChanges ||
        aEventInQueue == aCompareEventType)
        {
        // Unknown (category) changes found in queue. Incoming event
        // should not be added to queue.
        aAddEvent = EFalse;
        }
    else if (IsSpecificCategory(aEventInQueue))
        {
        aNoOfSpecificCats++;
        }
    else if (IsSpecificLandmark(aEventInQueue))
        {
        aNoOfSpecificLms++;
        }
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::IsSpecificLandmark
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmEventHandler::IsSpecificLandmark(
    TPosLmEventType aEventType)
    {
    return aEventType > EPosLmEventLandmarkUnknownChanges &&
        aEventType < EPosLmEventCategoryUnknownChanges;
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::IsSpecificCategory
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmEventHandler::IsSpecificCategory(
    TPosLmEventType aEventType)
    {
    return aEventType > EPosLmEventCategoryUnknownChanges;
    }

// -----------------------------------------------------------------------------
// CPosLmEventHandler::RemoveEvents
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CPosLmEventHandler::RemoveEvents(
    TRemoveEventType aRemoveType,
    TInt& aQueuePosition)
    {
    aQueuePosition = KErrNotFound;

    for (TInt i = 0; i < iEventQueue.Count(); i++)
        {
        TPosLmEventType eventInQueue = iEventQueue[i].iEventType;

        if (aRemoveType == ESpecificLandmarks &&
                IsSpecificLandmark(eventInQueue) ||
            aRemoveType == ESpecificCategories &&
                IsSpecificCategory(eventInQueue) ||
            aRemoveType == ENewDefaultDbs &&
                eventInQueue == EPosLmEventNewDefaultDatabaseLocation)
            {
            if (aQueuePosition == KErrNotFound)
                {
                aQueuePosition = i;
                }
            iEventQueue.Remove(i--);
            }
        }
    }

// End of File