ncdengine/engine/src/catalogsclientserverserversession.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/src/catalogsclientserverserversession.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,546 @@
+/*
+* 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:   Implementation of CCatalogsClientServerServerSession
+*
+*/
+
+
+#include <e32kpan.h>
+
+#include "catalogsclientserverserversession.h"
+#include "catalogsserverdefines.h"
+#include "catalogscommunicable.h"
+#include "catalogsbasemessageimpl.h"
+#include "catalogsincompletemessage.h"
+#include "catalogscontextimpl.h"
+#include "catalogsdebug.h"
+
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Cleanupfunction for cleanupitem usage. Closes CObject based
+// object as many times as needed to destroy it when removed
+// from cleanupstack.
+// ---------------------------------------------------------------------------
+//    
+void CCatalogsClientServerServerSession::CleanupCObjectBasedClass( TAny* aCObject )
+	{
+	CObject* convertedCObject = ( static_cast< CObject* > ( aCObject ) );
+	TInt accessCount = convertedCObject->AccessCount();
+    while ( accessCount > 0 )
+        {
+        convertedCObject->Close();
+        --accessCount;
+        }
+    // Now that last reference is closed, aCObject is destroyed
+	}
+
+
+// ======== MEMBER FUNCTIONS ========
+
+CCatalogsClientServerServerSession* CCatalogsClientServerServerSession::NewL(
+    RThread& aClient,
+    CCatalogsClientServerServer& aServer )
+    {
+    CCatalogsClientServerServerSession* self = 
+        CCatalogsClientServerServerSession::NewLC( aClient, aServer );
+    CleanupStack::Pop(self) ;
+    return self ;
+    }
+
+CCatalogsClientServerServerSession* CCatalogsClientServerServerSession::
+    NewLC( RThread& aClient, CCatalogsClientServerServer& aServer )
+    {
+    CCatalogsClientServerServerSession* self = 
+        new (ELeave) CCatalogsClientServerServerSession( aClient, aServer,
+            aServer.NewInstanceId() );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+CCatalogsClientServerServerSession::CCatalogsClientServerServerSession(
+    RThread& /*aClient*/,
+    CCatalogsClientServerServer& aServer,
+    TInt aInstanceId ) :
+    CSession2(),
+    iClientSideDownAnnounced( ENotInformed ),
+    iServer( aServer ),
+    iInstanceId( aInstanceId )
+    {
+    }
+
+CCatalogsClientServerServerSession::~CCatalogsClientServerServerSession()
+    {
+    DLTRACEIN((""));
+    ClientSideSessionDown();   
+    DLTRACE(("Deleting context")); 
+    delete iContext;
+    iServer.DecrementSessions();    
+    DLTRACEOUT((""));
+    }
+
+void CCatalogsClientServerServerSession::ConstructL() 
+    {    
+    iServer.IncrementSessions();
+    iMessageHandlers = CObjectIx::NewL();
+    iIncompleteMessageContainer = iServer.NewContainerL();
+    iIncompleteMessages = CObjectIx::NewL();
+
+    }
+
+void CCatalogsClientServerServerSession::ClientSideSessionDown()
+    {
+    DLTRACEIN((""));
+    if ( iClientSideDownAnnounced == ENotInformed )
+        {
+        DLTRACE(("Delete incomplete messages"));
+        // Incomplete messages act as receivers of messages as well
+        // as nodes etc.
+        delete iIncompleteMessages;
+        iIncompleteMessages = NULL;
+
+        // In examples, container is simply deleted, but here
+        // this ends up making a KERN-EXEC 3. Probably container is 
+        // removed for a second time when the container-index is removed.
+        if ( iIncompleteMessageContainer != NULL )
+            {
+            DLTRACE(("Remove container"));
+            iServer.RemoveContainer( iIncompleteMessageContainer );
+            DLTRACE(("Container removed"));
+            }
+        iIncompleteMessageContainer = NULL;
+        
+        
+        CloseMessageHandlers();
+        
+        DLTRACE(("Handle session removal"));
+        // Inform possibly interested objects of session removal
+        // so they know that this session does not exist anymore
+        iServer.HandleSessionRemoval( *this );
+        
+        iClientSideDownAnnounced = EInformed;        
+        }
+        
+    DLTRACEOUT((""));
+    }
+    
+
+TInt CCatalogsClientServerServerSession::WriteToLargerDesL(
+    const TDesC8& aOutputData,
+    TInt aStatus )
+    {
+    CCatalogsIncompleteMessage* incompleteMessage =
+        CCatalogsIncompleteMessage::NewL();
+
+    // NOTICE: Because a CObject-derived object cannot be deleted
+    //         when its reference count is not zero, we use a
+    //         cleanup-item. Another way could be to do it in the
+    //         destructor of the CObject-derived object, but
+    //         it could enable unintended destruction of the object.?
+    TCleanupItem cleanupCObjectInfo( CleanupCObjectBasedClass,
+                                 incompleteMessage );
+    CleanupStack::PushL( cleanupCObjectInfo );    
+    
+    incompleteMessage->SetMessageL( aOutputData, aStatus );
+    iIncompleteMessageContainer->AddL( incompleteMessage );
+    TInt handle = iIncompleteMessages->AddL( incompleteMessage );
+
+    CleanupStack::Pop( incompleteMessage );
+    return handle;
+    }
+
+TInt CCatalogsClientServerServerSession::WriteToLargerDesL(
+    const TDesC16& aOutputData,
+    TInt aStatus )
+    {
+    CCatalogsIncompleteMessage* incompleteMessage =
+        CCatalogsIncompleteMessage::NewL();
+
+    // NOTICE: Because a CObject-derived object cannot be deleted
+    //         when its reference count is not zero, we use a
+    //         cleanup-item. Another way could be to do it in the
+    //         destructor of the CObject-derived object, but
+    //         it could enable unintended destruction of the object.?
+    TCleanupItem cleanupCObjectInfo( CleanupCObjectBasedClass,
+                                 incompleteMessage );
+    CleanupStack::PushL( cleanupCObjectInfo );
+    
+    incompleteMessage->SetMessageL( aOutputData, aStatus );
+    iIncompleteMessageContainer->AddL( incompleteMessage );
+    TInt handle = iIncompleteMessages->AddL( incompleteMessage );
+
+    CleanupStack::Pop( incompleteMessage );
+    return handle;
+    }
+
+void CCatalogsClientServerServerSession::RemoveIncompleteMessage( TInt aHandle )
+    {
+    iIncompleteMessages->Remove( aHandle );
+    }
+
+void CCatalogsClientServerServerSession::ServiceL( const RMessage2& aMessage )
+    {
+    DLTRACEIN((""));
+    
+    // If ServiceL leaves, the framework calls ServiceError which by default
+    // completes the message with the leave code if it has not been completed
+    // yet
+    HandleMessageL( aMessage );
+    }
+
+TInt CCatalogsClientServerServerSession::AddObjectL(
+    CObject* aObject )
+    {
+    iServer.AddObjectToContainerL( aObject );
+    TInt handle( iMessageHandlers->AddL( aObject ) );
+    // Because add to the ix does not call Open() of the CObject,
+    // we have to do it ourselves
+    User::LeaveIfError( aObject->Open() );
+    return handle;
+    }
+
+void CCatalogsClientServerServerSession::RemoveObject( TInt aHandle )
+    {
+    // This closes the CObject once.
+    iMessageHandlers->Remove( aHandle );
+    }
+
+MCatalogsContext& CCatalogsClientServerServerSession::Context()
+    {
+    return *iContext;
+    }
+
+
+const MCatalogsContext* CCatalogsClientServerServerSession::ContextPtr() const
+    {
+    return iContext;
+    }
+
+
+void CCatalogsClientServerServerSession::HandleMessageL(
+    const RMessage2& aMessage )
+    {
+    DLTRACEIN(("Function: %X", aMessage.Function() ));
+
+    // NOTICE: If aMessage has to be stored and used later
+    //         then copy it and use the copy instead.
+
+    if ( iClientSideDownAnnounced == EInformed )
+        {
+        // Do not communicate to client anymore
+        // client-side session is going down
+        return;
+        }
+    else if( ( aMessage.Function() != ECatalogsCreateContext ) 
+             && ( iContext == NULL ) )
+        {
+        DLERROR(( "Completing message with KErrNotReady" ));
+        aMessage.Complete( KErrNotReady );
+        }
+
+    
+    if( aMessage.Function() == ECatalogsExternalMessage 
+        || aMessage.Function() == ECatalogsExternalAllocMessage )
+        {
+        HandleExternalMessageL( aMessage );
+        }
+    else
+        {
+        HandleInternalMessageL( aMessage );
+        }
+    DLTRACEOUT((""));
+    }
+
+void CCatalogsClientServerServerSession::HandleExternalMessageL(
+    const RMessage2& aMessage )
+    {
+    DLTRACEIN((""));
+    TPckgBuf<TInt> handle;
+    aMessage.ReadL( 1, handle );
+
+
+    CCatalogsCommunicable* receiver = ReceiverFromHandle( handle() );
+    
+    DLTRACE(("Receiver for message: %X", receiver ));
+
+    if( !receiver )
+        {
+        PanicClient( aMessage, EBadHandle );
+        return;
+        }
+    
+
+    CCatalogsBaseMessageImpl* baseMessage = 
+        CCatalogsBaseMessageImpl::NewLC( aMessage,
+                                         *this,
+                                         handle() );
+    TPckgBuf<TInt> funcNumber;
+    aMessage.ReadL( 0, funcNumber );
+        
+    CleanupStack::Pop( baseMessage );
+
+    DLTRACE(("Passing message"));
+
+    // Now the message is already passed to the receiver
+    // and it is its duty to use it to inform of possible
+    // error situations
+    //      -> Nothing is done here            
+    receiver->ReceiveMessage( baseMessage, funcNumber() );
+    
+    DLTRACEOUT(("Message passed"));    
+    }
+
+void CCatalogsClientServerServerSession::HandleInternalMessageL(
+    const RMessage2& aMessage )
+    {
+    DLTRACEIN((""));
+    switch( aMessage.Function() )
+        {
+        case ECatalogsCompleteMessage:
+            {
+            DLTRACE(("ECatalogsCompleteMessage"));
+            TPckgBuf<TInt> handle;
+            aMessage.ReadL( 1, handle );
+            
+            CCatalogsIncompleteMessage* incompleteMessage =
+                IncompleteMessageFromHandle( handle() );
+            if( !incompleteMessage )
+                {
+                PanicClient( aMessage, EBadHandle );
+                return;
+                }
+            
+            const TDesC8& message = incompleteMessage->Message();
+            TInt returnValue = incompleteMessage->ReturnValue();
+            
+            DLINFO(( "Writing message" ));
+            TRAPD( error, aMessage.WriteL( 3, message ) );                        
+            if ( error != KErrNone )
+                {
+                RemoveIncompleteMessage( handle() );
+                User::Leave( error );
+                }
+
+            DLINFO(( "Completing message with %d", returnValue ));
+            aMessage.Complete( returnValue );
+            
+            RemoveIncompleteMessage( handle() );            
+            break;
+            }
+            
+            
+        case ECatalogsCompleteMessageWide:
+            {
+            DLTRACE(("ECatalogsCompleteMessageWide"));
+            TPckgBuf<TInt> handle;
+            aMessage.ReadL( 1, handle );
+            
+            CCatalogsIncompleteMessage* incompleteMessage =
+                IncompleteMessageFromHandle( handle() );
+            if( !incompleteMessage )
+                {
+                PanicClient( aMessage, EBadHandle );
+                return;
+                }
+            
+            const TDesC16& message = incompleteMessage->MessageWide();
+            TInt returnValue = incompleteMessage->ReturnValue();
+
+            DLINFO(( "Writing message" ));
+            TRAPD( error, aMessage.WriteL( 3, message ) );
+            if ( error != KErrNone )
+                {
+                RemoveIncompleteMessage( handle() );
+                User::Leave( error );
+                }
+
+            DLINFO(( "Completing message with %d", returnValue ));
+            aMessage.Complete( returnValue );
+            RemoveIncompleteMessage( handle() );
+            break;
+            }
+                        
+        case ECatalogsRemoveIncompleteMessage:
+            {
+            DLTRACE(("ECatalogsRemoveIncompleteMessage"));
+            TPckgBuf<TInt> handle;
+            aMessage.ReadL( 1, handle );
+            RemoveIncompleteMessage( handle() );
+            DLINFO(( "Completing message with KErrNone" ));
+            aMessage.Complete( KErrNone );
+            
+            break;
+            }
+        case ECatalogsClientSideDown:
+            {
+            DLTRACE(("ECatalogsClientSideDown"));
+            ClientSideSessionDown();
+            DLINFO(( "Completing message with KErrNone" ));
+            aMessage.Complete( KErrNone );
+            break;
+            }
+
+        case ECatalogsCreateProvider:
+            {
+            DLTRACE(("Create Provider"));
+            
+            CreateProviderL( aMessage );
+            DLTRACE(("Create Provider done"));
+            break;
+            }
+
+        case ECatalogsCreateContext:
+            {
+            DLTRACE(("ECatalogsCreateContext"));
+            CreateContextL( aMessage );
+            break;
+            }
+
+        default:
+            {
+            }
+        }    
+    }
+
+void CCatalogsClientServerServerSession::CreateProviderL(
+    const RMessage2& aMessage )
+    {
+    DLTRACEIN((""));
+
+    TInt providerUid = aMessage.Int0();
+    TUint32 providerOptions = aMessage.Int2();
+    
+    // We have to have a integer which contains the handle to be
+    // able to write it into client side later.
+    TInt tempHandle( 0 );
+    
+    TRAPD( outcome,
+        iServer.CreateProviderL( 
+            *this, providerUid, tempHandle, providerOptions ) );
+    
+    // KErrNone and positive codes are a success. Cache cleaning
+    // can cause positive leaves
+    if ( outcome >= KErrNone ) 
+        {
+        DLTRACE(("Writing the provider handle to the message"));
+        TPckgBuf<TInt> handleBuf( tempHandle );
+    
+        TRAPD( err, aMessage.WriteL( 1, handleBuf ) );
+        if ( err != KErrNone )
+            {
+            DLTRACE(("Couldn't pass the handle back"));
+            // If we can't pass the handle back, there is no use
+            // to try to continue normally.
+            RemoveObject( tempHandle );
+            outcome = err;
+            }
+        }
+    DLTRACE(("Completing message with: %d", outcome ));    
+    aMessage.Complete( outcome );    
+    }
+
+
+void CCatalogsClientServerServerSession::CreateContextL(
+    const RMessage2& aMessage )
+    {
+    DLTRACEIN((""));
+    if ( iContext != NULL )
+        {
+        DLERROR(( "Completing message with KErrAlreadyExists" ));
+        aMessage.Complete( KErrAlreadyExists );
+        return;
+        }
+    
+    TInt familyIdTint = aMessage.Int0();
+    TUid familyIdUid = TUid::Uid( familyIdTint );    
+    TSecureId secureId = aMessage.SecureId();
+
+    iContext = CCatalogsContextImpl::NewL( familyIdUid, secureId, iInstanceId );
+
+    // cancel shutdown operations for this family
+    iServer.OperateShutdownOperations( Context(), EFalse );
+    
+    DLINFO(( "Completing message with KErrNone" ));
+    aMessage.Complete( KErrNone );
+    DLTRACEOUT((""));
+    }
+
+void CCatalogsClientServerServerSession::PanicClient(
+    const RMessage2& aMessage, TInt aPanic ) const
+    {
+    DLTRACEIN((""));
+    // NOTICE: KTxtCatalogsSession should not exceed 16 characters.
+    //         If it does, it will result in USER 23. So it seems
+    //         that RMEssage2::Panic does not truncate the characters
+    //         that exceed those 16 characters.
+    _LIT( KTxtCatalogsSession,"CCatalogsSession" );
+    aMessage.Panic( KTxtCatalogsSession, aPanic );
+    }
+
+CCatalogsCommunicable* 
+    CCatalogsClientServerServerSession::ReceiverFromHandle( TInt aHandle )
+    {
+    DLTRACEIN((""));
+    if ( iMessageHandlers == NULL )
+        {
+        return NULL;
+        }
+    // Normal situation
+    CCatalogsCommunicable* handler = 
+        static_cast<CCatalogsCommunicable*>( iMessageHandlers->At( aHandle ) );
+	DLTRACEOUT((""));
+    return handler;
+    }
+
+CCatalogsIncompleteMessage* 
+    CCatalogsClientServerServerSession::IncompleteMessageFromHandle( TInt aHandle )
+    {
+    DLTRACEIN((""));
+    if ( iIncompleteMessages == NULL )
+        {
+        return NULL;
+        }
+    
+    // Normal situation    
+    CCatalogsIncompleteMessage* message =
+        static_cast<CCatalogsIncompleteMessage*>( 
+            iIncompleteMessages->At( aHandle ) ); 
+    DLTRACEOUT((""));
+    return message;   
+    }
+    
+void CCatalogsClientServerServerSession::CloseMessageHandlers()
+    {
+    DLTRACEIN((""));
+    TInt communicableCount( iMessageHandlers->Count() );
+    for ( TInt index = 0; index < communicableCount; ++index )
+        {
+        CCatalogsCommunicable* handler = 
+            static_cast<CCatalogsCommunicable*>( ( *iMessageHandlers )[index] );
+        // If handlers have been removed, iMessageHandlers seem to contain
+        // null pointers in place of those removed handlers
+        if ( handler != NULL )
+            {
+            handler->CounterPartLost( *this );
+            }
+        }
+        
+    // Deletion closes all referenced objects once
+    delete iMessageHandlers;
+    iMessageHandlers = NULL;
+
+    DLTRACEOUT((""));
+    }