mtpfws/mtpfw/dataproviders/dputility/src/cmtpsvccompoundprocessor.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:11:40 +0200
changeset 0 d0791faffa3f
child 47 63cf70d3ecd8
permissions -rw-r--r--
Revision: 201003 Kit: 201005

// Copyright (c) 2008-2009 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:
// mw/remoteconn/mtpfws/mtpfw/dataproviders/dputility/src/cmtpsvccompoundprocessor.cpp

#include <mtp/mmtpdataproviderframework.h>

#include <mtp/cmtpobjectmetadata.h>
#include <mtp/cmtptypefile.h>
#include <mtp/cmtptypeobjectinfo.h>
#include <mtp/cmtptypeobjectproplist.h>
#include <mtp/cmtptypestring.h>
#include <mtp/mmtpobjectmgr.h>
#include <mtp/mmtpstoragemgr.h>
#include <mtp/mtpprotocolconstants.h> 
#include <mtp/tmtptypeint128.h>

#include "cmtpsvccompoundprocessor.h"
#include "mmtpservicedataprovider.h"
#include "mmtpsvcobjecthandler.h"

#include "cmtpconnection.h"
#include "cmtpconnectionmgr.h"
#include "mtpsvcdpconst.h"

// Class constants.
__FLOG_STMT(_LIT8(KComponent,"SvcCompound");)

EXPORT_C MMTPRequestProcessor* CMTPSvcCompoundProcessor::NewL(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection, MMTPServiceDataProvider& aDataProvider)
	{
	CMTPSvcCompoundProcessor* self = new (ELeave) CMTPSvcCompoundProcessor(aFramework, aConnection, aDataProvider);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

EXPORT_C CMTPSvcCompoundProcessor::~CMTPSvcCompoundProcessor()
	{
	__FLOG(_L8("~CMTPSvcCompoundProcessor - Entry"));
	delete iReceivedObjectMetaData;
	delete iObjectInfo;
	delete iObjectPropList;
	__FLOG(_L8("~CMTPSvcCompoundProcessor - Exit"));
	__FLOG_CLOSE; 
	}

CMTPSvcCompoundProcessor::CMTPSvcCompoundProcessor(MMTPDataProviderFramework& aFramework, MMTPConnection& aConnection, MMTPServiceDataProvider& aDataProvider) :
	CMTPRequestProcessor(aFramework, aConnection, 0, NULL),
	iDataProvider(aDataProvider), iState(EIdle), iIsCommited(EFalse), iIsRollBackHandlerObject(EFalse)
	{
	}

void CMTPSvcCompoundProcessor::ConstructL()
	{
	__FLOG_OPEN(KMTPSubsystem, KComponent);
	__FLOG(_L8("ConstructL - Entry"));
	iExpectedSendObjectRequest.SetUint16(TMTPTypeRequest::ERequestOperationCode, EMTPOpCodeSendObject);
	iReceivedObjectMetaData = CMTPObjectMetaData::NewL();
	iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EDataProviderId, iFramework.DataProviderId());
	__FLOG(_L8("ConstructL - Exit"));
	}

/**
Override to match both the SendObjectInfo/SendObjectPropList/UpdateObjectPropList and SendObject requests
@param aRequest    The request to match
@param aConnection The connection from which the request comes
@return ETrue if the processor can handle the request, otherwise EFalse
*/
TBool CMTPSvcCompoundProcessor::Match(const TMTPTypeRequest& aRequest, MMTPConnection& aConnection) const
	{
	__FLOG(_L8("Match - Entry"));
	TBool result = EFalse;
	TUint16 operationCode = aRequest.Uint16(TMTPTypeRequest::ERequestOperationCode);
	if ((&iConnection == &aConnection) && 
		(operationCode == EMTPOpCodeSendObjectInfo || 
		operationCode == EMTPOpCodeSendObject ||
		operationCode == EMTPOpCodeUpdateObjectPropList ||
		operationCode == EMTPOpCodeSendObjectPropList))
		{
		result = ETrue;
		}
	__FLOG(_L8("Match - Exit"));
	return result;
	}

TBool CMTPSvcCompoundProcessor::HasDataphase() const
	{
	return ETrue;
	}

/**
Verify the request
@return EMTPRespCodeOK if request is verified, otherwise one of the error response codes
*/
TMTPResponseCode CMTPSvcCompoundProcessor::CheckRequestL()
	{
	__FLOG(_L8("CheckRequestL - Entry"));
	TMTPResponseCode responseCode = CMTPRequestProcessor::CheckRequestL();
	if (EMTPRespCodeOK == responseCode)
		{
		responseCode = CheckSendingStateL();
		if (EMTPRespCodeOK == responseCode)
			{
			responseCode = CheckRequestParametersL();
			}
		}
	__FLOG_VA((_L8("CheckRequestL - Exit with code: 0x%04X"), responseCode));
	return responseCode;
	}

