diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdnodefolder.cpp --- /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& 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( 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& 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& CNcdNodeFolder::PreviousChildArray() + { + DLTRACEIN(("")); + return iPreviousChildren; + } + + +void CNcdNodeFolder::ExpireAndRemoveChildrenL() + { + DLTRACEIN(("")); + TInt count = iChildren.Count(); + + CNcdNode* node = NULL; + + RPointerArray 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(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 ); + } +