--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/client/src/ncdbaseoperationproxy.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,770 @@
+/*
+* 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 "ncdbaseoperationproxy.h"
+#include "ncdoperationfunctionids.h"
+#include "ncdsendableprogress.h"
+#include "ncdsendable.h"
+#include "catalogsclientserver.h"
+#include "ncdoperationproxyremovehandler.h"
+#include "ncdnode.h"
+#include "ncdnodeproxy.h"
+#include "ncdqueryimpl.h"
+#include "catalogsconstants.h"
+#include "catalogsutils.h"
+#include "ncdnodemanagerproxy.h"
+#include "ncdnodeidentifier.h"
+#include "ncdexpirednode.h"
+#include "ncdutils.h"
+#include "ncdpurchasehistory.h"
+#include "ncdnodemetadataproxy.h"
+#include "ncdproviderproxy.h"
+#include "ncdpanics.h"
+#include "catalogsdebug.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+
+MNcdOperation::TState CNcdBaseOperationProxy::DoOperationStateL() const
+ {
+ return iState;
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::DoStartOperationL()
+ {
+ DLTRACEIN((""));
+
+ if ( iState == MNcdOperation::EStateCancelled )
+ {
+ User::Leave( KErrCancel );
+ }
+
+ if ( iState != MNcdOperation::EStateStopped )
+ {
+ DLTRACE(("Already running"));
+ // Operation is already running.
+ //User::Leave( KErrInUse );
+ return;
+ }
+
+ InitBuffersL( 0, 0 );
+
+ ClientServerSession().SendAsyncAlloc( ENCDOperationFunctionStart,
+ SendBuf8L(),
+ iReceiveBuffer,
+ Handle(),
+ iStatus,
+ 0 );
+ DLTRACE(("Setting active"));
+ SetActive();
+ DASSERT( iStatus.Int() == KRequestPending );
+ SetState( MNcdOperation::EStateRunning );
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::DoCancelOperation()
+ {
+ DLTRACEIN((""));
+ if ( iState != MNcdOperation::EStateCancelled &&
+ iState != MNcdOperation::EStateComplete )
+ {
+ DLTRACE(("Sending cancel message to server"));
+
+ Cancel();
+
+ // Send cancel message to server-side
+ TInt tmpNum( 0 );
+ ClientServerSession().
+ SendSync( ENCDOperationFunctionCancel,
+ KNullDesC8(),
+ tmpNum,
+ Handle() );
+ iState = MNcdOperation::EStateCancelled;
+
+
+ DLTRACE(("Calling complete callback with KErrCancel"));
+ CompleteCallback( KErrCancel );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TNcdProgress CNcdBaseOperationProxy::DoProgress() const
+ {
+ DLTRACEIN((""));
+ TNcdProgress progress( iProgress.iProgress,
+ iProgress.iMaxProgress );
+ return progress;
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// Completes a query
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::DoCompleteQueryL( MNcdQuery& aQuery )
+ {
+ DLTRACEIN((""));
+ DASSERT( static_cast<CNcdQuery&>(aQuery).Id() == iQuery->Id() );
+ (void)aQuery; // to suppress compiler warning
+ delete iSendBuffer;
+ iSendBuffer = NULL;
+ iSendBuffer = CBufFlat::NewL( KBufExpandSize );
+ RBufWriteStream stream( *iSendBuffer );
+ CleanupClosePushL( stream );
+ iQuery->ExternalizeL( stream );
+ iQuery->InternalRelease();
+ iQuery = NULL;
+ iSendPtr.Set(iSendBuffer->Ptr( 0 ) );
+ DLINFO(("buf length= %d", iSendPtr.Length()));
+
+ delete iReceiveBuffer;
+ iReceiveBuffer = NULL;
+
+ ClientServerSession().SendAsyncAlloc( ENCDOperationFunctionQueryResponse,
+ iSendPtr,
+ iReceiveBuffer,
+ Handle(),
+ iStatus,
+ 0 );
+ CleanupStack::PopAndDestroy( &stream );
+ SetActive();
+
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdOperation
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+MNcdNode* CNcdBaseOperationProxy::DoNode()
+ {
+ if ( iNode )
+ {
+ // Increase the reference counter for the node if it exists.
+ iNode->AddRef();
+ }
+
+ return iNode;
+ }
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdBaseOperationProxy::CNcdBaseOperationProxy(
+ MNcdClientLocalizer* aLocalizer ):
+ iSendPtr( NULL, 0),
+ iStringLocalizer( aLocalizer )
+ {
+
+ DLTRACEIN((""));
+ }
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::ConstructL( MCatalogsClientServer& aSession,
+ TInt aHandle,
+ MNcdOperationProxyRemoveHandler* aRemoveHandler,
+ CNcdNodeProxy* aNode,
+ CNcdNodeManagerProxy* aNodeManager )
+ {
+ DLTRACEIN((""));
+ iSession = &aSession;
+ iHandle = aHandle;
+ iRemoveHandler = aRemoveHandler;
+ iNode = aNode;
+ iNodeManager = aNodeManager;
+
+ if ( iNode != NULL )
+ {
+ // Because we own the node for a while, increase the internal
+ // reference counter by one to be sure that is will be alive
+ iNode->InternalAddRef();
+ }
+
+ // Because this is an active object, we need to inform
+ // scheduler about it.
+ CActiveScheduler::Add( this );
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CNcdBaseOperationProxy::~CNcdBaseOperationProxy()
+ {
+ DLTRACEIN((""));
+
+ Cancel();
+
+ // Release the server-side operation
+ SendReleaseMessage();
+
+ delete iReceiveBuffer;
+ delete iSendBuffer;
+ delete iSendHeapBuf8;
+
+ if ( iNode != NULL )
+ {
+ iNode->InternalRelease();
+ }
+
+ if ( iQuery != NULL )
+ {
+ iQuery->InternalRelease();
+ }
+
+ iNodeManager = NULL;
+
+ // NOTE: Operation classes MUST remove themselves from
+ // the operation manager through the RemoveHandler
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::HandleCompletedMessage(
+ TNcdOperationMessageCompletionId aCompletionId,
+ RReadStream& aReadStream,
+ TInt aDataLength )
+ {
+ DLTRACEIN((_L("aCompletionId =%d, aDataLength =%d"), aCompletionId,
+ aDataLength));
+
+ TRAPD(err,
+ CleanupClosePushL( aReadStream );
+ switch ( aCompletionId )
+ {
+ case ENCDOperationMessageCompletionProgress:
+ {
+ DLTRACE(("Completion progress"));
+ // Read progress info
+ iProgress.InternalizeL( aReadStream );
+
+
+ // Progress callback is last so that the op is resumed
+ // as soon as possible
+ ProgressCallback();
+
+ SendContinueMessageL();
+ break;
+ }
+ case ENCDOperationMessageCompletionQuery:
+ {
+ DLTRACE(("Completion query"));
+ // A call to complete query is needed after this to
+ // continue operation.
+ iState = MNcdOperation::EStateQuery;
+ DASSERT( ! iQuery );
+ iQuery = CNcdQuery::NewL( aReadStream );
+ iQuery->SetClientLocalizer( iStringLocalizer );
+ if( iQuery->MessageTitle() == KNullDesC &&
+ iQuery->MessageBody() == KNullDesC &&
+ iQuery->ItemCount() < 1 )
+ {
+ DLTRACE(("No localizations for query without items, don't show"));
+ iQuery->SetResponseL( MNcdQuery::EAccepted );
+ DoCompleteQueryL( *iQuery );
+ }
+ else
+ {
+ QueryReceivedCallback( iQuery );
+ }
+ break;
+ }
+ case ENCDOperationMessageCompletionError:
+ {
+ DLTRACE(("Completion error: %d", iStatus.Int() ));
+ iState = MNcdOperation::EStateComplete;
+ CompleteCallback( iStatus.Int() );
+ break;
+ }
+ case ENCDOperationMessageCompletionComplete:
+ {
+ DLTRACE(("Completion complete"));
+ iState = MNcdOperation::EStateComplete;
+ CompleteCallback( KErrNone );
+ break;
+ }
+
+ case ENCDOperationMessageCompletionInit:
+ {
+ DLTRACE(("Completion init"));
+ iState = MNcdOperation::EStateStopped;
+ InitializationCallback( aReadStream, aDataLength );
+ break;
+ }
+
+ case ENCDOperationMessageCompletionExpirationInfo:
+ {
+ DLTRACE(("ENCDOperationMessageCompletionExpirationInfo"));
+ TInt nodeCount = aReadStream.ReadInt32L();
+ RPointerArray<CNcdExpiredNode> expiredNodes;
+ CleanupResetAndDestroyPushL( expiredNodes );
+ for ( TInt i = 0 ; i < nodeCount ; i++ )
+ {
+ CNcdExpiredNode* expiredNode = CNcdExpiredNode::NewLC(
+ aReadStream );
+ DLINFO( (_L("Expired node: id=%S, ns=%S, force update=%d"),
+ &expiredNode->NodeIdentifier().NodeId(),
+ &expiredNode->NodeIdentifier().NodeNameSpace(),
+ expiredNode->ForceUpdate() ) );
+ DLINFO(( "Appending nodes." ));
+ expiredNodes.AppendL( expiredNode );
+ DLINFO(( "Popping expired one." ));
+ CleanupStack::Pop( expiredNode );
+ }
+ // send expiration info to provider
+ DLINFO(( "Send exp info." ));
+ iNodeManager->HandleExpiredNodesL( expiredNodes );
+ DLINFO(( "Pop & destroy expired nodes." ));
+ CleanupStack::PopAndDestroy( &expiredNodes );
+ DLINFO(( "Continue message" ));
+ SendContinueMessageL();
+ DLTRACE(("ENCDOperationMessageCompletionExpirationInfo done"));
+ break;
+ }
+
+ default:
+ {
+ // Unknown completion id -> corrupt data
+ iState = MNcdOperation::EStateStopped;
+ CompleteCallback( KErrCorrupt );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &aReadStream );
+ ); // TRAPD
+ if ( err != KErrNone )
+ {
+ DLERROR(("Error %d! Calling CompleteCallback", err));
+ CompleteCallback( err );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::SendContinueMessageL()
+ {
+ DLTRACEIN(("IsActive: %d", IsActive() ));
+ DASSERT( iState != MNcdOperation::EStateCancelled );
+
+ // Prevents continue message sending when the server's response to
+ // an asyncronous message has not yet been received but some
+ // synchronous operation wants to send a continue msg because it
+ // thinks that there isn't any.
+ //
+ // Basically this fixes NCDALTCI-369 where client-side crashed when a
+ // download was quickly paused and resumed and the server had just
+ // completed a progress message before the download was paused but
+ // it got handled after the op was resumed again
+ if ( !IsActive() )
+ {
+ InitBuffersL( 0, 0 );
+ ClientServerSession().SendAsyncAlloc(
+ ENCDOperationFunctionContinue,
+ SendBuf8L(),
+ iReceiveBuffer,
+ Handle(),
+ iStatus,
+ 0 );
+ DLTRACE(("Setting active"));
+ SetActive();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Sends a message that releases the operation on the server side
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::SendReleaseMessage()
+ {
+ DLTRACEIN((""));
+
+ TInt tmpNum( 0 );
+ ClientServerSession().
+ SendSync( ENCDOperationFunctionRelease,
+ KNullDesC8(),
+ tmpNum,
+ Handle() );
+
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::InitBuffersL( TInt aSendSize, TInt /*aReceiveSize*/)
+ {
+ DLTRACEIN((""));
+
+ // Make sure that the send buffer exists.
+ TRAPD( sendError, SendBuf8L() );
+ if( sendError == KErrNotFound )
+ {
+ SetSendBuf8( HBufC8::NewL( aSendSize ) );
+ }
+
+ delete iReceiveBuffer;
+ iReceiveBuffer = NULL;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Initializes the operation
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::InitializeOperationL()
+ {
+ DLTRACEIN((""));
+
+ // Get the initialization buffer from the implementing class
+ HBufC8* initBuf = CreateInitializationBufferL();
+
+ SetSendBuf8( initBuf );
+
+ delete iReceiveBuffer;
+ iReceiveBuffer = NULL;
+
+ DLTRACE(("Sending init message"));
+ // Initialization is done synchronously
+ User::LeaveIfError( ClientServerSession().SendSyncAlloc(
+ ENCDOperationFunctionInit,
+ SendBuf8L(),
+ iReceiveBuffer,
+ Handle(),
+ 0 ) );
+
+ DLTRACE(("Received response, &iReceiveBuffer: %X, length: %d", iReceiveBuffer,
+ iReceiveBuffer->Length() ));
+ if ( ! iReceiveBuffer || iReceiveBuffer->Length() < sizeof(TInt) )
+ {
+ DLTRACE(("Corrupt data"));
+ // Corrupt data.
+ iState = MNcdOperation::EStateStopped;
+ User::Leave( KErrCorrupt );
+ }
+
+ DLTRACE(("Reading completion id"));
+ // Let's read the completion id
+ TInt dataLength( iReceiveBuffer->Length() );
+ RDesReadStream desReadStream( *iReceiveBuffer );
+ CleanupClosePushL( desReadStream );
+
+ TNcdOperationMessageCompletionId completionId =
+ static_cast<TNcdOperationMessageCompletionId>(
+ desReadStream.ReadInt32L() );
+
+ DASSERT( completionId == ENCDOperationMessageCompletionInit );
+
+ CleanupStack::Pop(); // RDesReadStream
+
+ DLTRACE(("Handling completed message"));
+ // Handler functions will take care of the rest.
+ HandleCompletedMessage( completionId, desReadStream,
+ dataLength );
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Empty implementation
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNcdBaseOperationProxy::CreateInitializationBufferL()
+ {
+ return HBufC8::NewL( 0 );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Empty implementation
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::InitializationCallback(
+ RReadStream& /* aReadStream */, TInt aDataLength )
+ {
+ DLTRACEIN( ( "Data length: %d", aDataLength ) );
+ (void)aDataLength; // to suppress compiler warning
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::SetState( MNcdOperation::TState aState )
+ {
+ iState = aState;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TNcdSendableProgress& CNcdBaseOperationProxy::SendableProgress()
+ {
+ return iProgress;
+ }
+
+
+CNcdNodeManagerProxy* CNcdBaseOperationProxy::NodeManager() const
+ {
+ return iNodeManager;
+ }
+
+CNcdNodeProxy* CNcdBaseOperationProxy::NodeProxy() const
+ {
+ return iNode;
+ }
+
+
+// ---------------------------------------------------------------------------
+// UpdateOperationInfoToPurchaseHistoryL
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::UpdateOperationInfoToPurchaseHistoryL( TInt aErrorCode )
+ {
+ DLTRACEIN((""));
+
+ CNcdNodeProxy* node( NodeProxy() );
+ NCD_ASSERT_ALWAYS( node, ENcdPanicNoData );
+
+ CNcdNodeMetadataProxy* metadata( node->Metadata() );
+ NCD_ASSERT_ALWAYS( metadata, ENcdPanicNoData );
+
+ // Notice, that release must be called, when history is not used anymore.
+ MNcdPurchaseHistory* purchaseHistory(
+ NodeManager()->Provider().PurchaseHistoryL() );
+ NCD_ASSERT_ALWAYS( purchaseHistory, ENcdPanicNoData );
+
+ CleanupReleasePushL( *purchaseHistory );
+
+ CNcdNodeIdentifier& identifier =
+ metadata->Identifier();
+
+
+ DLINFO(("Create filter"));
+ // Create the filter. So, we will get
+ // the purchase history details we want.
+ CNcdPurchaseHistoryFilter* filter =
+ CNcdPurchaseHistoryFilter::NewLC();
+
+ // Add client Uids to the filter
+ RArray< TUid > clientUids;
+ CleanupClosePushL( clientUids );
+ clientUids.AppendL( identifier.ClientUid() );
+ filter->SetClientUids( clientUids.Array() );
+ CleanupStack::PopAndDestroy( &clientUids );
+
+ // Add other filter values
+ filter->SetNamespaceL( identifier.NodeNameSpace() );
+ filter->SetEntityIdL( identifier.NodeId() );
+
+
+ // Get the ids. So, we can next get all the corresponding
+ // details and update them into the purchase history.
+ RArray< TUint > ids =
+ purchaseHistory->PurchaseIdsL( *filter );
+
+ CleanupStack::PopAndDestroy( filter );
+
+ CleanupClosePushL( ids );
+
+ // Get all the details and add history items into the
+ // array.
+ if ( ids.Count() > 0 )
+ {
+ DLINFO(("At least one purchase id existed: %d", ids.Count() ));
+
+ // Operations always use the newest details. So, use it here also.
+ // We do not want to load icons. So, use EFalse.
+
+ CNcdPurchaseDetails* details(
+ purchaseHistory->PurchaseDetailsL( ids[ 0 ] , EFalse ) );
+
+ if ( details != NULL )
+ {
+ CleanupStack::PushL( details );
+
+ DLINFO(("Details was found"));
+
+ // Set the error code and the lates operation time
+ details->SetLastOperationErrorCode( aErrorCode );
+ details->SetLastUniversalOperationTime();
+
+ // Save purchase details into the purchase history.
+ // This will replace the old detail.
+ // But, do not replace old icon, because we did not load it
+ // for the details above.
+ purchaseHistory->SavePurchaseL( *details, EFalse );
+
+ CleanupStack::PopAndDestroy( details );
+ details = NULL;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &ids );
+
+ CleanupStack::PopAndDestroy( purchaseHistory );
+
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// From CActive
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::RunL()
+ {
+ DLTRACEIN(("iReceiveBuffer=%X, status: %d, state: %d",
+ iReceiveBuffer, iStatus.Int(), iState ));
+
+
+ if ( iStatus.Int() == KErrCancel )
+ {
+ DLINFO(("The operation was cancelled by engine"));
+ // Do not complete with KErrCancel since it is used when the operation
+ // is cancelled by UI. These cases has to be distinguished somehow.
+ iState = MNcdOperation::EStateCancelled;
+ CompleteCallback( KErrAbort );
+ return;
+ }
+ else if ( iState == MNcdOperation::EStateCancelled )
+ {
+ DLINFO(("The operation has already been cancelled"));
+ // Ignore message
+ return;
+ }
+
+ if ( ! iReceiveBuffer || iReceiveBuffer->Length() < sizeof(TInt) )
+ {
+ DLTRACE(("corrupt data"));
+ // Corrupt data.
+ iState = MNcdOperation::EStateStopped;
+ // error callback: KErrCorrupt
+ CompleteCallback( KErrCorrupt );
+ return;
+ }
+
+ // Let's read the completion id
+ TInt dataLength( iReceiveBuffer->Length() );
+ RDesReadStream desReadStream( *iReceiveBuffer );
+ TNcdOperationMessageCompletionId completionId = ENCDOperationMessageCompletionError;
+ TRAPD( err, completionId =
+ static_cast<TNcdOperationMessageCompletionId>
+ ( desReadStream.ReadInt32L() ) );
+ if ( err != KErrNone )
+ {
+ DLTRACE(("corrupt"));
+ CompleteCallback( KErrCorrupt );
+ return;
+ }
+ DLTRACE(("id read"));
+ // Handler functions will take care of the rest.
+ HandleCompletedMessage( completionId, desReadStream,
+ dataLength );
+ DLTRACEOUT((""));
+ }
+
+// ---------------------------------------------------------------------------
+// From CActive
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdBaseOperationProxy::DoCancel()
+ {
+ DLTRACEIN((""));
+
+ DLTRACE(("Cancel async requests"));
+ ClientServerSession().AsyncMessageSenderDown( iStatus );
+ }
+
+
+// ---------------------------------------------------------------------------
+// From CActive
+// ---------------------------------------------------------------------------
+//
+TInt CNcdBaseOperationProxy::RunError( TInt aError )
+ {
+ DLTRACEIN(("Error: %d in RunL()", aError ));
+ return aError;
+ }
+
+MCatalogsClientServer& CNcdBaseOperationProxy::ClientServerSession() const
+ {
+ DLTRACEIN((""));
+ return *iSession;
+ }
+
+TInt CNcdBaseOperationProxy::Handle() const
+ {
+ return iHandle;
+ }
+
+
+const TDesC8& CNcdBaseOperationProxy::SendBuf8L()
+ {
+ if( iSendHeapBuf8 == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iSendHeapBuf8;
+ }
+
+
+void CNcdBaseOperationProxy::SetSendBuf8( HBufC8* aBuffer )
+ {
+ delete iSendHeapBuf8;
+ iSendHeapBuf8 = aBuffer;
+ }