ncdengine/provider/server/src/ncdsubscriptionoperationimpl.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdsubscriptionoperationimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1047 @@
+/*
+* 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:  
+*
+*/
+
+
+#include <s32mem.h>
+#include <apmstd.h>
+
+#include "ncdsubscriptionoperationimpl.h"
+#include "catalogsbasemessage.h"
+#include "catalogshttpincludes.h"
+#include "ncdsubscriptionmanagerimpl.h"
+#include "catalogsutils.h"
+#include "catalogscontext.h"
+#include "ncdproviderdefines.h"
+#include "ncddescriptordownloadsuboperation.h"
+#include "ncdrequestmanagesubscriptions.h"
+#include "ncdrequestgenerator.h"
+#include "ncdrequestconfigurationdata.h"
+#include "ncdprotocol.h"
+#include "ncdparser.h"
+#include "ncdprotocoldefaultobserver.h"
+#include "ncd_pp_error.h"
+#include "ncd_pp_subscription.h"
+#include "ncdsubscriptionimpl.h"
+#include "ncdpurchaseoperationimpl.h"
+#include "ncdsubscriptiongroup.h"
+#include "ncdnodeidentifier.h"
+#include "ncdserverdetails.h"
+#include "ncdconfigurationmanager.h"
+#include "ncdcapabilities.h"
+#include "ncderrors.h"
+#include "ncdsessionhandler.h"
+#include "ncdproviderutils.h"
+#include "ncdhttputils.h"
+#include "ncdgeneralmanager.h"
+
+#include "catalogsdebug.h"
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation* CNcdSubscriptionOperation::NewL( 
+    MNcdSubscriptionOperation::TType aSubscriptionOperationType,   
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,        
+    MCatalogsHttpSession& aHttpSession,    
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    {
+    CNcdSubscriptionOperation* self = CNcdSubscriptionOperation::NewLC(
+        aSubscriptionOperationType,
+        aGeneralManager,
+        aSubscriptionManager,
+        aHttpSession,
+        aRemoveHandler,
+        aSession );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// NewLC
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation* CNcdSubscriptionOperation::NewLC( 
+    MNcdSubscriptionOperation::TType aSubscriptionOperationType,
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    {
+    CNcdSubscriptionOperation* self =
+        new( ELeave ) CNcdSubscriptionOperation( 
+            aSubscriptionOperationType,
+            aGeneralManager,
+            aSubscriptionManager,
+            aHttpSession,
+            aRemoveHandler,
+            aSession );
+    CleanupClosePushL( *self );
+    self->ConstructL( NULL, KNullDesC, KNullDesC, KNullDesC, KNullDesC );
+    return self;
+    }
+    
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation* CNcdSubscriptionOperation::NewL(
+    MNcdSubscriptionOperation::TType aSubscriptionOperationType,
+    const TDesC& aPurchaseOptionId,
+    const TDesC& aEntityId,
+    const TDesC& aNamespace,
+    const TDesC& aServerUri,
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    {
+    CNcdSubscriptionOperation* self = CNcdSubscriptionOperation::NewLC(
+        aSubscriptionOperationType,
+        aPurchaseOptionId,
+        aEntityId,
+        aNamespace,
+        aServerUri,
+        aGeneralManager,
+        aSubscriptionManager,
+        aHttpSession,
+        aRemoveHandler,
+        aSession );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// NewLC
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation* CNcdSubscriptionOperation::NewLC(
+    MNcdSubscriptionOperation::TType aSubscriptionOperationType,
+    const TDesC& aPurchaseOptionId,
+    const TDesC& aEntityId,
+    const TDesC& aNamespace,
+    const TDesC& aServerUri,
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    {
+    CNcdSubscriptionOperation* self =
+        new( ELeave ) CNcdSubscriptionOperation( 
+            aSubscriptionOperationType,
+            aGeneralManager,
+            aSubscriptionManager,
+            aHttpSession,
+            aRemoveHandler,
+            aSession );
+    CleanupClosePushL( *self );
+    self->ConstructL(
+        NULL,
+        aPurchaseOptionId,
+        aEntityId,
+        aNamespace,
+        aServerUri );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation::~CNcdSubscriptionOperation()
+    {
+    DLTRACEIN((""));    
+
+    DLTRACE(("Closing suboperations"));
+    // Close operations
+    for ( TInt i = 0; i < iSubOps.Count(); i++ )
+        {
+        iSubOps[i]->Close();        
+        }
+                
+    DLTRACE(("Suboperations closed"));
+    iSubOps.Reset();
+    iFailedSubOps.Reset();
+    iCompletedSubOps.Reset();
+
+    if ( iTransaction )
+        {
+        iTransaction->Release();
+        iTransaction = NULL;
+        }
+
+    iServersSubscriptions.ResetAndDestroy();
+
+    delete iSource;
+    delete iPurchaseOptionId;
+    delete iEntityId;
+    delete iNamespace;
+    delete iServerUri;
+
+    delete iParser;
+
+    DLTRACEOUT((""));
+    }
+
+
+TInt CNcdSubscriptionOperation::RunOperation()
+    {
+    DLTRACEIN(( "Pending message: %X", iPendingMessage ));
+
+    // Cannot determine from iOperationState whether we are
+    // just starting this operation or continuing it after
+    // for example expiration info has been handled.
+    // This is because iOperationState will be EStateRunning
+    // In both cases. This is why we use our own internal
+    // variable.
+    if ( iSubscriptionOperationState == EBegin )
+        {
+        // Operation is being started and we come here for
+        // the first time
+        iSubscriptionOperationState = ERunning;
+        }
+    else if ( iSubscriptionOperationState == EComplete )
+        {
+        // It is possible that the operation has completed while we have
+        // been processing for example expired nodes. So we send completion
+        // message immediately.
+        if ( iPendingMessage )
+            {
+            return CompletePendingMessage();
+            }
+        return KErrGeneral;
+        }    
+    else if ( iSubscriptionOperationState == EHandlingQueries ) 
+        {
+        DLTRACE(("Queries handled"));
+        SubscriptionOperationComplete( iError );        
+        }
+    else
+        {
+        // We don't want to start the operation again as it
+        // is already running. Something should eventually trigger
+        // completion of iMessage
+        return KErrNone;
+        }
+
+    TRAPD( err,
+        {
+        switch ( iSubscriptionOperationType ) 
+            {
+            case MNcdSubscriptionOperation::EUnsubscribe:
+                RunUnsubscribeOperationL();
+                break;
+            case MNcdSubscriptionOperation::ERefreshSubscriptions:
+                RunRefreshOperationL();
+                break;
+            default:            
+                User::Leave( KErrNotSupported );
+                break;
+            }
+        } );
+
+    if ( err != KErrNone )
+        {
+        SubscriptionOperationComplete( err );
+        }
+
+    DLTRACEOUT(("err: %d", err));
+    return err;
+    }
+
+void CNcdSubscriptionOperation::Cancel()
+    {
+    DLTRACEIN( ( "" ) );
+
+    if ( iTransaction )
+        {
+        iTransaction->Cancel();
+        iTransaction = NULL;
+        }
+    if ( iParser )
+        {
+        iParser->CancelParsing();
+        //delete iParser;
+        //iParser = NULL;
+        }
+        
+    CancelSuboperations();            
+
+    DLTRACEOUT(( "" ));
+    }
+    
+
+TBool CNcdSubscriptionOperation::QueryCompletedL( CNcdQuery* /* aQuery */ )
+    {
+    DLTRACEIN((""));
+    return EFalse;
+    }
+    
+
+void CNcdSubscriptionOperation::HandleHttpEventL( 
+        MCatalogsHttpOperation& aOperation, 
+        TCatalogsHttpEvent aEvent )
+    {
+    DLTRACEIN((""));
+    DASSERT( &aOperation == iTransaction );
+    DASSERT( aOperation.OperationType() == ECatalogsHttpTransaction );
+
+    TCatalogsTransportProgress progress( iTransaction->Progress() );
+    
+    switch( aEvent.iOperationState ) 
+        {
+        // Handle completed operation
+        case ECatalogsHttpOpCompleted:
+            {
+            // Inform parser that no more data will be sent
+            iParser->EndL();
+            break;
+            }        
+        // Handle operation in progress
+        case ECatalogsHttpOpInProgress:
+            {
+            if( aEvent.iProgressState == ECatalogsHttpResponseBodyReceived )
+                {
+                // send received data to parser
+                iParser->ParseL( aOperation.Body() );
+                }      
+            break;
+            }
+                    
+        default:
+            {
+            break;
+            }
+        }
+        
+    DLTRACEOUT((""));    
+    }
+
+TBool CNcdSubscriptionOperation::HandleHttpError(
+        MCatalogsHttpOperation& aOperation,
+        TCatalogsHttpError aError )
+    {
+    DLTRACEIN(("Error type: %d, code: %d", aError.iType, aError.iError ));    
+    
+    DASSERT( &aOperation == iTransaction );
+    
+    aOperation.Release();
+    iTransaction = NULL;
+
+    SubscriptionOperationComplete( aError.iError );
+        
+    DLTRACEOUT((""));
+    return ETrue;
+    }
+
+void CNcdSubscriptionOperation::ParseError( TInt aErrorCode )
+    {
+    DLTRACEIN(("error:%d", aErrorCode ));
+
+    // Handle error only if operation is not completed already
+    // (cancellation of parsing may cause an unnecessary call to this function).
+    if ( iSubscriptionOperationState != EComplete )
+        {
+            if ( iTransaction )
+            {
+            iTransaction->Cancel();        
+            iTransaction = NULL;
+            }
+
+        SubscriptionOperationComplete( aErrorCode );
+
+        }
+    
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::ParseCompleteL( TInt aError )
+    {
+    DLTRACEIN((_L("error:%d"), aError ));
+
+    if ( iParser )
+        {
+        delete iParser;
+        iParser = NULL;
+        }
+
+    // HandleQuerysL will continue the operation in RunOperation
+    iSubscriptionOperationState = EHandlingQueries;
+    iError = aError;
+    HandleQuerysL();
+
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::ValidSubscriptionL(
+    MNcdPreminetProtocolSubscription* aData )
+    {
+    DLTRACEIN((""));
+
+    iServersSubscriptions.AppendL( aData );
+
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::OldSubscriptionL(
+    MNcdPreminetProtocolSubscription* aData )
+    {
+    DLTRACEIN((""));
+
+    iServersSubscriptions.AppendL( aData );
+
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdSubscriptionOperation::Progress( CNcdBaseOperation& /*aOperation*/ )
+    {
+    DLTRACEIN((""));
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::QueryReceived( CNcdBaseOperation& /*aOperation*/,
+                                CNcdQuery* /*aQuery*/ )
+    {
+    DLTRACEIN((""));
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::OperationComplete(
+    CNcdBaseOperation* aOperation,
+    TInt aError )
+    {
+    DLTRACEIN(("error=%d", aError));
+
+    if ( iSubscriptionOperationType == MNcdSubscriptionOperation::EUnsubscribe )
+        {
+        SubscriptionOperationComplete( aError );
+        }
+    else if ( iSubscriptionOperationType ==
+        MNcdSubscriptionOperation::ERefreshSubscriptions )
+        {
+        DLINFO(("Refresh subscription op complete."));
+        
+        TRAPD( err,
+            {
+            CNcdSubscriptionOperation* subOp =
+                static_cast<CNcdSubscriptionOperation*>( aOperation );
+                
+            if ( aError != KErrNone )
+                {
+                DLINFO(("Refresh sub operation failed."));
+                iFailedSubOps.AppendL( subOp );
+                if ( iCompletionErrorCode == KErrNone )
+                    {
+                    iCompletionErrorCode = aError;
+                    }
+                }
+            else
+                {
+                DLINFO(("Refresh sub operation successfull."));
+                iCompletedSubOps.AppendL( subOp );
+                }
+            } ); //TRAPD
+
+        if ( err != KErrNone )
+            {
+            DLERROR(("Internal subscription operation error"));
+            SubscriptionOperationComplete( err );
+            }
+        else if ( iFailedSubOps.Count() + iCompletedSubOps.Count() ==
+            iSubOps.Count() )
+            {
+            // All sub operations completed, the operation is complete.
+            if ( iFailedSubOps.Count() && iCompletedSubOps.Count() )
+                {
+                // Some suboperations has failed, but not all.
+                SubscriptionOperationComplete( KNcdErrorSomeSubscriptionsFailedToUpdate );
+                }
+            else if ( iFailedSubOps.Count() )
+                {
+                // All suboperations has failed.
+                SubscriptionOperationComplete( iCompletionErrorCode );
+                }
+            else
+                {                
+                SubscriptionOperationComplete( KErrNone );
+                }
+            }
+        }
+
+    DLTRACEOUT((""));
+    }
+
+void CNcdSubscriptionOperation::ErrorL( MNcdPreminetProtocolError* aData )
+    {
+    DLTRACEIN((""));
+
+    CleanupDeletePushL( aData );
+
+    // Map error codes to correct enumeration values.
+    switch ( aData->Code() ) 
+        {
+        case 404:
+            {
+            iError = KNcdErrorNotFound;
+            DASSERT( iSubscription );
+            if ( iSubscription )
+                {
+                RemoveSubscriptionL( *iSubscription );
+                iSubscription = NULL;
+                }                        
+            break;
+            }
+        case 416:
+            {
+            DLTRACE(("session expired"));
+            Cancel();
+            
+            switch ( iSubscriptionOperationType ) 
+                {
+                case MNcdSubscriptionOperation::EUnsubscribe:
+                    {
+                    iProtocol.SessionHandlerL( iSession.Context() ).
+                        RemoveSession( *iServerUri, *iNamespace );
+                    break;
+                    }
+                case MNcdSubscriptionOperation::ERefreshSubscriptions:
+                    {
+                    iProtocol.SessionHandlerL( iSession.Context() ).
+                        RemoveSession( iSource->Uri(), iSource->Namespace() );
+                    break;
+                    }                    
+                default:            
+                    DASSERT(0);
+                    break;
+                }
+            
+            DLINFO(("Start operation from the beginning"));            
+            // continue operation asynchronously to prevent problems with parser
+            ContinueOperationL();
+            break;
+            }
+        case 426:
+            iError = KNcdErrorSubscriptionPaymentAlreadyDone;
+            break;
+        case 427:
+            iError = KNcdErrorSubscriptionNotSubscribed;
+            DASSERT( iSubscription );
+            if ( iSubscription )
+                {
+                RemoveSubscriptionL( *iSubscription );
+                iSubscription = NULL;
+                }  
+            break;
+        case 428:
+            iError = KNcdErrorSubscriptionInvalid;
+            DASSERT( iSubscription );
+            if ( iSubscription )
+                {
+                RemoveSubscriptionL( *iSubscription );
+                iSubscription = NULL;
+                }  
+            break;
+        case 429:
+            iError = KNcdErrorSubscriptionNotEnoughCredits;
+            break;
+        default:
+            iError = KNcdProtocolErrorBase - aData->Code();
+            break;
+        }
+
+    //CNcdBaseOperation::ErrorL( aData );        
+
+    // Default observer deletes the data.
+    CleanupStack::Pop( aData );
+
+    iParser->DefaultObserver().ErrorL( aData );
+    
+    if( iError != KErrNone )
+        {
+        SubscriptionOperationComplete( iError );
+        }    
+
+    DLTRACEOUT((""));
+    }
+    
+void CNcdSubscriptionOperation::SubscriptionsInternalizeComplete(
+    TInt /*aError*/ )
+    {
+    DLTRACEIN((""));
+    
+    // call observers
+    DLINFO(("Calling observers."));
+    for ( TInt i = 0 ; i < iObservers.Count() ; i++ )
+        {
+        DLINFO(("Calling observer: %d .", i ));
+        iObservers[i]->OperationComplete( this, KErrNone );
+        }
+    }
+
+CNcdSubscriptionOperation* CNcdSubscriptionOperation::CreateSubOperationLC(
+    CNcdSubscriptionsSourceIdentifier* aSource,
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,    
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    {
+    CNcdSubscriptionOperation* self =
+        new( ELeave ) CNcdSubscriptionOperation( 
+            MNcdSubscriptionOperation::ERefreshSubscriptions,
+            aGeneralManager,
+            aSubscriptionManager,
+            aHttpSession,
+            aRemoveHandler,
+            aSession );
+    CleanupClosePushL( *self );
+    self->ConstructL( aSource, KNullDesC, KNullDesC, KNullDesC, KNullDesC );
+    return self;
+    }
+
+void CNcdSubscriptionOperation::RunRefreshOperationL()
+    {
+    DLTRACEIN((""));
+
+    if ( iSource )
+        {
+        DLTRACE(( "Sub operation" ));
+        // This is a sub operation. Send request to the given source.
+
+        CNcdRequestManageSubscriptions* request =
+            NcdRequestGenerator::CreateManageSubscriptionsRequestLC();
+
+        // Set namespace from the source.
+        request->SetNamespaceL( iSource->Namespace() );
+
+        MCatalogsContext& context( iSession.Context() );
+
+        HBufC8* data =
+            iProtocol.ProcessPreminetRequestL(
+                context,
+                *request,
+                iSource->Uri() );
+
+        CleanupStack::PopAndDestroy( request );
+        CleanupStack::PushL( data );
+
+        // create transaction
+        iGeneralManager.HttpUtils().CreateTransactionL(
+            iHttpSession,
+            iTransaction,
+            iSource->Uri(),
+            *this,
+            *data,
+            iSource->Namespace(),
+            MCatalogsAccessPointManager::EBrowse,
+            iClientUid );
+        
+        CleanupStack::PopAndDestroy( data );
+        
+        // create parser  
+        delete iParser;
+        iParser = NULL;
+        iParser = iProtocol.CreateParserL( context, iSource->Uri() );
+
+        // Set observers
+        MNcdParserObserverBundle& observers = iParser->Observers();
+        observers.SetParserObserver( this );
+        observers.SetSubscriptionObserver( this );
+        observers.SetInformationObserver( this );
+        observers.SetErrorObserver( this );
+
+        iParser->BeginAsyncL();
+
+        // start transaction
+        User::LeaveIfError( iTransaction->Start() );
+        }
+    else
+        {
+        DLTRACE(( "Main operation" ));
+        // This is the main operation. Sub operations are started
+        // from here.
+
+        // Get sources for sub operations.
+        RPointerArray<CNcdSubscriptionsSourceIdentifier> sources =
+            iSubscriptionManager.SubscriptionsSourcesL(
+                iClientUid );
+        CleanupResetAndDestroyPushL( sources );
+        
+        TInt count = sources.Count();
+        
+        DLTRACE(( "Source count: %d", count ));
+        
+        if ( count == 0 )
+            {
+            // No sources found.
+            CleanupStack::PopAndDestroy( &sources );
+            
+            SubscriptionOperationComplete( KErrNone );
+
+            DLTRACEOUT((""));
+            return;
+            }
+
+        // Start all sub operations.
+        for ( TInt i = 0; i < count; i++ )
+            {
+            DLTRACE(( _L("Source URI: %S"), &sources[0]->Uri() ));
+            DLTRACE(( _L("Source namespace: %S"), &sources[0]->Namespace() ));
+
+            const MCatalogsContext& context( iSession.Context() );
+            MNcdServerDetails& serverDetails =
+                iConfigurationManager.ServerDetailsL(
+                    context,
+                    sources[0]->Uri(),
+                    sources[0]->Namespace() );
+
+            // Capabilities are checked only if it is required
+            if ( sources[0]->RequiresCapabilityCheck() &&
+                     serverDetails.IsCapabilitySupported(
+                         NcdCapabilities::KSubscriptions )
+                 || !sources[0]->RequiresCapabilityCheck() )
+                {
+                DLTRACE(( "This source supports subscriptions!" ));
+                DLINFO(( "Capability check was required: %d",
+                         sources[0]->RequiresCapabilityCheck() ));
+
+                CNcdSubscriptionOperation* subOp =
+                    CNcdSubscriptionOperation::CreateSubOperationLC(
+                        sources[0],
+                        iGeneralManager,
+                        iSubscriptionManager,
+                        iHttpSession,
+                        *iRemoveHandler,
+                        iSession );
+                // CreateSubOperationLC takes the ownership of the first
+                // object in the sources array. Remove it from sources.
+                sources.Remove( 0 );
+                subOp->AddObserverL( this );
+                User::LeaveIfError( subOp->Start() );
+                DLTRACE(( "Sub operation started!" ));
+                iSubOps.AppendL( subOp );
+                CleanupStack::Pop( subOp );
+                }
+            else
+                {
+                DLTRACE(( "This source does not support subscriptions!" ));
+
+                // Do not use this source.
+                sources.Remove( 0 );
+                }
+            }
+
+        CleanupStack::PopAndDestroy( &sources );
+
+        // Any sub operations started
+        if ( iSubOps.Count() == 0 )
+            {
+            DLTRACE(( "None of the sources did not support subscriptions!" ));
+            SubscriptionOperationComplete( KErrNone );
+            }
+        }
+
+    DLTRACEOUT((""));
+    }
+    
+    
+void CNcdSubscriptionOperation::RunUnsubscribeOperationL()
+    {
+    DLTRACEIN((""));
+
+    CNcdRequestManageSubscriptions* request =
+        NcdRequestGenerator::CreateManageSubscriptionsRequestLC();
+
+    request->SetNamespaceL( *iNamespace );
+    request->AddSubscriptionL(
+        *iEntityId,
+        *iPurchaseOptionId,
+        EUnsubscribe );
+
+    MCatalogsContext& context( iSession.Context() );
+
+    HBufC8* data =
+        iProtocol.ProcessPreminetRequestL(
+            context,
+            *request,
+            *iServerUri );
+
+    CleanupStack::PopAndDestroy( request );
+    CleanupStack::PushL( data );
+
+    // create transaction
+    iGeneralManager.HttpUtils().CreateTransactionL(
+        iHttpSession,
+        iTransaction,
+        *iServerUri,
+        *this,
+        *data,
+        *iNamespace,
+        MCatalogsAccessPointManager::EBrowse,
+        iClientUid );
+        
+    CleanupStack::PopAndDestroy( data );
+            
+    // create parser  
+    delete iParser;
+    iParser = NULL;
+    iParser = iProtocol.CreateParserL( context, *iServerUri );
+
+    // Set observers
+    MNcdParserObserverBundle& observers = iParser->Observers();
+    observers.SetParserObserver( this );
+    observers.SetSubscriptionObserver( this );
+    observers.SetInformationObserver( this );
+    observers.SetErrorObserver( this );
+
+    iParser->BeginAsyncL();
+
+    // start transaction
+    User::LeaveIfError( iTransaction->Start() );
+
+    DLTRACEOUT((""));
+    }
+
+TInt CNcdSubscriptionOperation::SubscriptionOperationComplete( TInt aError )
+    {
+    DLTRACEIN((""));
+
+    // iSubscriptionOperationState is used in RunOperation to determine
+    // whether this operation has already completed (this function has been
+    // called).
+    // We should complete incoming message in RunOperation if it was not
+    // available in this function.
+    
+    // Notice that we cannot automatically set iOperationState to be
+    // EStateComplete as iOperationState is used when we receive
+    // continue message. State EStateComplete would produce an error in that
+    // case because it means that we are not waiting any messages anymore.
+    // This is why we have to use two state variables to inform of completion.
+    
+    iSubscriptionOperationState = EComplete;
+
+    // Also given error code has to be stored if iPendingMessage is not
+    // currently available    
+    iCompletionErrorCode = aError; 
+
+
+    if ( aError != KErrNone )
+        {
+        DLTRACE((_L("->Operation failed")));
+        // Operation failed, send error message.
+        Cancel();
+        if ( iPendingMessage )
+            {
+            CompletePendingMessage();
+            }
+        // call observers
+        for ( TInt i = 0 ; i < iObservers.Count() ; i++ )
+            {
+            iObservers[i]->OperationComplete( this, aError );
+            }
+        }
+    else
+        {
+        DLTRACE((_L("->Operation complete")));
+        // Operation has completed.
+
+        if ( iPendingMessage )
+            {
+            TInt err = CompletePendingMessage();
+            if ( err != KErrNone )
+                {
+                // call observers
+                for ( TInt i = 0 ; i < iObservers.Count() ; i++ )
+                    {
+                    iObservers[i]->OperationComplete( this, aError );
+                    }
+                return err;
+                }
+            }
+        
+        TInt err = KErrNone;
+        if ( iSource && iSubscriptionOperationType ==
+            MNcdSubscriptionOperation::ERefreshSubscriptions )
+            {
+            TRAP_IGNORE(
+                {
+                iSubscriptionManager.InternalizeSubscriptionsFromServerL(
+                    iClientUid,
+                    iSource->Uri(),
+                    iServersSubscriptions,
+                    &iSession.Context(),
+                    this );
+                } );
+                
+            // Do not call operation complete here if this is
+            // suboperation. Instead do it after internalize in
+            // SubscriptionsInternalizeComplete()
+            DLTRACEOUT((""));
+            return KErrNone;
+            }
+            
+        // call observers
+        DLINFO(("Calling observers."));
+        for ( TInt i = 0 ; i < iObservers.Count() ; i++ )
+            {
+            DLINFO(("Calling observer: %d .", i ));
+            iObservers[i]->OperationComplete( this, err );
+            }
+        }
+
+    DLTRACEOUT((""));
+    return KErrNone;
+    }
+
+TInt CNcdSubscriptionOperation::CompletePendingMessage()
+    {
+    DASSERT( iPendingMessage );
+    DLTRACEIN(( "Pending message: %X", iPendingMessage ));
+    
+    TInt err( 0 );
+    if ( iCompletionErrorCode != KErrNone )
+        {
+        err = CNcdBaseOperation::CompleteMessage(
+                       iPendingMessage,
+                       ENCDOperationMessageCompletionError,
+                       iCompletionErrorCode );
+        }
+    else
+        {
+        err = CNcdBaseOperation::CompleteMessage( iPendingMessage,
+            ENCDOperationMessageCompletionComplete,
+            iProgress,
+            KErrNone );
+        }            
+    // iPendingMessage = NULL set by CompleteMessage
+      
+    // Is this ok?
+    iOperationState = EStateComplete;
+    
+    return err;
+    }
+    
+void CNcdSubscriptionOperation::RemoveSubscriptionL(
+    const CNcdSubscription& aSubscription ) 
+    {
+    CNcdNodeIdentifier* nodeId = CNcdNodeIdentifier::NewLC(
+        aSubscription.ParentGroup().Namespace(),
+        aSubscription.ParentGroup().EntityId(), iClientUid );
+    iSubscriptionManager.RemoveSubscriptionL(
+        *nodeId, aSubscription.PurchaseOptionId() );
+    CleanupStack::PopAndDestroy( nodeId );
+    }
+    
+
+
+void CNcdSubscriptionOperation::ChangeToPreviousStateL()
+    {
+    DLTRACEIN((""));
+    // Nothing to do. This is needed for query handling, ResendRequestL uses this
+    }
+    
+void CNcdSubscriptionOperation::CancelSuboperations()
+    {
+    DLTRACEIN((""));
+    
+    for ( TInt i = 0; i < iSubOps.Count(); i++ )
+        {
+        CNcdSubscriptionOperation* operation = iSubOps[ i ];
+        if ( iCompletedSubOps.Find( operation ) == KErrNotFound &&
+             iFailedSubOps.Find( operation ) == KErrNotFound )
+            {
+            DLINFO(("operation not completed yet, cancel it"));
+            operation->Cancel();
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CNcdSubscriptionOperation::CNcdSubscriptionOperation(
+    MNcdSubscriptionOperation::TType aSubscriptionOperationType,
+    CNcdGeneralManager& aGeneralManager,
+    CNcdSubscriptionManager& aSubscriptionManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler& aRemoveHandler,
+    MCatalogsSession& aSession )
+    :
+    CNcdBaseOperation( aGeneralManager, &aRemoveHandler, ESubscriptionOperation, aSession ),
+    iSubscriptionOperationState( EBegin ),
+    iSubscriptionOperationType( aSubscriptionOperationType ),
+    iAccessPointManager( aGeneralManager.AccessPointManager() ),
+    iSubscriptionManager( aSubscriptionManager ),
+    iNodeManager( aGeneralManager.NodeManager() ),
+    iConfigurationManager( aGeneralManager.ConfigurationManager() ),
+    iHttpSession( aHttpSession ),
+    iProtocol( aGeneralManager.ProtocolManager() ),
+    iCompletionErrorCode( KErrNone )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------------------------
+//
+void CNcdSubscriptionOperation::ConstructL(
+    CNcdSubscriptionsSourceIdentifier* aSource,
+    const TDesC& aPurchaseOptionId,
+    const TDesC& aEntityId,
+    const TDesC& aNamespace,
+    const TDesC& aServerUri )
+
+    {
+    DLTRACEIN(("aSource=%08x", aSource));
+
+    // Call ConstructL for the base class
+    CNcdBaseOperation::ConstructL();
+
+    iSource = aSource;
+    iPurchaseOptionId = aPurchaseOptionId.AllocL();
+    iEntityId = aEntityId.AllocL();
+    iNamespace = aNamespace.AllocL();
+    iServerUri = aServerUri.AllocL();
+    
+    iClientUid = iSession.Context().FamilyId();
+
+    if ( iPurchaseOptionId->Length() > 0 &&
+        iEntityId->Length() > 0 &&
+        iNamespace->Length() > 0 )
+        {
+        iSubscription = &iSubscriptionManager.SubscriptionL(
+            *iEntityId,
+            *iNamespace,
+            *iPurchaseOptionId,
+            iClientUid );
+        }
+
+    DLTRACEOUT((""));
+    }