ncdengine/provider/client/src/ncdnodemanagerproxy.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/client/src/ncdnodemanagerproxy.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1235 @@
+/*
+* 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 CNcdNodeManagerProxy class
+*
+*/
+
+
+#include <e32err.h>
+
+#include "ncdnodemanagerproxy.h"
+#include "ncdnodeproxy.h"
+#include "ncdnodefolderproxy.h"
+#include "ncdbundlefolderproxy.h"
+#include "ncdsearchnodefolderproxy.h"
+#include "ncdnodeitemproxy.h"
+#include "ncdsearchnodeitemproxy.h"
+#include "catalogsclientserver.h"
+#include "ncdnodefunctionids.h"
+#include "ncdnodeclassids.h"
+#include "ncdproviderdefines.h"
+#include "ncdnodeidentifier.h"
+#include "ncdrootnodeproxy.h"
+#include "ncdpurchasedetails.h"
+#include "catalogsdebug.h"
+#include "ncdoperationmanagerproxy.h"
+#include "ncdsearchrootnodeproxy.h"
+#include "catalogsconstants.h"
+#include "catalogsutils.h"
+#include "ncdproviderproxy.h"
+#include "ncdexpirednode.h"
+#include "ncdnodesupplierproxy.h"
+#include "ncdnodeidentifiereditor.h"
+#include "ncdsearchnodebundleproxy.h"
+#include "ncdfavoritemanagerproxy.h"
+#include "ncdpanics.h"
+
+
+CNcdNodeManagerProxy* CNcdNodeManagerProxy::NewL(
+    MCatalogsClientServer& aSession, 
+    TInt aHandle,
+    CNcdOperationManagerProxy& aOperationManager,
+    CNcdSubscriptionManagerProxy& aSubscriptionManager,
+    CNcdProviderProxy& aProvider )
+    {
+    CNcdNodeManagerProxy* self = 
+        CNcdNodeManagerProxy::NewLC( aSession, 
+                                     aHandle,
+                                     aOperationManager,
+                                     aSubscriptionManager,
+                                     aProvider );
+    CleanupStack::Pop( self );
+    return self;        
+    }
+
+
+CNcdNodeManagerProxy* CNcdNodeManagerProxy::NewLC(
+    MCatalogsClientServer& aSession, 
+    TInt aHandle,
+    CNcdOperationManagerProxy& aOperationManager,
+    CNcdSubscriptionManagerProxy& aSubscriptionManager,
+    CNcdProviderProxy& aProvider )
+    {
+    CNcdNodeManagerProxy* self = 
+        new( ELeave ) CNcdNodeManagerProxy( aSession,
+                                            aHandle,
+                                            aOperationManager,
+                                            aSubscriptionManager,
+                                            aProvider );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;        
+    }
+
+
+CNcdNodeManagerProxy::CNcdNodeManagerProxy(
+    MCatalogsClientServer& aSession, 
+    TInt aHandle,
+    CNcdOperationManagerProxy& aOperationManager,
+    CNcdSubscriptionManagerProxy& aSubscriptionManager,
+    CNcdProviderProxy& aProvider )
+: CNcdBaseProxy( aSession, aHandle ),
+  iOperationManager( aOperationManager ),
+  iSubscriptionManager( aSubscriptionManager ),
+  iFavoriteManager( NULL ),
+  iProvider( aProvider )
+    {
+    }
+
+
+void CNcdNodeManagerProxy::ConstructL()
+    {
+    iOperationManager.SetNodeManager( this );
+
+    }
+
+
+CNcdNodeManagerProxy::~CNcdNodeManagerProxy()
+    {
+    DLTRACEIN((""));
+    
+    if( iSearchRootNode )
+        {
+        // release own reference to 
+        iSearchRootNode->InternalRelease();
+        }
+    
+    // Release all nodes without reference count. These nodes have not
+    // been used after creation.
+    for ( TInt i = iNodeCache.Count() - 1; i >= 0; i-- ) 
+        {
+        if ( iNodeCache[i]->TotalRefCount() == 0 )
+            {
+            // During delete, node is removed from the array automatically.
+            // Notice that it is safe to call delete here instead of Release,
+            // because we checked the total count above. Release implementation 
+            // contains DASSERT that would assert if we called Release here.
+            delete iNodeCache[i];
+            }
+        }
+    
+    // For debugging purposes check if some nodes have been left hanging.
+    // All the nodes should be released before manager is deleted.
+
+    DLINFO(("Cache count: %d", iNodeCache.Count()));
+
+    #ifdef CATALOGS_BUILD_CONFIG_DEBUG
+        DLINFO(("The following nodes have not been properly released:"));
+        for ( TInt i = 0; i < iNodeCache.Count(); i++ ) 
+            {
+            DLINFO(( _L("MNcdNode: %x, namespace: %S, id: %S, refcount: %d"), 
+                static_cast<MNcdNode*>( iNodeCache[i] ),
+                &iNodeCache[i]->Namespace(), &iNodeCache[i]->Id(),
+                iNodeCache[i]->TotalRefCount() ));
+                
+            }
+        DLINFO(("release check end"));        
+    #endif
+
+    DASSERT( iNodeCache.Count() == 0 );           
+        
+    // Close the cache.
+    iNodeCache.Close();
+
+    // Notice that the root node is also included into the cache.
+    // So, no need to delete it separately.
+
+    DLTRACEOUT((""));
+    }
+
+
+CNcdNodeProxy& CNcdNodeManagerProxy::NodeL( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((_L("Node ID: %S, %S, %d"), 
+                &aNodeIdentifier.NodeId(),
+                &aNodeIdentifier.NodeNameSpace(),
+                aNodeIdentifier.ClientUid()));
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does, do not create it.
+        
+    DLTRACE(("Node cache count: %d", iNodeCache.Count() ));
+
+    CNcdNodeProxy* node( NodeExists( aNodeIdentifier ) );
+    if ( node != NULL )
+        {
+        // Node was found. So, return it.
+        DLTRACEOUT(("Node found"));
+        return *node;
+        }
+    else if ( aNodeIdentifier.NodeNameSpace() 
+                == NcdProviderDefines::KRootNodeNameSpace )
+        {
+        DLTRACE(("RootNode"));
+        // Because the node was not found from the cache,
+        // create a new node.
+        return RootNodeL();
+        }
+    else
+        {
+        DLTRACE(("Create a new node"));
+        // Because the node was not found from the cache,
+        // create a new node.
+        return CreateNodeL( aNodeIdentifier );        
+        }
+    }
+
+
+CNcdRootNodeProxy& CNcdNodeManagerProxy::RootNodeL()
+    {
+    DLTRACEIN((""));
+
+    if( iRootNode == NULL )
+        {
+        DLTRACE(("Root did not exist. Create it."));
+        
+        // Root does not exist. So, create it.
+
+        // First get the handle to the node of the server side.
+        // The handle is gotten from the server side nodemanager.
+        TInt rootHandle( 0 );
+        User::LeaveIfError(
+                ClientServerSession().
+                    SendSync( NcdNodeFunctionIds::ENcdRootNodeHandle,
+                              KNullDesC,
+                              rootHandle,
+                              Handle() ) );
+
+        DLTRACE(("Root handle: %d", rootHandle ));
+        
+        // Now we have handle. So, create the actual root proxy. 
+        // Notice that if the proxy object leaves during the construction
+        // the destructor automatically releases the handle from the server side.               
+        iRootNode = 
+            CNcdRootNodeProxy::NewL( ClientServerSession(), 
+                                     rootHandle,
+                                     *this,
+                                     iOperationManager,
+                                     *iFavoriteManager );
+                                      
+        // Because root node is created now, it is not in the cache yet.
+        // Put it into the cache. So, users can find the root then also
+        // by using the NodeL function.
+        iNodeCache.AppendL( iRootNode );
+        }
+
+    DLTRACEOUT((""));
+    
+    return *iRootNode;
+    }
+  
+CNcdSearchRootNodeProxy& CNcdNodeManagerProxy::SearchRootNodeL()
+    {
+    DLTRACEIN((""));
+
+    if( iSearchRootNode == NULL )
+        {
+        DLTRACE(("Search root did not exist. Create it."));
+        
+        // Search root does not exist. So, create it.
+
+        // First get the handle to the node of the server side.
+        // The handle is gotten from the server side nodemanager.
+        TInt searchRootHandle( 0 );
+        User::LeaveIfError(
+                ClientServerSession().
+                    SendSync( NcdNodeFunctionIds::ENcdSearchRootNodeHandle,
+                              KNullDesC,
+                              searchRootHandle,
+                              Handle() ) );
+
+        DLTRACE(("Search root handle: %d", searchRootHandle ));
+        
+        // Now we have handle. So, create the actual search root proxy. 
+        // Notice that if the proxy object leaves during the construction
+        // the destructor automatically releases the handle from the server side.               
+        iSearchRootNode = 
+            CNcdSearchRootNodeProxy::NewL( ClientServerSession(), 
+                                     searchRootHandle,
+                                     *this,
+                                     iOperationManager,
+                                     *iFavoriteManager );
+        // call addref to keep search root alive for search ops (search root 
+        // is set as observer for them)
+        iSearchRootNode->InternalAddRef();
+        // Because search root node is created now, it is not in the cache yet.
+        // Put it into the cache. So, users can find the search root then also
+        // by using the NodeL function.
+        iNodeCache.AppendL( iSearchRootNode );
+        }
+
+    DLTRACEOUT((""));
+    
+    return *iSearchRootNode;
+    }
+
+
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateSchemeNodeL(
+    const CNcdNodeIdentifier& aMetadataIdentifier,
+    TNcdSchemeNodeType aType,
+    TBool aRemoveOnDisconnect,
+    TBool aForceCreate )
+    {
+    DLTRACEIN((""));
+    
+    CNcdNodeProxy* node( NULL );
+    
+    // Check the favorites for the given metadata and return the node which has
+    // the metadata if one exists.
+    node = iFavoriteManager->FavoriteNodeByMetaDataL( aMetadataIdentifier );
+    
+    if ( node )
+        {
+        return *node;
+        }
+        
+    // Node was not found from favorites.
+    if ( aForceCreate )
+        {
+        // Creation is forced, create node of correct type.
+        switch ( aType )
+            {
+            case ENcdSchemeItem:
+                
+                node = &CreateTemporaryNodeItemL( aMetadataIdentifier, EFalse );
+                break;
+                
+            case ENcdSchemeFolder:
+                node = &CreateTemporaryNodeFolderL( aMetadataIdentifier, EFalse );
+                break;
+                
+            case ENcdSchemeBundleFolder:
+                node = &CreateTemporaryBundleFolderL( aMetadataIdentifier, EFalse );
+                break;
+            
+            default:
+                NCD_ASSERT_ALWAYS( EFalse, ENcdPanicInvalidArgument );
+                break;
+            }
+        }
+    else 
+        {
+        // Creation not forced, create temporary node item if metadata exists already.
+        // This leaves with KErrNotFound if metadata does not exist, thus the
+        // node cannot be created.
+        node = &CreateTemporaryNodeIfMetadataExistsL( aMetadataIdentifier );
+        }
+
+    DASSERT( node );
+    
+    // Scheme nodes must be added to favourites.
+    node->AddToFavoritesL( aRemoveOnDisconnect );
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+
+
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryNodeL( 
+    const MNcdPurchaseDetails& aDetails )
+    {
+    DLTRACEIN((""));
+
+    CNcdNodeProxy* node( NULL );
+
+    CNcdNodeIdentifier* identifier( 
+        CNcdNodeIdentifier::NewLC( aDetails.Namespace(), 
+                                   aDetails.EntityId(), 
+                                   aDetails.ServerUri(),
+                                   aDetails.ClientUid() ) );
+
+    if ( aDetails.ItemType() == MNcdPurchaseDetails::EItem )
+        {
+        DLINFO(("Item from purchase history"));
+        node = &CreateTemporaryNodeItemL( *identifier, ETrue );
+        }
+    else if ( aDetails.ItemType() == MNcdPurchaseDetails::EFolder )
+        {
+        DLINFO(("Folder from purchase history"));
+        node = &CreateTemporaryNodeFolderL( *identifier, ETrue );
+        }
+    else
+        {
+        DLINFO(("Unknown from purchase history"));
+        node = &CreateTemporaryOrSupplierNodeL( *identifier );
+        }
+
+    CleanupStack::PopAndDestroy( identifier );
+
+    DLTRACEOUT((""));
+
+    return *node;
+    }
+    
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryNodeFolderL( 
+    const CNcdNodeIdentifier& aMetadataIdentifier, TBool aCreateMetaData )
+    {
+    DLTRACEIN((_L("Metadata ID: %S, %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                &aMetadataIdentifier.ServerUri(),
+                aMetadataIdentifier.ClientUid()));        
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+
+    // At first, try to find the node from cache by creating the node identifier
+    // from the metadata identifier.
+    CNcdNodeIdentifier* tempNodeIdentifier =
+        NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( aMetadataIdentifier );
+    CNcdNodeProxy* node( NodeExists( *tempNodeIdentifier ) );
+    
+    if ( node ) 
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        DLTRACEOUT(("Node found in cache"));
+        return *node;
+        }
+
+    // Notice that the actual node identifier is given here, instead of the
+    // metadata identifier.
+    HBufC8* nodeIdentifierData( tempNodeIdentifier->NodeIdentifierDataL() );
+    CleanupStack::PopAndDestroy( tempNodeIdentifier );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Get node handle"));
+    // First get the handle to the node of the server side.
+    // The handle is gotten from the server side nodemanager.
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    TInt function = aCreateMetaData ? 
+        NcdNodeFunctionIds::ENcdTemporaryNodeFolderWithMetaDataHandle : 
+        NcdNodeFunctionIds::ENcdTemporaryNodeFolderHandle;
+    
+    TInt nodeHandle( 0 );
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( function,
+                          *nodeIdentifierData,
+                          nodeHandle,
+                          Handle() ) );
+
+    DLTRACE(("Node handle: %d", nodeHandle ));
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+    // No need to check the class id here, because we requested an item
+    // node above.
+
+    node = 
+        CNcdNodeFolderProxy::NewLC( ClientServerSession(),
+                                    nodeHandle,
+                                    *this,
+                                    iOperationManager,
+                                    *iFavoriteManager );
+
+    // Because we creted a new node, it should be added to the cache.
+    iNodeCache.AppendL( node );
+
+    CleanupStack::Pop( node );
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+    
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryBundleFolderL(
+    const CNcdNodeIdentifier& aMetadataIdentifier, TBool aCreateMetaData )
+    {
+    DLTRACEIN((_L("Metadata ID: %S, %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                &aMetadataIdentifier.ServerUri(),
+                aMetadataIdentifier.ClientUid()));        
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+
+    // At first, try to find the node from cache by creating the node identifier
+    // from the metadata identifier.
+    CNcdNodeIdentifier* tempNodeIdentifier =
+        NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( aMetadataIdentifier );
+    CNcdNodeProxy* node( NodeExists( *tempNodeIdentifier ) );
+    
+    if ( node ) 
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        DLTRACEOUT(("Node found in cache"));
+        return *node;
+        }
+
+    // Notice that the actual node identifier is given here, instead of the
+    // metadata identifier.
+    HBufC8* nodeIdentifierData( tempNodeIdentifier->NodeIdentifierDataL() );
+    CleanupStack::PopAndDestroy( tempNodeIdentifier );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Get node handle"));
+    // First get the handle to the node of the server side.
+    // The handle is gotten from the server side nodemanager.
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    TInt function = aCreateMetaData ?
+        NcdNodeFunctionIds::ENcdTemporaryBundleFolderWithMetaDataHandle :
+        NcdNodeFunctionIds::ENcdTemporaryBundleFolderHandle;
+    
+    TInt nodeHandle( 0 );
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( function,
+                          *nodeIdentifierData,
+                          nodeHandle,
+                          Handle() ) );
+
+    DLTRACE(("Node handle: %d", nodeHandle ));
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+    // No need to check the class id here, because we requested a bundle folder
+    // node above.
+    node = 
+        CNcdBundleFolderProxy::NewLC( ClientServerSession(),
+                                      nodeHandle,
+                                      *this,
+                                      iOperationManager,
+                                      *iFavoriteManager );
+
+    // Because we creted a new node, it should be added to the cache.
+    iNodeCache.AppendL( node );
+
+    CleanupStack::Pop( node );
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+
+    
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryNodeItemL(
+    const CNcdNodeIdentifier& aMetadataIdentifier,
+    TBool aCreateMetaData )
+    {
+    DLTRACEIN((_L("Metadata ID: %S, %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                &aMetadataIdentifier.ServerUri(),
+                aMetadataIdentifier.ClientUid()));        
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+
+    // At first, try to find the node from cache by creating the node identifier
+    // from the metadata identifier.
+    CNcdNodeIdentifier* tempNodeIdentifier =
+        NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( aMetadataIdentifier );
+    CNcdNodeProxy* node( NodeExists( *tempNodeIdentifier ) );
+    
+    if ( node ) 
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        DLTRACEOUT(("Node found in cache"));
+        return *node;
+        }
+
+    // Notice that the actual node identifier is given here, instead of the
+    // metadata identifier.
+    HBufC8* nodeIdentifierData( tempNodeIdentifier->NodeIdentifierDataL() );
+    CleanupStack::PopAndDestroy( tempNodeIdentifier );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Get node handle"));
+    // First get the handle to the node of the server side.
+    // The handle is gotten from the server side nodemanager.
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    TInt function = aCreateMetaData ?
+        NcdNodeFunctionIds::ENcdTemporaryNodeItemWithMetaDataHandle :
+        NcdNodeFunctionIds::ENcdTemporaryNodeItemHandle;
+    
+    TInt nodeHandle( 0 );
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( function,
+                          *nodeIdentifierData,
+                          nodeHandle,
+                          Handle() ) );
+
+    DLTRACE(("Node handle: %d", nodeHandle ));
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+    // No need to check the class id here, because we requested an item
+    // node above.
+
+    node = 
+        CNcdNodeItemProxy::NewLC( ClientServerSession(),
+                                  nodeHandle,
+                                  *this,
+                                  iOperationManager,
+                                  *iFavoriteManager );
+
+    // Because we creted a new node, it should be added to the cache.
+    iNodeCache.AppendL( node );
+
+    CleanupStack::Pop( node );
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+    
+    
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryNodeIfMetadataExistsL(
+    const CNcdNodeIdentifier& aMetadataIdentifier )
+    {
+    DLTRACEIN((_L("Metadata ID: %S, %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                &aMetadataIdentifier.ServerUri(),
+                aMetadataIdentifier.ClientUid()));
+                
+    CNcdNodeIdentifier* tempNodeIdentifier =
+        NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( aMetadataIdentifier );
+                           
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+    CNcdNodeProxy* node( NodeExists( *tempNodeIdentifier ) );    
+    if ( node ) 
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        DLTRACEOUT(("Node found in cache"));
+        return *node;
+        }
+        
+    // Node was not found from the cache. So, new node proxy has to be created.
+                    
+    // Notice that the actual node identifier is given here for the server, instead of the
+    // metadata identifier.
+    HBufC8* nodeIdentifierData( tempNodeIdentifier->NodeIdentifierDataL() );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Create temporary if metadata exists"));
+
+    // This is the output value from SendSync. It tells whether the node was created in server side.
+    // It will be ETrue also when the node existed there already.
+    TBool isCreated( EFalse );
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    // This will create the temporary node in server side if the metadata exists there already.
+    // So, it can be requested next when the node proxy will be created.
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( NcdNodeFunctionIds::ENcdCreateTemporaryNodeIfMetadataExists,
+                          *nodeIdentifierData,
+                          isCreated,
+                          Handle() ) );
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+    
+    if ( isCreated ) 
+        {
+        // The node was created above in the server side if it did not
+        // already exist. So, we can be sure that we get the node below.
+        // NodeL knows how to create the correct node and inserts it to the cache. 
+        // So, use that function here.
+        // Notice, that there is no need to use ReplaceCacheNodeL here because the
+        // supplier node can use it itself when the correct node data has been loaded
+        // from the web.
+        node = &NodeL( *tempNodeIdentifier );
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        }
+    else 
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    DLTRACEOUT(("metadata was found and temporary node created"));
+    
+    return *node;
+    }
+    
+    
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateTemporaryOrSupplierNodeL(
+    const CNcdNodeIdentifier& aMetadataIdentifier )
+    {
+    DLTRACEIN((_L("Metadata ID: %S, %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                &aMetadataIdentifier.ServerUri(),
+                aMetadataIdentifier.ClientUid()));        
+
+    // Notice that the supplier node and the temporary node use same identifiers
+    // but only one version should exist at a time.
+
+    CNcdNodeIdentifier* tempNodeIdentifier =
+        NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( aMetadataIdentifier );
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+    CNcdNodeProxy* node( NodeExists( *tempNodeIdentifier ) );    
+    if ( node ) 
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( tempNodeIdentifier );
+        DLTRACEOUT(("Node found in cache"));
+        return *node;
+        }
+
+    // Node was not found from the cache. So, new node proxy has to be created.
+    
+    // Notice that the actual node identifier is given here for the server, instead of the
+    // metadata identifier.
+    HBufC8* nodeIdentifierData( tempNodeIdentifier->NodeIdentifierDataL() );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Create temporary or supplier node proxy"));
+
+    // tmpNum is not used for anything, but give the SendSync at least some parameter.    
+    TInt tmpNum( 0 );
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    // This will create the supplier or temporary node in server side. So, it can be
+    // requested next when the node proxy will be created.
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( NcdNodeFunctionIds::ENcdCreateTemporaryOrSupplierNode,
+                          *nodeIdentifierData,
+                          tmpNum,
+                          Handle() ) );
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+    // The node was created above in the server side if it did not
+    // already exist. So, we can be sure that we get the node below.
+    // NodeL knows how to create the correct node and inserts it to the cache. 
+    // So, use that function here.
+    // Notice, that there is no need to use ReplaceCacheNodeL here because the
+    // supplier node can use it itself when the correct node data has been loaded
+    // from the web.
+    node = &NodeL( *tempNodeIdentifier );
+    
+    CleanupStack::PopAndDestroy( tempNodeIdentifier );
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+
+
+CNcdNodeProxy& CNcdNodeManagerProxy::ReplaceCacheNodeL( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((""))
+    
+    // Remove the node that has the given identifier from the cache.
+    // Notice, that the node is now left hanging. And, it will be just deleted
+    // when the user releases it. Also, notice that when the node is deleted,
+    // CNcdNodeManager::NodeDeleted() will be called but it does not matter because the
+    // comparisons in that function are done by using pointers, not identifiers.
+    for ( TInt i = 0; i < iNodeCache.Count(); ++i )
+        {
+        // Because the UID may be set NULL for an identifier and because the
+        // UID should always be same for all the nodes in this application,
+        // the UID is not included when comparing node identifiers here.
+        if ( iNodeCache[ i ]->NodeIdentifier().
+                Equals( aNodeIdentifier, ETrue, ETrue, EFalse, EFalse ) ) 
+            {
+            iNodeCache.Remove( i );
+            }
+        }        
+
+    DLTRACEOUT((""));
+
+    // This will also insert the new node into the cache.
+    // Let the node call leave if something goes wrong. Actually, 
+    // at least some node should be found if one version of the node with the
+    // given identifier alreay exists in the server side.
+    // This call may also leave if we are out of memory. In that case just leave.
+    // Do not try to set the removed node back to the array. When memory is released.
+    // It can be requested from the server side normally later.
+    return NodeL( aNodeIdentifier );
+    }
+
+
+CNcdNodeProxy* CNcdNodeManagerProxy::NodeExists( const CNcdNodeIdentifier& aNodeIdentifier ) const
+    {
+    DLTRACEIN((""));
+    for ( TInt i = 0; i < iNodeCache.Count(); ++i )
+        {
+        // Because the UID may be set NULL for an identifier and because the
+        // UID should always be same for all the nodes in this application,
+        // the UID is not included when comparing node identifiers here.
+        if ( iNodeCache[ i ]->NodeIdentifier().
+                Equals( aNodeIdentifier, ETrue, ETrue, EFalse, EFalse ) ) 
+            {
+            // The node has already been created 
+            // because the link ids matched.
+            // Return the old node.
+            DLTRACE(("node found"));
+            return iNodeCache[ i ];
+            }
+        }
+    DLTRACE(("node not found"));
+    return NULL;
+    }
+
+
+void CNcdNodeManagerProxy::NodeDeleted( CNcdNodeProxy* aNode )
+    {
+    DLTRACEIN(("Node Deleted"));
+
+    CNcdNodeProxy* root( iRootNode );
+    CNcdNodeProxy* searchRoot( iSearchRootNode );
+    if( root == aNode )
+        {
+        DLTRACE(("Deleted root node"));
+        // Because the root node is deleted. Set the pointer value to null.
+        iRootNode = NULL;        
+        }
+    else if( searchRoot == aNode )
+        {
+        DLTRACE(("Deleted search node"));
+        // Because the search root node is deleted. Set the pointer value to
+        // null.
+        iSearchRootNode = NULL;
+        }
+
+    // Remove node from the cache because it will be or has been deleted.
+    for ( TInt i = 0; i < iNodeCache.Count(); ++i )
+        {
+        if( aNode == iNodeCache[ i ] )
+            {
+            DLTRACE(("Removing from cache"));
+            // Remove node from the array.
+            iNodeCache.Remove( i );
+            break;
+            }
+        }
+    }
+
+
+void CNcdNodeManagerProxy::InternalizeRelatedNodesL( CNcdNodeProxy& aNode ) const
+    {
+    DLTRACEIN((""));
+    
+    // First internalize the given node
+    aNode.InternalizeL();
+    
+    // Then check if there is some other nodes to internalize.
+    
+    // Get the metadata identifier of the given node.
+    CNcdNodeIdentifier* paramMetaIdentifier( 
+        NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( 
+            aNode.NodeIdentifier() ) );
+    CNcdNodeIdentifier* metaIdentifier( NULL );
+    CNcdNodeProxy* node( NULL );
+        
+    // Check if related nodes are found from the cache. 
+    for ( TInt i = 0; i < iNodeCache.Count(); ++i )
+        {
+        node = iNodeCache[ i ];
+        metaIdentifier = 
+            NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( 
+                node->NodeIdentifier() );
+            
+        // Because given node has already been internalized, there is no need to redo it
+        // here. But, internalize all related nodes.
+        // When identifiers are compared, compare only id and namespace. Omit comparison
+        // of URI and UID. UID may be NULL if the node has not been internalized before.
+        if ( &aNode != node
+             && paramMetaIdentifier->Equals( *metaIdentifier, 
+                                             ETrue, ETrue, EFalse, EFalse ) )
+            {
+            DLINFO(("Related node found. Internalize."));
+            node->InternalizeL();
+            }
+             
+        CleanupStack::PopAndDestroy( metaIdentifier );
+        metaIdentifier = NULL;
+        }
+
+    CleanupStack::PopAndDestroy( paramMetaIdentifier );    
+    DLTRACEOUT((""));
+    }
+
+
+CNcdSubscriptionManagerProxy&
+    CNcdNodeManagerProxy::SubscriptionManager() const
+    {
+    return iSubscriptionManager;
+    }
+    
+void CNcdNodeManagerProxy::SetFavoriteManager(
+    CNcdFavoriteManagerProxy& aFavoriteManager ) 
+    {
+    iFavoriteManager = &aFavoriteManager;
+    }
+    
+void CNcdNodeManagerProxy::ClearSearchResultsL()
+    {
+    DLTRACEIN((""));
+    TInt err = KErrNone;
+    User::LeaveIfError( ClientServerSession().SendSync(
+        NcdNodeFunctionIds::ENcdClearSearchResults,
+        KNullDesC,
+        err,
+        Handle() ) );
+    DLTRACEOUT(( "err = %d", err ));
+    }
+
+
+TBool CNcdNodeManagerProxy::IsCapabilitySupportedL( const CNcdNodeIdentifier& aNode, 
+    const TDesC& aCapability )
+    {
+    DLTRACEIN((""));
+    CBufBase* sendBuffer = CBufFlat::NewL( KBufExpandSize );
+    CleanupStack::PushL( sendBuffer );
+    RBufWriteStream stream( *sendBuffer );
+    CleanupClosePushL( stream );
+    
+    aNode.ExternalizeL( stream );
+    ExternalizeDesL( aCapability, stream );
+    
+    TPtrC8 sendPtr( sendBuffer->Ptr( 0 ) );
+    
+    CleanupStack::PopAndDestroy( &stream );
+    TBool isCapabilitySupported = EFalse;
+    
+    User::LeaveIfError( ClientServerSession().SendSync(
+        NcdNodeFunctionIds::ENcdIsCapabilitySupported,
+        sendPtr,
+        isCapabilitySupported,
+        Handle() ) );
+    
+    CleanupStack::PopAndDestroy( sendBuffer );
+    return isCapabilitySupported;
+    }
+
+
+void CNcdNodeManagerProxy::HandleExpiredNodesL(
+    RPointerArray< CNcdExpiredNode >& aExpiredNodes )
+    {
+    DLTRACEIN((""));
+    RCatalogsArray<MNcdNode> expiredNodeArray;
+    CleanupClosePushL( expiredNodeArray );
+    for( TInt i = 0 ; i < aExpiredNodes.Count() ; i++ )
+        {
+        CNcdNodeProxy* node = NodeExists( aExpiredNodes[i]->NodeIdentifier() );
+        if( node )
+            {
+            DLTRACE(("Node existed"));
+            // Perhaps errors should not be ignored?
+            TRAP_IGNORE( node->InternalizeL() );
+            if ( aExpiredNodes[i]->ForceUpdate() )
+                {
+                DLTRACE(("Force update set, add to array"));
+                node->AddRef();
+                expiredNodeArray.AppendL( node );
+                }
+            }
+        }
+    if( expiredNodeArray.Count() > 0 )
+        {
+        DLTRACE(("Send force update nodes to provider"));
+        iProvider.ExpirationCallback( expiredNodeArray );
+        }
+    CleanupStack::PopAndDestroy( &expiredNodeArray );
+    }
+
+
+CNcdProviderProxy& CNcdNodeManagerProxy::Provider() const
+    {
+    return iProvider;
+    }
+
+/*
+CNcdNodeProxy& CNcdNodeManagerProxy::CreateSchemeNodeL( 
+    const CNcdNodeIdentifier& aMetadataIdentifier,
+    TInt aFunctionId )
+    {
+    DLTRACEIN((_L("ID: %S, %S, %d"), 
+                &aMetadataIdentifier.NodeId(),
+                &aMetadataIdentifier.NodeNameSpace(),
+                aMetadataIdentifier.ClientUid()));        
+
+    // Check that the root is not in an unitialized state.
+    // Scheme should be created only if the root has been initialized before.
+    // Because the root is only used here internally, there is no need to increase
+    // the reference count.
+    CNcdRootNodeProxy& root( RootNodeL() );
+    if ( root.State() == MNcdNode::EStateNotInitialized )
+        {
+        DLERROR(("Root was not initialized before creation of scheme!"));
+        DASSERT( EFalse );
+        User::Leave( KErrNotReady );
+        }
+
+    CNcdNodeIdentifier* nodeIdentifier =
+        NcdNodeIdentifierEditor::CreateNodeIdentifierLC(
+            RootNodeL().NodeIdentifier(),
+            aMetadataIdentifier );
+
+    // Check if the node proxy already exists in the cache.
+    // Every node has its own namespace and dataid.
+    // If it does exist, do not create it.
+        
+    CNcdNodeProxy* node( NodeExists( *nodeIdentifier ) );
+    if ( node != NULL )
+        {
+        // Node was found. So, return it.
+        CleanupStack::PopAndDestroy( nodeIdentifier );
+        DLTRACEOUT(("Node found"));
+        return *node;
+        }
+
+    HBufC8* nodeIdentifierData( nodeIdentifier->NodeIdentifierDataL() );    
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+
+    // tmpNum will not be used for anything. It is just given as a dummy parameter for
+    // the session request.
+    TInt tmpNum( 0 );
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( aFunctionId,
+                          *nodeIdentifierData,
+                          tmpNum,
+                          Handle() ) );
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+    // The node was created above in the server side if it did not
+    // already exist. So, we can be sure that we get the node below.
+    // NodeL knows how to create the correct node and inserts it to the cache. 
+    // So, use that function here.
+    node = &NodeL( *nodeIdentifier );
+
+    CleanupStack::PopAndDestroy( nodeIdentifier );
+    
+    // Update root node by calling internalization because scheme nodes will
+    // be added to the root node also.
+    RootNodeL().InternalizeL();
+
+    DLTRACEOUT((""));
+    
+    return *node;
+    }
+*/
+
+ CNcdNodeProxy& CNcdNodeManagerProxy::CreateNodeL( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((""));
+
+    CNcdNodeProxy* node( NULL );
+
+    HBufC8* nodeIdentifierData( aNodeIdentifier.NodeIdentifierDataL() );
+    CleanupStack::PushL( nodeIdentifierData );
+        
+    DLINFO(("Get node handle"));
+    // First get the handle to the node of the server side.
+    // The handle is gotten from the server side nodemanager.
+    
+    // NOTE: The identifier may contain NULL UID here, but it will
+    // be replaced by the family id in the server side. And then
+    // the node proxy will contain the right UID when the created node is
+    // internalized during its creation.
+    
+    TInt nodeHandle( 0 );
+    User::LeaveIfError(
+            ClientServerSession().
+                SendSync( NcdNodeFunctionIds::ENcdNodeHandle,
+                          *nodeIdentifierData,
+                          nodeHandle,
+                          Handle() ) );
+
+    DLTRACE(("Node handle: %d", nodeHandle ));
+
+    CleanupStack::PopAndDestroy( nodeIdentifierData );
+
+
+    // Next, check the type of the node. So, we can create
+    // right type of the proxy.
+    TInt classId( 0 );    
+    TInt classIdError = 
+            ClientServerSession().
+                SendSync( NcdNodeFunctionIds::ENcdClassId,
+                          KNullDesC,
+                          classId,
+                          nodeHandle );
+    if ( classIdError != KErrNone )
+        {
+        // Because we can not create the proxy object for some reason,
+        // release the handle.
+        TInt tmpNum( 0 );
+        ClientServerSession().
+            SendSync( NcdNodeFunctionIds::ENcdRelease,
+                      KNullDesC,
+                      tmpNum,
+                      Handle() );
+        
+        // For debuggin reasons.
+        DLERROR(("Class id error"));
+        DASSERT( EFalse );
+        
+        User::Leave( classIdError );
+        }
+
+    // Create the node according to the class id
+    // Notice that if the proxy object leaves during the construction
+    // the destructor automatically releases the handle from the server side.               
+    switch( classId )
+        {
+        case NcdNodeClassIds::ENcdFolderNodeClassId:
+            node = 
+                CNcdNodeFolderProxy::NewLC( ClientServerSession(), 
+                                            nodeHandle,
+                                            *this,
+                                            iOperationManager,
+                                            *iFavoriteManager );
+            break;
+
+        case NcdNodeClassIds::ENcdTransparentFolderNodeClassId:
+            // The transparent folder is handled in the proxy
+            // side as a normal folder.
+            node = 
+                CNcdNodeFolderProxy::NewLC( ClientServerSession(), 
+                                            nodeHandle,
+                                            *this,
+                                            iOperationManager,
+                                            *iFavoriteManager );
+            break;
+            
+        case NcdNodeClassIds::ENcdBundleFolderNodeClassId:
+            node =
+                CNcdBundleFolderProxy::NewLC( ClientServerSession(),
+                                              nodeHandle,
+                                              *this,
+                                              iOperationManager,
+                                              *iFavoriteManager );
+            break;
+        
+        case NcdNodeClassIds::ENcdSearchFolderNodeClassId:
+            node = 
+                CNcdSearchNodeFolderProxy::NewLC( ClientServerSession(), 
+                                            nodeHandle,
+                                            *this,
+                                            iOperationManager,
+                                            *iFavoriteManager );
+            break;
+
+        case NcdNodeClassIds::ENcdItemNodeClassId:
+            node = 
+                CNcdNodeItemProxy::NewLC( ClientServerSession(),
+                                          nodeHandle,
+                                          *this,
+                                          iOperationManager,
+                                          *iFavoriteManager );
+            break;
+        
+        case NcdNodeClassIds::ENcdSearchItemNodeClassId:
+            node = 
+                CNcdSearchNodeItemProxy::NewLC( ClientServerSession(),
+                                          nodeHandle,
+                                          *this,
+                                          iOperationManager,
+                                          *iFavoriteManager );
+            break;
+            
+        case NcdNodeClassIds::ENcdSearchRootNodeClassId:
+            node = 
+                CNcdSearchRootNodeProxy::NewLC( ClientServerSession(),
+                                          nodeHandle,
+                                          *this,
+                                          iOperationManager,
+                                          *iFavoriteManager );
+            break;
+            
+
+        case NcdNodeClassIds::ENcdSupplierNodeClassId:
+            {
+            node = CNcdNodeSupplierProxy::NewLC( ClientServerSession(),
+                                                 nodeHandle,
+                                                 *this,
+                                                 iOperationManager,
+                                                 *iFavoriteManager );
+
+            break;
+            }
+            
+        case NcdNodeClassIds::ENcdSearchBundleNodeClassId:
+            {
+            node = 
+                CNcdSearchNodeBundleProxy::NewLC( ClientServerSession(), 
+                                            nodeHandle,
+                                            *this,
+                                            iOperationManager,
+                                            *iFavoriteManager );
+            break;
+            }            
+            
+        default:
+            // classId is not recognized
+            // So, node is left NULL
+            DLERROR(("Node class type was not recognized!"));
+            // For testing purposes assert here
+            DASSERT( EFalse );
+            break;
+        }
+
+    // Because we creted a new node, it should be added to the cache.
+    iNodeCache.AppendL( node );
+
+    CleanupStack::Pop( node );
+    DLTRACEOUT((""));
+    return *node;
+    }