/**
Verify if the SendObject request comes after SendObjectInfo/SendObjectPropList request
@return EMTPRespCodeOK if SendObject request comes after a valid SendObjectInfo request, otherwise
EMTPRespCodeNoValidObjectInfo
*/
TMTPResponseCode CMTPSvcCompoundProcessor::CheckSendingStateL()
	{
	__FLOG(_L8("CheckSendingStateL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	iOperationCode = Request().Uint16(TMTPTypeRequest::ERequestOperationCode);
	
	if (iOperationCode == EMTPOpCodeSendObject)
		{
		//In ParseRouter everytime SendObject gets resolved then will be removed from Registry
		//Right away therefore we need reRegister it here again in case possible cancelRequest
		//Against this SendObject being raised.
		iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
		iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
		}

	switch (iState)
		{
		case EIdle:
			// Received an orphan SendObject
			if (iOperationCode == EMTPOpCodeSendObject)
				{
				responseCode = EMTPRespCodeNoValidObjectInfo;
				__FLOG(_L8("EIdle: Received an orphan SendObject request"));
				}
			break;
		case EObjectInfoSucceed:
			// If another SendObjectInfo or SendObjectPropList operation occurs before a SendObject
			// operation, the new ObjectInfo or ObjectPropList shall replace the previously held one. 
			// If this occurs, any storage or memory space reserved for the object described in the 
			// overwritten ObjectInfo or ObjectPropList dataset should be freed before overwriting and 
			// allocating the resources for the new data. 
			
			// Here is for the processor received another SendObjectInfo or SendObjectPropList 
			// before a SendObject or process SendObject failed,
			if (iOperationCode == EMTPOpCodeSendObjectInfo ||
				iOperationCode == EMTPOpCodeSendObjectPropList ||
				iOperationCode == EMTPOpCodeUpdateObjectPropList)
				{
				iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
				if (!iIsCommited)
					{
					// Object Size != 0, need roll back all resource for the new SendInfo request
					CMTPSvcCompoundProcessor::RollBackObject(this);
					iFramework.ObjectMgr().UnreserveObjectHandleL(*iReceivedObjectMetaData);
					}
				delete iObjectInfo;
				iObjectInfo = NULL;
				delete iObjectPropList;
				iObjectPropList = NULL;
				delete iReceivedObjectMetaData;
				iReceivedObjectMetaData = NULL;
				iReceivedObjectMetaData = CMTPObjectMetaData::NewL();
				iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EDataProviderId, iFramework.DataProviderId());
				iObjectHandler = NULL;
				iState = EIdle;
				// Reset commit state to false
				iIsCommited = EFalse;
				__FLOG(_L8("EObjectInfoSucceed: Receive send obj info request again, return to EIdle"));
				}
			break;
		default:
			User::Leave(KErrGeneral);
		}
	__FLOG_VA((_L8("CheckSendingStateL - Exit with code: 0x%04X, state: %u"), responseCode, iState));
	return responseCode;
	}

/**
Validates the data type for a given property code.
@return EMTPRespCodeOK if the parent handle matches the store id, or another MTP response code if not
*/
TMTPResponseCode CMTPSvcCompoundProcessor::CheckRequestParametersL()
	{
	__FLOG(_L8("CheckRequestParametersL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	
	switch (iOperationCode)
		{
		case EMTPOpCodeSendObject:
			{
			__FLOG(_L8("Check SendObject request parameters"));
			// Check SendObject's session ID
			if (iSessionId != iLastSessionID)
				{
				responseCode = EMTPRespCodeNoValidObjectInfo;
				}
			else if ((iLastTransactionID + 1) != iTransactionCode)
				{
				// Check SendObject's transaction ID
				responseCode = EMTPRespCodeInvalidTransactionID;
				}
			break;
			}

		case EMTPOpCodeSendObjectInfo:
			{
			__FLOG(_L8("Check SendObjectInfo request parameters"));
			responseCode = CheckStoreAndParent();
			break;
			}
			
		case EMTPOpCodeSendObjectPropList:
			{
			__FLOG(_L8("Check SendObjectPropList request parameters"));
			responseCode = CheckStoreAndParent();
			if (EMTPRespCodeOK == responseCode)
				{
				// SendObjectPropList need check format code and size in the request
				TUint32 objectSizeHigh = Request().Uint32(TMTPTypeRequest::ERequestParameter4);
				TUint32 objectSizeLow  = Request().Uint32(TMTPTypeRequest::ERequestParameter5);
				iObjectSize = MAKE_TUINT64(objectSizeHigh, objectSizeLow);
				
				iFormatCode = Request().Uint32(TMTPTypeRequest::ERequestParameter3);
				responseCode = CheckFmtAndSetHandler(iFormatCode);
				iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EFormatCode, iFormatCode);
				}
			break;
			}

		case EMTPOpCodeUpdateObjectPropList:
			{
			__FLOG(_L8("Check UpdateObjectPropList request parameters"));
			TUint32 objectHandle = Request().Uint32(TMTPTypeRequest::ERequestParameter1);
			if (objectHandle != KMTPHandleNone)
				{
				// Find the updating object information
				MMTPObjectMgr& objects(iFramework.ObjectMgr());
				if (objects.ObjectL(objectHandle, *iReceivedObjectMetaData))
					{
					iFormatCode = iReceivedObjectMetaData->Uint(CMTPObjectMetaData::EFormatCode);
					if (iReceivedObjectMetaData->Uint(CMTPObjectMetaData::EDataProviderId) != iFramework.DataProviderId())
						{
						responseCode = EMTPRespCodeInvalidObjectHandle;
						}
					else
						{
						responseCode = CheckFmtAndSetHandler(iFormatCode);
						}
					}
				else
					{
					responseCode = EMTPRespCodeInvalidObjectHandle;
					}
				}
			else
				{
				responseCode = EMTPRespCodeInvalidObjectHandle;
				}
			break;
			}
			
		default:
			// Unexpected operation code
			responseCode = EMTPRespCodeOperationNotSupported;
			break;
		}
	__FLOG_VA((_L8("CheckRequestParametersL exit with code: 0x%x"), responseCode));
	return responseCode;
	}

/**
Validates the data type for a given property code.
@return EMTPRespCodeOK if the parent handle matches the store id, or another MTP response code if not
*/
TMTPResponseCode CMTPSvcCompoundProcessor::CheckStoreAndParent()
	{
	__FLOG(_L8("CheckStoreAndParent - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	iStorageId = Request().Uint32(TMTPTypeRequest::ERequestParameter1);
	iParentHandle = Request().Uint32(TMTPTypeRequest::ERequestParameter2);
	
	// If the first parameter is unused, it should be set to 0x00000000, and the responder should decide
	// in which store to place the object
	if (iStorageId == KMTPStorageDefault)
		{
		// If the second parameter is used, the first parameter must also be used.
		// If the second parameter is unused, it should be set to 0x00000000
		if (iParentHandle != KMTPHandleNone)
			{
			responseCode = EMTPRespCodeInvalidParentObject;
			}
		else
			{
			// Set storage id as service dp's logical storage id.
			iStorageId = iDataProvider.StorageId();
			}
		}
	else
		{
		// Check logical storage id.
		if (iStorageId != iDataProvider.StorageId())
			{
			responseCode = EMTPRespCodeInvalidStorageID;
			}
		}
	
	__FLOG_VA((_L8("CheckStoreAndParent - Exit with code: 0x%x"), responseCode));
	return responseCode;
	}

/**
SendObjectInfo/SendObjectPropList/UpdateObjectPropList/SendObject request handler
To maintain the state information between the two requests, the two requests are 
combined together in one request processor.
*/
void CMTPSvcCompoundProcessor::ServiceL()
	{
	__FLOG(_L8("ServiceL - Entry"));
	switch (iState)
		{
		case EIdle:
			ServiceObjectPropertiesL();
			break;
		case EObjectInfoSucceed:
			ServiceSendObjectL();
			break;
		default:
			__FLOG(_L8("Wrong state in ServiceL"));
			break;
		}
	__FLOG(_L8("ServiceL - Exit"));
	}

void CMTPSvcCompoundProcessor::ServiceObjectPropertiesL()
	{
	__FLOG(_L8("ServiceObjectPropertiesL - Entry"));
	switch (iOperationCode)
		{
		case EMTPOpCodeSendObjectInfo:
			ServiceSendObjectInfoL();
			break;
		
		case EMTPOpCodeSendObjectPropList:
		case EMTPOpCodeUpdateObjectPropList:
			ServiceSendObjectPropListL();
			break;
		default:
			break;
		}
	__FLOG(_L8("ServiceObjectPropertiesL - Exit"));
	}

/**
SendObject request handler
*/
void CMTPSvcCompoundProcessor::ServiceSendObjectL()
	{
	__FLOG(_L8("ServiceSendObjectL - Entry"));
	MMTPSvcObjectHandler* pHandler = iDataProvider.ObjectHandler(iFormatCode);
	if (pHandler)
		{
		pHandler->GetBufferForSendObjectL(*iReceivedObjectMetaData, &iObjectContent);
		}
	else
		{
		User::Leave(KErrGeneral);
		}
	ReceiveDataL(*iObjectContent);
	iState = EObjectSendProcessing;
	__FLOG(_L8("ServiceSendObjectL - Exit"));
	}

/**
SendObjectInfo request handler
*/
void CMTPSvcCompoundProcessor::ServiceSendObjectInfoL()
	{
	__FLOG(_L8("ServiceSendObjectInfoL - Entry"));
	delete iObjectInfo;
	iObjectInfo = NULL;
	iObjectInfo = CMTPTypeObjectInfo::NewL();
	ReceiveDataL(*iObjectInfo);
	iState = EObjectInfoProcessing;
	__FLOG(_L8("ServiceSendObjectInfoL - Exit"));
	}

/**
SendObjectPropList request handler
*/
void CMTPSvcCompoundProcessor::ServiceSendObjectPropListL()
	{
	__FLOG(_L8("ServiceSendObjectPropListL - Entry"));
	delete iObjectPropList;
	iObjectPropList = NULL;
	iObjectPropList = CMTPTypeObjectPropList::NewL();
	ReceiveDataL(*iObjectPropList);
	iState = EObjectInfoProcessing;
	__FLOG(_L8("ServiceSendObjectPropListL - Exit"));
	}

/**
Override to handle the response phase of SendObjectInfo/SendObjectPropList and SendObject requests
@return EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleResponsePhaseL()
	{
	__FLOG(_L8("DoHandleResponsePhaseL - Entry"));
	TBool successful = !iCancelled;
	switch (iState)
		{
		case EObjectInfoProcessing:
			{
			if (iOperationCode == EMTPOpCodeSendObjectInfo)
				{
				successful = DoHandleResponseSendObjectInfoL();
				}
			else if (iOperationCode == EMTPOpCodeSendObjectPropList)
				{
				successful = DoHandleResponseSendObjectPropListL();
				}
			else if (iOperationCode == EMTPOpCodeUpdateObjectPropList)
				{
				successful = DoHandleResponseUpdateObjectPropListL();
				}
			iState = (successful ? EObjectInfoSucceed : EIdle);
			break;
			}
		case EObjectSendProcessing:
			{
			successful = DoHandleResponseSendObjectL();
			iState = (successful ? EObjectSendSucceed : EObjectSendFail);
			break;
			}
		default:
			// Wrong State value.
			__FLOG_VA((_L8("DoHandleResponsePhaseL enter an abnormal state %d"), iState));
			break;
		}
	__FLOG(_L8("DoHandleResponsePhaseL - Exit"));
	return EFalse;
	}

/**
Override to handle the completing phase of SendObjectInfo/SendObjectPropList and SendObject requests
@return ETrue if succesfully received the object content, otherwise EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleCompletingPhaseL()
	{
	__FLOG(_L8("DoHandleCompletingPhaseL - Entry"));
	TBool result = ETrue;
	CMTPRequestProcessor::DoHandleCompletingPhaseL();
	
	__FLOG_VA((_L8("DoHandleCompletingPhaseL - Progress State: %u"), iState));
	switch (iState)
		{
		case EObjectInfoSucceed:
			{
			// Two cases will come here:
			// 1. SendObjInfo OK, Store ID for next SendObject checking;
			// 2. SendObject check request fail, such as wrong transaction id or wrong session id.
			//    needn't change transaction id.
			if (iOperationCode == EMTPOpCodeSendObjectInfo || 
				iOperationCode == EMTPOpCodeUpdateObjectPropList ||
				iOperationCode == EMTPOpCodeSendObjectPropList)
				{
				// Reset transaction id for new SendObjInfo request, but ignore wrong SendObject.
				iLastTransactionID = iTransactionCode;
				iLastSessionID = iSessionId;
				iLastInfoOperationCode = iOperationCode;
				}
			result = EFalse;
			__FLOG_VA((_L8("EObjectInfoSucceed: Save send info transaction id: %u, operation: 0x%x"), iLastTransactionID, iOperationCode));
			break;
			}
		case EObjectSendFail:
			{
			// When process SendObject fail, such as received size is wrong.
			iLastTransactionID++;
			iState = EObjectInfoSucceed;
			result = EFalse;
			break;
			}
		default:
			// The other cases will delete the processor:
			// 1. SendObject OK
			// 2. Framework error and call complete with error state.
			// 3. SendObjInfo fail
			// 4. First request is orphan SendObject, state is Idle
			break;
		}
	__FLOG(_L8("DoHandleCompletingPhaseL - Exit"));
	return result;
	}

/**
Handling the completing phase of SendObjectInfo request
@return ETrue if the specified object can be saved on the specified location, otherwise, EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleResponseSendObjectInfoL()
	{
	__FLOG(_L8("DoHandleResponseSendObjectInfoL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	TBool result(ETrue);
	iFormatCode = iObjectInfo->Uint16L(CMTPTypeObjectInfo::EObjectFormat);
	// Check format code and set object handler
	responseCode = CheckFmtAndSetHandler(iFormatCode);
	if (responseCode != EMTPRespCodeOK)
		{
		SendResponseL(responseCode);
		}
	else
		{
		iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EFormatCode, iFormatCode);
		iObjectSize = iObjectInfo->Uint32L(CMTPTypeObjectInfo::EObjectCompressedSize);
		
		TBuf<KMaxSUIDLength> suid;
		// Object mgr process dataset and create a temp object.
		responseCode = iObjectHandler->SendObjectInfoL(*iObjectInfo, iParentHandle, suid);
		if (responseCode != EMTPRespCodeOK)
			{
			SendResponseL(responseCode);
			}
		else
			{
			//if object size is zero, then directly store object without waiting for sendobject operation.
			if (iObjectSize == 0)
				{
				__FLOG(_L8("CommitReservedObject because object size is 0 and register for SendObject"));
				// Commit new temp object to object mgr, if leave, CleanupStack will rollback new temp object. 
				TCleanupItem rollBackTempObject(RollBackObject, this);
				CleanupStack::PushL(rollBackTempObject);
				// Commit prop to obj mgr
				iObjectHandler->CommitForNewObjectL(suid);
				CleanupStack::Pop(this);
	
				// Prepare to store the created object to framework
				iIsRollBackHandlerObject = ETrue;
				TCleanupItem rollBackTempObjectAndSuid(RollBackObject, this);
				CleanupStack::PushL(rollBackTempObjectAndSuid);
				// Set the created suid to meta
				iReceivedObjectMetaData->SetDesCL(CMTPObjectMetaData::ESuid, suid);
				// An object handle issued during a successful SendObjectInfo or SendObjectPropList operation should 
				// be reserved for the duration of the MTP session
				ReserveObjectL();
				// Commit the created object to framework, if leave, then framework will return General Error
				// CleanupStack will rollback the new created object via delete object operation.
				iFramework.ObjectMgr().CommitReservedObjectHandleL(*iReceivedObjectMetaData);
				CleanupStack::Pop(this);
				iIsRollBackHandlerObject = EFalse;
				iIsCommited = ETrue;
				RegisterRequestAndSendResponseL(responseCode);
				}
			else
				{
				// An object handle issued during a successful SendObjectInfo or SendObjectPropList operation should 
				// be reserved for the duration of the MTP session
				ReserveObjectL();
				RegisterRequestAndSendResponseL(responseCode);
				}
			}
		}
	result = (responseCode == EMTPRespCodeOK) ? ETrue : EFalse;
	__FLOG_VA((_L8("DoHandleResponseSendObjectInfoL exit with code: 0x%x"), responseCode));
	return result;
	}

/**
Handling the completing phase of SendObjectPropList request
@return ETrue if the specified object can be saved on the specified location, otherwise, EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleResponseSendObjectPropListL()
	{
	__FLOG(_L8("DoHandleResponseSendObjectPropListL - Entry"));
	TBool result = ETrue;
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	
	TBuf<KMaxSUIDLength> suid;
	TUint32 parameter = 0;
	responseCode = SendObjectPropListL(*iObjectPropList, iParentHandle, parameter, suid, iObjectSize);
	if (responseCode != EMTPRespCodeOK)
		{
		SendResponseL(responseCode, 4, &parameter);
		}
	else
		{
		//if object size is zero, then directly store object without waiting for sendobject operation.
		if (iObjectSize == 0)
			{
			__FLOG(_L8("CommitReservedObject because object size is 0 and register for SendObject"));
			// Commit new temp object to object mgr, if leave, CleanupStack will rollback new temp object. 
			TCleanupItem rollBackTempObject(RollBackObject, this);
			CleanupStack::PushL(rollBackTempObject);
			// Commit prop to obj mgr
			iObjectHandler->CommitForNewObjectL(suid);
			CleanupStack::Pop(this);

			// Prepare to store the created object to framework
			iIsRollBackHandlerObject = ETrue;
			TCleanupItem rollBackTempObjectAndSuid(RollBackObject, this);
			CleanupStack::PushL(rollBackTempObjectAndSuid);
			// Set the created suid to meta
			iReceivedObjectMetaData->SetDesCL(CMTPObjectMetaData::ESuid, suid);
			// An object handle issued during a successful SendObjectInfo or SendObjectPropList operation should 
			// be reserved for the duration of the MTP session
			ReserveObjectL();
			// Commit the created object to framework, if leave, then framework will return General Error
			// CleanupStack will rollback the new created object via delete object operation.
			iFramework.ObjectMgr().CommitReservedObjectHandleL(*iReceivedObjectMetaData);
			CleanupStack::Pop(this);
			iIsRollBackHandlerObject = EFalse;
			iIsCommited = ETrue;
			RegisterRequestAndSendResponseL(responseCode);
			}
		else
			{
			// An object handle issued during a successful SendObjectInfo or SendObjectPropList operation should 
			// be reserved for the duration of the MTP session
			ReserveObjectL();
			RegisterRequestAndSendResponseL(responseCode);
			}
		}

	result = (responseCode == EMTPRespCodeOK) ? ETrue : EFalse;
	__FLOG_VA((_L8("DoHandleResponseSendObjectPropListL exit with code = 0x%x"), responseCode));
	return result;
	}

/**
Handling the completing phase of UpdateObjectPropList request
@return ETrue if the specified object can be saved on the specified location, otherwise, EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleResponseUpdateObjectPropListL()
	{
	__FLOG(_L8("DoHandleResponseUpdateObjectPropListL - Entry"));
	TBool result = ETrue;
	TUint32 parameter = 0;
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	// Check object size property with format
	responseCode = ExtractObjectSizeL();
	if (responseCode == EMTPRespCodeOK)
		{
		responseCode = UpdateObjectPropListL(*iReceivedObjectMetaData, *iObjectPropList, parameter);
		}

	if (responseCode == EMTPRespCodeOK)
		{
		if (iObjectSize == 0)
			{
			// If commit leave, roll back the temp object.
			TCleanupItem rollBackTempObject(RollBackObject, this);
			CleanupStack::PushL(rollBackTempObject);
			// Commit prop to obj mgr
			iObjectHandler->CommitL();
			CleanupStack::Pop(this);
			// Commit to obj mgr is ok
			iIsCommited = ETrue;
			// Update operation needn't change framework property so far.
			iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
			iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
			}
		else
			{
			iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
			iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
			}
		}
	SendResponseL(responseCode, 1, &parameter);
	result = (responseCode == EMTPRespCodeOK) ? ETrue: EFalse;
	__FLOG_VA((_L8("DoHandleResponseUpdateObjectPropListL exit with code: 0x%x"), responseCode));
	return result;
	}

/**
Handling the completing phase of SendObject request
@return ETrue if the object has been successfully saved on the device, otherwise, EFalse
*/
TBool CMTPSvcCompoundProcessor::DoHandleResponseSendObjectL()
	{
	__FLOG(_L8("DoHandleResponseSendObjectL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	TBool result = ETrue;

	if (iCancelled)
		{
		iObjectHandler->RollBack();
		responseCode = EMTPRespCodeTransactionCancelled;
		}
	else if (iObjectSize != 0)
		{
		// For 0 sized object, ignore the object content verify
		TUint64 receiveSize = iObjectContent->Size();
		if (iObjectSize < receiveSize)
			{
			// If the object sent in the data phase of this operation is larger than 
			// the size indicated in the ObjectInfo dataset sent in the SendObjectInfo 
			// which precedes this operation, this operation should fail and a response 
			// code of Store_Full should be returned.
			responseCode = EMTPRespCodeStoreFull;
			}
		else if (iObjectSize > receiveSize)
			{
			responseCode = EMTPRespCodeIncompleteTransfer;
			}
		// If size is ok, then just need commit the object to data store.
		}
	
	// Commit or Unreserver from framework if object size is not 0.
	if (responseCode == EMTPRespCodeOK && iObjectSize != 0)
		{
		// For create new object, need commit the reserved handle to framework, but update needn't do that
		if (iLastInfoOperationCode != EMTPOpCodeUpdateObjectPropList)
			{
			TBuf<KMaxSUIDLength> suid;
			// Commit new temp object to object mgr, if leave, CleanupStack will rollback new temp object. 
			TCleanupItem rollBackTempObject(RollBackObject, this);
			CleanupStack::PushL(rollBackTempObject);
			// Commit prop to obj mgr
			iObjectHandler->CommitForNewObjectL(suid);
			CleanupStack::Pop(this);

			// Prepare to store the created object to framework
			iIsRollBackHandlerObject = ETrue;
			TCleanupItem rollBackTempObjectAndSuid(RollBackObject, this);
			CleanupStack::PushL(rollBackTempObjectAndSuid);
			// Set the created suid to meta
			iReceivedObjectMetaData->SetDesCL(CMTPObjectMetaData::ESuid, suid);
			// Commit the created object to framework, if leave, then framework will return General Error
			// CleanupStack will rollback the new created object via delete object operation.
			iFramework.ObjectMgr().CommitReservedObjectHandleL(*iReceivedObjectMetaData);
			CleanupStack::Pop(this);
			iIsRollBackHandlerObject = EFalse;
			iIsCommited = ETrue;
			}
		else
			{
			// If commit leave, roll back the temp object.
			TCleanupItem rollBackNewObject(RollBackObject, this);
			CleanupStack::PushL(rollBackNewObject);
			// Commit prop to obj mgr
			iObjectHandler->CommitL();
			CleanupStack::Pop(this);
			// Commit to obj mgr is ok
			iIsCommited = ETrue;
			}
		}

	SendResponseL(responseCode);
	// Release the processor when SendObject or Transaction Canceled and unregister SendObject.
	result = (responseCode == EMTPRespCodeOK || responseCode == EMTPRespCodeTransactionCancelled) ? ETrue : EFalse;
	if (result)
		{
		iFramework.RouteRequestUnregisterL(iExpectedSendObjectRequest, iConnection);
		}
	__FLOG_VA((_L8("DoHandleResponseSendObjectL exit with code = 0x%x"), responseCode));
	return result;
	}

TMTPResponseCode CMTPSvcCompoundProcessor::ExtractObjectSizeL()
	{
	__FLOG(_L8("ExtractObjectSizeL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	TBool foundSizeProp  = EFalse;
	const TUint KCount(iObjectPropList->NumberOfElements());
	iObjectPropList->ResetCursor();
	for (TUint i = 0; i < KCount; i++)
		{
		const CMTPTypeObjectPropListElement& KElement = iObjectPropList->GetNextElementL();
		if (EMTPObjectPropCodeObjectSize == KElement.Uint16L(CMTPTypeObjectPropListElement::EPropertyCode))
			{
			iObjectSize = KElement.Uint64L(CMTPTypeObjectPropListElement::EValue);
			foundSizeProp = ETrue;
			break;
			}
		}
	
	if (!foundSizeProp)
		{
		// Object size in data set is not available, get the corresponding object's current size property.
		const TDesC& suid = iReceivedObjectMetaData->DesC(CMTPObjectMetaData::ESuid);
		responseCode = iObjectHandler->GetObjectSizeL(suid, iObjectSize);
		if (iObjectSize == KObjectSizeNotAvaiable)
			{
			responseCode = EMTPRespCodeGeneralError;
			}
		}

	__FLOG(_L8("ExtractObjectSizeL - Exit"));
	return responseCode;
	}

/**
Reserves space for and assigns an object handle to the received object, then
sends a success response.
*/
void CMTPSvcCompoundProcessor::ReserveObjectL()
	{
	__FLOG(_L8("ReserveObjectL - Entry"));
	iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EStorageId, iStorageId);
	iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EParentHandle, iParentHandle);
	iReceivedObjectMetaData->SetUint(CMTPObjectMetaData::EFormatCode, iFormatCode);
	iFramework.ObjectMgr().ReserveObjectHandleL(*iReceivedObjectMetaData, iObjectSize);
	__FLOG_VA((_L8("ReserveObjectL Exit Storage:%u, ParentHandle:%u, FormatCode:%u, Size:%u "), iStorageId, iParentHandle, iFormatCode, iObjectSize));
	}

void CMTPSvcCompoundProcessor::RegisterRequestAndSendResponseL(TMTPResponseCode aResponseCode)
	{
	__FLOG(_L8("RegisterRequestAndSendResponseL - Entry"));
	// Register to framework for handle the next sendobj request
	iExpectedSendObjectRequest.SetUint32(TMTPTypeRequest::ERequestSessionID, iSessionId);
	iFramework.RouteRequestRegisterL(iExpectedSendObjectRequest, iConnection);
	TUint32 parameters[3];
	parameters[0] = iStorageId;
	parameters[1] = iParentHandle;
	// Responder’s reserved ObjectHandle for the incoming object
	parameters[2] = iReceivedObjectMetaData->Uint(CMTPObjectMetaData::EHandle);
	SendResponseL(aResponseCode, 3, parameters);
	__FLOG(_L8("RegisterRequestAndSendResponseL - Exit"));
	}

void CMTPSvcCompoundProcessor::RollBackObject(TAny* aObject)
	{
	reinterpret_cast<CMTPSvcCompoundProcessor*>(aObject)->RollBack();
	}

void CMTPSvcCompoundProcessor::RollBack()
	{
	iObjectHandler->RollBack();
	if (iIsRollBackHandlerObject)
		{
		TRAP_IGNORE(iObjectHandler->DeleteObjectL(*iReceivedObjectMetaData));
		iIsRollBackHandlerObject = EFalse;
		}
	}

TMTPResponseCode CMTPSvcCompoundProcessor::CheckFmtAndSetHandler(TUint32 aFormatCode)
	{
	__FLOG(_L8("CheckFmtAndSetHandler - Entry")); 
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	iObjectHandler = iDataProvider.ObjectHandler(aFormatCode);
	if (!iObjectHandler)
		{
		responseCode = EMTPRespCodeInvalidObjectFormatCode;
		}
	__FLOG(_L8("CheckFmtAndSetHandler - Exit"));
	return responseCode;
	}

TMTPResponseCode CMTPSvcCompoundProcessor::SendObjectPropListL(const CMTPTypeObjectPropList& aObjectPropList, TUint32& aParentHandle, 
														TUint32& aParameter, TDes& aSuid, TUint64 aObjectSize)
	{
	__FLOG(_L8("SendObjectPropListL - Entry"));
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	aParameter = 0;

	responseCode = iObjectHandler->SendObjectPropListL(aObjectSize, aObjectPropList, aParentHandle, aSuid);
	// If handler cache an entry in SendObjectPropList, then it should never return error code. Processor will 
	// not rollback in this case
	if (EMTPRespCodeOK == responseCode)
		{
		// Parse elements and set property for the object.
		const TUint count(aObjectPropList.NumberOfElements());
		aObjectPropList.ResetCursor();
		for (TUint i = 0; i < count && responseCode == EMTPRespCodeOK; i++)
			{
			CMTPTypeObjectPropListElement& element = aObjectPropList.GetNextElementL();
			TUint32 handle = element.Uint32L(CMTPTypeObjectPropListElement::EObjectHandle);
			// All ObjectHandle fields must contain the value 0x00000000, and all properties that are defined in 
			// this operation will be applied to the object, need check every handle value and keep all properties is atomic.
			if (handle != KMTPHandleNone)
				{
				responseCode = EMTPRespCodeInvalidDataset;
				aParameter = i;
				break;
				}
			else
				{
				// Create a new object, don't commit, it will be done in processor.
				responseCode = iObjectHandler->SetObjectPropertyL(aSuid, element, EMTPOpCodeSendObjectPropList);
				}
			if (responseCode != EMTPRespCodeOK)
				{
				aParameter = i;
				break;
				}
			}
		// Roll back the temp object
		if (EMTPRespCodeOK != responseCode)
			{
			iObjectHandler->RollBack();
			}
		}
	__FLOG_VA((_L8("SendObjectPropListL - Exit with responseCode = 0x%04X"), responseCode));
	return responseCode;
	}

// All object handlers current don't support partial update, so once update one parameter failed,
// all updated will be reverted.
TMTPResponseCode CMTPSvcCompoundProcessor::UpdateObjectPropListL(CMTPObjectMetaData& aObjectMetaData, 
														const CMTPTypeObjectPropList& aObjectPropList, 
														TUint32& /*aParameter*/)
	{
	__FLOG(_L8("UpdateObjectPropList - Entry")); 
	TMTPResponseCode responseCode = EMTPRespCodeOK;
	const TUint count = aObjectPropList.NumberOfElements();
	aObjectPropList.ResetCursor();
	for (TUint i = 0; i < count; i++)
		{
		CMTPTypeObjectPropListElement& element = aObjectPropList.GetNextElementL();
		TUint32 handle = element.Uint32L(CMTPTypeObjectPropListElement::EObjectHandle);
		// All object handle in dataset must contain either 0x00000000 or match with the parameter 1
		if (handle != aObjectMetaData.Uint(CMTPObjectMetaData::EHandle) && handle != KMTPHandleNone)
			{
			responseCode = EMTPRespCodeInvalidObjectHandle;
			}
		else
			{
			const TDesC& suid = aObjectMetaData.DesC(CMTPObjectMetaData::ESuid);
			// Update will be treated as adding a new object for RO object property.
			responseCode = iObjectHandler->SetObjectPropertyL(suid, element, EMTPOpCodeUpdateObjectPropList);
			}
		if(EMTPRespCodeOK != responseCode)
			{
			iObjectHandler->RollBack();
			break;
			}
		}
	__FLOG_VA((_L8("UpdateObjectPropListL - Exit with responseCode = 0x%04X"), responseCode));
	return responseCode;
	}