ncdengine/provider/server/src/ncdsearchoperationimpl.cpp
changeset 0 ba25891c3a9e
child 25 7333d7932ef7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdsearchoperationimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1429 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*
+*/
+
+
+#include <badesca.h>
+#include <s32mem.h>
+#include <limits.h>
+
+#include "ncdsearchoperationimpl.h"
+#include "ncdoperationfunctionids.h"
+#include "catalogsbasemessage.h"
+#include "catalogshttpsession.h"
+#include "catalogshttpoperation.h"
+#include "catalogshttpconfig.h"
+#include "catalogsdebug.h"
+#include "catalogsbigdes.h"
+#include "ncdrequestgenerator.h"
+#include "catalogsaccesspointmanager.h"
+
+#include "ncdrequestbase.h"
+#include "ncdrequestbrowsesearch.h"
+#include "ncdrequestconfiguration.h"
+#include "ncd_pp_itemref.h"
+#include "ncd_pp_folderref.h"
+#include "ncd_pp_dataentity.h"
+#include "ncd_pp_error.h"
+// remove these
+#include "ncd_pp_itemrefimpl.h"
+#include "ncd_pp_folderrefimpl.h"
+#include "ncd_pp_dataentityimpl.h"
+#include "ncd_pp_datablock.h"
+//
+#include "ncdprotocolutils.h"
+#include "ncdprotocol.h"
+#include "ncdprotocolimpl.h"
+#include "ncdparser.h"
+#include "ncdnodemanager.h"
+#include "ncdproviderdefines.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodefolder.h"
+#include "ncdoperationobserver.h"
+#include "catalogssession.h"
+#include "ncdnodeimpl.h"
+#include "ncdnodelink.h"
+#include "ncdqueryimpl.h"
+#include "catalogsutils.h"
+#include "ncd_cp_query.h"
+#include "ncdnodemetadata.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncderrors.h"
+#include "ncdoperationremovehandler.h"
+#include "ncdstoragedescriptordataitem.h"
+#include "ncdnodeiconimpl.h"
+#include "ncdnodelink.h"
+#include "catalogsconstants.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodecontentinfoimpl.h"
+#include "ncditempurpose.h"
+#include "ncdutils.h"
+#include "ncdsearchnodefolder.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodefactory.h"
+#include "ncdnodeidentifiereditor.h"
+#include "ncdsearchnodefolder.h"
+#include "ncdcapabilities.h"
+#include "ncdsearchnodebundle.h"
+#include "ncdchildentity.h"
+
+
+//_LIT8(KRequestBody, "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <preminetRequest xmlns=\"http://nokia.com/preminet/protocol/v/2/0\"  xmlns:cp=\"http://nokia.com/preminet/protocol/configuration/v/1/0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"2.0\" namespace=\"http://lynx.ionific.com:9086/ntp-cgw/catalogs\"> <configuration> <client> <cp:software version=\"3.2\" type=\"S60\"/> </client> </configuration> <search> <entity xsi:type=\"Folder\" id=\"cgw_normal\" timestamp=\"2007-12-17T09:30:47.0Z\"/> <entityFilter subscribableContent=\"false\"> <keywords all=\"true\" caseSensitive=\"false\"> <keyword exclude=\"false\">a</keyword> </keywords> <reviewScore>1</reviewScore> </entityFilter> <responseFilter structureDepth=\"2\" metadataDepth=\"2\" metadataPerLevel=\"5\" pageStart=\"2\" pageSize=\"2\"/> </search> </preminetRequest>");
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdSearchOperation* CNcdSearchOperation::NewL(    
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    const CNcdNodeIdentifier& aParentIdentifier,
+    const CNcdSearchFilter& aSearchFilter,
+    TNcdResponseFilterParams aFilterParams,    
+    CNcdGeneralManager& aGeneralManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue* aOperationQueue,
+    MCatalogsSession& aSession,
+    TBool aLoadChildren,
+    TNcdChildLoadMode aMode,
+    TInt aRecursionLevels,
+    TBool aIsSubOperation )
+    {
+    CNcdSearchOperation* self = CNcdSearchOperation::NewLC(
+        aNodeIdentifier,
+        aParentIdentifier,
+        aSearchFilter,
+        aFilterParams,        
+        aGeneralManager,        
+        aHttpSession,        
+        aRemoveHandler,
+        aOperationQueue,        
+        aSession,
+        aLoadChildren,
+        aMode,
+        aRecursionLevels,
+        aIsSubOperation );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdSearchOperation* CNcdSearchOperation::NewLC(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    const CNcdNodeIdentifier& aParentIdentifier,
+    const CNcdSearchFilter& aSearchFilter,
+    TNcdResponseFilterParams aFilterParams,
+    CNcdGeneralManager& aGeneralManager,    
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue* aOperationQueue,
+    MCatalogsSession& aSession,
+    TBool aLoadChildren,
+    TNcdChildLoadMode aMode,
+    TInt aRecursionLevels,
+    TBool aIsSubOperation )
+    {
+    CNcdSearchOperation* self =
+        new( ELeave ) CNcdSearchOperation( aFilterParams, aMode,
+            aLoadChildren, aGeneralManager, aHttpSession,
+            aRemoveHandler, aOperationQueue, aSession, aRecursionLevels,
+            aIsSubOperation );
+    CleanupClosePushL( *self );
+    self->ConstructL( aNodeIdentifier, aParentIdentifier, aSearchFilter );
+    return self;
+    }
+    
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdSearchOperation::~CNcdSearchOperation()
+    {    
+    DLTRACEIN((""));
+    delete iSearchFilter;
+    iRemoteFoldersChildOfTransparent.ResetAndDestroy();
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdSearchOperation::FolderRefL(
+    MNcdPreminetProtocolFolderRef* aData )
+    {
+    DLTRACEIN(("%X",aData));
+
+    if ( aData == NULL )
+        {
+        return;
+        }
+    TRAPD( err, DoFolderRefL( aData ) );
+
+    if( err != KErrNone )
+        {
+        Cancel();
+        iError = err;
+        iLoadNodeState = EFailed;
+        }
+    RunOperation();
+    
+    }
+
+void CNcdSearchOperation::DoFolderRefL( MNcdPreminetProtocolFolderRef* aData )    
+    {
+    DLTRACEIN((""));        
+
+    // Normal PushL causes USER 42
+    CleanupDeletePushL( aData );
+    
+    DLTRACE(( _L("folder id=%S, ns=%S"), 
+        &aData->Id(), &aData->Namespace() ));
+    DLTRACE(( _L("Parent id=%S, ns=%S"), 
+        &aData->ParentId(), &aData->ParentNamespace() ));
+
+#ifdef CATALOGS_BUILD_CONFIG_DEBUG    
+    if ( iParentIdentifier ) 
+        {
+        DLNODEID( (*iParentIdentifier) );
+        }
+#endif
+    
+    TBool nodeAdded = EFalse;
+    
+    // This will contain pointer to the iNodeIdentifier or to the iParentIdentifier
+    // So, we will know in the end which one is the parent of the current data item.
+    // Do not delete this in the end because this just points to the member
+    // variables.
+    CNcdNodeIdentifier* tmpSearchParentIdentifier( iParentIdentifier );
+    CNcdNodeIdentifier* metaIdentifier =
+                    NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( *iNodeIdentifier );
+    
+    switch ( iLoadMode )
+        {
+        case EContentSource:
+            {
+            DLTRACE(("Should never come here, ERROR"));
+            DASSERT(0);
+            User::Leave( KErrGeneral );
+            break;
+            }
+        case ESingleNode:
+            {
+            DASSERT( iNodeIdentifier );
+            DLINFO(( _L("iNodeIdentifier: ns= %S, id= %S, aData: ns= %S, id= %S"),
+                &iNodeIdentifier->NodeNameSpace(), &iNodeIdentifier->NodeId(),
+                &aData->Namespace(), &aData->Id() ));
+            // Because aData contains metadata ids, we have to get
+            // the metadata id from the iNodeIdentifier
+            
+            if ( aData->Id() == metaIdentifier->NodeId() && 
+                aData->Namespace() == metaIdentifier->NodeNameSpace() )
+                {
+                DLTRACE(("ESingleNode"));
+                // Because the data id is same as the meta id, we know
+                // that this can not be the root search. Root search namespace
+                // and id are defined locally here in the client, not in the 
+                // web server.
+                
+                CNcdNodeManager::TNcdRefHandleMode mode;
+                if( CNcdNodeFactory::NodePurposeL(
+                    iNodeManager->NodeL( *iNodeIdentifier ) ) ==
+                        CNcdNodeFactory::ENcdSearchNode )
+                    {
+                    mode = CNcdNodeManager::EUpdate;
+                    }
+                else
+                    {
+                    mode =  CNcdNodeManager::EInsert;
+                    }
+                
+                iNodeManager->RefHandlerL( *iParentIdentifier,
+                    *aData,
+                    iClientUid,
+                    mode,
+                    0,
+                    iParentType,
+                    CNcdNodeFactory::ENcdSearchNode,
+                    CNcdNodeFactory::ENcdSearchNode );
+                nodeAdded = ETrue;
+                }
+            else if( aData->ParentId() == metaIdentifier->NodeId() &&
+                aData->ParentNamespace() == metaIdentifier->NodeNameSpace() )
+                {
+                DLINFO(("ESingleNode, adding children"));
+                // A child of the node that we are loading is received
+                
+                                    
+                CNcdNode& node = 
+                    iNodeManager->RefHandlerL( *iNodeIdentifier,
+                                                *aData,
+                                                iClientUid,
+                                                CNcdNodeManager::EInsert, // use insertion because child count is not known yet
+                                                iNodeIndex++,
+                                                CNcdNodeFactory::ENcdNodeFolder,
+                                                CNcdNodeFactory::ENcdSearchNode,
+                                                CNcdNodeFactory::ENcdSearchNode );
+                                                
+                // Before saving the node information make sure that the node remote info is
+                // set correctly. Because nodeAdded will be set true below the node will be 
+                // saved in the end of this function.
+                if ( aData->RemoteUri() != KNullDesC )
+                    {
+                    DLINFO((_L("Remote search node: %S"), &node.Identifier().NodeId()));
+                    node.NodeLinkL().SetRemoteFlag( ETrue );
+                    if ( iNodeManager->SearchFolderL( *iNodeIdentifier ).IsTransparent() )
+                        {
+                        DLINFO(("Parent is transparent folder, add child to remote folder array"));
+                        iRemoteFoldersChildOfTransparent.AppendL( CNcdNodeIdentifier::NewLC( node.Identifier() ) );
+                        CleanupStack::Pop(); // the nodeidentifier
+                        }
+                    else if ( iRecursionLeft ) 
+                        {
+                        // Sub operations should not go any further in recursion
+                        DLINFO(("Recursion left"));
+                        iRemoteFolders.AppendL( CNcdNodeIdentifier::NewLC( node.Identifier() ) );
+                        CleanupStack::Pop(); // the nodeidentifier
+                        }
+                     
+                    }
+                else
+                    {
+                    DLINFO((_L("Normal search node: %S"), &node.Identifier().NodeId()));
+                    node.NodeLinkL().SetRemoteFlag( EFalse );
+                    }
+                           
+                // The parent is not the node identified by the iParentIdentifier
+                tmpSearchParentIdentifier = iNodeIdentifier;
+                nodeAdded = ETrue;
+                }
+            break;
+            }
+            
+        case EChildren:
+            {
+            DLTRACE(("EChildren"));
+            DASSERT( iNodeIdentifier );
+
+            // Get the parent node. So, we can use its link to get the metadataidentifier.
+            // The parent always has the link information set here.    
+            CNcdNode& currentNode = iNodeManager->NodeL( *iNodeIdentifier );
+            DLNODEID( currentNode.NodeLinkL().MetaDataIdentifier() );
+            if ( aData->Id() == currentNode.NodeLinkL().MetaDataIdentifier().NodeId() && 
+                aData->Namespace() == currentNode.NodeLinkL().MetaDataIdentifier().NodeNameSpace() )
+                {
+                DLINFO(("EChildren Add parent"));
+                // Get the actual parent for this operation. This is required to check
+                // if the parent is root or some other kind of folder.
+                CNcdNode& addParent = iNodeManager->NodeL( *iParentIdentifier );                    
+                // add parent
+                iNodeManager->RefHandlerL( *iParentIdentifier,
+                    *aData,
+                    iClientUid,
+                    CNcdNodeManager::EUpdate,
+                    0, // Should give no index in this case
+                    CNcdNodeFactory::NodeTypeL( addParent ),
+                    CNcdNodeFactory::ENcdSearchNode,
+                    CNcdNodeFactory::ENcdSearchNode );
+                nodeAdded = ETrue;
+                // Structure loaded for parent -> send update notification
+                // for parent node so that it gets internalized.
+                CNcdNodeIdentifier* loadedNodeId = 
+                    CNcdNodeIdentifier::NewLC( currentNode.Identifier() );
+                iLoadedNodes.AppendL( loadedNodeId );
+                CleanupStack::Pop( loadedNodeId );
+                }
+            else if ( aData->ParentId() == metaIdentifier->NodeId() ||
+                aData->ParentNamespace() == metaIdentifier->NodeNameSpace() )
+                {
+                DLINFO(("EChildren"));
+                // add child
+                // We are loading the children of the current node that is
+                // identified by the iNodeIdentifier.
+                CNcdNode& node = 
+                    iNodeManager->RefHandlerL( *iNodeIdentifier,
+                                                *aData,
+                                                iClientUid,
+                                                CNcdNodeManager::EReplace,
+                                                iNodeIndex++,
+                                                CNcdNodeFactory::ENcdNodeFolder,
+                                                CNcdNodeFactory::ENcdSearchNode,
+                                                CNcdNodeFactory::ENcdSearchNode );
+
+                // Before saving the node information make sure that the node remote info is
+                // set correctly. Because nodeAdded will be set true below the node will be 
+                // saved in the end of this function.
+                if ( aData->RemoteUri() != KNullDesC )
+                    {
+                    DLINFO((_L("Remote search node: %S"), &node.Identifier().NodeId()));
+                    node.NodeLinkL().SetRemoteFlag( ETrue );
+                    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( node.Identifier() );
+                    iRemoteFolders.AppendL( identifier );
+                    CleanupStack::Pop( identifier );
+                    }
+                else
+                    {
+                    DLINFO((_L("Normal search node: %S"), &node.Identifier().NodeId()));
+                    node.NodeLinkL().SetRemoteFlag( EFalse );
+                    }
+                            
+                // The parent is not the node identified by the iParentIdentifier
+                tmpSearchParentIdentifier = iNodeIdentifier;
+                nodeAdded = ETrue;
+                }
+            break;
+            }
+        }
+    CleanupStack::PopAndDestroy( metaIdentifier );
+            
+    // add search filter to folder, this is needed so that consecutive
+    // search ops (started while paging results) can get the filter
+    if ( nodeAdded )
+        {
+        CNcdNodeIdentifier* searchMetaIdentifier = 
+            CNcdNodeIdentifier::NewLC( aData->Namespace(),
+                                       aData->Id(), 
+                                       aData->ServerUri(),
+                                       iClientUid );
+        CNcdSearchNodeFolder& searchFolder = iNodeManager->SearchFolderL(
+            *tmpSearchParentIdentifier,
+            *searchMetaIdentifier );
+        searchFolder.SetSearchFilterL( *iSearchFilter );
+        if( iLoadMode == ESingleNode && CNcdNodeFactory::NodePurposeL(
+            iNodeManager->NodeL( *iNodeIdentifier ) ) !=
+                CNcdNodeFactory::ENcdSearchNode )
+            {
+            // search op started for a normal node, add origin identifier
+            searchFolder.SetOriginIdentifierL( *iNodeIdentifier );
+            }
+        iNodeManager->DbSaveNodeL( searchFolder );
+        CleanupStack::PopAndDestroy( searchMetaIdentifier );
+        }
+    
+    // Delete data because ownership has been transferred.
+    CleanupStack::PopAndDestroy( aData );
+    
+    DLTRACEOUT((""));
+    }
+    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//    
+void CNcdSearchOperation::FolderDataL(
+    MNcdPreminetProtocolDataEntity* aData )
+    {
+    DLTRACEIN((""));
+    if ( aData != NULL )
+        {
+        TInt err( KErrNone );
+        TRAP( err,
+        // Normal PushL causes USER 42
+        CleanupDeletePushL( aData );
+        
+        // This node will contain the metadata that is updated by calling
+        // the handler function.
+        // Notice that after this the metadata has also been created.
+        // So, metadata can be directly used.
+        CNcdNodeIdentifier* parentIdentifier( NULL );
+        TBool addMetaData = ETrue;
+        if( iLoadMode == EChildren || iLoadMode == ESingleNode )
+            {
+            DLINFO(("EChildren"));
+            DASSERT( iNodeIdentifier );
+            CNcdNodeIdentifier* metaIdentifier = 
+                NcdNodeIdentifierEditor::CreateMetaDataIdentifierL( *iNodeIdentifier );
+            if ( aData->Id() != metaIdentifier->NodeId() || 
+                 aData->Namespace() != metaIdentifier->NodeNameSpace() )
+                {
+                // aData must be child of iNodeIdentifier
+                parentIdentifier = CNcdNodeIdentifier::NewLC( *iNodeIdentifier );
+                }
+            delete metaIdentifier;
+            metaIdentifier = NULL;
+            }
+        if( addMetaData )
+            {
+            // set iParentIdentifier as parent if not set otherwise, this would be the case of a
+            // normal top-level node from a content source
+            if ( ! parentIdentifier ) 
+                {
+                parentIdentifier = CNcdNodeIdentifier::NewLC( *iParentIdentifier );
+                }
+                
+            CNcdNode& node = 
+                iNodeManager->DataHandlerL( *parentIdentifier, *aData, iClientUid );
+                
+            CleanupStack::PopAndDestroy( parentIdentifier );
+
+            // Notice that the loaded nodes should contain the actual node identifier
+            // instead of metadata identifier, because the identifiers are returned to
+            // the proxy side after operation completes.
+            CNcdNodeIdentifier* loadedNodeId = 
+                CNcdNodeIdentifier::NewLC( node.Identifier() );
+            iLoadedNodes.AppendL( loadedNodeId );
+            CleanupStack::Pop( loadedNodeId );
+            
+            DLINFO(("node loaded, id: %S", &node.Identifier().NodeId() ));
+
+            // If the data contains icon id and datablock id, they are stored until
+            // the datablock arrives later (in DataBlocksL method).
+            const MNcdPreminetProtocolIcon* icon = aData->Icon();
+            if ( icon != NULL ) 
+                {
+                const TDesC& iconId = icon->Id();
+                const TDesC& dataBlockId = icon->DataBlock();
+                if ( iconId != KNullDesC && dataBlockId != KNullDesC ) 
+                    {
+                    // Icon id may be mapped to the metadata id here
+                    MapIconIdForDataBlockL( iconId, dataBlockId, 
+                                            node.NodeMetaDataL().Identifier() );
+                    // Notice that here we need to get the node by using the
+                    // parent identifier and metadata id, because the metadata
+                    // identifier itself is not enough to identify the node.
+                    node.NodeMetaDataL().IconL().SetIconDataReady( EFalse );
+                    }
+                }
+            }
+        else if ( parentIdentifier )
+            {
+            CleanupStack::PopAndDestroy( parentIdentifier );
+            }
+
+        // Delete data because ownership has been transferred.
+        CleanupStack::PopAndDestroy( aData );
+        ); //TRAPD
+        if( err != KErrNone )
+            {
+            iError = err;
+            iLoadNodeState = EFailed;
+            }
+        }
+    RunOperation();
+    
+    DLTRACEOUT((""));
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdSearchOperation::ItemRefL( MNcdPreminetProtocolItemRef* aData )
+    {
+    DLTRACEIN((""));
+
+    // Item references are handled only when children are loaded or if the 
+    // search mode is not ENormal
+    //
+    // If all item refs were handled recursive searching would be veeery
+    // slow and we might run out of memory due to very high number of 
+    // nodes (800 and more)
+    if ( ( iSearchFilter->SearchMode() == MNcdSearchFilter::ENormal && 
+           iLoadMode != EChildren &&
+           !iNodeManager->SearchFolderL( *iNodeIdentifier ).IsTransparent() ) || 
+         !aData )
+        {
+        delete aData;
+        DLTRACEOUT(("Not loading children or no data"));
+        return;
+        }
+            
+    TRAPD( err, DoItemRefL( aData ) );
+
+    // Delete data because ownership has been transferred.
+    delete aData;     
+    aData = NULL;    
+ 
+    if( err != KErrNone )
+        {
+        DLERROR(("Error: %d", err));
+        iError = err;
+        iLoadNodeState = EFailed;
+        }
+        
+    RunOperation();    
+    }    
+    
+    
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void CNcdSearchOperation::DoItemRefL( MNcdPreminetProtocolItemRef* aData )
+    {
+    DLTRACEIN((""));
+    // Because aData contains metadata ids, we have to get
+    // the metadata id from the iNodeIdentifier
+    CNcdNodeIdentifier* metaIdentifier =
+        NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( *iNodeIdentifier );
+    
+    switch ( iLoadMode )
+        {
+        case EContentSource:
+            {                    
+            DLTRACE(("Should never come here, ERROR"));
+            DASSERT(0);
+            break;
+            }
+            
+        case ESingleNode:
+            {
+            DLINFO(("Search single node"));
+            DASSERT( iNodeIdentifier );
+            
+            if ( aData->Id() == metaIdentifier->NodeId() && 
+                aData->Namespace() == metaIdentifier->NodeNameSpace() )
+                {
+                iNodeManager->RefHandlerL( *iParentIdentifier,
+                                            *aData,
+                                            iClientUid,
+                                            CNcdNodeManager::EUpdate,
+                                            0,
+                                            iParentType,
+                                            CNcdNodeFactory::ENcdSearchNode,
+                                            CNcdNodeFactory::ENcdSearchNode );
+                }
+            else if( aData->ParentId() == metaIdentifier->NodeId() &&
+                aData->ParentNamespace() == metaIdentifier->NodeNameSpace() )
+                {
+                // add child
+                iNodeManager->RefHandlerL( *iNodeIdentifier,
+                    *aData,
+                    iClientUid,
+                    CNcdNodeManager::EInsert, // use insertion because child count is not known yet
+                    iNodeIndex++,
+                    CNcdNodeFactory::ENcdNodeFolder,
+                    CNcdNodeFactory::ENcdSearchNode,
+                    CNcdNodeFactory::ENcdSearchNode );
+                }
+            break;
+            }
+            
+        case EChildren:
+            {
+            DLINFO(("Search children"));
+            DASSERT( iNodeIdentifier );
+
+            // Get the parent node. So, we can use its link to get the metadataidentifier.
+            // The parent always has the link information set here.    
+            CNcdNode& parentNode = iNodeManager->NodeL( *iNodeIdentifier );
+            if ( aData->Id() == parentNode.NodeLinkL().MetaDataIdentifier().NodeId() && 
+                aData->Namespace() == parentNode.NodeLinkL().MetaDataIdentifier().NodeNameSpace() )
+                {
+                // add parent
+                iNodeManager->RefHandlerL( *iParentIdentifier,
+                    *aData,
+                    iClientUid,
+                    CNcdNodeManager::EUpdate,
+                    0,
+                    iParentType,
+                    CNcdNodeFactory::ENcdSearchNode,
+                    CNcdNodeFactory::ENcdSearchNode );
+                }
+            else if ( aData->ParentId() == metaIdentifier->NodeId() &&
+                aData->ParentNamespace() == metaIdentifier->NodeNameSpace() )
+                {
+                // add child
+                iNodeManager->RefHandlerL( *iNodeIdentifier,
+                    *aData,
+                    iClientUid,
+                    CNcdNodeManager::EReplace,
+                    iNodeIndex++,
+                    CNcdNodeFactory::ENcdNodeFolder,
+                    CNcdNodeFactory::ENcdSearchNode,
+                    CNcdNodeFactory::ENcdSearchNode );
+                }
+            break;
+            }
+        }   
+        
+    CleanupStack::PopAndDestroy( metaIdentifier );
+    DLTRACEOUT((""));
+    }
+    
+
+void CNcdSearchOperation::ItemDataL(
+    MNcdPreminetProtocolDataEntity* aData )
+    {
+    DLTRACEIN((""));
+
+    // Item metadata is handled only when children are loaded or if the 
+    // search mode is not ENormal
+    //
+    // If all item refs were handled recursive searching would be veeery
+    // slow and we might run out of memory due to very high number of 
+    // nodes (800 and more)
+    if ( ( iSearchFilter->SearchMode() == MNcdSearchFilter::ENormal && 
+           iLoadMode != EChildren &&
+           !iNodeManager->SearchFolderL( *iNodeIdentifier ).IsTransparent() ) || 
+         !aData )
+        {
+        delete aData;
+        DLTRACEOUT(("Not loading children or no data"));
+        return;
+        }
+            
+    TRAPD( err, DoItemDataL( aData ) );
+
+    // Delete data because ownership has been transferred.
+    delete aData;     
+    aData = NULL;    
+ 
+    if( err != KErrNone )
+        {
+        DLERROR(("Error: %d", err));
+        iError = err;
+        iLoadNodeState = EFailed;
+        }
+        
+    RunOperation();    
+    }    
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CNcdSearchOperation::DoItemDataL(
+    MNcdPreminetProtocolDataEntity* aData )
+    {
+    DLTRACEIN((""));
+    TBool addMetaData = ETrue;
+    CNcdNodeIdentifier* parentIdentifier( NULL );
+    if( iLoadMode == EChildren || iLoadMode == ESingleNode )
+        {
+        DLINFO(("EChildren or ESingleNode"));
+        DASSERT( iNodeIdentifier );
+        CNcdNodeIdentifier* metaIdentifier = 
+            NcdNodeIdentifierEditor::CreateMetaDataIdentifierL( *iNodeIdentifier );
+        if ( aData->Id() != metaIdentifier->NodeId() || 
+             aData->Namespace() != metaIdentifier->NodeNameSpace() )
+            {
+            // aData must be child of iNodeIdentifier
+            parentIdentifier = CNcdNodeIdentifier::NewLC( *iNodeIdentifier );
+            }
+        delete metaIdentifier;
+        metaIdentifier = NULL;
+        }
+    if( addMetaData )
+        {
+        // set iParentIdentifier as parent if not set otherwise, this would be the case of a
+        // normal top-level node from a content source
+        if ( ! parentIdentifier ) 
+            {
+            parentIdentifier = CNcdNodeIdentifier::NewLC( *iParentIdentifier );
+            }
+        
+        // Get the node reference from the data handler.
+        // The node has the given parent and its metadata
+        // will be internalized with the given data.
+        CNcdNode& node =
+            iNodeManager->DataHandlerL( *parentIdentifier, *aData, iClientUid );
+            
+        CleanupStack::PopAndDestroy( parentIdentifier );
+
+        // Notice that the loaded nodes should contain the actual node identifier
+        // instead of metadata identifier, because the identifiers are returned to
+        // the proxy side after operation completes.
+        CNcdNodeIdentifier* loadedNodeId = 
+            CNcdNodeIdentifier::NewLC( node.Identifier() );
+        iLoadedNodes.AppendL( loadedNodeId );
+        CleanupStack::Pop( loadedNodeId );        
+
+        // If the data contains icon id and datablock id, they are stored until
+        // the datablock arrives later.
+        const MNcdPreminetProtocolIcon* icon = aData->Icon();
+        if ( icon != NULL ) 
+            {
+            const TDesC& iconId = icon->Id();
+            const TDesC& dataBlockId = icon->DataBlock();
+            if ( iconId != KNullDesC && dataBlockId != KNullDesC ) 
+                {
+                // The node metadata was created by using the DataHandlerL
+                // and inserted for the node.
+                // So, the metadata can be asked from the node now.
+                MapIconIdForDataBlockL(iconId, dataBlockId, 
+                                       node.NodeMetaDataL().Identifier() );
+                node.NodeMetaDataL().IconL().SetIconDataReady( EFalse );
+                }
+            }
+        }
+    else if ( parentIdentifier )
+        {
+        CleanupStack::PopAndDestroy( parentIdentifier );
+        }
+    DLTRACEOUT((""));
+    }
+    
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+CNcdSearchOperation::CNcdSearchOperation(
+    TNcdResponseFilterParams aFilterParams,
+    TNcdChildLoadMode aMode,
+    TBool aLoadChildren,
+    CNcdGeneralManager& aGeneralManager,
+    MCatalogsHttpSession& aHttpSession,
+    MNcdOperationRemoveHandler* aRemoveHandler,
+    MNcdOperationQueue* aOperationQueue,
+    MCatalogsSession& aSession,
+    TInt aRecursionLevels,
+    TBool aIsSubOperation )
+    : CNcdLoadNodeOperationImpl( CNcdNodeFactory::ENcdSearchNode, 
+        aFilterParams, aMode, aLoadChildren,
+        aGeneralManager, aHttpSession,
+        aRemoveHandler, aOperationQueue, aSession, aIsSubOperation, ETrue ), 
+      iParentType( CNcdNodeFactory::ENcdNodeFolder ),
+      iRecursionLeft( aRecursionLevels )
+    {
+    iOperationType = ESearchOperation;
+    }
+
+// ---------------------------------------------------------------------------
+// ?description_if_needed
+// ---------------------------------------------------------------------------
+//
+void CNcdSearchOperation::ConstructL(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    const CNcdNodeIdentifier& aParentIdentifier,
+    const CNcdSearchFilter& aFilter )
+    {
+    DLTRACEIN((""));
+    CNcdLoadNodeOperationImpl::ConstructL( aNodeIdentifier,
+        aParentIdentifier );
+    iSearchFilter = CNcdSearchFilter::NewL( aFilter );
+    DetermineParentTypeL( aNodeIdentifier.ClientUid() );
+    CNcdNode& node = iNodeManager->NodeL( *iNodeIdentifier );
+    if( node.ClassId() == NcdNodeClassIds::ENcdBundleFolderNodeClassId )
+        {
+        // Search op started for a bundle.
+        // Search op started from a non-search node (i.e. starting a new search via search api).
+        // Create a search folder skeleton and replace iNodeIdentifier with the
+        // resulting search folder's identifier. This makes stuff easier elsewhere in the op.
+        CNcdNodeIdentifier* originalIdentifier = iNodeIdentifier;
+        CNcdNode& searchNode = CreateSearchBundleSkeletonL();
+        iNodeIdentifier = CNcdNodeIdentifier::NewL( searchNode.Identifier() );
+        delete originalIdentifier;
+        }
+    else if ( CNcdNodeFactory::NodePurposeL( node.ClassId() ) !=
+        CNcdNodeFactory::ENcdSearchNode )
+        {
+        // Search op started from a non-search node (i.e. starting a new search via search api).
+        // Create a search folder skeleton and replace iNodeIdentifier with the
+        // resulting search folder's identifier. This makes stuff easier elsewhere in the op.
+        CNcdNodeIdentifier* originalIdentifier = iNodeIdentifier;
+        CNcdNode& searchNode = CreateSearchFolderSkeletonL();
+        iNodeIdentifier = CNcdNodeIdentifier::NewL( searchNode.Identifier() );
+        delete originalIdentifier;
+        }
+    DLTRACEOUT((""));
+    }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNcdSearchOperation::CreateRequestLC(
+    CNcdNodeIdentifier* aNodeIdentifier,    
+    TNcdResponseFilterParams aFilterParams,
+    const TDesC& aUri )
+    {
+    //DLTRACEIN(("pagesize=%d, pagestart=%d, depth=%d",aPageSize,aPageStart,aDepth));
+    DLTRACEIN((""));
+    
+    CNcdRequestBrowseSearch* req =
+        NcdRequestGenerator::CreateSearchRequestLC();
+        
+    // create textual representations for content purposes
+    CDesC16ArrayFlat* contentPurposes = new ( ELeave ) CDesC16ArrayFlat(
+        KListGranularity );
+    CleanupStack::PushL( contentPurposes );
+    TUint purposes = iSearchFilter->ContentPurposes();
+    if ( purposes & ENcdItemPurposeMusic )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeMusic );
+        }
+    if ( purposes & ENcdItemPurposeRingtone )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeRingtone );
+        }
+    if ( purposes & ENcdItemPurposeWallpaper )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeWallpaper );
+        }
+    if ( purposes & ENcdItemPurposeVideo )
+        {        
+        contentPurposes->AppendL( KNcdContentPurposeVideo );
+        }
+    if ( purposes & ENcdItemPurposeTheme )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeTheme );
+        }
+    if ( purposes & ENcdItemPurposeApplication )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeApplication );
+        }
+    if ( purposes & ENcdItemPurposeHtmlPage )
+        {        
+        contentPurposes->AppendL( KNcdContentPurposeHtmlPage );
+        }
+    if ( purposes & ENcdItemPurposeGame )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeGame );
+        }
+    if ( purposes & ENcdItemPurposeScreensaver )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeScreensaver );
+        }
+    if ( purposes & ENcdItemPurposeStream )
+        {
+        contentPurposes->AppendL( KNcdContentPurposeStream );
+        }
+        
+    // The parameter is the actual search node identifier. So, it can be used
+    // to get the node from the manager.
+    DLINFO((_L("Search node ns: %S, Id: %S"), 
+            &aNodeIdentifier->NodeNameSpace(), 
+            &aNodeIdentifier->NodeId()));
+    CNcdNode& node = iNodeManager->NodeL( *aNodeIdentifier );
+
+    req->SetNamespaceL( aNodeIdentifier->NodeNameSpace() );
+    CDesC16ArrayFlat* elements = new (ELeave) CDesC16ArrayFlat(1);
+    CleanupStack::PushL( elements );
+
+    switch ( iLoadMode )
+        {        
+        case ESingleNode:
+            {
+            DLTRACE(("ESingleNode"))
+            DASSERT( aNodeIdentifier );
+            DASSERT( node.ClassId() != NcdNodeClassIds::ENcdItemNodeClassId );
+            if ( node.ClassId() == NcdNodeClassIds::ENcdSearchItemNodeClassId )
+                {
+                // search op started for item, can't do a search
+                req->SetSearch( EFalse );
+                }
+            else if ( node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId  )
+                {
+                DLTRACE(("Searching from bundle, load children as sub-operations"));
+                CNcdSearchNodeFolder& folder = iNodeManager->SearchFolderL( node.Identifier() );
+                const RPointerArray<CNcdChildEntity>& children = folder.ChildArray();
+                for ( TInt i = 0 ; i < children.Count() ; i++ )
+                    {
+                    CNcdNode& childNode = iNodeManager->NodeL( children[i]->Identifier() );
+                    // remote folders are loaded separately
+                    CNcdNodeIdentifier* remoteFolderId =
+                        CNcdNodeIdentifier::NewLC(
+                            childNode.Identifier() );
+                    iRemoteFolders.AppendL( remoteFolderId );
+                    CleanupStack::Pop( remoteFolderId );
+                    }
+                DLTRACE(("Only search bundle children to load"));
+                User::Leave( KNcdLoadNodeErrRemoteOnly );
+                }
+            else
+                {
+                // search op started for folder, add search filter
+                req->AddEntityFilterL( iSearchFilter->Keywords(),
+                    *contentPurposes,
+                    ETrue,
+                    ETrue);
+                }            
+
+            req->AddEntityL( 
+                node.NodeLinkL().MetaDataIdentifier().NodeId(),
+                node.NodeLinkL().Timestamp(),
+                ETrue );
+
+            // Use response filter only for non-transparent folders            
+            if( node.ClassId() == NcdNodeClassIds::ENcdSearchFolderNodeClassId &&
+                !iNodeManager->SearchFolderL( node.Identifier() ).IsTransparent() )
+                {
+                // If not using recursion or we are on the last level of recursion
+                // we don't need to load the children. This ensures that
+                // with 0 recursion depth search works just like in 3.1.50
+                
+                TInt childCount = INT_MAX; // load all the children
+                if ( !iRecursionLeft ) 
+                    {
+                    childCount = 1; // load just one child
+                    }
+                    
+                req->AddResponseFilterL(
+                    childCount, 
+                    0, // pageStart: load from the first child
+                    1, // structureDepth: load child structure
+                    0, // metaDataDepth: don't load child metadata
+                    1, // metaDataPerLevel: only load one metadata per level
+                    *elements,
+                    *elements );
+                }
+            
+            DLTRACE(("ESingleNode done"))
+            break;
+            }
+            
+        case EChildren:
+            {
+            DLTRACE(("EChildren"));
+            // load children can only be done for folders
+            DASSERT( node.ClassId() == NcdNodeClassIds::ENcdSearchFolderNodeClassId ||
+                node.ClassId() == NcdNodeClassIds::ENcdFolderNodeClassId ||
+                node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId );
+            
+            // add search filter
+            req->AddEntityFilterL( iSearchFilter->Keywords(),
+                *contentPurposes,
+                ETrue,
+                ETrue);
+
+            req->AddEntityL( 
+                node.NodeLinkL().MetaDataIdentifier().NodeId(),
+                node.NodeLinkL().Timestamp(),
+                EFalse ); // Don't load parent metadata.
+            
+            // loading children, use filter params
+            switch ( iChildLoadMode )
+                {
+                case ELoadStructure:
+                    {
+                    DLTRACE(("ELoadStructure"));
+                    // Calculate correct pagesize.
+                    TInt pageSize = CalculateStructPageSize(aFilterParams.iPageStart,
+                        aFilterParams.iPageSize,
+                        iNodeManager->FolderL( node.Identifier() ),
+                        iChildLoadMode );
+                    // Add response filter to get only the desired amount of children.
+                    req->AddResponseFilterL(
+                        pageSize,
+                        aFilterParams.iPageStart,
+                        1, // structureDepth: load child structure
+                        0, // metaDataDepth:  don't load child metadata
+                        0, // metaDataPerLevel: don't load child metadata
+                        *elements,
+                        *elements );
+                    break;
+                    }
+                    
+                case ELoadMetadata:
+                    {
+                    DLTRACE(("ELoadMetadata"));
+                    // search op should never load metadata for non-search folders
+                    // as in this case no search is conducted 
+                    DASSERT( node.ClassId() == 
+                        NcdNodeClassIds::ENcdSearchFolderNodeClassId ||
+                        node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId);
+                    CNcdNodeFolder& folder = iNodeManager->FolderL( *aNodeIdentifier );
+                    // Special handling for bundle folders.
+                    if ( folder.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId )
+                        {
+                        DLTRACE(("Search bundle -> load children in sub ops."));
+                        for ( TInt i = aFilterParams.iPageStart ;
+                             i < aFilterParams.iPageStart + aFilterParams.iPageSize ;
+                             i++ )
+                            {
+                            CNcdNode& childNode = iNodeManager->NodeL( folder.ChildL( i ) );
+                            
+                            if ( !childNode.NodeMetaData() || childNode.NodeLinkL().IsExpired() )
+                                {
+                                // load node only if it has no metadata or if it's expired
+                            
+                                CNcdNodeIdentifier* remoteFolderId =
+                                    CNcdNodeIdentifier::NewLC( childNode.Identifier() );
+                                // Remote folderlist contains actual node ids.
+                                iRemoteFolders.AppendL( remoteFolderId );
+                                CleanupStack::Pop( remoteFolderId );
+                                }
+                            }
+                        if( iRemoteFolders.Count() > 0 )
+                            {
+                            DLTRACE(("Only remote folders to load"));
+                            User::Leave( KNcdLoadNodeErrRemoteOnly );
+                            }
+                        else
+                            {
+                            DLTRACE(("Nothing to do -> complete operation"));
+                            User::Leave( KNcdLoadNodeErrNothingToDo );
+                            }
+                        }
+                    else
+                        {
+                        DLTRACE(("Normal search folder"));
+                        // Calculate correct pagesize.
+                        TInt pageSize = CalculateStructPageSize(aFilterParams.iPageStart,
+                            aFilterParams.iPageSize,
+                            folder,
+                            iChildLoadMode );
+                        // Add response filter to get only the desired amount of children.                      
+                        req->AddResponseFilterL(
+                            pageSize, // pageSize: 
+                            aFilterParams.iPageStart, // pageStart: not applicable in this case as pageSize is 0
+                            1, // structureDepth: load child structure
+                            1, // metaDataDepth: load child metadata
+                            aFilterParams.iPageSize,// metaDataPerLevel: load metadata only for the requested page
+                            *elements,
+                            *elements );
+                        }
+                    DLTRACE(("ELoadMetadata done"));
+                    break;
+                    }
+                }
+            DLTRACE(("EChildren done"));
+            break;
+            }
+            
+        case EContentSource:
+        default:
+            {
+            // this should never happen
+            DASSERT( 0 );
+            break;
+            }
+        }
+    CleanupStack::PopAndDestroy( elements );
+    CleanupStack::PopAndDestroy( contentPurposes );
+    
+    AddQueryResponsesL( req );
+    
+    HBufC8* data = NULL;
+    
+    data = iProtocol.ProcessPreminetRequestL(
+        iSession.Context(), *req, aUri );
+    
+    CleanupStack::PopAndDestroy( req );
+    CleanupStack::PushL( data );
+    return data;
+    }
+    
+void CNcdSearchOperation::CreateSubOperationsL()
+    {
+    DLTRACEIN(("remote folder count: %d", iRemoteFolders.Count()));
+    
+    for ( TInt i = 0 ; i < iRemoteFolders.Count() ; i++ )
+        {
+        CNcdNode& remoteFolder = iNodeManager->NodeL( *iRemoteFolders[i] );
+        CNcdSearchOperation* loadOp =
+            CNcdSearchOperation::NewLC(
+                *iRemoteFolders[i],
+                remoteFolder.NodeLinkL().ParentIdentifier(),
+                *iSearchFilter,
+                TNcdResponseFilterParams(),
+                iGeneralManager,
+                iHttpSession,
+                iRemoveHandler,
+                iOperationQueue,
+                iSession,
+                EFalse, // Results in  ESingleNode load mode.
+                ELoadStructure, // Not used in ESingleNode mode.
+                iRecursionLeft - 1,
+                ETrue );
+        
+        loadOp->AddObserverL( this );
+        User::LeaveIfError( loadOp->Start() );
+        iSubOps.AppendL( loadOp );
+        CleanupStack::Pop( loadOp );
+        }
+        
+    DLINFO(("Child of transparent count: %d", iRemoteFoldersChildOfTransparent.Count() ));
+    
+    // Create load operations for children of transparent folders.
+    for ( TInt i = 0 ; i < iRemoteFoldersChildOfTransparent.Count() ; i++ )
+        {
+        CNcdNode& remoteFolder = iNodeManager->NodeL( *iRemoteFoldersChildOfTransparent[i] );
+        CNcdSearchOperation* loadOp =
+            CNcdSearchOperation::NewLC(
+                *iRemoteFoldersChildOfTransparent[i],
+                remoteFolder.NodeLinkL().ParentIdentifier(),
+                *iSearchFilter,
+                TNcdResponseFilterParams(),
+                iGeneralManager,
+                iHttpSession,
+                iRemoveHandler,
+                iOperationQueue,
+                iSession,
+                EFalse, // Results in  ESingleNode load mode.
+                ELoadStructure, // Not used in ESingleNode mode.
+                iRecursionLeft, // Don't decrease the recursion level for child of transparent
+                ETrue );
+        
+        loadOp->AddObserverL( this );
+        User::LeaveIfError( loadOp->Start() );
+        iSubOps.AppendL( loadOp );
+        CleanupStack::Pop( loadOp );
+        }
+    }
+    
+TBool CNcdSearchOperation::IsLoadingNecessaryL()
+    {
+    DLTRACEIN((""));
+    DASSERT( iNodeIdentifier );
+    CNcdNode& node = iNodeManager->NodeL( *iNodeIdentifier );
+    
+    if ( node.ClassId() == NcdNodeClassIds::ENcdSearchRootNodeClassId )
+        {
+        DLTRACE(("Search root -> don't load"));
+        return EFalse;
+        }
+    else if ( iLoadMode == EChildren && iChildLoadMode == ELoadMetadata && 
+              node.ClassId() != NcdNodeClassIds::ENcdSearchBundleNodeClassId )
+        {
+        DLTRACE(("ELoadMetadata for normal folder -> load"));
+        return ETrue;
+        }
+    else if( iLoadMode == ESingleNode && node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId )
+        {
+        DLTRACE(("Search bundle and ESingleNode -> load"));
+        return ETrue;
+        }
+    else if( node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId ||
+        node.ClassId() == NcdNodeClassIds::ENcdBundleFolderNodeClassId )
+        {
+        DLTRACE(("Bundle or search bundle -> don't load"));
+        return EFalse;
+        }
+    else
+        {
+        DLTRACE(("load"));
+        return ETrue;
+        }
+    }
+    
+TBool CNcdSearchOperation::IsChildClearingNecessaryL()
+    {
+    DLTRACEIN((""));
+    CNcdNode& node = iNodeManager->NodeL( *iNodeIdentifier );
+    return node.ClassId() == NcdNodeClassIds::ENcdSearchFolderNodeClassId && 
+           iLoadMode == ESingleNode;
+    }
+
+
+void CNcdSearchOperation::DetermineParentTypeL( const TUid& aUid )
+    {
+    DLTRACEIN((""));
+    CNcdNodeIdentifier* searchRoot = 
+        NcdNodeIdentifierEditor::CreateSearchRootIdentifierForClientLC( aUid );
+    DASSERT( iNodeIdentifier );
+    DASSERT( iParentIdentifier );
+    // don't do parent type check for search root as it has no parent
+    if ( !searchRoot->Equals( *iNodeIdentifier ) ) 
+        {
+        iParentType = CNcdNodeFactory::NodeTypeL(
+        iNodeManager->NodeL( *iParentIdentifier ) );
+        }
+    CleanupStack::PopAndDestroy( searchRoot );
+    }
+
+CNcdNode& CNcdSearchOperation::CreateSearchBundleSkeletonL()
+    {
+    DLTRACEIN((""));
+    
+    CNcdNodeFolder& bundle = iNodeManager->FolderL( *iNodeIdentifier );
+    
+    CNcdNodeMetaData& bundleMeta = bundle.NodeMetaDataL();
+    
+    CNcdSearchNodeBundle& searchBundle = 
+        iNodeManager->CreateSearchBundleL( bundleMeta.Identifier(),
+        *iParentIdentifier );
+        
+    // Create a link for the bundle
+    CNcdNodeLink& link = searchBundle.CreateAndSetLinkL();
+    
+    // Also, notice that it is essential to insert the metadata identifier into the
+    // link info. So, the right metadata will be found when the bundle is opened
+    // from the database. For example when application has been started.
+    link.SetMetaDataIdentifierL( bundleMeta.Identifier() );
+    
+    // Set the metadata to the search bundle because it was not set during creation.
+    searchBundle.SetNodeMetaDataL( bundleMeta );
+    
+    searchBundle.SetSearchFilterL( *iSearchFilter );
+    
+    // Set the search bundle as child of the parent node.
+    iNodeManager->AddToParentL( *iParentIdentifier, bundleMeta.Identifier(), 
+                                iParentType,
+                                CNcdNodeFactory::ENcdSearchNode,
+                                CNcdNodeFactory::ENcdSearchNode,
+                                CNcdNodeManager::EInsert, 0 );
+    
+    // Add child folders to search bundle
+    const RPointerArray<CNcdChildEntity>& children = bundle.ChildArray();
+    for( TInt i = 0 ; i < children.Count() ; i++ )
+        {
+        // bundle's children can only be folders
+        CNcdNodeFolder& bundleChild = iNodeManager->FolderL( children[i]->Identifier() );
+        
+        // add only children with search capability
+        if( iNodeManager->IsCapabilitySupportedL( bundleChild.Identifier(),
+            NcdCapabilities::KSearch,
+            iSession.Context() ) )
+            {
+            // Bunlde child's metadata may be unavailable so just use the 
+            // metadata identifier from link
+            //CNcdNodeMetaData& bundleChildMeta = bundleChild.NodeMetaDataL();
+            CNcdNodeLink& bundleChildLink = bundleChild.NodeLinkL();
+            
+            CNcdSearchNodeFolder& searchBundleChild = 
+                iNodeManager->CreateSearchFolderL( bundleChildLink.MetaDataIdentifier(),
+                searchBundle.Identifier() );
+                
+            // Create a link for the child
+            CNcdNodeLink& childLink = searchBundleChild.CreateAndSetLinkL();
+            
+            // Also, notice that it is essential to insert the metadata identifier into the
+            // link info. So, the right metadata will be found when the node is opened
+            // from the database. For example when application has been started.
+            childLink.SetMetaDataIdentifierL( bundleChildLink.MetaDataIdentifier() );
+            
+            // copy server uri from original node
+            if( bundleChild.NodeLinkL().RemoteUri() != KNullDesC )
+                {
+                childLink.SetServerUriL( bundleChild.NodeLinkL().RemoteUri() );
+                }
+            else
+                {
+                childLink.SetServerUriL( bundleChild.NodeLinkL().ServerUri() );
+                }
+            
+            // Set the metadata to the bundle folder because it was not set during creation.
+            //searchBundleChild.SetNodeMetaDataL( bundleChildMeta );
+            
+            searchBundleChild.SetSearchFilterL( *iSearchFilter );
+
+            TBool transparent = 
+                ( bundleChild.ClassId() == NcdNodeClassIds::ENcdTransparentFolderNodeClassId );
+                        
+            searchBundleChild.SetTransparent( transparent );
+                
+            
+            // Set the folder as child of search bundle.
+            iNodeManager->AddToParentL( searchBundle.Identifier(), bundleChildLink.MetaDataIdentifier(), 
+                                        CNcdNodeFactory::ENcdNodeSearchBundle,
+                                        CNcdNodeFactory::ENcdSearchNode,
+                                        CNcdNodeFactory::ENcdSearchNode, //This parameter is unused
+                                        CNcdNodeManager::EAppend, 
+                                        0,
+                                        transparent );
+                                        
+            searchBundleChild.SetOriginIdentifierL( bundleChild.Identifier() );
+            iNodeManager->DbSaveNodeL( searchBundleChild );
+            }
+        }
+    iNodeManager->DbSaveNodeL( searchBundle );
+    return searchBundle;
+    }
+
+CNcdNode& CNcdSearchOperation::CreateSearchFolderSkeletonL()
+    {
+    DLTRACEIN((""));
+    
+    CNcdNodeFolder& folder = iNodeManager->FolderL( *iNodeIdentifier );
+    
+    CNcdNodeMetaData& folderMeta = folder.NodeMetaDataL();
+    
+    CNcdSearchNodeFolder& searchFolder = 
+        iNodeManager->CreateSearchFolderL( folderMeta.Identifier(),
+        *iParentIdentifier );
+        
+    // Create a link for the folder
+    CNcdNodeLink& link = searchFolder.CreateAndSetLinkL();
+    
+    // Also, notice that it is essential to insert the metadata identifier into the
+    // link info. So, the right metadata will be found when the folder is opened
+    // from the database. For example when application has been started.
+    link.SetMetaDataIdentifierL( folderMeta.Identifier() );
+    
+    // copy server uri from original node
+    if( folder.NodeLinkL().RemoteUri() != KNullDesC )
+        {
+        link.SetServerUriL( folder.NodeLinkL().RemoteUri() );
+        }
+    else
+        {
+        link.SetServerUriL( folder.NodeLinkL().ServerUri() );
+        }
+    
+    // Set the metadata to the search bundle because it was not set during creation.
+    searchFolder.SetNodeMetaDataL( folderMeta );
+    
+    searchFolder.SetSearchFilterL( *iSearchFilter );
+    
+    TBool transparent = 
+        ( folder.ClassId() == NcdNodeClassIds::ENcdTransparentFolderNodeClassId );
+        
+    // Set the search folder as child of the parent node.
+    iNodeManager->AddToParentL( *iParentIdentifier, 
+                                folderMeta.Identifier(), 
+                                iParentType,
+                                CNcdNodeFactory::ENcdSearchNode,
+                                CNcdNodeFactory::ENcdSearchNode,
+                                CNcdNodeManager::EInsert, 
+                                0,
+                                transparent );
+    
+    searchFolder.SetOriginIdentifierL( *iNodeIdentifier );
+    
+    // Because AddToParentL only saves the parent information after child is added to it
+    // we should always save the bundle node here. So, it will be usable after client is
+    // restarted.
+    iNodeManager->DbSaveNodeL( searchFolder );
+    
+    return searchFolder;
+    }
+    
+void CNcdSearchOperation::ErrorL( MNcdPreminetProtocolError* aData )
+    {
+    DLTRACEIN((""));
+    switch ( aData->Code() )
+        {
+        case 404:
+            {
+            // Removed/missing nodes need no special handling in search op,
+            // so just fail the operation.
+            iError = KNcdErrorNodeWasRemoved;
+            iLoadNodeState = EFailed;
+            Cancel();
+            delete aData;
+            RunOperation();
+            break;
+            }
+        default:
+            {
+            CNcdLoadNodeOperationImpl::ErrorL( aData );
+            break;
+            }
+        }    
+    }
+
+TInt CNcdSearchOperation::RemoteFolderCount() const
+    {
+    DLTRACEIN((""));
+    return iRemoteFolders.Count() + iRemoteFoldersChildOfTransparent.Count();
+    }
+    
+    
+void CNcdSearchOperation::RemoveChildrenL( CNcdNodeFolder& aFolder ) 
+    {
+    DLTRACEIN((""));
+    aFolder.RemoveChildren();
+    }
+