ncdengine/provider/server/src/ncdnodeimpl.cpp
changeset 0 ba25891c3a9e
equal deleted inserted replaced
-1:000000000000 0:ba25891c3a9e
       
     1 /*
       
     2 * Copyright (c) 2006-2008 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 CNcdNode class
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <e32err.h>
       
    20 #include <e32base.h>
       
    21 
       
    22 #include "ncdnodeimpl.h"
       
    23 #include "ncdnodemanager.h"
       
    24 #include "ncdnodelink.h"
       
    25 #include "ncdnodeitemlink.h"
       
    26 #include "ncdnodefolderlink.h"
       
    27 #include "ncdnodemetadataimpl.h"
       
    28 #include "catalogssession.h"
       
    29 #include "catalogsbasemessage.h"
       
    30 #include "ncdnodefunctionids.h"
       
    31 #include "ncdnodeidentifier.h"
       
    32 #include "ncdnodemetadataimpl.h"
       
    33 #include "ncdnodeuserdataimpl.h"
       
    34 #include "ncdutils.h"
       
    35 #include "catalogsconstants.h"
       
    36 #include "catalogsdebug.h"
       
    37 #include "catalogsutils.h"
       
    38 #include "ncdnodeseenimpl.h"
       
    39 
       
    40 
       
    41 CNcdNode::CNcdNode(
       
    42     CNcdNodeManager& aNodeManager,
       
    43     NcdNodeClassIds::TNcdNodeClassId aNodeClassId, 
       
    44     NcdNodeClassIds::TNcdNodeClassId aAcceptedLinkClassId,
       
    45     NcdNodeClassIds::TNcdNodeClassId aAcceptedMetaDataClassId )
       
    46 : CCatalogsCommunicable(), 
       
    47   iNodeManager( aNodeManager ),
       
    48   iNodeClassId( aNodeClassId ),
       
    49   iAcceptedLinkClassId( aAcceptedLinkClassId ),
       
    50   iAcceptedMetaDataClassId( aAcceptedMetaDataClassId )
       
    51     {
       
    52     }
       
    53 
       
    54 
       
    55 void CNcdNode::ConstructL( const CNcdNodeIdentifier& aIdentifier )
       
    56     {
       
    57     DLTRACEIN((_L("ns: %S, id: %S"), &aIdentifier.NodeNameSpace(), &aIdentifier.NodeId()));
       
    58     // Set the identifier for this node.
       
    59     iNodeIdentifier =
       
    60         CNcdNodeIdentifier::NewL( aIdentifier );
       
    61     iNodeSeen = CNcdNodeSeen::NewL( iNodeManager.SeenInfo(), *this );
       
    62     }
       
    63 
       
    64 
       
    65 CNcdNode::~CNcdNode()
       
    66     {
       
    67     DLTRACEIN((""));
       
    68     delete iNodeIdentifier;
       
    69     
       
    70     // Notice that CCatalogsCommunicable object should not be deleted but
       
    71     // only closed.
       
    72     
       
    73     if ( iNodeLink ) 
       
    74         {
       
    75         DLINFO(("Closing node link"));
       
    76         iNodeLink->Close();
       
    77         }
       
    78         
       
    79     if ( iNodeSeen )
       
    80         {
       
    81         DLINFO(("Closing node seen"));
       
    82         iNodeSeen->Close();
       
    83         }
       
    84     
       
    85     // Do not delete iNodeMetaData here.
       
    86     // It is managers responsibility
       
    87     // Also, do not delete the manager because it is providers job.
       
    88 
       
    89     DLTRACEOUT((""));
       
    90     }
       
    91 
       
    92 
       
    93 const CNcdNodeIdentifier& CNcdNode::Identifier() const
       
    94     {
       
    95     DASSERT( iNodeIdentifier );
       
    96     return *iNodeIdentifier;
       
    97     }
       
    98 
       
    99 
       
   100 NcdNodeClassIds::TNcdNodeClassId CNcdNode::ClassId() const
       
   101     {
       
   102     return iNodeClassId;
       
   103     }
       
   104 
       
   105 
       
   106 CNcdNodeManager& CNcdNode::NodeManager() const
       
   107     {
       
   108     return iNodeManager;
       
   109     }
       
   110 
       
   111 
       
   112 CNcdNodeLink& CNcdNode::CreateAndSetLinkL()
       
   113     {
       
   114     iNodeLink = CreateLinkL();
       
   115     if ( iNodeMetaData ) 
       
   116         {
       
   117         // Ensure that link has the correct metadata timestamp
       
   118         iNodeLink->SetMetadataTimeStampL( iNodeMetaData->TimeStamp() );
       
   119         }
       
   120     return *iNodeLink;
       
   121     }
       
   122 
       
   123 
       
   124 CNcdNodeLink& CNcdNode::NodeLinkL() const
       
   125     {
       
   126     if( iNodeLink == NULL )
       
   127         {
       
   128         User::Leave( KErrNotFound );
       
   129         }         
       
   130        
       
   131     return *iNodeLink;
       
   132     }
       
   133 
       
   134 
       
   135 CNcdNodeLink* CNcdNode::NodeLink() const
       
   136     {       
       
   137     return iNodeLink;
       
   138     }
       
   139     
       
   140 
       
   141 CNcdNodeSeen& CNcdNode::NodeSeen() const
       
   142     {
       
   143     DASSERT( iNodeSeen );
       
   144     return *iNodeSeen;
       
   145     }
       
   146 
       
   147 
       
   148 void CNcdNode::InternalizeLinkL( const MNcdPreminetProtocolEntityRef& aData,
       
   149                                  const CNcdNodeIdentifier& aParentIdentifier,
       
   150                                  const CNcdNodeIdentifier& aRequestParentIdentifier,
       
   151                                  const TUid& aClientUid )
       
   152     {
       
   153     DLTRACEIN((""));
       
   154     
       
   155     TBool linkCreated( EFalse );
       
   156     
       
   157     if ( iNodeLink == NULL )
       
   158         {
       
   159         DLINFO(("Create link"));
       
   160         
       
   161         // Because the node link did not exist create it.
       
   162         // Create link should be implemented in child classes. So the right
       
   163         // kind of link is set here.
       
   164         iNodeLink = CreateLinkL();
       
   165         linkCreated = ETrue;
       
   166         }
       
   167         
       
   168     DLINFO(("Internalize link"));
       
   169 
       
   170     TRAPD( err, iNodeLink->InternalizeL( 
       
   171         aData, aParentIdentifier, aRequestParentIdentifier, aClientUid ) );
       
   172     
       
   173     if( err != KErrNone )
       
   174         {
       
   175         DLINFO(("Internalize link error: %d", err));
       
   176 
       
   177         if( linkCreated )
       
   178             {
       
   179             // Because the link was created but the internalization went wrong,
       
   180             // delete the link because it does not contain correct data.
       
   181             iNodeLink->Close();
       
   182             iNodeLink = NULL;
       
   183             }
       
   184         User::Leave( err );
       
   185         }
       
   186 
       
   187     DLTRACEOUT(( _L("Link internalized for node: %S, %S"), 
       
   188                    &iNodeIdentifier->NodeNameSpace(),
       
   189                    &iNodeIdentifier->NodeId()));
       
   190     }
       
   191 
       
   192 
       
   193 CNcdNodeMetaData& CNcdNode::NodeMetaDataL() const
       
   194     {
       
   195     if( iNodeMetaData == NULL )
       
   196         {
       
   197         User::Leave( KErrNotFound );
       
   198         }        
       
   199     
       
   200     return *iNodeMetaData;
       
   201     }
       
   202   
       
   203     
       
   204 CNcdNodeMetaData* CNcdNode::NodeMetaData() const
       
   205     {    
       
   206     return iNodeMetaData;
       
   207     }
       
   208 
       
   209 
       
   210 void CNcdNode::SetNodeMetaDataL( CNcdNodeMetaData& aMetaData )
       
   211     {
       
   212     DLTRACEIN((("this-ptr: %x"), this));
       
   213 
       
   214     if( iAcceptedMetaDataClassId == aMetaData.ClassId() )
       
   215         {
       
   216         // The metadata is of the right type, so it is safe to 
       
   217         // insert as member variable.
       
   218         // Do not delete metadata because manager owns it.
       
   219         iNodeMetaData = &aMetaData;
       
   220         
       
   221         // Temp nodes don't necessarily have a link set at this point   
       
   222         if ( iNodeLink ) 
       
   223             {            
       
   224             iNodeLink->SetMetadataTimeStampL( iNodeMetaData->TimeStamp() );
       
   225             }
       
   226         DLINFO(("Metadata inserted"));
       
   227         }
       
   228     else
       
   229         {
       
   230         DLINFO(( "Metadata was of the wrong type: %d, %d", 
       
   231                  iAcceptedMetaDataClassId, aMetaData.ClassId() ));
       
   232         DASSERT( EFalse );
       
   233         // Because the metadata was of the wrong type we do not set
       
   234         // metadata for this object
       
   235         User::Leave( KErrArgument );
       
   236         }
       
   237         
       
   238     DLTRACEOUT(( _L("MetaData set for: %S, %S"), 
       
   239                     &iNodeIdentifier->NodeNameSpace(),
       
   240                     &iNodeIdentifier->NodeId() ));
       
   241     }
       
   242     
       
   243 
       
   244 MNcdNode::TState CNcdNode::State() const
       
   245     {
       
   246     DLTRACEIN((""));
       
   247     
       
   248     CNcdNodeLink* link = NodeLink();    
       
   249     if ( link == NULL )
       
   250         {
       
   251         DLTRACEOUT(("Link NULL"));
       
   252         
       
   253         // Because link did not exist. The node is not initialized
       
   254         return MNcdNode::EStateNotInitialized;
       
   255         }
       
   256 
       
   257     CNcdNodeMetaData* meta = NodeMetaData();    
       
   258     if ( meta == NULL )
       
   259         {
       
   260         DLTRACEOUT(("Meta NULL"));
       
   261 
       
   262         // Because metadata did not exist. 
       
   263         // Then the state can not be initialized.
       
   264         return MNcdNode::EStateNotInitialized;
       
   265         }
       
   266 
       
   267     // Because link and meta both existed the node has required data
       
   268     // but check if the node is expired.
       
   269     if ( link->IsExpired() )
       
   270         {
       
   271         DLTRACEOUT(("Link was expired"));
       
   272         
       
   273         return MNcdNode::EStateExpired;
       
   274         }
       
   275     
       
   276     DLTRACEOUT(("State was initalized"));
       
   277     
       
   278     // Everything was set. So, the node state is initialized
       
   279     return MNcdNode::EStateInitialized;
       
   280     }
       
   281 
       
   282 
       
   283 void CNcdNode::ReceiveMessage( MCatalogsBaseMessage* aMessage,
       
   284                                TInt aFunctionNumber )
       
   285     {
       
   286     DLTRACEIN(("handle: %d, function: %d", aMessage->Handle(), 
       
   287         aFunctionNumber));
       
   288 
       
   289     DASSERT( aMessage );
       
   290     
       
   291     // Now, we can be sure that rest of the time iMessage exists.
       
   292     // This member variable is set for the CounterPartLost function.
       
   293     iMessage = aMessage;
       
   294                 
       
   295     TRAPD( trapError, DoReceiveMessageL( *aMessage, aFunctionNumber ) );
       
   296     if ( trapError != KErrNone )
       
   297         {
       
   298         // Because something went wrong the complete has not been
       
   299         // yet called for the message.
       
   300         // So, inform the client about the error.
       
   301         DLTRACEIN(("Complete with error message"));
       
   302         aMessage->CompleteAndRelease( trapError );
       
   303         }
       
   304 
       
   305     // Because the message should not be used after this, set it NULL.
       
   306     // So, CounterPartLost function will know that no messages are
       
   307     // waiting the response at the moment.
       
   308     iMessage = NULL;
       
   309 
       
   310     if ( aFunctionNumber == NcdNodeFunctionIds::ENcdRelease )
       
   311         {
       
   312         // Because release was called for this object it may be time to
       
   313         // delete this object. Inform manager about the release so it may
       
   314         // close this object and clear the cache if needed.
       
   315         // Notice that if the manager closes this object then this object will
       
   316         // be deleted. It is safe to do here because no memeber variables are
       
   317         // needed here after the call.
       
   318         NodeManager().NodeReleased( *this );       
       
   319         }
       
   320             
       
   321     DLTRACEOUT((""));
       
   322     }
       
   323 
       
   324 
       
   325 void CNcdNode::DoReceiveMessageL( 
       
   326     MCatalogsBaseMessage& aMessage,
       
   327     TInt aFunctionNumber )
       
   328     {
       
   329     switch( aFunctionNumber )
       
   330         {
       
   331         case NcdNodeFunctionIds::ENcdInternalize:
       
   332             InternalizeRequestL( aMessage );
       
   333             break;
       
   334             
       
   335         case NcdNodeFunctionIds::ENcdLinkHandle:
       
   336             LinkHandleRequestL( aMessage );
       
   337             break;
       
   338 
       
   339         case NcdNodeFunctionIds::ENcdMetadataHandle:
       
   340             MetadataHandleRequestL( aMessage );
       
   341             break;
       
   342             
       
   343         case NcdNodeFunctionIds::ENcdNodeSeenHandle:
       
   344             NodeSeenHandleRequestL( aMessage );
       
   345             break;
       
   346 
       
   347         case NcdNodeFunctionIds::ENcdClassId:
       
   348             ClassIdRequestL( aMessage );
       
   349             break;
       
   350 
       
   351         case NcdNodeFunctionIds::ENcdRelease:
       
   352             ReleaseRequest( aMessage );
       
   353             break;
       
   354 
       
   355         default:
       
   356             DLERROR(("Unidentified function request"));
       
   357             User::Leave( KErrNotSupported );
       
   358             break;
       
   359         }    
       
   360     }
       
   361 
       
   362 
       
   363 
       
   364 void CNcdNode::CounterPartLost( const MCatalogsSession& aSession )
       
   365     {
       
   366     // This function may be called whenever -- when the message is waiting
       
   367     // response or when the message does not exist.
       
   368     // iMessage may be NULL here, because in the end of the
       
   369     // ReceiveMessage it is set to NULL. The life time of the message
       
   370     // ends shortly after CompleteAndRelease is called.
       
   371     if ( iMessage != NULL )
       
   372         {
       
   373         iMessage->CounterPartLost( aSession );
       
   374         }    
       
   375     }
       
   376 
       
   377 
       
   378 
       
   379 void CNcdNode::ExternalizeL( RWriteStream& aStream )
       
   380     {
       
   381     DLTRACEIN((""));
       
   382 
       
   383     // Set all the membervariable values to the stream. So,
       
   384     // that the stream may be used later to create a new
       
   385     // object.
       
   386 
       
   387     // First insert data that node manager will use to
       
   388     // create this class object
       
   389     aStream.WriteInt32L( iNodeClassId );
       
   390 
       
   391     // This object acts as a wrapper. So, externalize all the objects that
       
   392     // it owns. Note, that metadata is not owned by the node. So, it is not
       
   393     // handled here. Metadata is managers responsibility because same metadata
       
   394     // may be used by multiple nodes.
       
   395     
       
   396     // Node Link
       
   397     ExternalizeLinkL( aStream );
       
   398         
       
   399     DLTRACEOUT((""));
       
   400     }
       
   401     
       
   402     
       
   403 void CNcdNode::InternalizeL( RReadStream& aStream )
       
   404     {
       
   405     DLTRACEIN((""));
       
   406 
       
   407     // NOTICE that this internalize function supposes that
       
   408     // classid and identifier info that are
       
   409     // inserted during externalization, are already read from
       
   410     // the stream before calling this function.
       
   411     
       
   412 
       
   413     // No need to read additional membervariable values from the stream 
       
   414     // because all the necessary info has been set during the creation of this
       
   415     // object. All other information belongs to the objects that this node
       
   416     // wraps.
       
   417 
       
   418     InternalizeLinkL( aStream );
       
   419     
       
   420     // Check: if additional objects will be added for this node. Then their internalization
       
   421     // should be called here. 
       
   422     
       
   423         
       
   424     DLTRACEOUT((""));
       
   425     }
       
   426 
       
   427  
       
   428 
       
   429 void CNcdNode::InternalizeRequestL( MCatalogsBaseMessage& aMessage ) const
       
   430     {
       
   431     DLTRACEIN((""));
       
   432     
       
   433     CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
       
   434     CleanupStack::PushL( buf );
       
   435     
       
   436     RBufWriteStream stream( *buf );
       
   437     CleanupClosePushL( stream );
       
   438 
       
   439 
       
   440     // Include all the necessary node data to the stream
       
   441     ExternalizeDataForRequestL( stream );     
       
   442     
       
   443     
       
   444     // Commits data to the stream when closing.
       
   445     CleanupStack::PopAndDestroy( &stream );
       
   446 
       
   447     if ( buf->Size() > 0 ) 
       
   448         {
       
   449         DLINFO(( "Completing the message, buf len: %d", buf->Ptr(0).Length() ));
       
   450         }
       
   451         
       
   452     // If this leaves ReceiveMessage function will complete the message.
       
   453     aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
       
   454         
       
   455     
       
   456     DLINFO(("Deleting the buf"));
       
   457     CleanupStack::PopAndDestroy( buf );
       
   458         
       
   459     DLTRACEOUT((""));
       
   460     }
       
   461 
       
   462 
       
   463 void CNcdNode::ExternalizeDataForRequestL( RWriteStream& aStream ) const
       
   464     {
       
   465     DLTRACEIN((""));
       
   466 
       
   467     // Insert node class id just in case somebody wants to check that the data
       
   468     // is of the right type
       
   469     aStream.WriteInt32L( iNodeClassId );
       
   470 
       
   471     Identifier().ExternalizeL( aStream );
       
   472         
       
   473     DLTRACEOUT((""));
       
   474     }
       
   475 
       
   476 
       
   477 void CNcdNode::LinkHandleRequestL( MCatalogsBaseMessage& aMessage ) const
       
   478     {
       
   479     DLTRACEIN((""));    
       
   480     
       
   481     if( iNodeLink == NULL )
       
   482         {
       
   483         DLINFO(("Node link NULL"));
       
   484         User::Leave( KErrNotFound );
       
   485         }
       
   486 
       
   487     // Get the session that will contain the handle of the node
       
   488     MCatalogsSession& requestSession( aMessage.Session() );
       
   489 
       
   490     // Add the link to the session and get the handle.
       
   491     // If the node already existed in the session we will still
       
   492     // get a new handle to the same object.
       
   493     TInt32 handle( requestSession.AddObjectL( iNodeLink ) );
       
   494 
       
   495     DLINFO(("Link handle: %d", handle ));
       
   496         
       
   497     // Send the information to the client side
       
   498     // If this leaves ReceiveMessage will complete the message.
       
   499     aMessage.CompleteAndReleaseL( handle, KErrNone );
       
   500 
       
   501     DLTRACEOUT((""));    
       
   502     }
       
   503   
       
   504     
       
   505 void CNcdNode::MetadataHandleRequestL( MCatalogsBaseMessage& aMessage ) const
       
   506     {
       
   507     DLTRACEIN((("this-ptr: %x"), this));    
       
   508     
       
   509     if( iNodeMetaData == NULL )
       
   510         {
       
   511         DLINFO(("Node metadata NULL"));
       
   512         User::Leave( KErrNotFound );
       
   513         }
       
   514 
       
   515     // Get the session that will contain the handle of the node
       
   516     MCatalogsSession& requestSession( aMessage.Session() );
       
   517 
       
   518     // Add the metadata to the session and get the handle.
       
   519     // If the node already existed in the session we will still
       
   520     // get a new handle to the same object.
       
   521     TInt32 handle( requestSession.AddObjectL( iNodeMetaData ) );
       
   522 
       
   523     DLINFO(("Metadata handle: %d", handle ));
       
   524         
       
   525     // Send the information to the client side
       
   526     // If this leaves, ReceiveMessage will complete the message.
       
   527     aMessage.CompleteAndReleaseL( handle, KErrNone );
       
   528 
       
   529     DLTRACEOUT((""));            
       
   530     }
       
   531     
       
   532 
       
   533 void CNcdNode::NodeSeenHandleRequestL( MCatalogsBaseMessage& aMessage ) const
       
   534     {
       
   535     DLTRACEIN((("this-ptr: %x"), this));
       
   536     DASSERT( iNodeSeen );
       
   537     
       
   538     // Get the session that will contain the handle of the node seen object
       
   539     MCatalogsSession& requestSession( aMessage.Session() );
       
   540 
       
   541     // Add the node seen object to the session and get the handle.
       
   542     // If the object already existed in the session we will still
       
   543     // get a new handle to the same object.
       
   544     TInt32 handle( requestSession.AddObjectL( iNodeSeen ) );
       
   545 
       
   546     DLINFO(("Node seen handle: %d", handle ));
       
   547         
       
   548     // Send the information to the client side
       
   549     // If this leaves, ReceiveMessage will complete the message.
       
   550     aMessage.CompleteAndReleaseL( handle, KErrNone );
       
   551     }
       
   552 
       
   553 
       
   554 void CNcdNode::ClassIdRequestL( MCatalogsBaseMessage& aMessage ) const
       
   555     {
       
   556     DLTRACEIN((""));
       
   557 
       
   558     // If this leaves, ReceiveMessage will complete the message.
       
   559     aMessage.CompleteAndReleaseL( ClassId(), KErrNone );
       
   560         
       
   561     DLTRACEOUT((""));
       
   562     }
       
   563 
       
   564 
       
   565 void CNcdNode::ReleaseRequest( MCatalogsBaseMessage& aMessage ) const
       
   566     {
       
   567     DLTRACEIN((""));
       
   568 
       
   569     // Decrease the reference count for this object.
       
   570     // When the reference count reaches zero, this object will be destroyed
       
   571     // and removed from the session.
       
   572     MCatalogsSession& requestSession( aMessage.Session() );
       
   573     TInt handle( aMessage.Handle() );
       
   574     aMessage.CompleteAndRelease( KErrNone );
       
   575     requestSession.RemoveObject( handle );
       
   576 
       
   577     DLTRACEOUT((""));
       
   578     }
       
   579 
       
   580 
       
   581 void CNcdNode::ExternalizeLinkL( RWriteStream& aStream )
       
   582     {
       
   583     DLTRACEIN((""));
       
   584 
       
   585     if ( iNodeLink != NULL )
       
   586         {
       
   587         iNodeLink->ExternalizeL( aStream );
       
   588         }
       
   589     else 
       
   590         {
       
   591         DLINFO(("No link"));
       
   592         aStream.WriteInt32L( NcdNodeClassIds::ENcdNullObjectClassId );
       
   593         } 
       
   594     
       
   595     // Should handle other objects like nodelink above when they are created
       
   596         
       
   597     DLTRACEOUT((""));
       
   598     }
       
   599 
       
   600 
       
   601 void CNcdNode::InternalizeLinkL( RReadStream& aStream )
       
   602     {
       
   603     DLTRACEIN((""));
       
   604 
       
   605     TInt classId( aStream.ReadInt32L() );
       
   606     
       
   607     if ( classId == NcdNodeClassIds::ENcdNullObjectClassId )
       
   608         {
       
   609         // The link was NULL when the data was externalized. So, do not do anything.
       
   610         DLTRACEIN(("Link object was null. No need to internalize it")); 
       
   611         return;           
       
   612         }
       
   613 
       
   614     TBool linkCreated( EFalse );
       
   615     
       
   616     if ( iNodeLink == NULL )
       
   617         {
       
   618         // Because the node link did not exist create it.
       
   619         // Create link should be implemented in child classes. So the right
       
   620         // kind of link is set here.
       
   621         iNodeLink = CreateLinkL();
       
   622         linkCreated = ETrue;
       
   623         }
       
   624         
       
   625     TRAPD( err, iNodeLink->InternalizeL( aStream ) );
       
   626     
       
   627     if( err != KErrNone )
       
   628         {
       
   629         if( linkCreated )
       
   630             {
       
   631             // Because the link was created but the internalization went wrong,
       
   632             // delete the link because it does not contain correct data.            
       
   633             iNodeLink->Close();
       
   634             iNodeLink = NULL;
       
   635             }
       
   636         User::Leave( err );
       
   637         }
       
   638         
       
   639     DLTRACEOUT((""));
       
   640     }