ncdengine/provider/server/src/ncdnodeidentifiereditor.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdnodeidentifiereditor.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,746 @@
+/*
+* 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 NcdNodeIdentifierEditor namespace
+*
+*/
+
+
+#include "ncdnodeidentifiereditor.h"
+#include "ncdnodeidentifier.h"
+#include "ncdproviderdefines.h"
+#include "catalogsutils.h"
+//#include "catalogsdebug.h"
+
+// disable logging for this file
+#undef DLTRACEIN
+#define DLTRACEIN( x )
+
+#undef DLTRACEOUT
+#define DLTRACEOUT( x )
+
+#undef DLTRACE
+#define DLTRACE( x )
+
+#undef DLINFO
+#define DLINFO( x )
+
+#undef DLERROR
+#define DLERROR( x )
+
+#undef DASSERT
+#define DASSERT( x )
+
+// This is used to inform if the current part of the identifier is namespace instead
+// of the metadata id. This value is added after the length info before the length separator
+// text.
+const TText KNameSpaceCheck = 'N';
+
+// This character is used to separate the length information from the
+// actual descriptor text. 
+const TText KNumSeparator = '_';
+
+
+// ---------------------------------------------------------------------------
+// Functions to create correct node identifier
+// ---------------------------------------------------------------------------
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateNodeIdentifierLC( const CNcdNodeIdentifier& aParentIdentifier,
+                                                                     const CNcdNodeIdentifier& aMetaDataIdentifier )
+    {
+    DLTRACEIN(( _L("MetaId: %S, ParentId: %S"), 
+                &aMetaDataIdentifier.NodeId(),
+                &aParentIdentifier.NodeId() ));
+    
+    // The id descriptor is going to be of the following format:
+    // When the namespace of the child differs from the namespace of the parent,
+    // a new namespace will be included into the node id before the normal metadata id
+    // is inserted. This way all the node identifiers will always be unique.
+    // 1. The length of the descriptor
+    // 2. If the descriptor describes namespace, then KNameSpaceCheck.
+    // 3. KNumSeparator
+    // 4. Id descriptor
+    // 5. Loop to 1. if necessary
+
+    // Create newId with the maximum length possibility.
+    // The id may contain parent namespace and metadata namespace if
+    // root or content source is handled. Also, remember the length infos.
+    const TInt KNumOfLengthInfos( 2 );
+    const TInt KMaxLengthInfoLength( 12 );    
+    HBufC* newId =
+        HBufC::NewLC( aParentIdentifier.NodeId().Length()
+                      + aMetaDataIdentifier.NodeId().Length()
+                      + aParentIdentifier.NodeNameSpace().Length()
+                      + aMetaDataIdentifier.NodeNameSpace().Length()
+                      + KMaxLengthInfoLength * KNumOfLengthInfos );
+
+    if ( aParentIdentifier.NodeId().Length() > 0 )
+        {
+        // Insert the parent information into stream if
+        // it exists. If the current node is root, then the parent
+        // is empty and empty info should not be added in front.
+        // Notice that here we do not insert the length info in front
+        // because it has already been inserted before.
+        newId->Des().Copy( aParentIdentifier.NodeId() );
+        }
+
+    DLINFO((_L("New id after parent: %S"), newId));
+    
+    // Check if the metadata or parent describes the root node.
+    // If this is case, then the namespace has to be inserted before the
+    // actual id.
+    // Because temporary nodes do not have parent. Then, if the given parent is empty,
+    // Also, insert the namespace.
+    //
+    
+    // Always insert namespace if it differs from parent's namespace
+    if ( aParentIdentifier.NodeNameSpace() != aMetaDataIdentifier.NodeNameSpace() )
+        {
+        DLINFO(("Identifies root or temporary node or catalog"));
+        // Namespace has to be inserted also. So, the
+        // node name will be unique
+        newId->Des().AppendNum( aMetaDataIdentifier.NodeNameSpace().Length() );
+        newId->Des().Append( KNameSpaceCheck );
+        newId->Des().Append( KNumSeparator );
+        newId->Des().Append( aMetaDataIdentifier.NodeNameSpace() );        
+        }
+
+    DLINFO((_L("New id after root check: %S"), newId));
+
+    // Now that the beginning of the nodeid is of the correct form,
+    // we can insert the actual id information.
+    newId->Des().AppendNum( aMetaDataIdentifier.NodeId().Length() );
+    newId->Des().Append( KNumSeparator );
+    newId->Des().Append( aMetaDataIdentifier.NodeId() );
+
+
+#ifdef COMPONENT_CATALOGSSERVEREXE  
+    
+    // Due to reference counting, copying is way faster than creating
+    // a new identifier
+    CNcdNodeIdentifier* identifier =
+        CNcdNodeIdentifier::NewLC( aMetaDataIdentifier );
+    identifier->SetNodeIdL( *newId );    
+
+    CleanupStack::Pop( identifier );
+    
+#else
+
+    CNcdNodeIdentifier* identifier =
+        CNcdNodeIdentifier::NewL( aMetaDataIdentifier.NodeNameSpace(), 
+                                  *newId,
+                                  aMetaDataIdentifier.ServerUri(), 
+                                  aMetaDataIdentifier.ClientUid() );
+    
+#endif    
+    
+    DLINFO((_L("New id: %S"), newId ));
+    
+    // Delete unnecessary descriptor
+    CleanupStack::PopAndDestroy( newId );  
+
+    // Insert the identifier into the stack
+    CleanupStack::PushL( identifier );
+    
+    DLTRACEOUT((""));
+    
+    return identifier;
+    }
+
+void NcdNodeIdentifierEditor::MarkMetaDataPartL( TLex& aMetaId )
+    {
+    // This sets the next character (in this case the first) to be marked.
+    aMetaId.Mark();
+
+    // Find the metadata part of the identifier id
+    TInt tmpLength( 0 );
+    
+    while( !aMetaId.Eos() )
+        {            
+        if ( aMetaId.Peek() == KNumSeparator
+             || aMetaId.Peek() == KNameSpaceCheck )
+            {
+            // Now we are in the end of the number value, because
+            // next mark is some separator.
+            TLex valueLex( aMetaId.MarkedToken() );  
+            
+            User::LeaveIfError( valueLex.Val( tmpLength ) );
+
+            if ( aMetaId.Peek() == KNameSpaceCheck )
+                {
+                // This means that the namespace instead of the id value follows next.
+                aMetaId.Inc();
+                
+                // Now we are at the namespace check and the next character should be
+                // the separator.
+                }
+
+            // Increase the current place by one,
+            // so the current place is the separator.
+            aMetaId.Inc();
+
+            // Mark the beginning of the metadata identifier.
+            // This will be changed to the beginning of the next length
+            // info below if necessary.
+            aMetaId.Mark();
+                
+            // Skip to the end of the id, now that we know the length
+            // of the actual identifier. This way we will get
+            // the next length.
+            aMetaId.Inc( tmpLength );
+
+            if ( aMetaId.Eos() )
+                {
+                // We are at the end So, no need to continue.
+                // Do not mark the end, because we want the mark
+                // to be in the start of the metadata id text.
+                break;
+                }
+            else
+                {
+                // Mark the next character that is the beginning of the actual
+                // identifier.
+                aMetaId.Mark();                
+                }
+            }
+        else if ( !aMetaId.Peek().IsDigit() )
+            {
+            DLERROR(("Should be number but is not."));
+            User::Leave( KErrArgument );
+            }
+        else
+            {
+            // Find the end of the length number by peeking until separator
+            // is found
+            aMetaId.Inc();
+            }
+        }
+    }
+    
+void NcdNodeIdentifierEditor::GetParentIdAndNsL( const TDesC& aChildId,
+    TPtrC& aParentId, TPtrC& aParentNs )
+    {
+    DLTRACEIN((""));
+    TLex childIdLex( aChildId );
+    // This sets the next character (in this case the first) to be marked.
+    childIdLex.Mark();
+
+    // Find the metadata part of the identifier id
+    TInt tmpLength( 0 );    
+    
+    TInt nextIdStartPos = -1;
+    TInt latestIdStartPos = -1;
+    TInt latestNsStartPos = -1;
+    TInt latestNsLength = -1;
+    TInt previousNsStartPos = -1;
+    TInt previousNsLength = -1;
+    
+    while( !childIdLex.Eos() )
+        {
+            
+        if ( childIdLex.Peek() == KNumSeparator
+             || childIdLex.Peek() == KNameSpaceCheck )
+            {
+            // Now we are in the end of the number value, because
+            // next mark is some separator.
+            TLex valueLex( childIdLex.MarkedToken() );    
+            User::LeaveIfError( valueLex.Val( tmpLength ) );
+
+            if ( childIdLex.Peek() == KNameSpaceCheck )
+                {
+                // This means that the namespace instead of the id value follows next.
+                childIdLex.Inc();
+                
+                // Now we are at the namespace check and the next character should be
+                // the separator.
+                
+                // update ns positions
+                previousNsStartPos = latestNsStartPos;
+                previousNsLength = latestNsLength;
+                latestNsStartPos = childIdLex.Offset() + 1;
+                latestNsLength = tmpLength;
+                }
+            else
+                {
+                // update id positions
+                latestIdStartPos = nextIdStartPos;
+                nextIdStartPos = childIdLex.Offset() + 1 + tmpLength;
+                }
+
+            // Increase the current place by one,
+            // so the current place is the separator.
+            childIdLex.Inc();
+
+            // Mark the beginning of the metadata identifier.
+            // This will be changed to the beginning of the next length
+            // info below if necessary.
+            childIdLex.Mark();
+                
+            // Skip to the end of the id, now that we know the length
+            // of the actual identifier. This way we will get
+            // the next length.
+            childIdLex.Inc( tmpLength );
+
+            if ( childIdLex.Eos() )
+                {
+                // We are at the end So, no need to continue.
+                // Do not mark the end, because we want the mark
+                // to be in the start of the metadata id text.
+                break;
+                }
+            else
+                {
+                // Mark the next character that is the beginning of the actual
+                // identifier.
+                childIdLex.Mark();                
+                }
+            }
+        else if ( !childIdLex.Peek().IsDigit() )
+            {
+            DLERROR(("Should be number but is not."));
+            User::Leave( KErrArgument );
+            }
+        else
+            {
+            // Find the end of the length number by peeking until separator
+            // is found
+            childIdLex.Inc();
+            }
+        }
+    
+    if( previousNsStartPos < 0 || previousNsStartPos < 0)
+        {
+        // no parent found
+        aParentId.Set( KNullDesC );
+        aParentId.Set( KNullDesC );
+        }
+    else
+        {
+        // latest ns is part of latest id (child has own ns)
+        if( latestIdStartPos < latestNsStartPos )
+            {
+            // previous ns is parent's ns
+            // and latest ns is child's ns
+            aParentNs.Set( aChildId.Mid( previousNsStartPos, previousNsLength ) );
+            }
+        // latest ns not part of latest id (child is of same ns)
+        else
+            {
+            // latest ns is parent's ns
+            aParentNs.Set( aChildId.Mid( latestNsStartPos, latestNsLength ) );
+            }
+        aParentId.Set( aChildId.Mid( 0, latestIdStartPos ) );
+        }
+
+    DLINFO((_L("parent id:%S"),&aParentId));
+    DLINFO((_L("parent ns:%S"),&aParentNs));
+    }
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateMetaDataIdentifierL( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((""));
+    
+    CNcdNodeIdentifier* metaIdentifier( 
+        CreateMetaDataIdentifierLC( aNodeIdentifier ) );
+    
+    CleanupStack::Pop( metaIdentifier );
+    DLTRACEOUT((""));
+    return metaIdentifier;
+    }
+
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateMetaDataIdentifierLC( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    DLTRACEIN((_L("NodeIdentifier: %S"), &aNodeIdentifier.NodeId()));
+    
+    if ( aNodeIdentifier.ContainsEmptyFields() )
+        {
+        DLERROR(("Node identifier was empty"));
+        User::Leave( KErrArgument );
+        }
+        
+    TLex metaId( aNodeIdentifier.NodeId() );
+    NcdNodeIdentifierEditor::MarkMetaDataPartL( metaId );
+    
+#ifdef COMPONENT_CATALOGSSERVEREXE
+    
+    // Due to reference counting copying a nodeidentifier is a lot faster
+    // than creating a new one so we first copy and then set the new value
+    CNcdNodeIdentifier* metaIdentifier = 
+            CNcdNodeIdentifier::NewLC( aNodeIdentifier );
+    metaIdentifier->SetNodeIdL( metaId.RemainderFromMark() );
+
+#else
+
+    CNcdNodeIdentifier* metaIdentifier = 
+        CNcdNodeIdentifier::NewLC( aNodeIdentifier.NodeNameSpace(),
+                                   metaId.RemainderFromMark(),
+                                   aNodeIdentifier.ServerUri(),
+                                   aNodeIdentifier.ClientUid() );
+    
+#endif    
+    DLTRACEOUT((_L("parsed metaIdentifier: %S"), 
+                &metaIdentifier->NodeId())); 
+           
+    return metaIdentifier;
+    }
+
+TBool NcdNodeIdentifierEditor::DoesMetaDataIdentifierMatchL( const CNcdNodeIdentifier& aNodeIdentifier,
+    const TDesC& aMetaId, const TDesC& aMetaNameSpace, const TUid& aMetaUid )
+    {
+    if ( aMetaUid != aNodeIdentifier.ClientUid() ||
+         aMetaNameSpace != aNodeIdentifier.NodeNameSpace() )
+        {
+        // no need to parse id if namespace and uid don't match
+        return EFalse;
+        }
+    TLex metaId( aNodeIdentifier.NodeId() );
+    NcdNodeIdentifierEditor::MarkMetaDataPartL( metaId );
+    
+    return aMetaId == metaId.RemainderFromMark();
+    }
+
+TBool NcdNodeIdentifierEditor::DoesMetaDataIdentifierMatchL( const CNcdNodeIdentifier& aMetaDataIdentifier,
+    const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    return DoesMetaDataIdentifierMatchL( aNodeIdentifier, 
+        aMetaDataIdentifier.NodeId(),
+        aMetaDataIdentifier.NodeNameSpace(),
+        aMetaDataIdentifier.ClientUid() );
+    }
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateRootIdentifierForClientLC( const TUid& aUid )
+    {
+    DLTRACEIN((""));
+
+    // The root has an empty parent.    
+    CNcdNodeIdentifier* empty( CNcdNodeIdentifier::NewLC() );
+
+    // All the roots have the same namespace, but their ids are
+    // the client UIDs.        
+    CNcdNodeIdentifier* initRoot( 
+        CNcdNodeIdentifier::NewLC( NcdProviderDefines::KRootNodeNameSpace,
+                                   CleanUidName( aUid ),
+                                   KNullDesC,
+                                   aUid ) );
+                                   
+    // Create the actual root identifier from the initial version
+    CNcdNodeIdentifier* root( 
+        CreateNodeIdentifierLC( *empty, *initRoot ) );
+    CleanupStack::Pop( root );
+    
+    // Delete temporary identifiers
+    CleanupStack::PopAndDestroy( initRoot );
+    CleanupStack::PopAndDestroy( empty );
+    
+    // Push the root back to the stack
+    CleanupStack::PushL( root );        
+
+    DLTRACEOUT((""));
+    
+    return root;
+    }
+
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateSearchRootIdentifierForClientLC( const TUid& aUid )
+    {
+    DLTRACEIN((""));
+
+    // The root has an empty parent.    
+    CNcdNodeIdentifier* empty( CNcdNodeIdentifier::NewLC() );
+
+    // All the roots have the same namespace, but their ids are
+    // the client UIDs.        
+    CNcdNodeIdentifier* initRoot( 
+        CNcdNodeIdentifier::NewLC( NcdProviderDefines::KSearchRootNameSpace,
+                                   CleanUidName( aUid ),
+                                   KNullDesC,
+                                   aUid ) );
+                                   
+    // Create the actual root identifier from the initial version
+    CNcdNodeIdentifier* root( 
+        CreateNodeIdentifierLC( *empty, *initRoot ) );
+    CleanupStack::Pop( root );
+    
+    // Delete temporary identifiers
+    CleanupStack::PopAndDestroy( initRoot );
+    CleanupStack::PopAndDestroy( empty );
+    
+    // Push the root back to the stack
+    CleanupStack::PushL( root );        
+
+    DLTRACEOUT((""));
+    
+    return root;
+    }                                   
+
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::CreateTemporaryNodeIdentifierLC( const CNcdNodeIdentifier& aMetaDataIdentifier )
+    {
+    DLTRACEIN((""));
+
+    CNcdNodeIdentifier* identifier( NULL );
+
+    CNcdNodeIdentifier* empty =
+        CNcdNodeIdentifier::NewLC();
+    
+    // Just create the node identifier that has no parent. Notice that
+    // even the namespace will not be included into the identifier id
+    // because this is not a root identifier. So, this id differs from the
+    // meta id just by the length info in front of the id.
+    identifier = CreateNodeIdentifierLC( *empty, aMetaDataIdentifier );
+    CleanupStack::Pop( identifier );
+        
+    CleanupStack::PopAndDestroy( empty );
+    
+    CleanupStack::PushL( identifier );
+        
+    DLTRACEOUT((""));
+    
+    return identifier;
+    }
+    
+    
+
+// ---------------------------------------------------------------------------
+// Functions that can provide information that is included to the identifiers
+// ---------------------------------------------------------------------------
+
+TInt NcdNodeIdentifierEditor::NodeDepthL( const CNcdNodeIdentifier& aNodeIdentifier )
+    {
+    //DLTRACEIN((""));
+    
+    if ( aNodeIdentifier.ContainsEmptyFields() )
+        {
+        DLERROR(("Node identifier was empty"));
+        User::Leave( KErrArgument );
+        }
+
+    TInt depth( 0 );
+
+    TLex metaId( aNodeIdentifier.NodeId() );
+    // This sets the next character (in this case the first) to be marked.
+    metaId.Mark();
+
+    // Find the metadata part of the identifier id
+    TInt tmpLength( 0 );
+    
+    while( ETrue )
+        {
+        if ( metaId.Eos() )
+            {
+            // The whole thing has been checked.
+            break;
+            }
+
+        if ( metaId.Peek() == KNumSeparator
+             || metaId.Peek() == KNameSpaceCheck )
+            {
+            // Now we are in the end of the number value, because
+            // next mark is one of the separators.
+            TLex valueLex( metaId.MarkedToken() );    
+            User::LeaveIfError( valueLex.Val( tmpLength ) );
+
+            if ( metaId.Peek() == KNameSpaceCheck )
+                {
+                // Because the namespaces should be skipped when
+                // depth is calculated decrease the depth because it will
+                // be increased later.
+                --depth;
+                metaId.Inc();
+                // Now we are at the namespace separator value and the
+                // next character should be the separator.   
+                }
+
+            // Increase the current place by one,
+            // so the current place is the separator.
+            metaId.Inc();
+            
+            // Skip to the end of the id, now that we know the length
+            // of the actual identifier. This way we will get
+            // the next length.
+            metaId.Inc( tmpLength );
+
+            // Start the next phase from the beginning of the new
+            // length info.
+            metaId.Mark();
+            
+            // Also, update depth value, because we had some namespace or
+            // id descriptor here.
+            ++depth;
+            }
+        else if ( !metaId.Peek().IsDigit() )
+            {
+            DLERROR((_L("Should be number but is not. Most likely not identifier of node. Ns: %S, Id: %S"),
+                     &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId()));
+            // Most likely we have gotten an identifier that is not used for node.
+            // This may be case for example when a metadata identifier has been given here.
+            // Leave with error argument. So, user may do what ever it wants with the error.
+            User::Leave( KErrArgument );
+            }
+        else
+            {
+            // Find the end of the length number by peeking until separator
+            // is found
+            metaId.Inc();
+            }
+        }
+
+    // Notice that the depth does not contain the possible namespaces.
+    // Also, because root depth should be zero, decrease the given depth info
+    // by one.
+    --depth;
+/*            
+    DLTRACEOUT((_L("Node depth: %d, id: %S"), 
+                depth, &aNodeIdentifier.NodeId()));
+  */          
+    return depth;
+    }
+
+
+TBool NcdNodeIdentifierEditor::IdentifiesSomeRoot( const CNcdNodeIdentifier& aIdentifier )
+    {
+    const TDesC& nameSpace = aIdentifier.NodeNameSpace();
+    
+    if ( nameSpace == NcdProviderDefines::KRootNodeNameSpace
+         || nameSpace == NcdProviderDefines::KSearchRootNameSpace )
+        {
+        // Identifier identified some root.
+        return ETrue;
+        }
+    else
+        {
+        // Identifier does not identify root.
+        return EFalse;
+        }
+    }
+
+
+TBool NcdNodeIdentifierEditor::IdentifiesTemporaryNodeL( const CNcdNodeIdentifier& aIdentifier )
+    {
+    TBool isTemporary( ETrue );
+    
+    CNcdNodeIdentifier* rootIdentifier =
+        CreateRootIdentifierForClientLC( aIdentifier.ClientUid() );
+    CNcdNodeIdentifier* searchRootIdentifier =
+            CreateSearchRootIdentifierForClientLC( aIdentifier.ClientUid() );
+
+    // All the nodes that do not start with the root id are thought to be
+    // temporary nodes.
+    
+    
+    if ( aIdentifier.NodeId().Length() >= rootIdentifier->NodeId().Length() &&
+        aIdentifier.NodeId().Mid( 0, rootIdentifier->NodeId().Length() )
+            == rootIdentifier->NodeId() )
+        {
+        isTemporary = EFalse;
+        }
+    else if ( aIdentifier.NodeId().Length() >= searchRootIdentifier->NodeId().Length() &&
+        aIdentifier.NodeId().Mid( 0, searchRootIdentifier->NodeId().Length() )
+            == searchRootIdentifier->NodeId() )
+        {
+        isTemporary = EFalse;
+        }
+    
+    CleanupStack::PopAndDestroy( searchRootIdentifier );
+    CleanupStack::PopAndDestroy( rootIdentifier );
+    
+    return isTemporary;
+    }
+
+
+TBool NcdNodeIdentifierEditor::ParentOf( const CNcdNodeIdentifier& aParentNodeIdentifier,
+                                         const CNcdNodeIdentifier& aChildNodeIdentifier )
+    {
+    DLTRACEIN((""));
+    
+    // If the child identifier starts with the parent identifier id,
+    // then the child is actually a real child.
+    // Notice that the child can not be its own parent. So,
+    // id lengths are also checked.
+    if ( aParentNodeIdentifier.NodeId().Length()
+            < aChildNodeIdentifier.NodeId().Length()
+         && aChildNodeIdentifier.NodeId().Mid( 0, aParentNodeIdentifier.NodeId().Length() )
+                == aParentNodeIdentifier.NodeId()
+         && aChildNodeIdentifier.ClientUid() 
+                == aParentNodeIdentifier.ClientUid() )
+        {
+        DLTRACEOUT((_L("%S::%S was parent of %S::%S"), 
+                    &aParentNodeIdentifier.NodeNameSpace(),
+                    &aParentNodeIdentifier.NodeId(),
+                    &aChildNodeIdentifier.NodeNameSpace(),
+                    &aChildNodeIdentifier.NodeId()));
+        return ETrue;
+        }
+    else
+        {
+        DLTRACEOUT((_L("%S::%S was not parent of %S::%S"), 
+                    &aParentNodeIdentifier.NodeNameSpace(),
+                    &aParentNodeIdentifier.NodeId(),
+                    &aChildNodeIdentifier.NodeNameSpace(),
+                    &aChildNodeIdentifier.NodeId()));
+        return EFalse;
+        }
+    }
+
+
+CNcdNodeIdentifier* NcdNodeIdentifierEditor::ParentOfLC( const CNcdNodeIdentifier& aChildNodeIdentifier )
+    {
+    DLTRACEIN((_L("ChildNodeIdentifier: %S"), &aChildNodeIdentifier.NodeId()));
+    
+    if ( aChildNodeIdentifier.ContainsEmptyFields() )
+        {
+        DLERROR(("Node identifier was empty"));
+        User::Leave( KErrArgument );
+        }
+
+    TPtrC parentId;
+    TPtrC parentNs;
+    GetParentIdAndNsL( aChildNodeIdentifier.NodeId(), parentId, parentNs );
+    
+    if( parentId == KNullDesC || parentId == KNullDesC )
+        {
+        DLERROR(("Node identifier contained no parent"));
+        User::Leave( KErrArgument );
+        }
+    
+    CNcdNodeIdentifier* parentIdentifier =
+        CNcdNodeIdentifier::NewLC( parentNs,
+                                  parentId,
+                                  aChildNodeIdentifier.ServerUri(),
+                                  aChildNodeIdentifier.ClientUid() );
+                                   
+    DLTRACEOUT((_L("parsed parent Identifier: %S"), 
+                &parentIdentifier->NodeId())); 
+           
+    return parentIdentifier;
+    }
+
+TBool NcdNodeIdentifierEditor::IdentifiesSearchNodeL( const CNcdNodeIdentifier& aIdentifier )
+    {
+    TBool isSearch( EFalse );
+    
+    CNcdNodeIdentifier* searchRootIdentifier =
+            CreateSearchRootIdentifierForClientLC( aIdentifier.ClientUid() );
+
+    // All the nodes that do not start with the root id are thought to be
+    // temporary nodes.
+    if ( aIdentifier.NodeId().Mid( 0, searchRootIdentifier->NodeId().Length() )
+            == searchRootIdentifier->NodeId() )
+        {
+        isSearch = ETrue;
+        }
+    
+    CleanupStack::PopAndDestroy( searchRootIdentifier );
+    return isSearch;
+    }