ncdengine/provider/server/src/ncdnodefolder.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdnodefolder.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,657 @@
+/*
+* 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 CNcdNodeFolder class
+*
+*/
+
+
+#include "ncdnodefolder.h"
+#include "ncdnodefolderlink.h"
+#include "ncdnodefoldermetadata.h"
+#include "ncdnodemanager.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodefunctionids.h"
+#include "catalogsbasemessage.h"
+#include "catalogsutils.h"
+#include "ncdchildentity.h"
+#include "ncdnodefolderlink.h"
+#include "ncdnodeseenfolderimpl.h"
+#include "ncdexpirednode.h"
+
+#include "catalogsdebug.h"
+
+CNcdNodeFolder::CNcdNodeFolder( CNcdNodeManager& aNodeManager,
+    NcdNodeClassIds::TNcdNodeClassId aNodeClassId, 
+    NcdNodeClassIds::TNcdNodeClassId aAcceptedLinkClassId,
+    NcdNodeClassIds::TNcdNodeClassId aAcceptedMetaDataClassId )
+: CNcdNode( aNodeManager,
+            aNodeClassId,
+            aAcceptedLinkClassId,
+            aAcceptedMetaDataClassId ),
+  iPreviousChildCount( KErrNotFound )
+    {
+    }
+
+void CNcdNodeFolder::ConstructL( const CNcdNodeIdentifier& aIdentifier )
+    {
+    DLTRACEIN(("this: %X", this ));
+
+    CNcdNode::ConstructL( aIdentifier );
+    
+    iNodeSeenFolder = CNcdNodeSeenFolder::NewL( *this );
+        
+    DLTRACEOUT((""));
+    }
+
+
+CNcdNodeFolder::~CNcdNodeFolder()
+    {
+    DLTRACEIN(("this: %X", this));
+    for ( TInt i = 0; i < iChildren.Count(); ++i ) 
+        {
+        DLINFO(( _L("Child %d, ns: %S, id: %S"), i,
+                 &iChildren[i]->Identifier().NodeNameSpace(),
+                 &iChildren[i]->Identifier().NodeId() ));
+        }
+    RemoveChildren();
+    
+    if ( iNodeSeenFolder )
+        {
+        DLINFO(("Closing node seen folder"));
+        iNodeSeenFolder->Close();
+        iNodeSeenFolder = NULL;
+        }
+        
+    iPreviousChildren.ResetAndDestroy();
+
+    DLTRACEOUT((""));
+    }
+
+
+CNcdNodeFolder* CNcdNodeFolder::NewL( CNcdNodeManager& aNodeManager,
+                                      const CNcdNodeIdentifier& aIdentifier  )
+    {
+    CNcdNodeFolder* self = 
+        CNcdNodeFolder::NewLC( aNodeManager, aIdentifier );
+    CleanupStack::Pop( self );
+    return self;        
+    }
+
+CNcdNodeFolder* CNcdNodeFolder::NewLC( CNcdNodeManager& aNodeManager,
+                                       const CNcdNodeIdentifier& aIdentifier )
+    {
+    CNcdNodeFolder* self = 
+        new( ELeave ) CNcdNodeFolder( aNodeManager );
+    CleanupClosePushL( *self );
+    self->ConstructL( aIdentifier );
+    return self;        
+    }
+                                  
+
+TInt CNcdNodeFolder::ChildCount() const
+    {
+    DLTRACEIN(( "this: %X, ChildCount: %d", this, iChildren.Count() ));
+    return iChildren.Count();
+    }
+
+
+const CNcdNodeIdentifier& CNcdNodeFolder::ChildL( TInt aIndex ) const
+    {
+    DLTRACEIN(( "" ));
+    if( aIndex < 0 || aIndex > iChildren.Count() )
+        {
+        User::Leave( KErrArgument );
+        }
+    return iChildren[aIndex]->Identifier();
+    }
+    
+TInt CNcdNodeFolder::ServerChildCountL() const
+    {
+    DLTRACEIN((""));
+    TInt serverChildCount = FolderLinkL().ExpectedChildrenCount();
+    DLTRACEOUT(("this: %X, ServerChildCount: %d", this, serverChildCount ));
+    return serverChildCount;
+    }
+
+const CNcdNodeIdentifier& CNcdNodeFolder::ChildByServerIndexL( TInt aIndex ) const
+    {
+    DLTRACEIN((""));
+    return ChildEntityByServerIndexL( aIndex ).Identifier();
+    }
+
+const CNcdChildEntity& CNcdNodeFolder::ChildEntityByServerIndexL( TInt aIndex ) const
+    {
+    DLTRACEIN(( "aIndex: %d", aIndex )); 
+           
+    // search for a child with given index
+    const CNcdChildEntity* child = NULL;
+    for( TInt i = 0 ; i < iChildren.Count() ; i++ )
+        {
+        if ( iChildren[i]->Index() == aIndex )
+            {
+            child = iChildren[i];
+            break;
+            }
+        else if ( iChildren[i]->Index() > aIndex )
+            {
+            // no sense in searching further
+            break;
+            }
+        }
+       
+    if ( child == NULL )
+        {
+        // Leave because the child is set NULL.
+        // NULL can not be returned as a reference value.
+        DLINFO(("Child node identifier was NULL. So, leave with KErrNotFound"))
+        User::Leave( KErrNotFound );
+        }
+    
+    DLTRACEOUT((""));
+
+    return *child;
+    }
+
+const RPointerArray<CNcdChildEntity>& CNcdNodeFolder::ChildArray() const
+    {
+    return iChildren;
+    }
+
+
+TBool CNcdNodeFolder::ReplaceChildL( 
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    TInt aIndex,
+    TBool aTransparent,
+    CNcdNodeFactory::TNcdNodeType aNodeType )
+    {
+    DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S, Child ns, id: %S, %S, aIndex: %d childCount: %d"),
+        this, &Identifier().NodeNameSpace(), &Identifier().NodeId(),
+        &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId(),
+        aIndex, iChildren.Count() ));
+
+    TInt expectedChildCount = FolderLinkL().ExpectedChildrenCount();
+    if ( aIndex < 0 /*|| aIndex >= expectedChildCount*/ )
+        {
+        // For debugging purposes
+        DLERROR(("Wrong child index"));
+        DASSERT( EFalse );
+        
+        User::Leave( KErrArgument );   
+        }
+        
+    
+    TBool childFound = EFalse;
+    TInt i = 0;
+    for ( ; i < iChildren.Count() ; i++ )
+        {
+        if( iChildren[i]->Index() == aIndex )
+            {
+            DLTRACE(("Child with the same index found."));
+            if( ! (iChildren[i]->Identifier().Equals( aNodeIdentifier  ) ) )
+                {
+                DLTRACE(("Not the same child, replace."));
+                iChildren[i]->SetIdentifierL( aNodeIdentifier );
+                iChildren[i]->SetTransparent( aTransparent );
+                iChildren[i]->SetNodeType( aNodeType );
+                // Should the old child be expired via nodemgr?
+                }
+            else
+                {
+                iChildren[i]->SetTransparent( aTransparent );
+                iChildren[i]->SetNodeType( aNodeType );
+                // exactly the same child, do nothing
+                }
+            childFound = ETrue;
+            break;
+            }
+        else if ( iChildren[i]->Index() > aIndex )
+            {
+            // no sense in searching further
+            break;
+            }
+        }
+        
+    if ( !childFound )
+        {
+        DLTRACE(("Child not found, create new"))
+        CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( 
+            aIndex,
+            aNodeIdentifier,
+            aTransparent,
+            aNodeType );
+            
+        if ( i == iChildren.Count() )
+            {
+            // last child, append
+            DLTRACE(("Appending"));
+            iChildren.AppendL( childEntity );
+            }
+        else
+            {
+            DLTRACE(("Inserting"));
+            iChildren.InsertL( childEntity, i );
+            }
+        CleanupStack::Pop( childEntity );
+        }
+        
+    #ifdef CATALOGS_BUILD_CONFIG_DEBUG
+    for( TInt j = 0 ; j < iChildren.Count() ; j++ )
+        {
+        CNcdChildEntity* child = iChildren[j];
+        DLINFO((_L("Child id: %S, array index: %d, real index: %d"),
+            &child->Identifier().NodeId(), j, child->Index() ));
+        }
+    #endif
+    
+    return !childFound;
+    }
+        
+        
+TBool CNcdNodeFolder::InsertChildL( 
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    TInt aIndex,
+    TBool aTransparent,
+    CNcdNodeFactory::TNcdNodeType aNodeType )
+    {
+    DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S, Child ns, id: %S, %S, aIndex: %d, childCount: %d"),
+        this, &Identifier().NodeNameSpace(), &Identifier().NodeId(),
+        &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId(),
+        aIndex, iChildren.Count() ));
+               
+    DPROFILING_BEGIN( x );
+    if ( aIndex < 0 || aIndex > iChildren.Count() )
+        {
+        // For debugging purposes
+        DLERROR(("Wrong child index"));
+        DASSERT( EFalse );
+        
+        User::Leave( KErrArgument );
+        }
+    
+    CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( 
+        aIndex,
+        aNodeIdentifier,
+        aTransparent,
+        aNodeType );
+    if( aIndex == iChildren.Count() )
+        {
+        // last index, append
+        DLTRACE(("Appending"));
+        iChildren.AppendL( childEntity );
+        }
+    else
+        {
+        DLTRACE(("Inserting"));
+        iChildren.InsertL( childEntity, aIndex );
+        }    
+    CleanupStack::Pop( childEntity );    
+
+    #ifdef CATALOGS_BUILD_CONFIG_DEBUG
+    for( TInt i = 0 ; i < iChildren.Count() ; i++ )
+        {
+        DLINFO(( _L("Child: index: %d, real index: %d, id: %S, ns: %S "),
+            i, iChildren[i]->Index(), &iChildren[i]->Identifier().NodeId(),
+            &iChildren[i]->Identifier().NodeNameSpace() ));
+        }
+    #endif
+
+    DPROFILING_END( x );
+    return ETrue;
+    }
+    
+    
+TBool CNcdNodeFolder::AppendChildL( 
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    TBool aTransparent,
+    CNcdNodeFactory::TNcdNodeType aNodeType ) 
+    {
+    DLTRACEIN((""));
+    return InsertChildL( aNodeIdentifier, iChildren.Count(), aTransparent,
+        aNodeType );
+    }
+    
+CNcdNodeFolderLink& CNcdNodeFolder::FolderLinkL() const
+    {
+    // safe to cast because folders always have folder links
+    return static_cast<CNcdNodeFolderLink&>( NodeLinkL() );
+    }
+    
+
+CNcdNodeSeenFolder& CNcdNodeFolder::NodeSeenFolder() const 
+    {
+    return *iNodeSeenFolder;
+    }                  
+    
+    
+void CNcdNodeFolder::RemoveChild( const CNcdNodeIdentifier& aNodeIdentifier ) 
+    {
+    DLTRACEIN(( _L("this: %X, Parent ns, id: %S, %S"), this,
+                &Identifier().NodeNameSpace(), &Identifier().NodeId() ));
+    DLINFO(( _L("child to remove ns, id: %S, %S"),
+             &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId() ));
+    DPROFILING_BEGIN( x );
+    for ( TInt i = 0 ; i < iChildren.Count() ; i++ )
+        {
+        if( iChildren[i]->Identifier().Equals( aNodeIdentifier ) )
+            {
+            DeleteFromArray( iChildren, i );
+            DPROFILING_END( x );
+            return;
+            }
+        }
+    
+    DPROFILING_END( x );
+    DLWARNING(("Unable to remove nonexisting child"));
+    }
+    
+
+void CNcdNodeFolder::RemoveChildrenL()
+    {
+    DLTRACEIN((""));
+    DPROFILING_BEGIN( x );
+    NodeManager().RemoveChildrenL( *this );
+    DPROFILING_END( x );
+    }
+    
+
+void CNcdNodeFolder::RemoveChildren()
+    {
+    DLTRACEIN((""));
+    iChildren.ResetAndDestroy();
+    // Also set children previously loaded flag to false,
+    // because child list is no longer valid
+    iChildrenPreviouslyLoaded = EFalse;
+    DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
+    DLTRACE(("iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
+    }
+    
+void CNcdNodeFolder::StoreChildrenToPreviousListL()
+    {
+    DLTRACEIN((""));
+    StoreChildrenToPreviousListL( iChildren,
+        FolderLinkL().ExpectedChildrenCount() );
+    }
+
+void CNcdNodeFolder::StoreChildrenToPreviousListL(
+    const RPointerArray<CNcdChildEntity>& aPreviousChildren,
+    TInt aPreviousChildCount )
+    {
+    DLTRACEIN((""));
+    // First clear previous list.
+    iPreviousChildren.ResetAndDestroy();
+    for( TInt i = 0 ; i < aPreviousChildren.Count() ; i++ )
+        {
+        CNcdChildEntity* childEntity = CNcdChildEntity::NewLC(
+            *aPreviousChildren[i] );
+        DLTRACE((_L("Adding child entity, identifier: %S, index: %d"),
+             &childEntity->Identifier().NodeId(), childEntity->Index() ));
+        iPreviousChildren.AppendL( childEntity );
+        CleanupStack::Pop( childEntity );
+        }
+    DLTRACE(("Setting previous child count: %d", aPreviousChildCount ));
+    iPreviousChildCount = aPreviousChildCount;
+    }
+
+TBool CNcdNodeFolder::ChildrenPreviouslyLoaded()
+    {
+    DLTRACEIN((""));
+    DLINFO(("ret: %d",iChildrenPreviouslyLoaded));
+    return iChildrenPreviouslyLoaded;
+    }
+
+void CNcdNodeFolder::SetChildrenPreviouslyLoaded( TBool aChildrenPreviouslyLoaded )
+    {
+    DLTRACEIN((""));
+    iChildrenPreviouslyLoaded = aChildrenPreviouslyLoaded;
+    }
+
+TInt CNcdNodeFolder::PreviousChildCount()
+    {
+    DLTRACEIN((""));
+    return iPreviousChildCount;
+    }
+
+const RPointerArray<CNcdChildEntity>& CNcdNodeFolder::PreviousChildArray()
+    {
+    DLTRACEIN((""));
+    return iPreviousChildren;
+    }
+    
+    
+void CNcdNodeFolder::ExpireAndRemoveChildrenL()
+    {
+    DLTRACEIN((""));
+    TInt count = iChildren.Count();
+    
+    CNcdNode* node = NULL;
+    
+    RPointerArray<CNcdExpiredNode> expiredNodes;
+    CleanupResetAndDestroyPushL( expiredNodes );
+    expiredNodes.ReserveL( count );
+    
+    while( count-- ) 
+        {        
+        node = NodeManager().NodePtrL( iChildren[ count ]->Identifier() );
+        if ( node )
+            {
+            NodeManager().SetNodeExpiredL( *node, EFalse, EFalse, expiredNodes );
+             
+            }
+        }
+    CleanupStack::PopAndDestroy( &expiredNodes );
+    // Delete child metadatas from disk cache
+    NodeManager().RemoveChildrenMetadataL( *this );
+    
+    // Empty children lists
+    RemoveChildren();    
+    }
+    
+    
+void CNcdNodeFolder::ReceiveMessage(
+    MCatalogsBaseMessage* aMessage,
+    TInt aFunctionNumber )
+    {
+    DLTRACEIN(("this-ptr: %x", this));
+    
+    DASSERT( aMessage );
+    
+    // Now, we can be sure that rest of the time iMessage exists.
+    // This member variable is set for the CounterPartLost function.
+    iMessage = aMessage;
+        
+    TInt trapError( KErrNone );
+    
+    switch( aFunctionNumber )
+        {
+        case NcdNodeFunctionIds::ENcdNodeSeenFolderHandle:
+            TRAP( trapError, NodeSeenFolderHandleRequestL( *aMessage ) );            
+            break;
+            
+        default:
+            // Let base class handle this
+            iMessage = NULL;
+            CNcdNode::ReceiveMessage( aMessage, aFunctionNumber );
+            return;
+        }
+        
+   if ( trapError != KErrNone )
+        {
+        // Because something went wrong the complete has not been
+        // yet called for the message.
+        // So, inform the client about the error.
+        DLTRACEIN(("Complete with error message"));
+        aMessage->CompleteAndRelease( trapError );
+        }
+    
+    // Because the message should not be used after this, set it NULL.
+    // So, CounterPartLost function will know that no messages are
+    // waiting the response at the moment.
+    iMessage = NULL;    
+    }
+            
+                
+
+void CNcdNodeFolder::ExternalizeL( RWriteStream& aStream )
+    {
+    DLTRACEIN(("this: %X, children: %d", this, iChildren.Count() ));
+
+    // First use the parent to externalize the general data
+    CNcdNode::ExternalizeL( aStream );
+
+    ExternalizeChildArrayL( aStream );
+    
+    aStream.WriteInt8L( iChildrenPreviouslyLoaded );
+    DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
+    DLTRACE(("wrote iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
+
+    DLTRACEOUT((""));
+    }
+    
+void CNcdNodeFolder::InternalizeL( RReadStream& aStream )
+    {
+    DLTRACEIN(("this: %X", this));
+
+    // First use the parent to internalize the general data
+    CNcdNode::InternalizeL( aStream );
+    
+    DLINFO(("Parent class internalized"));
+    // Now internalize the data of this specific class
+
+    // Insert child information to iChildren array
+    // But first release previous info if it exists.
+    iChildren.ResetAndDestroy();
+    
+    
+    TInt childCount( aStream.ReadInt32L() );
+    DLINFO(("Children: %d", childCount ));
+    NcdNodeClassIds::TNcdNodeClassId classObjectType = 
+        NcdNodeClassIds::ENcdNullObjectClassId;
+    
+    for ( TInt i = 0; i < childCount; ++i )
+        {
+        // This is safe casting because enum is same as TInt
+        classObjectType = 
+            static_cast<NcdNodeClassIds::TNcdNodeClassId>(aStream.ReadInt32L());
+        if ( NcdNodeClassIds::ENcdChildEntityClassId == classObjectType )
+            {
+            CNcdChildEntity* childEntity = CNcdChildEntity::NewLC( aStream );
+            iChildren.AppendL( childEntity );
+            CleanupStack::Pop( childEntity );
+            }
+        else
+            {
+            // Wrong kind of class object info
+            User::Leave( KErrCorrupt );
+            }
+        }
+    
+    iChildrenPreviouslyLoaded = aStream.ReadInt8L();
+    DLTRACE((_L("node id: %S"), &Identifier().NodeId() ));
+    DLTRACE(("read iChildrenPreviouslyLoaded: %d",iChildrenPreviouslyLoaded ));
+    DLTRACEOUT((""));
+    }
+
+
+CNcdNodeLink* CNcdNodeFolder::CreateLinkL()
+    {
+    DLTRACEIN((""));
+    CNcdNodeLink* link = NodeLink();
+        
+    if ( link != NULL )
+        {
+        DLTRACEOUT(("Link already exists"));
+        // The link was already created
+        return link;
+        }
+    else
+        {
+        DLTRACEOUT(("Creating a new link"));
+        // Link was not already created.
+        // So, create new.
+        return CNcdNodeFolderLink::NewL( *this );        
+        }
+    }
+
+                                    
+void CNcdNodeFolder::ExternalizeDataForRequestL( RWriteStream& aStream ) const
+    {
+    DLTRACEIN(("this: %X", this));
+
+    CNcdNode::ExternalizeDataForRequestL( aStream );
+
+    // Return also, the child information.
+    // Use the virtual function here. So, different children may provide their
+    // own functionality here. For example. Root folder may work differently than
+    // normal folder.
+    ExternalizeChildArrayForRequestL( aStream );
+        
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNodeFolder::ExternalizeChildArrayL( RWriteStream& aStream ) const
+    {
+    DLTRACEIN(("this: %X, childcount: %d", this, iChildren.Count() ));
+    DPROFILING_BEGIN( x );
+    // Now externalize the data of this specific class
+    aStream.WriteInt32L( iChildren.Count() );
+    
+    for( TInt i = 0; i < iChildren.Count(); ++i )
+        {
+        DASSERT( iChildren[i] );
+        aStream.WriteInt32L( NcdNodeClassIds::ENcdChildEntityClassId );
+        iChildren[ i ]->ExternalizeL( aStream );        
+        /*
+        DLINFO((_L("Child id: %S, array index: %d, real index: %d"),
+            &iChildren[i]->Identifier().NodeId(), i, iChildren[i]->Index() ));
+            */
+
+        }    
+    DPROFILING_END( x );
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNodeFolder::ExternalizeChildArrayForRequestL( RWriteStream& aStream ) const
+    {
+    DLTRACEIN(("this: %X", this));
+
+    // No special functionality needed here.
+    ExternalizeChildArrayL( aStream );
+
+    DLTRACEOUT((""));
+    }
+    
+    
+void CNcdNodeFolder::NodeSeenFolderHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((("this-ptr: %x"), this));
+    DASSERT( iNodeSeenFolder );
+    
+    // Get the session that will contain the handle of the node seen folder object
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Add the node seen folder object to the session and get the handle.
+    // If the object already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 handle( requestSession.AddObjectL( iNodeSeenFolder ) );
+
+    DLINFO(("Node seen folder handle: %d", handle ));
+        
+    // Send the information to the client side
+    // If this leaves, ReceiveMessage will complete the message.
+    aMessage.CompleteAndReleaseL( handle, KErrNone );
+    }
+