--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cellularsrvapitest/datatransferhaitest/common/src/DataDealer.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,341 @@
+/*
+* Copyright (c) 2005-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:
+*
+*/
+
+
+#include <e32base.h>
+#include <ecom/ecomresolverparams.h>
+#include <ecom/ecom.h>
+
+#include "DataDealer.h"
+#include "DataDealerParams.h"
+
+// We cannot use UIDs that are reserved from Symbian (neither protected
+// nor unprotected) since Publish&Subscribe properties require that
+// the running process they are defined in has the secure id that matches
+// the id of the P&S property (secure id check is not made for legacy UIDs
+// which are < 0x10273357).
+// So we use a UID from development range: 0x00000000 - 0x0FFFFFFF
+const TUid KPropertyCategory = { 0x077A5355 };
+//const TUid KPropertyCategory = { 0xA00023E0 };
+
+// Time to wait before re-checking property values
+const TInt KWaitForPropertyTime( 100000 );
+
+
+const TUid KDataDealerImplUID1 = {0xA00023E2};
+
+/**
+ * @param aProducer Set to ETrue if this is a producer instance.
+ * @param aKey The Publish&Subscribe key that is used for data passing.
+ */
+CDataDealer* CDataDealer::NewL( const TBool aProducer, const TUint aKey )
+ {
+ TDataDealerParams params( aProducer, aKey );
+
+ TAny* implementation =
+ REComSession::CreateImplementationL( KDataDealerImplUID1,
+ _FOFF( CDataDealer, iDtorID ),
+ ¶ms );
+
+
+ CDataDealer* self = new (ELeave) CDataDealer( params.iProducer, params.iKey );
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ return self;
+ }
+
+CDataDealer::~CDataDealer()
+ {
+ // wait that the property is empty (= data consumed)
+ TRAPD( err, WaitForConsumerL() );
+ if( err != KErrNone )
+ {
+ // WaitForConsumerL error!
+ }
+
+ // The producer is responsible of creating and destroying the property
+ if( iProducer )
+ {
+ // CDataDealer: This is a producer instance, delete the P&S property
+ TInt err = iProperty.Delete( KPropertyCategory, iKey );
+ if( err != KErrNone )
+ {
+ // CDataDealer: Could not delete property
+ }
+ iProperty.Close();
+ }
+
+
+ // Notify the ECom server that we released one implementation of some
+ // DLL. When the counter hits zero ECom server may unload the DLL.
+ REComSession::DestroyedImplementation( iDtorID );
+ }
+
+void CDataDealer::ConstructL()
+ {
+ // The producer is responsible of creating and destroying the property
+ if( iProducer )
+ {
+ // CDataDealer: This is a producer instance, create the P&S property
+ TInt err = iProperty.Define( KPropertyCategory,
+ iKey,
+ RProperty::EByteArray,
+ iPropertySize );
+ if( err == KErrAlreadyExists )
+ {
+ // Property already exists. Clear contents.
+ User::LeaveIfError( iProperty.Set( KPropertyCategory, iKey, KNullDesC8 ) );
+ }
+ else if( err != KErrNone )
+ {
+ // Could not create pub&sub property
+ User::Leave( err );
+ }
+ }
+ // Consumer waits that the property is created by producer
+ else
+ {
+ WaitForPropertyToBeCreatedL();
+ }
+ }
+
+
+/**
+ * Consumer uses this to wait for the property to be created by producer
+ * when DataDealer is constructed.
+ */
+void CDataDealer::WaitForPropertyToBeCreatedL()
+ {
+ const TInt KTempPropertyValueLength(2);
+ TBuf8<KTempPropertyValueLength> tempValue;
+
+ TInt err = iProperty.Get( KPropertyCategory, iKey, tempValue );
+ while( err == KErrNotFound )
+ {
+ // Property did not created yet, wait
+ const TInt KWaitForProperty( 500000 );
+ // User::After here is not a critical error. It is used here to wait for the RProperty instance
+ // to be created. The best solution would be to use RProperty notifications to do that but it is
+ // currently too heavy considering how DataDealer is used: in testing context without any UI
+ User::After( KWaitForProperty );
+ err = iProperty.Get( KPropertyCategory, iKey, tempValue );
+ }
+ if( err != KErrNone && err != KErrOverflow )
+ {
+ // Unexpected error!
+ User::Leave( err );
+ }
+ }
+
+CDataDealer::CDataDealer( const TBool aProducer, const TUint aKey )
+: CBase(),
+ // Use KMaxPropertySize as default size to ensure "real time" setting of a value
+ iPropertySize( RProperty::KMaxPropertySize ),
+ iProducer( aProducer ),
+ iKey( aKey ),
+ iDtorID()
+ {
+ }
+
+/**
+ * Produce data to the data storage defined in the constructor.
+ */
+void CDataDealer::ProduceDataL( const TDesC8& aData )
+ {
+ // "CDataDealer::ProduceDataL: %S", &aData
+
+ // Check for misuse
+ if( !iProducer ) User::Leave( KErrNotSupported );
+
+ for( TInt i(0); i < aData.Length(); i += iPropertySize )
+ {
+ // wait that the property is empty (= data consumed)
+ WaitForConsumerL();
+
+ // Then write data block-by-block
+ TPtrC8 dataBlock( KNullDesC8 );
+ if( ( i + iPropertySize ) < aData.Length() )
+ dataBlock.Set( aData.Mid( i, iPropertySize ) );
+ else
+ dataBlock.Set( aData.Mid( i, aData.Length() - i ) );
+ // Write single block
+ User::LeaveIfError( iProperty.Set( KPropertyCategory, iKey, dataBlock ) );
+ }
+ }
+
+/**
+ * Wait synchronously until the consumer has deleted the data we have produced.
+ * Used by data dealer that is producing data.
+ */
+void CDataDealer::WaitForConsumerL()
+ {
+ const TInt KTempPropertyValueLength(2);
+ TBuf8<KTempPropertyValueLength> tempValue;
+
+ TInt err = iProperty.Get( KPropertyCategory, iKey, tempValue );
+
+ if( err != KErrOverflow && err != KErrNone )
+ {
+ // un-expected error
+ // CDataDealer: Could not get property value.
+ User::Leave( err );
+ }
+
+ while( err == KErrOverflow || tempValue != KNullDesC8 )
+ {
+ // Not empty yet, wait
+
+ // User::After here is not a critical error. It is used here to wait for the RProperty instance
+ // to be created. The best solution would be to use RProperty notifications to do that but it is
+ // currently too heavy considering how DataDealer is used: in testing context without any UI
+ User::After( KWaitForPropertyTime ); // CSI: 92 #
+ err = iProperty.Get( KPropertyCategory, iKey, tempValue );
+ }
+
+ }
+
+/**
+ * @param aData On return contains a pointer to heap descriptor containing the received data.
+ */
+void CDataDealer::ConsumeDataL( HBufC8*& aData )
+ {
+ // Check for misuse
+ if( iProducer ) User::Leave( KErrNotSupported );
+
+ TInt err( KErrNone );
+ HBufC8* data = HBufC8::NewLC( iPropertySize );
+ TPtr8 dataPtr = data->Des();
+ const TInt KMinHBufCLength(1);
+ HBufC8* wholeData = HBufC8::NewLC( KMinHBufCLength );
+
+ // Loop until the property is destroyed by the producer
+ for( TInt i(0); err != KErrNotFound; )
+ {
+ // check if the property exists and has data
+ err = iProperty.Get( KPropertyCategory, iKey, dataPtr );
+ TBool empty = ( dataPtr == KNullDesC8 );
+ if( err == KErrNone )
+ {
+ if( empty )
+ {
+ // Property empty, cannot consume, wait
+ // If the property exists but is empty, wait for data
+ // User::After here is not a critical error. It is used here to wait for the RProperty instance
+ // to be created. The best solution would be to use RProperty notifications to do that but it is
+ // currently too heavy considering how DataDealer is used: in testing context without any UI
+ User::After( KWaitForPropertyTime ); // CSI: 92 #
+ }
+ else
+ {
+ // Clear the property...
+ User::LeaveIfError( iProperty.Set( KPropertyCategory, iKey, KNullDesC8 ) );
+
+ // Append the retrieved data to the buffer that will be returned
+ // CDataDealer: Data ready, consumed
+ HBufC8* newWholeData = wholeData->ReAllocL( wholeData->Length() + iPropertySize );
+ CleanupStack::Pop( wholeData );
+ wholeData = newWholeData;
+ CleanupStack::PushL( wholeData );
+ wholeData->Des().Append( *data );
+ // Clear the buffer
+ dataPtr.Zero();
+
+ // ..and set new storage index
+ i += iPropertySize;
+ }
+ }
+ // If the property is not found, it means that there is (no more) data to be consumed available
+ else if( err != KErrNotFound )
+ {
+ // CDataDealer: Could not open the property.
+ User::Leave( err );
+ }
+ }
+
+ // "CDataDealer::ConsumeDataL: %S", wholeData
+ // Ownership transferred
+ CleanupStack::Pop( wholeData );
+ aData = wholeData;
+ CleanupStack::PopAndDestroy( data );
+ }
+
+/**
+ * Consume data that is produced to the data storage defined in the constructor.
+ * @param aData On return contains a pointer to heap descriptor containing the received data.
+ * @param aMaxSize The maximum size of the data block.
+ * @param aMore ETrue if there is more data to be consumed.
+ */
+void CDataDealer::ConsumeDataL( HBufC8*& aData, const TInt aMaxSize, TBool& aMore )
+ {
+ // Check for misuse
+ if( iProducer ) User::Leave( KErrNotSupported );
+
+ HBufC8* data = HBufC8::NewLC( iPropertySize );
+ TPtr8 dataPtr = data->Des();
+
+ // Loop until data is produced to the property
+ TInt err( KErrNone );
+ while( err != KErrNotFound && dataPtr.Length() == 0 )
+ {
+ // check if the property exists and has data
+ err = iProperty.Get( KPropertyCategory, iKey, dataPtr );
+ TBool empty = ( dataPtr == KNullDesC8 );
+
+ if( err == KErrNone )
+ {
+ if( empty )
+ {
+ // If the property exists but is empty, wait for data
+ // User::After here is not a critical error. It is used here to wait for the RProperty instance
+ // to be created. The best solution would be to use RProperty notifications to do that but it is
+ // currently too heavy considering how DataDealer is used: in testing context without any UI
+ User::After( KWaitForPropertyTime ); // CSI: 92 #
+ }
+ else if( dataPtr.Length() > aMaxSize )
+ {
+ // Too long data (%i, max: %i): consuming only the first block", dataPtr.Length(), aMaxSize
+ // Consuming only the first aMaxSize characters; save the rest of the data to the property
+ iProperty.Set( KPropertyCategory, iKey, dataPtr.Right( dataPtr.Length() - aMaxSize ) );
+ // Take the first aMaxSize characters and ignore the rest
+ data->Des().Copy( dataPtr.Left( aMaxSize ) );
+ }
+ else
+ {
+ // Clear the property...
+ User::LeaveIfError( iProperty.Set( KPropertyCategory, iKey, KNullDesC8 ) );
+ }
+ }
+ // If the property is not found, it means that there is (no more) data to be consumed available
+ else if( err == KErrNotFound )
+ {
+ // CDataDealer: No more data in the property (KErrNotFound)
+ aMore = EFalse;
+ }
+ else
+ {
+ // CDataDealer: Could not open the property.
+ aMore = EFalse;
+ User::Leave( err );
+ }
+ }
+
+ CleanupStack::Pop( data );
+ aData = data;
+ }
+