--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdsubscriptionmanagerimpl.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1541 @@
+/*
+* 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: Implements CNcdSubscriptionManager class
+*
+*/
+
+
+#include "ncdsubscriptionmanagerimpl.h"
+
+#include <s32mem.h>
+#include <bamdesca.h> // MDesCArray
+
+#include "catalogssession.h"
+#include "catalogsbasemessage.h"
+#include "ncdnodefunctionids.h"
+#include "ncdnodeclassids.h"
+#include "catalogsconstants.h"
+#include "ncd_pp_dataentity.h"
+#include "ncd_pp_subscription.h"
+#include "ncd_cp_query.h"
+#include "catalogsutils.h"
+#include "ncdstoragedataitem.h"
+#include "ncdsubscriptionssourceidentifier.h"
+#include "ncdserverpartofsubscription.h"
+#include "ncdclientssubscriptions.h"
+#include "ncdsubscriptiongroup.h"
+#include "catalogscontext.h"
+#include "ncddatabasestorage.h"
+#include "ncdstorage.h"
+#include "ncdproviderdefines.h"
+#include "ncdstorageitem.h"
+#include "ncdstoragemanagerimpl.h"
+#include "ncdpurchaseoptionimpl.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodemanager.h"
+#include "ncdrootnode.h"
+#include "ncdsubscriptiongroup.h"
+#include "ncdutils.h"
+#include "ncdnodeiconimpl.h"
+
+// This is for the contentsourcemap
+#include "ncdloadrootnodeoperationimpl.h"
+
+#include "ncdsubscriptionmanagerobserver.h"
+#include "ncdsubscriptiondatacompleter.h"
+
+#include "catalogsdebug.h"
+
+CNcdSubscriptionManager::CNcdSubscriptionManager(
+ CNcdStorageManager& aStorageManager,
+ CNcdNodeManager& aNodeManager )
+ : CCatalogsCommunicable(),
+ iStorageManager( aStorageManager ),
+ iNodeManager( aNodeManager )
+ {
+ DLTRACEIN((""));
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::ConstructL()
+ {
+ }
+
+CNcdSubscriptionManager* CNcdSubscriptionManager::NewL(
+ CNcdStorageManager& aStorageManager,
+ CNcdNodeManager& aNodeManager )
+ {
+ CNcdSubscriptionManager* self =
+ CNcdSubscriptionManager::NewLC( aStorageManager, aNodeManager );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+CNcdSubscriptionManager* CNcdSubscriptionManager::NewLC(
+ CNcdStorageManager& aStorageManager,
+ CNcdNodeManager& aNodeManager )
+ {
+ CNcdSubscriptionManager* self =
+ new( ELeave ) CNcdSubscriptionManager( aStorageManager, aNodeManager );
+ CleanupClosePushL( *self );
+ self->ConstructL();
+ return self;
+ }
+
+
+CNcdSubscriptionManager::~CNcdSubscriptionManager()
+ {
+ DLTRACEIN((""));
+
+ iSubscriptionDataCompleters.ResetAndDestroy();
+
+ // All subscriptions should be saved into database if they
+ // are new or changed. So there is no need to save all of them
+ // here.
+
+ const TInt clientsCount( iClientSubscriptions.Count() );
+ TInt indexer( 0 );
+
+ while( indexer < clientsCount )
+ {
+ delete iClientSubscriptions[indexer];
+
+ ++indexer;
+ }
+ iClientSubscriptions.Reset();
+
+ // Complete the pending messages
+ NotifyAllListeners( KErrServerTerminated );
+ iPendingMessages.Close();
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::SetOperationManager(
+ CNcdOperationManager* aManager )
+ {
+ iOperationManager = aManager;
+ }
+
+
+
+
+RPointerArray<CNcdSubscriptionsSourceIdentifier>
+ CNcdSubscriptionManager::SubscriptionsSourcesL( TUid aClientUid ) const
+ {
+ DLTRACEIN((""));
+
+ // First read possibly existing subscriptions sources from the
+ // subscriptions database
+ TInt clientIndex( -1 );
+ RPointerArray<CNcdSubscriptionsSourceIdentifier> sources;
+ TRAP_IGNORE( clientIndex = IsInCacheL( aClientUid ) );
+ if ( clientIndex > -1 )
+ {
+ TRAP_IGNORE( sources = SubscriptionsSourcesL( clientIndex ) );
+ }
+
+
+ DLINFO(( "Getting subscriptions sources from the root node." ));
+
+ // Get content sources from root node.
+ CNcdRootNode& rootNode =
+ iNodeManager.CreateRootL( aClientUid );
+ CNcdContentSourceMap& csMap = rootNode.ContentSourceMap();
+ DLTRACE(("Content sources: %d", csMap.ContentSourceCount() ));
+
+
+ TIdentityRelation<CNcdSubscriptionsSourceIdentifier> match(
+ &CNcdSubscriptionsSourceIdentifier::CompareIdentifiers );
+
+ for ( TInt i = 0; i < csMap.ContentSourceCount(); i++ )
+ {
+ CNcdContentSource& contentSource = csMap.ContentSource( i );
+ // When we get the source identifier from the root node, we don't know
+ // if it supports subscriptions so that has to be checked when sending
+ // requests -> aRequireCapabilityCheck (last param) is set ETrue
+ CNcdSubscriptionsSourceIdentifier* sourceId =
+ CNcdSubscriptionsSourceIdentifier::NewLC(
+ contentSource.Uri(), contentSource.NameSpace(), ETrue );
+
+ // Do not add the source identifier if the same exists already.
+ if ( sources.Find( sourceId, match ) == KErrNotFound )
+ {
+ sources.AppendL( sourceId );
+ DLINFO(( "Subscriptions source appended into the array." ));
+ CleanupStack::Pop( sourceId );
+ }
+ else
+ {
+ DLINFO(( "Subscriptions source already found from the array." ));
+ CleanupStack::PopAndDestroy( sourceId );
+ }
+
+ DLINFO(( _L( "Source namespace: %S."), &contentSource.NameSpace() ));
+ }
+
+ // Handle bundle content sources. This actually helps only after the
+ // user has browsed inside a bundle because we won't know the capabilities
+ // of the bundle's servers before that
+ TInt bundleCount = csMap.BundleFolderCount();
+ DLINFO(("Bundle folders: %d", bundleCount ));
+ for ( TInt i = 0; i < bundleCount; i++ )
+ {
+ const CNcdNodeIdentifier& bundleId = csMap.BundleFolder( i );
+ TInt folderIndex = csMap.FindFolder( bundleId );
+ CNcdFolderContent& folderContent = csMap.FolderContent( folderIndex );
+
+ DLTRACE(("Bundle has %d content sources",
+ folderContent.ContentSourceCount() ));
+
+ for ( TInt index = 0; index < folderContent.ContentSourceCount(); ++index )
+ {
+ CNcdContentSource& contentSource = folderContent.ContentSource( index );
+ // When we get the source identifier from the root node, we don't know
+ // if it supports subscriptions so that has to be checked when sending
+ // requests -> aRequireCapabilityCheck (last param) is set ETrue
+ CNcdSubscriptionsSourceIdentifier* sourceId =
+ CNcdSubscriptionsSourceIdentifier::NewLC(
+ contentSource.Uri(), contentSource.NameSpace(), ETrue );
+
+ // Do not add the source identifier if the same exists already.
+ if ( sources.Find( sourceId, match ) == KErrNotFound )
+ {
+ sources.AppendL( sourceId );
+ CleanupStack::Pop( sourceId );
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy( sourceId );
+ }
+ DLINFO(( _L( "Source namespace: %S."), &contentSource.NameSpace() ));
+ }
+ }
+
+ return sources;
+ }
+
+void CNcdSubscriptionManager::InternalizeSubscriptionsFromServerL(
+ TUid aClientUid,
+ const TDesC& aUri,
+ RPointerArray<MNcdPreminetProtocolSubscription>& aServersSubscriptions,
+ MCatalogsContext* aContext,
+ MNcdSubscriptionManagerObserver* aObserver )
+ {
+ DLTRACEIN((""));
+
+ // Should do leave handling
+
+ // First we create objects resembling subscriptions
+ // and mark them as recently created.
+ // This also writes subscriptions to database.
+ InternalizeAndMarkSubscriptionsL( aClientUid,
+ aUri,
+ aServersSubscriptions );
+
+ // Get the subscriptions related to given server
+ // Here we should get also the recently created ones
+ RPointerArray<CNcdSubscriptionGroup> serversGroups =
+ ServersGroupsL( aClientUid, aUri );
+
+ // In the end we remove subscriptions that were
+ // not received in the aServersSubscriptions array and reset
+ // the flags of subscriptions that were received. (Subscriptions that
+ // were not received from the server in the aServersSubscriptions array
+ // and are marked as received from the server (earlier) are removed
+ // from the database, from the cache and from the serversGroups
+ // array.)
+ TRAP_IGNORE( RemoveUnmarkedSubscriptionsL( aClientUid, serversGroups ) );
+
+ // Check that server's current subscriptions have all needed data and
+ // if not get them from the corresponding nodes. Do also the needed
+ // callback of observer and notifying of subscription manager's listeners
+ // Also database write is done after completion. The earlier write
+ // was done to ensure that some entry is found from the db if this
+ // operation does not end before shutdown or some possible error situation
+ // occurs.
+ TRAP_IGNORE( CompleteSubscriptionsDataL( aClientUid,
+ serversGroups,
+ aContext,
+ aObserver ) );
+
+ // As the subscriptions are stored in member variable,
+ // they should not be deleted. Just close for the array.
+ serversGroups.Close();
+ }
+
+
+void CNcdSubscriptionManager::InternalizeSubscriptionL(
+ TUid aClientUid,
+ const TDesC& aUri,
+ MNcdPreminetProtocolSubscription& aSubscription,
+ MCatalogsContext* aContext,
+ MNcdSubscriptionManagerObserver* aObserver )
+ {
+ DLTRACEIN((""));
+
+ // Get or create subscription group
+
+ CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
+ aClientUid,
+ aSubscription.EntityId(),
+ aSubscription.Namespace(),
+ aUri );
+
+
+ groupForSubscription.InternalizeSubscriptionL( aSubscription );
+
+ DLTRACE(( "Subscription internalized." ));
+
+ // Database should always have updated info so at this point we have
+ // to write updates there.
+
+ // Because there is a database for each client the writing has
+ // to be done here where we know which group was updated.
+
+ SaveGroupIntoDatabaseL( aClientUid,
+ groupForSubscription );
+
+ DLTRACE(( "Subscription group saved into database." ));
+
+
+ // Check that current subscription (and its group) has all needed
+ // data and if not, get them from the corresponding nodes. Do also
+ // the needed callback of observer and notifying of subscription
+ // manager's listeners. Also database write is done after completion.
+ // The earlier write was done to ensure that some entry is found
+ // from the db if this operation does not end before shutdown or
+ // some possible error situation occurs.
+ RPointerArray<CNcdSubscriptionGroup> groups;
+ groups.AppendL( &groupForSubscription );
+ TRAP_IGNORE( CompleteSubscriptionsDataL( aClientUid,
+ groups,
+ aContext,
+ aObserver ) );
+
+ // As the subscriptions are stored in member variable,
+ // they should not be deleted. Just close for the array.
+ groups.Close();
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdSubscriptionManager::RemoveSubscriptionL(
+ const CNcdNodeIdentifier& aData,
+ const TDesC& aPurchaseOptionId)
+ {
+
+ CNcdSubscriptionGroup& group = FindGroupL( aData.ClientUid(),
+ aData.NodeId(),
+ aData.NodeNameSpace() );
+
+ group.RemoveSubscriptionL( aPurchaseOptionId );
+
+ if ( group.SubscriptionCount() == 0 )
+ {
+ TInt index = IsInCacheL( aData.ClientUid() );
+ CNcdClientsSubscriptions* clientsSubscriptions =
+ iClientSubscriptions[index];
+
+ clientsSubscriptions->RemoveGroup( &group );
+
+ RemoveGroupFromDatabaseL( aData.ClientUid(),
+ group );
+ }
+ else
+ {
+ SaveGroupIntoDatabaseL( aData.ClientUid(), group );
+ }
+
+ // As the clientsSubscriptions only exists in the cache,
+ // it is not checked that if groups still exist after this
+ // group removal and whether the clientsSubscriptions
+ // should be removed.
+
+ // Notify the listeners.
+ NotifyListeners( aData.ClientUid() );
+ }
+
+CNcdSubscription& CNcdSubscriptionManager::SubscriptionL(
+ const TDesC& aNodeId,
+ const TDesC& aNodeNameSpace,
+ const TDesC& aPurchaseOptionId,
+ const TUid& aClientUid )
+ {
+ DLTRACEIN((""));
+
+ TInt index = IsInCacheL( aClientUid );
+ CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
+ RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
+ TInt groupIndex = FindGroupL( groups, aNodeId, aNodeNameSpace );
+ CNcdSubscriptionGroup* group = groups[groupIndex];
+ return group->SubscriptionIfExistsL( aPurchaseOptionId );
+ }
+
+
+void CNcdSubscriptionManager::ClearSubscriptionDbL( const MCatalogsContext& aContext )
+ {
+ DLTRACEIN((""));
+ iStorageManager.RemoveStorageL(
+ aContext.FamilyId().Name(), NcdProviderDefines::KSubscriptionNamespace );
+
+ // Remove from RAM cache too.
+ for ( TInt i = 0; i < iClientSubscriptions.Count(); i++ )
+ {
+ if ( iClientSubscriptions[i]->ClientId() == aContext.FamilyId() )
+ {
+ delete iClientSubscriptions[i];
+ iClientSubscriptions.Remove( i );
+ break;
+ }
+ }
+ }
+
+
+void CNcdSubscriptionManager::NotifyListeners( TUid aClientUid )
+ {
+ DLTRACEIN((""));
+ for ( TInt i = iPendingMessages.Count() - 1; i >= 0; i-- )
+ {
+ if ( iPendingMessages[i]->Session().Context().FamilyId() ==
+ aClientUid )
+ {
+ iPendingMessages[i]->CompleteAndRelease( KErrNone );
+ iPendingMessages.Remove( i );
+ }
+ }
+ }
+
+void CNcdSubscriptionManager::SubscriptionCompleted(
+ CNcdSubscriptionDataCompleter* aFinishedCompleter )
+ {
+ const TInt KCompleterAmount( iSubscriptionDataCompleters.Count() );
+ TInt completerIndexer( 0 );
+
+ CNcdSubscriptionDataCompleter* tempCompleter( NULL );
+ while ( completerIndexer < KCompleterAmount )
+ {
+ tempCompleter = iSubscriptionDataCompleters[ completerIndexer ];
+ if ( tempCompleter == aFinishedCompleter )
+ {
+ iSubscriptionDataCompleters.Remove( completerIndexer );
+ delete aFinishedCompleter;
+ return;
+ }
+ ++completerIndexer;
+ }
+ }
+
+void CNcdSubscriptionManager::SaveGroupIntoDatabaseL(
+ TUid aClientUid,
+ CNcdSubscriptionGroup& aGroup )
+ {
+ DLTRACEIN((""));
+
+ // Databases are created for each client. (for each uid)
+ // As a namespace we use a constant namespace (KSubscriptionNameSpace)
+ // so we know in the future where from to load all data.
+
+ HBufC* dataId = GenerateGroupDataIdL( aGroup );
+ CleanupStack::PushL( dataId );
+
+ DLTRACE(( _L("DataId for subscription group database item: %S"),
+ dataId ));
+
+
+ SaveDataIntoDatabaseL( aClientUid,
+ NcdProviderDefines::KSubscriptionNamespace,
+ *dataId,
+ aGroup,
+ NcdNodeClassIds::ENcdSubscriptionsData );
+
+ CleanupStack::PopAndDestroy( dataId );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdSubscriptionManager::ReceiveMessage(
+ MCatalogsBaseMessage* aMessage,
+ TInt aFunctionNumber )
+ {
+ DLTRACEIN((""));
+
+ DASSERT( aMessage );
+
+ // Now, we can be sure that rest of the time iMessage exists.
+ // This member variable is set for the CounterPartLost function.
+ iMessage = aMessage;
+
+ TInt trapError( KErrNone );
+
+ // Check which function is called by the proxy side object.
+ // Function number are located in ncdnodefunctinoids.h file.
+ switch( aFunctionNumber )
+ {
+ case NcdNodeFunctionIds::ENcdSubscriptionGroupIdentifiers:
+ // Subscription group identifiers requested from proxy side.
+ TRAP( trapError, SubscriptionGroupIdentifiersRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdInternalize:
+ // Internalize the proxy side according to the data
+ // of this object.
+ TRAP( trapError, InternalizeRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdRelease:
+ // The proxy does not want to use this object anymore.
+ // So, release the handle from the session.
+ ReleaseRequest( *aMessage );
+ break;
+
+ case NcdNodeFunctionIds::ENcdListenerEnrollment:
+ // The proxy wants to enroll as listener.
+ TRAP( trapError, ListenerEnrolledL( *aMessage ) );
+ break;
+
+ default:
+ break;
+ }
+
+ if ( trapError != KErrNone )
+ {
+ // Because something went wrong, the complete has not been
+ // yet called for the message.
+ // So, inform the client about the error if the
+ // message is still available.
+ aMessage->CompleteAndRelease( trapError );
+ }
+
+ // Because the message should not be used after this, set it NULL.
+ // So, CounterPartLost function will know that no messages are
+ // waiting the response at the moment.
+ iMessage = NULL;
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdSubscriptionManager::CounterPartLost(
+ const MCatalogsSession& aSession )
+ {
+ // This function may be called whenever -- when the message is waiting
+ // response or when the message does not exist.
+ // iMessage may be NULL here, because in the end of the
+ // ReceiveMessage it is set to NULL. The life time of the message
+ // ends shortly after CompleteAndRelease is called.
+ if ( iMessage != NULL )
+ {
+ iMessage->CounterPartLost( aSession );
+ }
+
+ for ( TInt i = 0; i < iPendingMessages.Count(); i++ )
+ {
+ iPendingMessages[i]->CounterPartLost( aSession );
+ }
+ }
+
+
+
+void CNcdSubscriptionManager::ReleaseRequest(
+ MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+
+ // Decrease the reference count for this object.
+ // When the reference count reaches zero, this object will be destroyed
+ // and removed from the session.
+ MCatalogsSession& requestSession( aMessage.Session() );
+ TInt handle( aMessage.Handle() );
+
+ DLTRACE(("Calling counterpart lost for messages"));
+ for ( TInt i = 0; i < iPendingMessages.Count(); i++ )
+ {
+ iPendingMessages[i]->CounterPartLost( requestSession );
+ }
+
+
+ // Send complete information back to proxy.
+ aMessage.CompleteAndRelease( KErrNone );
+
+ // Remove this object from the session.
+ requestSession.RemoveObject( handle );
+
+ DLTRACEOUT((""));
+ }
+
+
+
+
+void CNcdSubscriptionManager::InternalizeRequestL(
+ MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+
+ // Parse the input message and create an array containing
+ // subscription group identifiers which are requested.
+ RPointerArray<CNcdKeyValuePair> groupIds;
+ CleanupResetAndDestroyPushL( groupIds );
+
+ HBufC8* input = HBufC8::NewLC( aMessage.InputLength() );
+ TPtr8 inputPtr = input->Des();
+ aMessage.ReadInput( inputPtr );
+ RDesReadStream inputStream( *input );
+ CleanupClosePushL( inputStream );
+
+ TInt32 groupCount = inputStream.ReadInt32L();
+ groupIds.ReserveL( groupCount );
+ for ( TInt i = 0; i < groupCount; i++ )
+ {
+ CNcdKeyValuePair* pair = CNcdKeyValuePair::NewL( inputStream );
+ groupIds.Append( pair );
+ }
+
+ CleanupStack::PopAndDestroy( &inputStream );
+ CleanupStack::PopAndDestroy( input );
+
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+
+ // We need session info in the functions for example to
+ // check the client id (there can be several clients)
+ // and to register needed objects to the session.
+ MCatalogsSession& session = aMessage.Session();
+ TUid clientUid = session.Context().FamilyId();
+
+ ExternalizeClientsSubscriptionsL( session, groupIds, stream );
+
+ // Commits data to the stream when closing.
+ CleanupStack::PopAndDestroy( &stream );
+
+
+ // If this leaves, ReceiveMessage will complete the message.
+ // NOTE: that here we expect that the buffer contains at least
+ // some data. So, make sure that ExternalizeDataForRequestL inserts
+ // something to the buffer.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+
+
+ DLTRACE(("Deleting the buf"));
+ CleanupStack::PopAndDestroy( buf );
+ CleanupStack::PopAndDestroy( &groupIds );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdSubscriptionManager::SubscriptionGroupIdentifiersRequestL(
+ MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+ TUid clientUid = aMessage.Session().Context().FamilyId();
+ TInt clientIndex( -1 );
+ TRAPD( err, clientIndex = IsInCacheL( clientUid ) );
+ if ( err == KErrNotFound )
+ {
+ // Check also storage.
+ // Needed for example when the engine has not retrieved
+ // the info from db after last restart.
+ TRAP_IGNORE( LoadClientsInfoFromStorageL( clientUid ) );
+
+ TRAP_IGNORE( clientIndex = IsInCacheL( clientUid ) );
+ }
+
+ if ( clientIndex < 0 )
+ {
+ stream.WriteInt32L( 0 );
+ }
+ else
+ {
+ CNcdClientsSubscriptions* subscriptions =
+ iClientSubscriptions[clientIndex];
+ RPointerArray<CNcdSubscriptionGroup>& groups =
+ subscriptions->Groups();
+ stream.WriteInt32L( groups.Count() );
+ for ( TInt i = 0; i < groups.Count(); i++ )
+ {
+ CNcdKeyValuePair* pair = CNcdKeyValuePair::NewLC(
+ groups[i]->Namespace(), groups[i]->EntityId() );
+ pair->ExternalizeL( stream );
+ CleanupStack::PopAndDestroy( pair );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &stream );
+
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+
+ CleanupStack::PopAndDestroy( buf );
+ }
+
+
+void CNcdSubscriptionManager::CompleteSubscriptionsDataL(
+ TUid aClientUid,
+ RPointerArray<CNcdSubscriptionGroup>& aServersGroups,
+ MCatalogsContext* aContext,
+ MNcdSubscriptionManagerObserver* aObserver )
+ {
+ DLTRACEIN((""));
+ // Create array of node identifiers to identify the nodes
+ // (and subscriptions)
+ // and create array of purchase option ids to identify
+ // the subscriptions
+ RPointerArray<CNcdNodeIdentifier> nodeIds;
+ CDesCArrayFlat* purchaseOptionIDs( NULL );
+
+ CNcdSubscriptionDataCompleter* completer( NULL );
+ TRAPD( error,
+ {
+ purchaseOptionIDs = new (ELeave) CDesCArrayFlat( 5 );
+ IdentifiersForCompletionL( aServersGroups,
+ nodeIds,
+ *purchaseOptionIDs );
+
+ // Create data completer object
+ completer =
+ CNcdSubscriptionDataCompleter::NewL( *this,
+ iNodeManager,
+ *iOperationManager );
+ iSubscriptionDataCompleters.AppendL( completer );
+
+ } );
+ if ( error != KErrNone )
+ {
+ nodeIds.ResetAndDestroy();
+
+ if ( purchaseOptionIDs )
+ {
+ purchaseOptionIDs->Reset();
+ }
+ User::Leave( error );
+ }
+
+ // passing ownership of identifiers
+ completer->CompleteSubscriptions( aClientUid,
+ nodeIds,
+ purchaseOptionIDs,
+ aContext,
+ aObserver );
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::IdentifiersForCompletionL(
+ RPointerArray<CNcdSubscriptionGroup>& aGroups,
+ RPointerArray<CNcdNodeIdentifier>& aNodeIds,
+ CDesCArrayFlat& aPurchaseOptionIDs )
+ {
+ DLTRACEIN((""));
+ TInt groupIndex( 0 );
+ const TInt KGroupCount( aGroups.Count() );
+ while( groupIndex < KGroupCount )
+ {
+ DLINFO(( "group nro: %d", groupIndex ));
+ aGroups[groupIndex]->AppendIncompleteSubscriptionIDsL(
+ aNodeIds,
+ aPurchaseOptionIDs );
+
+ ++groupIndex;
+ }
+ DLTRACEOUT((""));
+ }
+
+TInt CNcdSubscriptionManager::IsInCacheL( TUid aUid ) const
+ {
+ DLTRACEIN((""));
+
+ TInt clientIndex( 0 );
+ const TInt KClientCount( iClientSubscriptions.Count() );
+ while( clientIndex < KClientCount )
+ {
+ if ( iClientSubscriptions[clientIndex]->ClientId() == aUid )
+ {
+ return clientIndex;
+ }
+ ++clientIndex;
+ }
+
+ User::Leave( KErrNotFound );
+ DLTRACEOUT((""));
+ return KErrNotFound;
+ }
+
+
+TInt CNcdSubscriptionManager::ClientsSubscriptionsL( TUid aClientUid )
+ {
+ DLTRACEIN((""));
+ TInt clientIndex( -1 );
+ TRAPD( searchError, clientIndex = IsInCacheL( aClientUid ) );
+ if ( searchError == KErrNotFound )
+ {
+ // Let's create new ClientsSubscriptions because it was not
+ // found
+ CNcdClientsSubscriptions* clientsSubscriptions =
+ CNcdClientsSubscriptions::NewLC( aClientUid );
+ iClientSubscriptions.AppendL( clientsSubscriptions );
+ CleanupStack::Pop( clientsSubscriptions );
+
+ // set clientIndex to the appended clients subscriptions
+ clientIndex = iClientSubscriptions.Count() - 1;
+ }
+ else if ( searchError != KErrNone )
+ {
+ // If leave occurs and it is not KErrNotFound, leave.
+ User::Leave( searchError );
+ }
+
+ return clientIndex;
+ }
+
+
+TInt CNcdSubscriptionManager::FindGroupL(
+ const RPointerArray<CNcdSubscriptionGroup>& aGroups,
+ const TDesC& aEntityId,
+ const TDesC& aNamespace ) const
+ {
+ DLTRACEIN((""));
+
+ TInt groupIndex( 0 );
+ const TInt KGroupCount( aGroups.Count() );
+ while( groupIndex < KGroupCount )
+ {
+ if ( aGroups[groupIndex]->EntityId() == aEntityId &&
+ aGroups[groupIndex]->Namespace() == aNamespace )
+ {
+ return groupIndex;
+ }
+ ++groupIndex;
+ }
+
+ User::Leave( KErrNotFound );
+ DLTRACEOUT((""));
+ return KErrNotFound;
+ }
+
+CNcdSubscriptionGroup& CNcdSubscriptionManager::FindGroupL(
+ TUid aClientUid,
+ const TDesC& aEntityId,
+ const TDesC& aNamespace ) const
+ {
+ DLTRACEIN((""));
+ TInt index = IsInCacheL( aClientUid );
+ CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
+ RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
+ TInt groupIndex = FindGroupL( groups, aEntityId, aNamespace );
+ return *groups[groupIndex];
+ }
+
+CNcdSubscriptionGroup& CNcdSubscriptionManager::ClientsSubscriptionGroupL(
+ const TDesC& aUri,
+ const CNcdPurchaseOptionImpl& aData )
+ {
+ DLTRACEIN((""));
+
+ const CNcdNodeIdentifier& nodeIdentifier = aData.ParentMetaIdentifier();
+ const TDesC& nameSpace = nodeIdentifier.NodeNameSpace();
+ const TUid& clientUid = nodeIdentifier.ClientUid();
+ const TDesC& entityId = nodeIdentifier.NodeId();
+
+ CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
+ clientUid,
+ entityId,
+ nameSpace,
+ aUri );
+
+ // Icon is always set here to be sure that it is set. So it does
+ // not have to be retrieved later on.
+ // Icon for the subscription is at the moment thought to be icon
+ // of the node where from the subscription is bought
+ const CNcdNodeIcon& metaDataIcon = aData.ParentIconL();
+ HBufC8* icon = metaDataIcon.IconDataL();
+ CleanupStack::PushL( icon );
+ groupForSubscription.SetIconL( *icon );
+ CleanupStack::PopAndDestroy( icon );
+
+ return groupForSubscription;
+ }
+
+CNcdSubscriptionGroup& CNcdSubscriptionManager::ClientsSubscriptionGroupL(
+ TUid aClientUid,
+ const TDesC& aEntityId,
+ const TDesC& aNamespace,
+ const TDesC& aUri )
+ {
+ DLTRACEIN((""));
+ // Get or create object for clients subscription info
+ TInt clientIndex( ClientsSubscriptionsL( aClientUid ) );
+
+ RPointerArray<CNcdSubscriptionGroup>& groupsOfClient =
+ iClientSubscriptions[clientIndex]->Groups();
+
+ // Go through groups resembling subscriptions and if a group
+ // is from the same dataentity as the given
+ // protocol-subscription, use it.
+
+ TInt groupIndex( -1 );
+ TRAPD( searchError, groupIndex = FindGroupL( groupsOfClient,
+ aEntityId,
+ aNamespace ) );
+ if ( searchError == KErrNotFound )
+ {
+ // Let's create new group because it was not
+ // found
+ CNcdSubscriptionGroup* group =
+ CNcdSubscriptionGroup::NewLC();
+ groupsOfClient.AppendL( group );
+ CleanupStack::Pop( group );
+
+ group->SetEntityInfoL( aEntityId,
+ aNamespace,
+ aUri,
+ aClientUid );
+
+ // set clientIndex to the appended clients subscriptions
+ groupIndex = groupsOfClient.Count() - 1;
+ }
+ else if ( searchError != KErrNone )
+ {
+ // If leave occurs and it is not KErrNotFound, leave.
+ User::Leave( searchError );
+ }
+
+ return *(groupsOfClient[groupIndex]);
+ }
+
+RPointerArray<CNcdSubscriptionGroup> CNcdSubscriptionManager::ServersGroupsL(
+ TUid aClientUid,
+ const TDesC& aUri ) const
+ {
+ DLTRACEIN((""));
+ // Into this array we gather all groups that are got from the given
+ // server
+ RPointerArray<CNcdSubscriptionGroup> returnArray;
+ CleanupClosePushL( returnArray );
+
+ TInt index = IsInCacheL( aClientUid );
+ CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
+ // All groups (also groups from other servers)
+ RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
+
+ // And now, take only groups that are from the given server
+ TInt groupCount( groups.Count() );
+ TInt groupIndex( 0 );
+
+ while ( groupIndex < groupCount )
+ {
+ if ( aUri == groups[groupIndex]->ServerUri() )
+ {
+ returnArray.AppendL( groups[groupIndex] );
+ }
+ ++groupIndex;
+ }
+
+ CleanupStack::Pop( &returnArray );
+ return returnArray;
+ }
+
+void CNcdSubscriptionManager::InternalizeAndMarkSubscriptionsL(
+ TUid aClientUid,
+ const TDesC& aUri,
+ RPointerArray<MNcdPreminetProtocolSubscription>&
+ aServersSubscriptions )
+ {
+ DLTRACEIN((""));
+ TInt count( aServersSubscriptions.Count() );
+
+ for ( TInt i = 0; i < count; i++ )
+ {
+ DLINFO(( "index: %d of count: %d", i, count ));
+ // Write all that can be updated. If some are not
+ // successfull, continue to next one.
+ TRAP_IGNORE( InternalizeAndMarkSubscriptionL(
+ aClientUid,
+ aUri,
+ *aServersSubscriptions[i] ) );
+ }
+ }
+
+void CNcdSubscriptionManager::InternalizeAndMarkSubscriptionL(
+ TUid aClientUid,
+ const TDesC& aUri,
+ MNcdPreminetProtocolSubscription& aSubscription )
+ {
+ DLTRACEIN((""));
+ // First internalize and write to db
+ InternalizeSubscriptionL( aClientUid,
+ aUri,
+ aSubscription );
+ DLINFO((""));
+ // Search for group and then mark it as updated so that
+ // all that were not updated can be removed later on.
+ // If this fails, then this subscription will probably be
+ // removed later on.
+
+ CNcdSubscriptionGroup& group = FindGroupL( aClientUid,
+ aSubscription.EntityId(),
+ aSubscription.Namespace() );
+
+ SaveGroupIntoDatabaseL( aClientUid, group );
+ DLTRACE(( "Subscription group saved into database." ));
+
+ // With this flag we later determine if this subscription was
+ // received from the server and should not be removed.
+ group.SetRecentlyUpdatedL( ETrue,
+ aSubscription.PurchaseOptionId() );
+ DLINFO(("subscription set as recently updated"));
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::InternalizeSubscriptionL(
+ TUid aClientUid,
+ const TDesC& aUri,
+ MNcdPreminetProtocolSubscription& aSubscription )
+ {
+ DLTRACEIN((""));
+
+ // Get or create subscription group
+
+ CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
+ aClientUid,
+ aSubscription.EntityId(),
+ aSubscription.Namespace(),
+ aUri );
+
+
+ groupForSubscription.InternalizeSubscriptionL( aSubscription );
+
+ DLTRACE(( "Subscription internalized." ));
+
+ // Database should always have updated info so at this point we have
+ // to write updates there.
+
+ // Because there is a database for each client the writing has
+ // to be done here where we know which group was updated.
+
+ SaveGroupIntoDatabaseL( aClientUid,
+ groupForSubscription );
+
+ DLTRACE(( "Subscription group saved into database." ));
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::RemoveUnmarkedSubscriptionsL(
+ TUid aClientUid,
+ RPointerArray<CNcdSubscriptionGroup>& aGroups )
+ {
+ DLTRACEIN((""));
+ // Client reference is only needed if a whole group has to be removed
+ TInt index = IsInCacheL( aClientUid );
+ CNcdClientsSubscriptions* clientsSubscriptions =
+ iClientSubscriptions[index];
+
+
+ TInt groupIndex( aGroups.Count() - 1 );
+
+ while ( groupIndex > -1 )
+ {
+ TBool changesMade =
+ aGroups[groupIndex]->RemoveUnmarkedSubscriptionsAndUnmarkL();
+
+ if ( changesMade )
+ {
+ if ( aGroups[groupIndex]->SubscriptionCount() == 0 )
+ {
+ // No subscriptions left in the group, remove the group
+
+ // from cache
+ clientsSubscriptions->RemoveGroup( aGroups[groupIndex] );
+ // from db
+ RemoveGroupFromDatabaseL( aClientUid,
+ *aGroups[groupIndex] );
+
+ // Remove the group also from the array given array
+ // so the array is up to date and can be used after
+ // completion of this function
+ aGroups.Remove( groupIndex );
+ }
+ else
+ {
+ // Subscriptions left in the group, write current
+ // status of the group into db
+ SaveGroupIntoDatabaseL( aClientUid, *aGroups[groupIndex] );
+ }
+ }
+ --groupIndex;
+ }
+
+ // As the clientsSubscriptions only exists in the cache,
+ // it is not checked that if groups still exist after this
+ // group removal and whether the clientsSubscriptions
+ // should be removed.
+ }
+
+RPointerArray<CNcdSubscriptionsSourceIdentifier>
+ CNcdSubscriptionManager::SubscriptionsSourcesL( TInt aClientIndex ) const
+ {
+ DLTRACEIN(( "Getting subscriptions sources from subscriptions db." ));
+ RPointerArray<CNcdSubscriptionGroup>& clientsGroups =
+ iClientSubscriptions[aClientIndex]->Groups();
+
+ TInt groupCount( clientsGroups.Count() );
+ if ( groupCount < 1 )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ RPointerArray<CNcdSubscriptionsSourceIdentifier> returnArray;
+ CleanupResetAndDestroyPushL( returnArray );
+
+ // Let's take the first subscriptions source info always into
+ // the array because nothing is yet in the array.
+
+ // Notice that in this function we set all source identifiers not
+ // to require capability check. This is because we assume that
+ // if the server has once supported subscriptions, it will support
+ // them also later.
+
+ TInt groupIndex( 0 );
+
+ CNcdSubscriptionsSourceIdentifier* tmpIdentifier =
+ CNcdSubscriptionsSourceIdentifier::NewLC(
+ clientsGroups[groupIndex]->ServerUri(),
+ clientsGroups[groupIndex]->Namespace(),
+ EFalse );
+
+ returnArray.AppendL( tmpIdentifier );
+ CleanupStack::Pop( tmpIdentifier );
+ tmpIdentifier = NULL;
+
+ ++groupIndex;
+
+ // Then go through others one at a time and check that such info
+ // is not already found from the array.
+
+ // Notice that only uri and namespace are compared here,
+ // capability requirement is not checked
+ TIdentityRelation<CNcdSubscriptionsSourceIdentifier> match(
+ &CNcdSubscriptionsSourceIdentifier::CompareIdentifiers );
+
+ while ( groupIndex < groupCount )
+ {
+ tmpIdentifier = CNcdSubscriptionsSourceIdentifier::NewLC(
+ clientsGroups[groupIndex]->ServerUri(),
+ clientsGroups[groupIndex]->Namespace(),
+ EFalse );
+
+ if ( returnArray.Find( tmpIdentifier, match ) == KErrNotFound )
+ {
+ returnArray.AppendL( tmpIdentifier );
+ CleanupStack::Pop( tmpIdentifier );
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy( tmpIdentifier );
+ }
+
+ tmpIdentifier = NULL;
+
+ ++groupIndex;
+ }
+
+ CleanupStack::Pop( &returnArray );
+
+ return returnArray;
+ }
+
+
+void CNcdSubscriptionManager::ExternalizeClientsSubscriptionsL(
+ MCatalogsSession& aSession,
+ const RPointerArray<CNcdKeyValuePair>& aGroupIdentifiers,
+ RWriteStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ if ( aGroupIdentifiers.Count() == 0)
+ {
+ aStream.WriteInt32L( 0 );
+ return;
+ }
+
+ // Because one subscription manager serves all clients, we
+ // check here which client uid the client has and pass it
+ // forward
+ MCatalogsContext& context = aSession.Context();
+ TUid familyId = context.FamilyId();
+
+ // check if clients info is in cache
+ TInt index( -1 );
+ index = IsInCacheL( familyId );
+
+ ExternalizeDataForRequestL( index, aSession, aGroupIdentifiers, aStream );
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::LoadClientsInfoFromStorageL( TUid aUid )
+ {
+ DLTRACEIN((""));
+
+ DLTRACE(( "Loading subscription info from storage for client: %d",
+ aUid.iUid ));
+
+ // Loading from the current client
+ MNcdStorage& storage = *StorageL( aUid,
+ NcdProviderDefines::KSubscriptionNamespace );
+
+ // NOTE: this creates the database if it does not already exist
+ MNcdDatabaseStorage& database =
+ storage.DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
+
+ CNcdClientsSubscriptions* clientsSubscriptions =
+ CNcdClientsSubscriptions::NewLC( aUid );
+
+ iClientSubscriptions.AppendL( clientsSubscriptions );
+
+ CleanupStack::Pop( clientsSubscriptions );
+
+
+ RPointerArray<MNcdStorageItem> items;
+ CleanupClosePushL( items );
+ database.StorageItemsL( items );
+
+ const TInt foudItemCount( items.Count() );
+
+ DLTRACE(( "Found %d subscription storage items for client %d.",
+ foudItemCount,
+ aUid.iUid ));
+
+ if ( items.Count() < 1 )
+ {
+ // Nothing is found for given client, but the
+ // ClientsSubscriptions-object is created for possible later
+ // use
+ CleanupStack::PopAndDestroy( &items );
+ return;
+ }
+
+ TInt itemIndex( 0 );
+ while( itemIndex < foudItemCount )
+ {
+ CNcdSubscriptionGroup* group = CNcdSubscriptionGroup::NewLC();
+
+ clientsSubscriptions->AddGroupL( group );
+
+ CleanupStack::Pop( group );
+
+ // Note: database has the ownership of the item
+ MNcdStorageItem* item = items[itemIndex];
+
+ // Get data from database by using aDataItem as the target so that
+ // internalize will be called for it
+ item->SetDataItem( group );
+
+ // Read node data -> calls InternalizeL of aDataItem
+ item->ReadDataL();
+
+ ++itemIndex;
+ }
+ CleanupStack::PopAndDestroy( &items );
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdSubscriptionManager::ExternalizeDataForRequestL(
+ TInt aIndex,
+ MCatalogsSession& aSession,
+ const RPointerArray<CNcdKeyValuePair>& aGroupIdentifiers,
+ RWriteStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ if ( aIndex < 0 )
+ {
+ // No entries with given client uid. If there was one, then its
+ // Externalize (which is called later) has to write the amount
+ // of groups as its first entry. This way we have entry amount
+ // always as the first entry in the stream.
+ aStream.WriteInt32L( 0 );
+ return;
+ }
+
+ CNcdClientsSubscriptions* clientsSubscriptions =
+ iClientSubscriptions[aIndex];
+
+ RPointerArray<CNcdSubscriptionGroup>& groups =
+ clientsSubscriptions->Groups();
+
+ aStream.WriteInt32L( aGroupIdentifiers.Count() );
+ for ( TInt i = 0; i < aGroupIdentifiers.Count(); i++ )
+ {
+ const TDesC& nameSpace = aGroupIdentifiers[i]->Key();
+ const TDesC& entityId = aGroupIdentifiers[i]->Value();
+
+ TBool found = EFalse;
+ for ( TInt i = 0; i < groups.Count(); i++ )
+ {
+ CNcdSubscriptionGroup* group = groups[i];
+ if ( group->Namespace() == nameSpace &&
+ group->EntityId() == entityId )
+ {
+ TInt tmpHandle( aSession.AddObjectL( group ) );
+ DLTRACE(( "Sending subscriptiongroup handle: %i",
+ tmpHandle ));
+ TRAPD( addError, aStream.WriteInt32L( tmpHandle ));
+ if ( addError != KErrNone )
+ {
+ // Should all other added objects be removed from
+ // the session also?
+ aSession.RemoveObject( tmpHandle );
+ User::Leave( addError );
+ }
+ found = ETrue;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ User::Leave( KErrNotFound );
+ }
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+HBufC* CNcdSubscriptionManager::GenerateGroupDataIdL(
+ CNcdSubscriptionGroup& aGroup )
+ {
+ // Items written to database are identified by classtype (integer)
+ // and dataid (string). Here we use a constant classtype so the
+ // dataid has to be unique. Because group contains subscriptions
+ // available from one entity, we use entityid and namespace to
+ // identify the item. The format is as follows:
+ // namespace<separator>entityid
+ // This kind of format does not promise full uniqueness but it is
+ // hopefully close enough.
+
+ const TDesC& entityNamespace = aGroup.Namespace();
+ TInt namespaceLength( entityNamespace.Length() );
+
+ const TDesC& entityId = aGroup.EntityId();
+ TInt entityIdLength( entityId.Length() );
+
+ _LIT( KIdSeparator, "|" );
+
+ HBufC* dataId = HBufC::NewL( namespaceLength + entityIdLength + 1 );
+ TPtr modifiableDataId = dataId->Des();
+
+ modifiableDataId.Append( entityNamespace );
+ modifiableDataId.Append( KIdSeparator );
+ modifiableDataId.Append( entityId );
+
+ return dataId;
+ }
+
+void CNcdSubscriptionManager::RemoveGroupFromDatabaseL(
+ TUid aClientUid,
+ CNcdSubscriptionGroup& aGroup )
+ {
+ DLTRACEIN((""));
+
+ // Databases are created for each client. (for each uid)
+ // As a namespace we use a constant namespace (KSubscriptionNameSpace)
+ // so we know in the future where from to load all data.
+
+ HBufC* dataId = GenerateGroupDataIdL( aGroup );
+ CleanupStack::PushL( dataId );
+
+ DLTRACE(( _L("DataId for subscription group database item: %S"),
+ dataId ));
+
+
+ RemoveDataFromDatabaseL( aClientUid,
+ NcdProviderDefines::KSubscriptionNamespace,
+ *dataId,
+ NcdNodeClassIds::ENcdSubscriptionsData );
+
+ CleanupStack::PopAndDestroy( dataId );
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::RemoveDataFromDatabaseL(
+ TUid aUid,
+ const TDesC& aNamespace,
+ const TDesC& aDataId,
+ NcdNodeClassIds::TNcdNodeClassType aClassType )
+ {
+ DLTRACEIN(( _L("%S::%S"), &aNamespace, &aDataId ));
+
+ DLTRACE(( _L("Removing database item with dataid: %S and classtype: %d"),
+ &aDataId,
+ aClassType ));
+
+ if( aNamespace == KNullDesC || aDataId == KNullDesC )
+ {
+ DLTRACE(( _L("Empty namespace or id given for storage removing: %S, %S"),
+ &aNamespace,
+ &aDataId ));
+ User::Leave( KErrArgument );
+ }
+
+ // Removing from the current client and from the namespace in which
+ // the metadata is defined
+ MNcdStorage* storage = StorageL( aUid, aNamespace );
+
+ // NOTE: this creates the database if it does not already exist
+ MNcdDatabaseStorage& database =
+ storage->DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
+
+ // Get/create the storage item which is used in removal
+ // Note: database has the ownership of the item
+ MNcdStorageItem* storageItem =
+ database.StorageItemL( aDataId, aClassType );
+
+ // Remove the item from the storage
+ storageItem->RemoveFromStorageL();
+
+ // Make the removing happen.
+ database.CommitL();
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdSubscriptionManager::SaveDataIntoDatabaseL(
+ TUid aUid,
+ const TDesC& aNamespace,
+ const TDesC& aDataId,
+ MNcdStorageDataItem& aDataItem,
+ NcdNodeClassIds::TNcdNodeClassType aClassType )
+ {
+ DLTRACEIN(( _L("%S::%S"), &aNamespace, &aDataId ));
+
+ DLTRACE(( _L("Saving to database item with dataid: %S and classtype: %d"),
+ &aDataId,
+ aClassType ));
+
+ if( aNamespace == KNullDesC || aDataId == KNullDesC )
+ {
+ DLTRACE(( _L("Empty namespace or id given for storage saving: %S, %S"),
+ &aNamespace,
+ &aDataId ));
+ User::Leave( KErrArgument );
+ }
+
+ // Storing to the current client and to the namespace in which
+ // the metadata is defined
+ MNcdStorage* storage = StorageL( aUid, aNamespace );
+
+ // NOTE: this creates the database if it does not already exist
+ MNcdDatabaseStorage& database =
+ storage->DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
+
+ // Get/create the storage item where the data is saved
+ // Note: database has the ownership of the item
+ MNcdStorageItem* storageItem =
+ database.StorageItemL( aDataId, aClassType );
+
+ // Here call the storage functions that will handle
+ // the saving of the data
+
+ // Save new item to database
+ storageItem->SetDataItem( &aDataItem );
+ storageItem->OpenL();
+
+ // Calls ExternalizeL for data item
+ storageItem->WriteDataL();
+
+ // Save the data to the database.
+ // The data object implements MNcdStorageDataItem interface.
+ // So, the externalize function will insert the data to the stream
+ // that the database handler will save to the database.
+ storageItem->SaveL();
+
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// StorageL
+// ---------------------------------------------------------------------------
+//
+MNcdStorage* CNcdSubscriptionManager::StorageL(
+ TUid aUid,
+ const TDesC& aNamespace ) const
+ {
+ DLTRACEIN((""));
+ MNcdStorage* storage = NULL;
+
+ DLTRACE(( _L("Subscriptions storage namespace: %S"), &aNamespace ));
+
+ // No need to clean the name anymore
+ HBufC* uid = aUid.Name().AllocLC();
+
+ TRAPD( err,
+ {
+ storage = &iStorageManager.StorageL( *uid,
+ aNamespace );
+ });
+
+ if ( err == KErrNotFound )
+ {
+ DLTRACE(("Creating subscription storage for the client"));
+ DLTRACE(( _L("Client identifying uid is %S"), uid ));
+ storage =
+ &iStorageManager.CreateStorageL( *uid,
+ aNamespace );
+ }
+ else if ( err != KErrNone )
+ {
+ DLTRACE(("Leaving: %i", err));
+ User::Leave( err );
+ }
+
+ CleanupStack::PopAndDestroy( uid );
+
+ DLTRACEOUT((""));
+ return storage;
+ }
+
+void CNcdSubscriptionManager::ListenerEnrolledL(
+ MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+ iPendingMessages.AppendL( &aMessage );
+ }
+
+void CNcdSubscriptionManager::NotifyAllListeners( TInt aError )
+ {
+ DLTRACEIN((""));
+ for ( TInt i = 0; i < iPendingMessages.Count(); i++ )
+ {
+ iPendingMessages[i]->CompleteAndRelease( aError );
+ }
+ iPendingMessages.Reset();
+ }