devicediagnosticsfw/diagresultsdb/server/src/diagresultsdbtestrecordsubsession.cpp
changeset 0 b497e44ab2fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devicediagnosticsfw/diagresultsdb/server/src/diagresultsdbtestrecordsubsession.cpp	Thu Dec 17 09:07:52 2009 +0200
@@ -0,0 +1,645 @@
+/*
+* Copyright (c) 2007 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:  Class definition of 
+*
+*/
+
+
+#include "diagresultsdatabasecommon.h"
+#include "diagresultsdbsession.h"
+#include "diagresultsdbtestrecordsubsession.h"
+#include "diagresultsdbtestrecord.h"
+#include "diagresultsdbtestrecordhandle.h"
+#include "diagresultsdbrecordengineparam.h"
+#include "diagresultsdatabase.h"
+
+#include <s32mem.h> 
+
+//this matches the size in the client side.
+const TInt KResultsDatabaseSubsessionBufferLength = 0x250;
+const TInt KResultsDatabaseSubsessionGranuality = 50;
+
+// ---------------------------------------------------------------------------
+// NewL.
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDbTestRecordSubsession* CDiagResultsDbTestRecordSubsession::NewL(
+                             CDiagResultsDbSession* aSession, 
+                             CDiagResultsDbTestRecordHandle* aTestRecordHandle,
+                             TBool aReadonly
+                             )
+    {
+    CDiagResultsDbTestRecordSubsession* self = new( ELeave ) 
+                CDiagResultsDbTestRecordSubsession( aSession, 
+                                                    aTestRecordHandle,
+                                                    aReadonly
+                                                    );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor. Checks has the test record been written into the DB.
+// If it hasn't been written, destructor writes the data. 
+// This situation happens when for example client dies suddenly.
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDbTestRecordSubsession::~CDiagResultsDbTestRecordSubsession()
+    {
+    delete iTestRecordHandle;
+    iTestRecordHandle = NULL;
+    
+    if ( iBuffer )
+        {
+        iBuffer->Reset();
+        delete iBuffer;
+        iBuffer = NULL;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ConstructL. Creates the server side buffer.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::ConstructL()
+    {
+    // buffer for IPC. Objects are transmitted in this buffer.
+	// Size of the buffer has to be selected carefully.
+	// It should be 'large enough' but not too large.
+	// If you see too many overflows, increase the size.
+	// Subsession buffer can be smaller than the session buffer
+	iBuffer = CBufFlat::NewL( KResultsDatabaseSubsessionGranuality  );
+	iBuffer->ResizeL( KResultsDatabaseSubsessionBufferLength );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles subsession requests. 
+// ---------------------------------------------------------------------------
+// 
+TBool CDiagResultsDbTestRecordSubsession::DispatchMessageL(
+                                                    const RMessage2& aMessage)
+    {
+    TInt function = aMessage.Function();
+    switch( function )
+		{
+        case DiagResultsDbCommon::ESubsessionGetTestRecordId:
+            {            
+            TPckgBuf<TUid> uid( iTestRecordHandle->RecordInfo().iRecordId);
+            aMessage.Write( 0, uid );
+            return EFalse;
+            }
+        
+        case DiagResultsDbCommon::ESubsessionTestCompleted: //SYNC
+            {
+            iMsg = aMessage;
+           
+            CompleteTestRecordL( aMessage );
+            
+            aMessage.Complete( KErrNone );
+            
+            //Do compacting after subsession is completed to
+            //minimize disk space usage
+            if ( iSession->SessionHasWritten() )
+                {
+                iSession->Store().CompactDatabase();
+                }
+            
+            //Not asynchronous, but this prevents calling Complete again.
+            return ETrue;
+            }
+  
+        case DiagResultsDbCommon::ESubsessionGetStatus:
+            {
+            GetStatusL ( aMessage );
+            return EFalse;
+            }
+		case DiagResultsDbCommon::ESubsessionSuspend: //SYNC
+		    {
+		    iMsg = aMessage;
+           
+            SuspendTestRecordL( aMessage );
+            
+            aMessage.Complete( KErrNone );
+            
+            //Do compacting after subsession is completed to
+            //minimize disk space usage
+            if ( iSession->SessionHasWritten() )
+                {
+                iSession->Store().CompactDatabase();
+                }
+            
+            //Not asynchronous, but this prevents calling Complete again.
+            return ETrue;
+		    }
+            
+        case DiagResultsDbCommon::ESubsessionIsTestCompleted:
+            {
+            TPckgBuf<TBool> pckg ( Completed() );
+            aMessage.Write( 0, pckg );
+            return EFalse;
+            }
+        case DiagResultsDbCommon::ESubsessionGetRecordInfo:
+            {
+            TPckgBuf<TDiagResultsDatabaseTestRecordInfo> pckg(
+                                                 iTestRecordHandle->RecordInfo());
+            aMessage.Write( 0, pckg );
+            return EFalse;
+            }
+        case DiagResultsDbCommon::ESubsessionGetTestUids:
+            {
+            GetTestUidsL( aMessage );
+            return EFalse;
+            }
+            
+		case DiagResultsDbCommon::ESubsessionIsSuspended:
+		    {
+		    TBool suspended = EFalse;
+            if ( iTestRecordHandle->RecordInfo().iRecordStatus ==
+                    TDiagResultsDatabaseTestRecordInfo::ESuspended )
+                {
+                suspended = ETrue;
+                }
+                
+            TPckgBuf<TBool> pckg ( suspended );
+            aMessage.Write( 0, pckg );
+            return EFalse;
+		    }
+		
+		case DiagResultsDbCommon::ESubsessionGetEngineParam:
+		    {
+		    GetEngineParamL( aMessage );
+            return EFalse;
+		    }    
+		    
+        case DiagResultsDbCommon::ESubsessionLogTestResult: //ASYNC
+            {
+            iMsg = aMessage;
+            iCompletedLogTest = EFalse;
+            LogTestResultL( aMessage );
+            return ETrue;
+            }
+        
+        case DiagResultsDbCommon::ESubsessionCancelLogTestResult: 
+            {
+            CancelLogTestResult( aMessage );
+            
+            return EFalse;
+            }
+
+        case DiagResultsDbCommon::ESubsessionGetTestResult:
+            {
+            GetTestResultL( aMessage );
+            return EFalse;
+            }
+            
+        case DiagResultsDbCommon::ESubsessionGetTestResults:
+            {
+            GetTestResultsL( iTestRecordHandle, aMessage );
+            return EFalse;
+            }
+        default:
+            break;
+		}
+	aMessage.Panic( _L("DiagSrv panic: unknown command"), 
+	                    DiagResultsDbCommon::EBadRequest );
+	return EFalse;
+	}
+
+
+// ---------------------------------------------------------------------------
+// Returns record complete status.
+// ---------------------------------------------------------------------------
+// 
+TBool CDiagResultsDbTestRecordSubsession::Completed() const
+    {
+    TBool completed = EFalse;
+     
+    if ( iTestRecordHandle->RecordInfo().iCompleted )
+        {
+        completed = ETrue;
+        }
+    return completed;         
+    }
+
+
+// ---------------------------------------------------------------------------
+// Maps server side status into user side status.
+// ---------------------------------------------------------------------------
+//  
+void CDiagResultsDbTestRecordSubsession::GetStatusL ( const RMessage2& aMessage )
+    {
+    
+    RDiagResultsDatabaseRecord::TRecordStatus status;
+    
+    if ( iTestRecordHandle->RecordInfo().iCompleted )
+        {
+        
+        if ( iTestRecordHandle->RecordInfo().iRecordStatus == 
+                                    TDiagResultsDatabaseTestRecordInfo::EOpen )
+            {
+            
+            status = RDiagResultsDatabaseRecord::EPartiallyCompleted;
+            }
+        else if ( iTestRecordHandle->RecordInfo().iRecordStatus == 
+                                    TDiagResultsDatabaseTestRecordInfo::ESuspended )
+            {
+            status = RDiagResultsDatabaseRecord::EPartiallyCompleted;
+            }
+        else if (  iTestRecordHandle->RecordInfo().iRecordStatus == 
+                                    TDiagResultsDatabaseTestRecordInfo::ECompleted )   
+            {
+            status = RDiagResultsDatabaseRecord::ECompleted;
+            }     
+        else 
+        	{        		  
+            User::Panic( _L("DiagDbServer error"), DiagResultsDbCommon::EGetStatusPanic);                  
+			status = RDiagResultsDatabaseRecord::ECrashed;	
+        	}
+        }
+    else // iCompleted == EFalse
+        {
+         if ( iTestRecordHandle->RecordInfo().iRecordStatus == 
+                                    TDiagResultsDatabaseTestRecordInfo::EOpen )
+            {
+            if ( iSession->SessionHasWritten() )
+                {
+                status = RDiagResultsDatabaseRecord::EOpen;
+                }
+            else
+                {
+                status = RDiagResultsDatabaseRecord::ECrashed;
+                }
+            }
+        else if ( iTestRecordHandle->RecordInfo().iRecordStatus == 
+                                    TDiagResultsDatabaseTestRecordInfo::ESuspended )
+            {
+            status = RDiagResultsDatabaseRecord::ESuspended;
+            }
+         // TDiagResultsDatabaseTestRecordInfo::ECompleted is not valid combination either
+        else     
+            {
+            User::Panic( _L("DiagDbServer error"), DiagResultsDbCommon::EGetStatusPanic);
+			status = RDiagResultsDatabaseRecord::ECrashed;
+            }        
+        }
+        
+    TPckgBuf<RDiagResultsDatabaseRecord::TRecordStatus> pckg( status );
+    aMessage.Write( 0, pckg );    
+    }
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//     
+CDiagResultsDbTestRecordSubsession::CDiagResultsDbTestRecordSubsession(
+                            CDiagResultsDbSession* aSession, 
+                            CDiagResultsDbTestRecordHandle* aTestRecordHandle,
+                            TBool aReadonly
+                            ):
+        iSession( aSession ), iTestRecordHandle( aTestRecordHandle ), 
+        iReadonly (aReadonly), iCompletedLogTest( EFalse )
+    {
+	
+    }
+
+// ---------------------------------------------------------------------------
+// Read-only subsession or not
+// ---------------------------------------------------------------------------
+// 
+TBool CDiagResultsDbTestRecordSubsession::ReadonlySubsession() const
+    {
+    return iReadonly;
+    }
+
+// ---------------------------------------------------------------------------
+// Retrieve session params.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::GetEngineParamL( const RMessage2& aMessage )
+    {    
+    iSession->ReadBufferL( aMessage, 0, iBuffer );
+
+	RBufWriteStream stream ( *iBuffer );
+	CleanupClosePushL( stream );
+
+    iTestRecordHandle->GetEngineParam().ExternalizeL( stream );    
+    
+    stream.CommitL();
+    
+	CleanupStack::PopAndDestroy( &stream );
+	
+	 // if client buffer is not big enough	    
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) )
+        {
+        User::Leave( KErrOverflow );
+        }
+    
+    aMessage.Write( 0, iBuffer->Ptr(0) ); //write to client's address space 
+    }
+
+
+// ---------------------------------------------------------------------------
+// Log data into the store. This does not write data into the file.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::LogTestResultL( 
+                                                const RMessage2& aMessage )
+    {
+    if ( Completed() )
+        {
+        User::Leave( KErrAlreadyExists );
+        }
+        
+    if ( ReadonlySubsession() )
+        {
+        User::Leave( KErrAccessDenied  );
+        }
+        
+    //Writing anymore results into suspended record is considered as resume   
+    iTestRecordHandle->RecordInfo().iRecordStatus = 
+                                    TDiagResultsDatabaseTestRecordInfo::EOpen;
+        
+    iSession->ReadBufferL( aMessage, 0, iBuffer );
+    
+    RBufReadStream stream( *iBuffer );
+    CleanupClosePushL ( stream );
+    
+    CDiagResultsDatabaseItem * item = 
+                            CDiagResultsDatabaseItem::NewL ( stream );
+    CleanupStack::PushL( item );    
+
+    //Update handle + write data into the file. Handle and DB must be in sync.
+    TInt error = iSession->Store().CompleteTestResult( ETrue, 
+                                                       *iTestRecordHandle, 
+                                                       *item );
+    
+    //item has been written, so delete the object
+    CleanupStack::PopAndDestroy( item ); 
+    CleanupStack::PopAndDestroy( &stream );
+    
+    iCompletedLogTest = ETrue;
+    
+    // LogTestResult is asynchronous.
+    if( error == KErrNone )
+        {
+        iSession->HasWritten();
+        aMessage.Complete( KErrNone );   
+        }
+    else 
+        {
+        if ( error == KErrDiskFull )
+            {
+            iSession->DoNotCompact();
+            }
+            
+        aMessage.Complete ( error );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cancel LogTestResultL.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::CancelLogTestResult( 
+                                               const RMessage2& /*aMessage*/ )
+    {
+    if (!iMsg.IsNull() && !iCompletedLogTest )
+        {  
+        iMsg.Complete( KErrCancel ); //Complete client's request. 
+        }
+    }
+
+    
+// ---------------------------------------------------------------------------
+// Returns the test record.
+// ---------------------------------------------------------------------------
+// 
+CDiagResultsDbTestRecordHandle* CDiagResultsDbTestRecordSubsession::CurrentTestRecordHandle()
+    {
+    return iTestRecordHandle;
+    }
+
+// ---------------------------------------------------------------------------
+// Finds one test result and serialize it. If it is not found, return KErrNone
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::GetTestResultL( 
+                                                   const RMessage2& aMessage )
+    {
+    iSession->ReadBufferL( aMessage, 1, iBuffer );
+    
+    TPckgBuf<TUid> uidpckg;
+	aMessage.Read(0, uidpckg);
+    TUid testUid = uidpckg(); 
+	
+	//Find right stream Id from the handle
+	TStreamId id;
+	TInt error = iTestRecordHandle->MatchingStreamId( testUid, id );
+	
+	User::LeaveIfError ( error );
+	
+	CDiagResultsDatabaseItem* item = 
+	     iSession->Store().OpenExistingTestResultL( id );
+	CleanupStack::PushL( item );
+	  
+	RBufWriteStream stream ( *iBuffer );
+	CleanupClosePushL( stream );
+	item->ExternalizeL( stream );
+	stream.CommitL();
+	CleanupStack::PopAndDestroy( &stream );
+	
+	CleanupStack::PopAndDestroy( item );
+	          
+	if ( iBuffer->Size() == 0 ) // Item was not found
+	    {
+	    User::Leave ( KErrNotFound );
+	    }
+	
+	 // if client buffer is not big enough	    
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(1) )
+        {
+        User::Leave( KErrOverflow );
+        }
+    
+    aMessage.Write( 1, iBuffer->Ptr(0) ); //write to client's address space 
+   
+    }
+
+// ---------------------------------------------------------------------------
+// Complete test record i.e. write it to file in parts.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::CompleteTestRecordL( 
+                                                   const RMessage2& aMessage )
+    {
+    if ( Completed() )
+        {
+        User::Leave( KErrAlreadyExists );
+        }
+    if ( ReadonlySubsession() )
+        {
+        User::Leave( KErrAccessDenied  );
+        }    
+    
+    TPckgBuf<TBool> completeFullyPckg;
+	aMessage.Read(0, completeFullyPckg);
+    TBool completeFully = completeFullyPckg();
+    
+    if ( completeFully )
+        {
+        iTestRecordHandle->RecordInfo().iRecordStatus = 
+                                TDiagResultsDatabaseTestRecordInfo::ECompleted;
+                                
+        iTestRecordHandle->RecordInfo().iCompleted = ETrue;
+        }
+    else // partial complete. iRecordStatus is not changed.
+        {
+        iTestRecordHandle->RecordInfo().iCompleted = ETrue;
+        }
+    
+    //Cleanup is not necessary if logging failed.
+    TInt error = iSession->Store().CompleteRecord( *iTestRecordHandle );
+    
+    if ( error == KErrDiskFull )
+            {
+            iSession->DoNotCompact();
+            }
+   
+    User::LeaveIfError ( error );         
+    
+    iSession->HasWritten();
+    
+    iSession->Store().CleanUpDatabaseL( ETrue );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Suspend test record i.e. write it to file in parts.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::SuspendTestRecordL( 
+                                                   const RMessage2& /*aMessage*/ )
+    {
+    if ( Completed() )
+        {
+        User::Leave( KErrAlreadyExists );
+        }
+    if ( ReadonlySubsession() )
+        {
+        User::Leave( KErrAccessDenied  );
+        }    
+    
+    iTestRecordHandle->RecordInfo().iRecordStatus = 
+                                TDiagResultsDatabaseTestRecordInfo::ESuspended;
+
+    iTestRecordHandle->RecordInfo().iCompleted = EFalse;
+                                
+    TInt error = iSession->Store().CompleteRecord( *iTestRecordHandle );
+    
+     if ( error == KErrDiskFull )
+            {
+            iSession->DoNotCompact();
+            }
+   
+    User::LeaveIfError ( error );         
+        
+    iSession->Store().CleanUpDatabaseL( ETrue );
+    
+    iSession->HasWritten();
+    }
+
+// ---------------------------------------------------------------------------
+// Observers function. Observers store after CompleteTestRecordL has been
+// called.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::CompletedRecordL( TInt aError )
+    {
+    iMsg.Complete( aError ); // complete async function
+    }
+
+
+// ---------------------------------------------------------------------------
+// Get test results of a test record.
+// ---------------------------------------------------------------------------
+// 
+void CDiagResultsDbTestRecordSubsession::GetTestResultsL( 
+                                        CDiagResultsDbTestRecordHandle* aHandle, 
+                                        const RMessage2& aMessage )
+    {
+    iSession->ReadBufferL( aMessage, 0, iBuffer );
+    
+    	
+    RBufWriteStream stream ( *iBuffer );
+    CleanupClosePushL ( stream );
+    stream.WriteInt16L( aHandle->Count() );
+	
+	CDiagResultsDbTestRecord* testrecord = 
+	    iSession->Store().OpenExistingRecordL( TUid::Uid(aHandle->RecordId().Value()), ETrue );
+	CleanupStack::PushL (testrecord);
+	
+	for ( TInt i = 0; i < aHandle->Count(); ++i )
+	    {
+	    const CDiagResultsDatabaseItem& item = (*testrecord)[i];
+	    item.ExternalizeL( stream );
+	    }
+	    
+    CleanupStack::PopAndDestroy( testrecord );
+    
+    // if client buffer is not big enough
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) ) 
+        {
+        User::Leave( KErrOverflow );
+        }
+
+    aMessage.Write( 0, iBuffer->Ptr(0) );  //write to client's address space
+    
+    CleanupStack::PopAndDestroy( &stream );
+    } 
+
+// ---------------------------------------------------------------------------
+// Get UIDs of test results that are stored inside the test record.
+// ---------------------------------------------------------------------------
+//     
+void CDiagResultsDbTestRecordSubsession::GetTestUidsL( 
+                                            const RMessage2& aMessage )
+    {
+    iSession->ReadBufferL( aMessage, 0, iBuffer );
+    
+   	RBufWriteStream stream ( *iBuffer );
+   	CleanupClosePushL( stream );
+
+   	//Write how many uids there are.
+   	stream.WriteInt16L( iTestRecordHandle->Count() );
+   	
+	for (TInt i = 0; i < iTestRecordHandle->Count(); ++i)
+	    {
+	    stream.WriteInt32L( iTestRecordHandle->Get(i).iTestUid.iUid ) ;        
+	    }
+	        
+	// if client buffer is not big enough        
+    if ( iBuffer->Ptr(0).Length() > aMessage.GetDesMaxLength(0) ) 
+        {
+        User::Leave( KErrOverflow );
+        }
+    
+    
+    aMessage.Write( 0, iBuffer->Ptr(0) ); //write to client's address space 
+   
+    CleanupStack::PopAndDestroy( &stream );
+    }