ncdengine/provider/server/src/ncdnodefolder.cpp
changeset 0 ba25891c3a9e
equal deleted inserted replaced
-1:000000000000 0:ba25891c3a9e
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implements CNcdNodeFolder class
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "ncdnodefolder.h"
       
    20 #include "ncdnodefolderlink.h"
       
    21 #include "ncdnodefoldermetadata.h"
       
    22 #include "ncdnodemanager.h"
       
    23 #include "ncdnodeclassids.h"
       
    24 #include "ncdnodeidentifier.h"
       
    25 #include "ncdnodefunctionids.h"
       
    26 #include "catalogsbasemessage.h"
       
    27 #include "catalogsutils.h"
       
    28 #include "ncdchildentity.h"
       
    29 #include "ncdnodefolderlink.h"
       
    30 #include "ncdnodeseenfolderimpl.h"
       
    31 #include "ncdexpirednode.h"
       
    32 
       
    33 #include "catalogsdebug.h"
       
    34 
       
    35 CNcdNodeFolder::CNcdNodeFolder( CNcdNodeManager& aNodeManager,
       
    36     NcdNodeClassIds::TNcdNodeClassId aNodeClassId, 
       
    37     NcdNodeClassIds::TNcdNodeClassId aAcceptedLinkClassId,
       
    38     NcdNodeClassIds::TNcdNodeClassId aAcceptedMetaDataClassId )
       
    39 : CNcdNode( aNodeManager,
       
    40             aNodeClassId,
       
    41             aAcceptedLinkClassId,
       
    42             aAcceptedMetaDataClassId ),
       
    43   iPreviousChildCount( KErrNotFound )
       
    44     {
       
    45     }
       
    46 
       
    47 void CNcdNodeFolder::ConstructL( const CNcdNodeIdentifier& aIdentifier )
       
    48     {
       
    49     DLTRACEIN(("this: %X", this ));
       
    50 
       
    51     CNcdNode::ConstructL( aIdentifier );
       
    52     
       
    53     iNodeSeenFolder = CNcdNodeSeenFolder::NewL( *this );
       
    54         
       
    55     DLTRACEOUT((""));
       
    56     }
       
    57 
       
    58 
       
    59 CNcdNodeFolder::~CNcdNodeFolder()
       
    60     {
       
    61     DLTRACEIN(("this: %X", this));
       
    62     for ( TInt i = 0; i < iChildren.Count(); ++i ) 
       
    63         {
       
    64         DLINFO(( _L("Child %d, ns: %S, id: %S"), i,
       
    65                  &iChildren[i]->Identifier().NodeNameSpace(),
       
    66                  &iChildren[i]->Identifier().NodeId() ));
       
    67         }
       
    68     RemoveChildren();
       
    69     
       
    70     if ( iNodeSeenFolder )
       
    71         {
       
    72         DLINFO(("Closing node seen folder"));
       
    73         iNodeSeenFolder->Close();
       
    74         iNodeSeenFolder = NULL;
       
    75         }
       
    76         
       
    77     iPreviousChildren.ResetAndDestroy();
       
    78 
       
    79     DLTRACEOUT((""));
       
    80     }
       
    81 
       
    82 
       
    83 CNcdNodeFolder* CNcdNodeFolder::NewL( CNcdNodeManager& aNodeManager,
       
    84                                       const CNcdNodeIdentifier& aIdentifier  )
       
    85     {
       
    86     CNcdNodeFolder* self = 
       
    87         CNcdNodeFolder::NewLC( aNodeManager, aIdentifier );
       
    88     CleanupStack::Pop( self );
       
    89     return self;        
       
    90     }
       
    91 
       
    92 CNcdNodeFolder* CNcdNodeFolder::NewLC( CNcdNodeManager& aNodeManager,
       
    93                                        const CNcdNodeIdentifier& aIdentifier )
       
    94     {
       
    95     CNcdNodeFolder* self = 
       
    96         new( ELeave ) CNcdNodeFolder( aNodeManager );
       
    97     CleanupClosePushL( *self );
       
    98     self->ConstructL( aIdentifier );
       
    99     return self;        
       
   100     }
       
   101                                   
       
   102 
       
   103 TInt CNcdNodeFolder::ChildCount() const
       
   104     {
       
   105     DLTRACEIN(( "this: %X, ChildCount: %d", this, iChildren.Count() ));
       
   106     return iChildren.Count();
       
   107     }
       
   108 
       
   109 
       
   110 const CNcdNodeIdentifier& CNcdNodeFolder::ChildL( TInt aIndex ) const
       
   111     {
       
   112     DLTRACEIN(( "" ));
       
   113     if( aIndex < 0 || aIndex > iChildren.Count() )
       
   114         {
       
   115         User::Leave( KErrArgument );
       
   116         }
       
   117     return iChildren[aIndex]->Identifier();
       
   118     }
       
   119     
       
   120 TInt CNcdNodeFolder::ServerChildCountL() const
       
   121     {
       
   122     DLTRACEIN((""));
       
   123     TInt serverChildCount = FolderLinkL().ExpectedChildrenCount();
       
   124     DLTRACEOUT(("this: %X, ServerChildCount: %d", this, serverChildCount ));
       
   125     return serverChildCount;
       
   126     }
       
   127 
       
   128 const CNcdNodeIdentifier& CNcdNodeFolder::ChildByServerIndexL( TInt aIndex ) const
       
   129     {
       
   130     DLTRACEIN((""));
       
   131     return ChildEntityByServerIndexL( aIndex ).Identifier();
       
   132     }
       
   133 
       
   134 const CNcdChildEntity& CNcdNodeFolder::ChildEntityByServerIndexL( TInt aIndex ) const
       
   135     {
       
   136     DLTRACEIN(( "aIndex: %d", aIndex )); 
       
   137            
       
   138     // search for a child with given index
       
   139     const CNcdChildEntity* child = NULL;
       
   140     for( TInt i = 0 ; i < iChildren.Count() ; i++ )
       
   141         {
       
   142         if ( iChildren[i]->Index() == aIndex )
       
   143             {
       
   144             child = iChildren[i];
       
   145             break;
       
   146             }
       
   147         else if ( iChildren[i]->Index() > aIndex )
       
   148             {
       
   149             // no sense in searching further
       
   150             break;
       
   151             }
       
   152         }
       
   153        
       
   154     if ( child == NULL )
       
   155         {
       
   156         // Leave because the child is set NULL.
       
   157         // NULL can not be returned as a reference value.
       
   158         DLINFO(("Child node identifier was NULL. So, leave with KErrNotFound"))
       
   159         User::Leave( KErrNotFound );
       
   160         }
       
   161     
       
   162     DLTRACEOUT((""));
       
   163 
       
   164     return *child;
       
   165     }
       
   166 
       
   167 const RPointerArray<CNcdChildEntity>& CNcdNodeFolder::ChildArray() const
       
   168     {
       
   169     return iChildren;
       
   170     }
       
   171 
       
   172 
       
   173 TBool CNcdNodeFolder::ReplaceChildL( 
       
   174     const CNcdNodeIdentifier& aNodeIdentifier,
       
   175     TInt aIndex,
       
   176     TBool aTransparent,
       
   177     CNcdNodeFactory::TNcdNodeType aNodeType )
       
   178     {
       
   179     DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S, Child ns, id: %S, %S, aIndex: %d childCount: %d"),
       
   180         this, &Identifier().NodeNameSpace(), &Identifier().NodeId(),
       
   181         &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId(),
       
   182         aIndex, iChildren.Count() ));
       
   183 
       
   184     TInt expectedChildCount = FolderLinkL().ExpectedChildrenCount();
       
   185     if ( aIndex < 0 /*|| aIndex >= expectedChildCount*/ )
       
   186         {
       
   187         // For debugging purposes
       
   188         DLERROR(("Wrong child index"));
       
   189         DASSERT( EFalse );
       
   190         
       
   191         User::Leave( KErrArgument );   
       
   192         }
       
   193         
       
   194     
       
   195     TBool childFound = EFalse;
       
   196     TInt i = 0;
       
   197     for ( ; i < iChildren.Count() ; i++ )
       
   198         {
       
   199         if( iChildren[i]->Index() == aIndex )
       
   200             {
       
   201             DLTRACE(("Child with the same index found."));
       
   202             if( ! (iChildren[i]->Identifier().Equals( aNodeIdentifier  ) ) )
       
   203                 {
       
   204                 DLTRACE(("Not the same child, replace."));
       
   205                 iChildren[i]->SetIdentifierL( aNodeIdentifier );
       
   206                 iChildren[i]->SetTransparent( aTransparent );
       
   207                 iChildren[i]->SetNodeType( aNodeType );
       
   208                 // Should the old child be expired via nodemgr?
       
   209                 }
       
   210             else
       
   211                 {
       
   212                 iChildren[i]->SetTransparent( aTransparent );
       
   213                 iChildren[i]->SetNodeType( aNodeType );
       
   214                 // exactly the same child, do nothing
       
   215                 }
       
   216             childFound = ETrue;
       
   217             break;
       
   218             }
       
   219         else if ( iChildren[i]->Index() > aIndex )
       
   220             {
       
   221             // no sense in searching further
       
   222             break;
       
   223             }
       
   224         }
       
   225         
       
   226     if ( !childFound )
       
   227         {
       
   228         DLTRACE(("Child not found, create new"))
       
   229         CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( 
       
   230             aIndex,
       
   231             aNodeIdentifier,
       
   232             aTransparent,
       
   233             aNodeType );
       
   234             
       
   235         if ( i == iChildren.Count() )
       
   236             {
       
   237             // last child, append
       
   238             DLTRACE(("Appending"));
       
   239             iChildren.AppendL( childEntity );
       
   240             }
       
   241         else
       
   242             {
       
   243             DLTRACE(("Inserting"));
       
   244             iChildren.InsertL( childEntity, i );
       
   245             }
       
   246         CleanupStack::Pop( childEntity );
       
   247         }
       
   248         
       
   249     #ifdef CATALOGS_BUILD_CONFIG_DEBUG
       
   250     for( TInt j = 0 ; j < iChildren.Count() ; j++ )
       
   251         {
       
   252         CNcdChildEntity* child = iChildren[j];
       
   253         DLINFO((_L("Child id: %S, array index: %d, real index: %d"),
       
   254             &child->Identifier().NodeId(), j, child->Index() ));
       
   255         }
       
   256     #endif
       
   257     
       
   258     return !childFound;
       
   259     }
       
   260         
       
   261         
       
   262 TBool CNcdNodeFolder::InsertChildL( 
       
   263     const CNcdNodeIdentifier& aNodeIdentifier,
       
   264     TInt aIndex,
       
   265     TBool aTransparent,
       
   266     CNcdNodeFactory::TNcdNodeType aNodeType )
       
   267     {
       
   268     DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S, Child ns, id: %S, %S, aIndex: %d, childCount: %d"),
       
   269         this, &Identifier().NodeNameSpace(), &Identifier().NodeId(),
       
   270         &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId(),
       
   271         aIndex, iChildren.Count() ));
       
   272                
       
   273     DPROFILING_BEGIN( x );
       
   274     if ( aIndex < 0 || aIndex > iChildren.Count() )
       
   275         {
       
   276         // For debugging purposes
       
   277         DLERROR(("Wrong child index"));
       
   278         DASSERT( EFalse );
       
   279         
       
   280         User::Leave( KErrArgument );
       
   281         }
       
   282     
       
   283     CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( 
       
   284         aIndex,
       
   285         aNodeIdentifier,
       
   286         aTransparent,
       
   287         aNodeType );
       
   288     if( aIndex == iChildren.Count() )
       
   289         {
       
   290         // last index, append
       
   291         DLTRACE(("Appending"));
       
   292         iChildren.AppendL( childEntity );
       
   293         }
       
   294     else
       
   295         {
       
   296         DLTRACE(("Inserting"));
       
   297         iChildren.InsertL( childEntity, aIndex );
       
   298         }    
       
   299     CleanupStack::Pop( childEntity );    
       
   300 
       
   301     #ifdef CATALOGS_BUILD_CONFIG_DEBUG
       
   302     for( TInt i = 0 ; i < iChildren.Count() ; i++ )
       
   303         {
       
   304         DLINFO(( _L("Child: index: %d, real index: %d, id: %S, ns: %S "),
       
   305             i, iChildren[i]->Index(), &iChildren[i]->Identifier().NodeId(),
       
   306             &iChildren[i]->Identifier().NodeNameSpace() ));
       
   307         }
       
   308     #endif
       
   309 
       
   310     DPROFILING_END( x );
       
   311     return ETrue;
       
   312     }
       
   313     
       
   314     
       
   315 TBool CNcdNodeFolder::AppendChildL( 
       
   316     const CNcdNodeIdentifier& aNodeIdentifier,
       
   317     TBool aTransparent,
       
   318     CNcdNodeFactory::TNcdNodeType aNodeType ) 
       
   319     {
       
   320     DLTRACEIN((""));
       
   321     return InsertChildL( aNodeIdentifier, iChildren.Count(), aTransparent,
       
   322         aNodeType );
       
   323     }
       
   324     
       
   325 CNcdNodeFolderLink& CNcdNodeFolder::FolderLinkL() const
       
   326     {
       
   327     // safe to cast because folders always have folder links
       
   328     return static_cast<CNcdNodeFolderLink&>( NodeLinkL() );
       
   329     }
       
   330     
       
   331 
       
   332 CNcdNodeSeenFolder& CNcdNodeFolder::NodeSeenFolder() const 
       
   333     {
       
   334     return *iNodeSeenFolder;
       
   335     }                  
       
   336     
       
   337     
       
   338 void CNcdNodeFolder::RemoveChild( const CNcdNodeIdentifier& aNodeIdentifier ) 
       
   339     {
       
   340     DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S"), this,
       
   341                 &Identifier().NodeNameSpace(), &Identifier().NodeId() ));
       
   342     DLINFO(( _L("child to remove ns, id: %S, %S"),
       
   343              &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId() ));
       
   344     DPROFILING_BEGIN( x );
       
   345     for ( TInt i = 0 ; i < iChildren.Count() ; i++ )
       
   346         {
       
   347         if( iChildren[i]->Identifier().Equals( aNodeIdentifier ) )
       
   348             {
       
   349             DeleteFromArray( iChildren, i );
       
   350             DPROFILING_END( x );
       
   351             return;
       
   352             }
       
   353         }
       
   354     
       
   355     DPROFILING_END( x );
       
   356     DLWARNING(("Unable to remove nonexisting child"));
       
   357     }
       
   358     
       
   359 
       
   360 void CNcdNodeFolder::RemoveChildrenL()
       
   361     {
       
   362     DLTRACEIN((""));
       
   363     DPROFILING_BEGIN( x );
       
   364     NodeManager().RemoveChildrenL( *this );
       
   365     DPROFILING_END( x );
       
   366     }
       
   367     
       
   368 
       
   369 void CNcdNodeFolder::RemoveChildren()
       
   370     {
       
   371     DLTRACEIN((""));
       
   372     iChildren.ResetAndDestroy();
       
   373     // Also set children previously loaded flag to false,
       
   374     // because child list is no longer valid
       
   375     iChildrenPreviouslyLoaded = EFalse;
       
   376     DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
       
   377     DLTRACE(("iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
       
   378     }
       
   379     
       
   380 void CNcdNodeFolder::StoreChildrenToPreviousListL()
       
   381     {
       
   382     DLTRACEIN((""));
       
   383     StoreChildrenToPreviousListL( iChildren,
       
   384         FolderLinkL().ExpectedChildrenCount() );
       
   385     }
       
   386 
       
   387 void CNcdNodeFolder::StoreChildrenToPreviousListL(
       
   388     const RPointerArray<CNcdChildEntity>& aPreviousChildren,
       
   389     TInt aPreviousChildCount )
       
   390     {
       
   391     DLTRACEIN((""));
       
   392     // First clear previous list.
       
   393     iPreviousChildren.ResetAndDestroy();
       
   394     for( TInt i = 0 ; i < aPreviousChildren.Count() ; i++ )
       
   395         {
       
   396         CNcdChildEntity* childEntity = CNcdChildEntity::NewLC(
       
   397             *aPreviousChildren[i] );
       
   398         DLTRACE((_L("Adding child entity, identifier: %S, index: %d"),
       
   399              &childEntity->Identifier().NodeId(), childEntity->Index() ));
       
   400         iPreviousChildren.AppendL( childEntity );
       
   401         CleanupStack::Pop( childEntity );
       
   402         }
       
   403     DLTRACE(("Setting previous child count: %d", aPreviousChildCount ));
       
   404     iPreviousChildCount = aPreviousChildCount;
       
   405     }
       
   406 
       
   407 TBool CNcdNodeFolder::ChildrenPreviouslyLoaded()
       
   408     {
       
   409     DLTRACEIN((""));
       
   410     DLINFO(("ret: %d",iChildrenPreviouslyLoaded));
       
   411     return iChildrenPreviouslyLoaded;
       
   412     }
       
   413 
       
   414 void CNcdNodeFolder::SetChildrenPreviouslyLoaded( TBool aChildrenPreviouslyLoaded )
       
   415     {
       
   416     DLTRACEIN((""));
       
   417     iChildrenPreviouslyLoaded = aChildrenPreviouslyLoaded;
       
   418     }
       
   419 
       
   420 TInt CNcdNodeFolder::PreviousChildCount()
       
   421     {
       
   422     DLTRACEIN((""));
       
   423     return iPreviousChildCount;
       
   424     }
       
   425 
       
   426 const RPointerArray<CNcdChildEntity>& CNcdNodeFolder::PreviousChildArray()
       
   427     {
       
   428     DLTRACEIN((""));
       
   429     return iPreviousChildren;
       
   430     }
       
   431     
       
   432     
       
   433 void CNcdNodeFolder::ExpireAndRemoveChildrenL()
       
   434     {
       
   435     DLTRACEIN((""));
       
   436     TInt count = iChildren.Count();
       
   437     
       
   438     CNcdNode* node = NULL;
       
   439     
       
   440     RPointerArray<CNcdExpiredNode> expiredNodes;
       
   441     CleanupResetAndDestroyPushL( expiredNodes );
       
   442     expiredNodes.ReserveL( count );
       
   443     
       
   444     while( count-- ) 
       
   445         {        
       
   446         node = NodeManager().NodePtrL( iChildren[ count ]->Identifier() );
       
   447         if ( node )
       
   448             {
       
   449             NodeManager().SetNodeExpiredL( *node, EFalse, EFalse, expiredNodes );
       
   450              
       
   451             }
       
   452         }
       
   453     CleanupStack::PopAndDestroy( &expiredNodes );
       
   454     // Delete child metadatas from disk cache
       
   455     NodeManager().RemoveChildrenMetadataL( *this );
       
   456     
       
   457     // Empty children lists
       
   458     RemoveChildren();    
       
   459     }
       
   460     
       
   461     
       
   462 void CNcdNodeFolder::ReceiveMessage(
       
   463     MCatalogsBaseMessage* aMessage,
       
   464     TInt aFunctionNumber )
       
   465     {
       
   466     DLTRACEIN(("this-ptr: %x", this));
       
   467     
       
   468     DASSERT( aMessage );
       
   469     
       
   470     // Now, we can be sure that rest of the time iMessage exists.
       
   471     // This member variable is set for the CounterPartLost function.
       
   472     iMessage = aMessage;
       
   473         
       
   474     TInt trapError( KErrNone );
       
   475     
       
   476     switch( aFunctionNumber )
       
   477         {
       
   478         case NcdNodeFunctionIds::ENcdNodeSeenFolderHandle:
       
   479             TRAP( trapError, NodeSeenFolderHandleRequestL( *aMessage ) );            
       
   480             break;
       
   481             
       
   482         default:
       
   483             // Let base class handle this
       
   484             iMessage = NULL;
       
   485             CNcdNode::ReceiveMessage( aMessage, aFunctionNumber );
       
   486             return;
       
   487         }
       
   488         
       
   489    if ( trapError != KErrNone )
       
   490         {
       
   491         // Because something went wrong the complete has not been
       
   492         // yet called for the message.
       
   493         // So, inform the client about the error.
       
   494         DLTRACEIN(("Complete with error message"));
       
   495         aMessage->CompleteAndRelease( trapError );
       
   496         }
       
   497     
       
   498     // Because the message should not be used after this, set it NULL.
       
   499     // So, CounterPartLost function will know that no messages are
       
   500     // waiting the response at the moment.
       
   501     iMessage = NULL;    
       
   502     }
       
   503             
       
   504                 
       
   505 
       
   506 void CNcdNodeFolder::ExternalizeL( RWriteStream& aStream )
       
   507     {
       
   508     DLTRACEIN(("this: %X, children: %d", this, iChildren.Count() ));
       
   509 
       
   510     // First use the parent to externalize the general data
       
   511     CNcdNode::ExternalizeL( aStream );
       
   512 
       
   513     ExternalizeChildArrayL( aStream );
       
   514     
       
   515     aStream.WriteInt8L( iChildrenPreviouslyLoaded );
       
   516     DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
       
   517     DLTRACE(("wrote iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
       
   518 
       
   519     DLTRACEOUT((""));
       
   520     }
       
   521     
       
   522 void CNcdNodeFolder::InternalizeL( RReadStream& aStream )
       
   523     {
       
   524     DLTRACEIN(("this: %X", this));
       
   525 
       
   526     // First use the parent to internalize the general data
       
   527     CNcdNode::InternalizeL( aStream );
       
   528     
       
   529     DLINFO(("Parent class internalized"));
       
   530     // Now internalize the data of this specific class
       
   531 
       
   532     // Insert child information to iChildren array
       
   533     // But first release previous info if it exists.
       
   534     iChildren.ResetAndDestroy();
       
   535     
       
   536     
       
   537     TInt childCount( aStream.ReadInt32L() );
       
   538     DLINFO(("Children: %d", childCount ));
       
   539     NcdNodeClassIds::TNcdNodeClassId classObjectType = 
       
   540         NcdNodeClassIds::ENcdNullObjectClassId;
       
   541     
       
   542     for ( TInt i = 0; i < childCount; ++i )
       
   543         {
       
   544         // This is safe casting because enum is same as TInt
       
   545         classObjectType = 
       
   546             static_cast<NcdNodeClassIds::TNcdNodeClassId>(aStream.ReadInt32L());
       
   547         if ( NcdNodeClassIds::ENcdChildEntityClassId == classObjectType )
       
   548             {
       
   549             CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( aStream );
       
   550             iChildren.AppendL( childEntity );
       
   551             CleanupStack::Pop( childEntity );
       
   552             }
       
   553         else
       
   554             {
       
   555             // Wrong kind of class object info
       
   556             User::Leave( KErrCorrupt );
       
   557             }
       
   558         }
       
   559     
       
   560     iChildrenPreviouslyLoaded = aStream.ReadInt8L();
       
   561     DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
       
   562     DLTRACE(("read iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
       
   563     DLTRACEOUT((""));
       
   564     }
       
   565 
       
   566 
       
   567 CNcdNodeLink* CNcdNodeFolder::CreateLinkL()
       
   568     {
       
   569     DLTRACEIN((""));
       
   570     CNcdNodeLink* link = NodeLink();
       
   571         
       
   572     if ( link != NULL )
       
   573         {
       
   574         DLTRACEOUT(("Link already exists"));
       
   575         // The link was already created
       
   576         return link;
       
   577         }
       
   578     else
       
   579         {
       
   580         DLTRACEOUT(("Creating a new link"));
       
   581         // Link was not already created.
       
   582         // So, create new.
       
   583         return CNcdNodeFolderLink::NewL( *this );        
       
   584         }
       
   585     }
       
   586 
       
   587                                     
       
   588 void CNcdNodeFolder::ExternalizeDataForRequestL( RWriteStream& aStream ) const
       
   589     {
       
   590     DLTRACEIN(("this: %X", this));
       
   591 
       
   592     CNcdNode::ExternalizeDataForRequestL( aStream );
       
   593 
       
   594     // Return also, the child information.
       
   595     // Use the virtual function here. So, different children may provide their
       
   596     // own functionality here. For example. Root folder may work differently than
       
   597     // normal folder.
       
   598     ExternalizeChildArrayForRequestL( aStream );
       
   599         
       
   600     DLTRACEOUT((""));
       
   601     }
       
   602 
       
   603 
       
   604 void CNcdNodeFolder::ExternalizeChildArrayL( RWriteStream& aStream ) const
       
   605     {
       
   606     DLTRACEIN(("this: %X, childcount: %d", this, iChildren.Count() ));
       
   607     DPROFILING_BEGIN( x );
       
   608     // Now externalize the data of this specific class
       
   609     aStream.WriteInt32L( iChildren.Count() );
       
   610     
       
   611     for( TInt i = 0; i < iChildren.Count(); ++i )
       
   612         {
       
   613         DASSERT( iChildren[i] );
       
   614         aStream.WriteInt32L( NcdNodeClassIds::ENcdChildEntityClassId );
       
   615         iChildren[ i ]->ExternalizeL( aStream );        
       
   616         /*
       
   617         DLINFO((_L("Child id: %S, array index: %d, real index: %d"),
       
   618             &iChildren[i]->Identifier().NodeId(), i, iChildren[i]->Index() ));
       
   619             */
       
   620 
       
   621         }    
       
   622     DPROFILING_END( x );
       
   623     DLTRACEOUT((""));
       
   624     }
       
   625 
       
   626 
       
   627 void CNcdNodeFolder::ExternalizeChildArrayForRequestL( RWriteStream& aStream ) const
       
   628     {
       
   629     DLTRACEIN(("this: %X", this));
       
   630 
       
   631     // No special functionality needed here.
       
   632     ExternalizeChildArrayL( aStream );
       
   633 
       
   634     DLTRACEOUT((""));
       
   635     }
       
   636     
       
   637     
       
   638 void CNcdNodeFolder::NodeSeenFolderHandleRequestL( MCatalogsBaseMessage& aMessage ) const
       
   639     {
       
   640     DLTRACEIN((("this-ptr: %x"), this));
       
   641     DASSERT( iNodeSeenFolder );
       
   642     
       
   643     // Get the session that will contain the handle of the node seen folder object
       
   644     MCatalogsSession& requestSession( aMessage.Session() );
       
   645 
       
   646     // Add the node seen folder object to the session and get the handle.
       
   647     // If the object already existed in the session we will still
       
   648     // get a new handle to the same object.
       
   649     TInt32 handle( requestSession.AddObjectL( iNodeSeenFolder ) );
       
   650 
       
   651     DLINFO(("Node seen folder handle: %d", handle ));
       
   652         
       
   653     // Send the information to the client side
       
   654     // If this leaves, ReceiveMessage will complete the message.
       
   655     aMessage.CompleteAndReleaseL( handle, KErrNone );
       
   656     }
       
   657