ncdengine/provider/server/src/ncdnodeimpl.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdnodeimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,640 @@
+/*
+* Copyright (c) 2006-2008 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 CNcdNode class
+*
+*/
+
+
+#include <e32err.h>
+#include <e32base.h>
+
+#include "ncdnodeimpl.h"
+#include "ncdnodemanager.h"
+#include "ncdnodelink.h"
+#include "ncdnodeitemlink.h"
+#include "ncdnodefolderlink.h"
+#include "ncdnodemetadataimpl.h"
+#include "catalogssession.h"
+#include "catalogsbasemessage.h"
+#include "ncdnodefunctionids.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncdnodeuserdataimpl.h"
+#include "ncdutils.h"
+#include "catalogsconstants.h"
+#include "catalogsdebug.h"
+#include "catalogsutils.h"
+#include "ncdnodeseenimpl.h"
+
+
+CNcdNode::CNcdNode(
+    CNcdNodeManager& aNodeManager,
+    NcdNodeClassIds::TNcdNodeClassId aNodeClassId, 
+    NcdNodeClassIds::TNcdNodeClassId aAcceptedLinkClassId,
+    NcdNodeClassIds::TNcdNodeClassId aAcceptedMetaDataClassId )
+: CCatalogsCommunicable(), 
+  iNodeManager( aNodeManager ),
+  iNodeClassId( aNodeClassId ),
+  iAcceptedLinkClassId( aAcceptedLinkClassId ),
+  iAcceptedMetaDataClassId( aAcceptedMetaDataClassId )
+    {
+    }
+
+
+void CNcdNode::ConstructL( const CNcdNodeIdentifier& aIdentifier )
+    {
+    DLTRACEIN((_L("ns: %S, id: %S"), &aIdentifier.NodeNameSpace(), &aIdentifier.NodeId()));
+    // Set the identifier for this node.
+    iNodeIdentifier =
+        CNcdNodeIdentifier::NewL( aIdentifier );
+    iNodeSeen = CNcdNodeSeen::NewL( iNodeManager.SeenInfo(), *this );
+    }
+
+
+CNcdNode::~CNcdNode()
+    {
+    DLTRACEIN((""));
+    delete iNodeIdentifier;
+    
+    // Notice that CCatalogsCommunicable object should not be deleted but
+    // only closed.
+    
+    if ( iNodeLink ) 
+        {
+        DLINFO(("Closing node link"));
+        iNodeLink->Close();
+        }
+        
+    if ( iNodeSeen )
+        {
+        DLINFO(("Closing node seen"));
+        iNodeSeen->Close();
+        }
+    
+    // Do not delete iNodeMetaData here.
+    // It is managers responsibility
+    // Also, do not delete the manager because it is providers job.
+
+    DLTRACEOUT((""));
+    }
+
+
+const CNcdNodeIdentifier& CNcdNode::Identifier() const
+    {
+    DASSERT( iNodeIdentifier );
+    return *iNodeIdentifier;
+    }
+
+
+NcdNodeClassIds::TNcdNodeClassId CNcdNode::ClassId() const
+    {
+    return iNodeClassId;
+    }
+
+
+CNcdNodeManager& CNcdNode::NodeManager() const
+    {
+    return iNodeManager;
+    }
+
+
+CNcdNodeLink& CNcdNode::CreateAndSetLinkL()
+    {
+    iNodeLink = CreateLinkL();
+    if ( iNodeMetaData ) 
+        {
+        // Ensure that link has the correct metadata timestamp
+        iNodeLink->SetMetadataTimeStampL( iNodeMetaData->TimeStamp() );
+        }
+    return *iNodeLink;
+    }
+
+
+CNcdNodeLink& CNcdNode::NodeLinkL() const
+    {
+    if( iNodeLink == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }         
+       
+    return *iNodeLink;
+    }
+
+
+CNcdNodeLink* CNcdNode::NodeLink() const
+    {       
+    return iNodeLink;
+    }
+    
+
+CNcdNodeSeen& CNcdNode::NodeSeen() const
+    {
+    DASSERT( iNodeSeen );
+    return *iNodeSeen;
+    }
+
+
+void CNcdNode::InternalizeLinkL( const MNcdPreminetProtocolEntityRef& aData,
+                                 const CNcdNodeIdentifier& aParentIdentifier,
+                                 const CNcdNodeIdentifier& aRequestParentIdentifier,
+                                 const TUid& aClientUid )
+    {
+    DLTRACEIN((""));
+    
+    TBool linkCreated( EFalse );
+    
+    if ( iNodeLink == NULL )
+        {
+        DLINFO(("Create link"));
+        
+        // Because the node link did not exist create it.
+        // Create link should be implemented in child classes. So the right
+        // kind of link is set here.
+        iNodeLink = CreateLinkL();
+        linkCreated = ETrue;
+        }
+        
+    DLINFO(("Internalize link"));
+
+    TRAPD( err, iNodeLink->InternalizeL( 
+        aData, aParentIdentifier, aRequestParentIdentifier, aClientUid ) );
+    
+    if( err != KErrNone )
+        {
+        DLINFO(("Internalize link error: %d", err));
+
+        if( linkCreated )
+            {
+            // Because the link was created but the internalization went wrong,
+            // delete the link because it does not contain correct data.
+            iNodeLink->Close();
+            iNodeLink = NULL;
+            }
+        User::Leave( err );
+        }
+
+    DLTRACEOUT(( _L("Link internalized for node: %S, %S"), 
+                   &iNodeIdentifier->NodeNameSpace(),
+                   &iNodeIdentifier->NodeId()));
+    }
+
+
+CNcdNodeMetaData& CNcdNode::NodeMetaDataL() const
+    {
+    if( iNodeMetaData == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }        
+    
+    return *iNodeMetaData;
+    }
+  
+    
+CNcdNodeMetaData* CNcdNode::NodeMetaData() const
+    {    
+    return iNodeMetaData;
+    }
+
+
+void CNcdNode::SetNodeMetaDataL( CNcdNodeMetaData& aMetaData )
+    {
+    DLTRACEIN((("this-ptr: %x"), this));
+
+    if( iAcceptedMetaDataClassId == aMetaData.ClassId() )
+        {
+        // The metadata is of the right type, so it is safe to 
+        // insert as member variable.
+        // Do not delete metadata because manager owns it.
+        iNodeMetaData = &aMetaData;
+        
+        // Temp nodes don't necessarily have a link set at this point   
+        if ( iNodeLink ) 
+            {            
+            iNodeLink->SetMetadataTimeStampL( iNodeMetaData->TimeStamp() );
+            }
+        DLINFO(("Metadata inserted"));
+        }
+    else
+        {
+        DLINFO(( "Metadata was of the wrong type: %d, %d", 
+                 iAcceptedMetaDataClassId, aMetaData.ClassId() ));
+        DASSERT( EFalse );
+        // Because the metadata was of the wrong type we do not set
+        // metadata for this object
+        User::Leave( KErrArgument );
+        }
+        
+    DLTRACEOUT(( _L("MetaData set for: %S, %S"), 
+                    &iNodeIdentifier->NodeNameSpace(),
+                    &iNodeIdentifier->NodeId() ));
+    }
+    
+
+MNcdNode::TState CNcdNode::State() const
+    {
+    DLTRACEIN((""));
+    
+    CNcdNodeLink* link = NodeLink();    
+    if ( link == NULL )
+        {
+        DLTRACEOUT(("Link NULL"));
+        
+        // Because link did not exist. The node is not initialized
+        return MNcdNode::EStateNotInitialized;
+        }
+
+    CNcdNodeMetaData* meta = NodeMetaData();    
+    if ( meta == NULL )
+        {
+        DLTRACEOUT(("Meta NULL"));
+
+        // Because metadata did not exist. 
+        // Then the state can not be initialized.
+        return MNcdNode::EStateNotInitialized;
+        }
+
+    // Because link and meta both existed the node has required data
+    // but check if the node is expired.
+    if ( link->IsExpired() )
+        {
+        DLTRACEOUT(("Link was expired"));
+        
+        return MNcdNode::EStateExpired;
+        }
+    
+    DLTRACEOUT(("State was initalized"));
+    
+    // Everything was set. So, the node state is initialized
+    return MNcdNode::EStateInitialized;
+    }
+
+
+void CNcdNode::ReceiveMessage( MCatalogsBaseMessage* aMessage,
+                               TInt aFunctionNumber )
+    {
+    DLTRACEIN(("handle: %d, function: %d", aMessage->Handle(), 
+        aFunctionNumber));
+
+    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;
+                
+    TRAPD( trapError, DoReceiveMessageL( *aMessage, aFunctionNumber ) );
+    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;
+
+    if ( aFunctionNumber == NcdNodeFunctionIds::ENcdRelease )
+        {
+        // Because release was called for this object it may be time to
+        // delete this object. Inform manager about the release so it may
+        // close this object and clear the cache if needed.
+        // Notice that if the manager closes this object then this object will
+        // be deleted. It is safe to do here because no memeber variables are
+        // needed here after the call.
+        NodeManager().NodeReleased( *this );       
+        }
+            
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::DoReceiveMessageL( 
+    MCatalogsBaseMessage& aMessage,
+    TInt aFunctionNumber )
+    {
+    switch( aFunctionNumber )
+        {
+        case NcdNodeFunctionIds::ENcdInternalize:
+            InternalizeRequestL( aMessage );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdLinkHandle:
+            LinkHandleRequestL( aMessage );
+            break;
+
+        case NcdNodeFunctionIds::ENcdMetadataHandle:
+            MetadataHandleRequestL( aMessage );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdNodeSeenHandle:
+            NodeSeenHandleRequestL( aMessage );
+            break;
+
+        case NcdNodeFunctionIds::ENcdClassId:
+            ClassIdRequestL( aMessage );
+            break;
+
+        case NcdNodeFunctionIds::ENcdRelease:
+            ReleaseRequest( aMessage );
+            break;
+
+        default:
+            DLERROR(("Unidentified function request"));
+            User::Leave( KErrNotSupported );
+            break;
+        }    
+    }
+
+
+
+void CNcdNode::CounterPartLost( const MCatalogsSession& aSession )
+    {
+    // This function may be called whenever -- when the message is waiting
+    // response or when the message does not exist.
+    // iMessage may be NULL here, because in the end of the
+    // ReceiveMessage it is set to NULL. The life time of the message
+    // ends shortly after CompleteAndRelease is called.
+    if ( iMessage != NULL )
+        {
+        iMessage->CounterPartLost( aSession );
+        }    
+    }
+
+
+
+void CNcdNode::ExternalizeL( RWriteStream& aStream )
+    {
+    DLTRACEIN((""));
+
+    // Set all the membervariable values to the stream. So,
+    // that the stream may be used later to create a new
+    // object.
+
+    // First insert data that node manager will use to
+    // create this class object
+    aStream.WriteInt32L( iNodeClassId );
+
+    // This object acts as a wrapper. So, externalize all the objects that
+    // it owns. Note, that metadata is not owned by the node. So, it is not
+    // handled here. Metadata is managers responsibility because same metadata
+    // may be used by multiple nodes.
+    
+    // Node Link
+    ExternalizeLinkL( aStream );
+        
+    DLTRACEOUT((""));
+    }
+    
+    
+void CNcdNode::InternalizeL( RReadStream& aStream )
+    {
+    DLTRACEIN((""));
+
+    // NOTICE that this internalize function supposes that
+    // classid and identifier info that are
+    // inserted during externalization, are already read from
+    // the stream before calling this function.
+    
+
+    // No need to read additional membervariable values from the stream 
+    // because all the necessary info has been set during the creation of this
+    // object. All other information belongs to the objects that this node
+    // wraps.
+
+    InternalizeLinkL( aStream );
+    
+    // Check: if additional objects will be added for this node. Then their internalization
+    // should be called here. 
+    
+        
+    DLTRACEOUT((""));
+    }
+
+ 
+
+void CNcdNode::InternalizeRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));
+    
+    CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+    CleanupStack::PushL( buf );
+    
+    RBufWriteStream stream( *buf );
+    CleanupClosePushL( stream );
+
+
+    // Include all the necessary node data to the stream
+    ExternalizeDataForRequestL( stream );     
+    
+    
+    // Commits data to the stream when closing.
+    CleanupStack::PopAndDestroy( &stream );
+
+    if ( buf->Size() > 0 ) 
+        {
+        DLINFO(( "Completing the message, buf len: %d", buf->Ptr(0).Length() ));
+        }
+        
+    // If this leaves ReceiveMessage function will complete the message.
+    aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+        
+    
+    DLINFO(("Deleting the buf"));
+    CleanupStack::PopAndDestroy( buf );
+        
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::ExternalizeDataForRequestL( RWriteStream& aStream ) const
+    {
+    DLTRACEIN((""));
+
+    // Insert node class id just in case somebody wants to check that the data
+    // is of the right type
+    aStream.WriteInt32L( iNodeClassId );
+
+    Identifier().ExternalizeL( aStream );
+        
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::LinkHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));    
+    
+    if( iNodeLink == NULL )
+        {
+        DLINFO(("Node link NULL"));
+        User::Leave( KErrNotFound );
+        }
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Add the link to the session and get the handle.
+    // If the node already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 handle( requestSession.AddObjectL( iNodeLink ) );
+
+    DLINFO(("Link handle: %d", handle ));
+        
+    // Send the information to the client side
+    // If this leaves ReceiveMessage will complete the message.
+    aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+    DLTRACEOUT((""));    
+    }
+  
+    
+void CNcdNode::MetadataHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((("this-ptr: %x"), this));    
+    
+    if( iNodeMetaData == NULL )
+        {
+        DLINFO(("Node metadata NULL"));
+        User::Leave( KErrNotFound );
+        }
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Add the metadata to the session and get the handle.
+    // If the node already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 handle( requestSession.AddObjectL( iNodeMetaData ) );
+
+    DLINFO(("Metadata handle: %d", handle ));
+        
+    // Send the information to the client side
+    // If this leaves, ReceiveMessage will complete the message.
+    aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+    DLTRACEOUT((""));            
+    }
+    
+
+void CNcdNode::NodeSeenHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((("this-ptr: %x"), this));
+    DASSERT( iNodeSeen );
+    
+    // Get the session that will contain the handle of the node seen object
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Add the node seen 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( iNodeSeen ) );
+
+    DLINFO(("Node seen handle: %d", handle ));
+        
+    // Send the information to the client side
+    // If this leaves, ReceiveMessage will complete the message.
+    aMessage.CompleteAndReleaseL( handle, KErrNone );
+    }
+
+
+void CNcdNode::ClassIdRequestL( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));
+
+    // If this leaves, ReceiveMessage will complete the message.
+    aMessage.CompleteAndReleaseL( ClassId(), KErrNone );
+        
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::ReleaseRequest( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));
+
+    // Decrease the reference count for this object.
+    // When the reference count reaches zero, this object will be destroyed
+    // and removed from the session.
+    MCatalogsSession& requestSession( aMessage.Session() );
+    TInt handle( aMessage.Handle() );
+    aMessage.CompleteAndRelease( KErrNone );
+    requestSession.RemoveObject( handle );
+
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::ExternalizeLinkL( RWriteStream& aStream )
+    {
+    DLTRACEIN((""));
+
+    if ( iNodeLink != NULL )
+        {
+        iNodeLink->ExternalizeL( aStream );
+        }
+    else 
+        {
+        DLINFO(("No link"));
+        aStream.WriteInt32L( NcdNodeClassIds::ENcdNullObjectClassId );
+        } 
+    
+    // Should handle other objects like nodelink above when they are created
+        
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNode::InternalizeLinkL( RReadStream& aStream )
+    {
+    DLTRACEIN((""));
+
+    TInt classId( aStream.ReadInt32L() );
+    
+    if ( classId == NcdNodeClassIds::ENcdNullObjectClassId )
+        {
+        // The link was NULL when the data was externalized. So, do not do anything.
+        DLTRACEIN(("Link object was null. No need to internalize it")); 
+        return;           
+        }
+
+    TBool linkCreated( EFalse );
+    
+    if ( iNodeLink == NULL )
+        {
+        // Because the node link did not exist create it.
+        // Create link should be implemented in child classes. So the right
+        // kind of link is set here.
+        iNodeLink = CreateLinkL();
+        linkCreated = ETrue;
+        }
+        
+    TRAPD( err, iNodeLink->InternalizeL( aStream ) );
+    
+    if( err != KErrNone )
+        {
+        if( linkCreated )
+            {
+            // Because the link was created but the internalization went wrong,
+            // delete the link because it does not contain correct data.            
+            iNodeLink->Close();
+            iNodeLink = NULL;
+            }
+        User::Leave( err );
+        }
+        
+    DLTRACEOUT((""));
+    }