commsfwsupport/commselements/StateMachine/src/StateMachine.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwsupport/commselements/StateMachine/src/StateMachine.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,215 @@
+// Copyright (c) 2003-2009 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:
+// Offers a base class for an asynchronous state machine
+// 
+//
+
+/**
+ @file 
+*/
+
+#include "StateMachine.h"
+#include "AsynchEvent.h"
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ElemStateMachStM, "ElemStateMachStM");
+#endif
+
+EXPORT_C CStateMachine::CStateMachine() :
+   CActive( EPriorityStandard )
+   {
+	CActiveScheduler::Add(this);
+   }
+
+EXPORT_C CStateMachine::~CStateMachine()
+   {
+   delete iFragment;
+   }
+
+EXPORT_C HBufC8* CStateMachine::ReAllocL( TInt aNewLength )
+/** 
+ * Re-allocates the instance fragment
+ *
+ * @param aNewLength a length to put into the buffer
+ * @return a pointer to the allocated fragment
+ */
+   {
+   if ( !iFragment )
+      {
+      iFragment = HBufC8::NewL( aNewLength );
+      }
+   else
+      {
+      TInt n = iFragment->Length();
+      if ( (iFragment->Des().MaxLength() - n) < aNewLength )
+         {
+         iFragment = iFragment->ReAllocL( aNewLength + n );
+         }
+      }
+   return iFragment;
+   }
+
+EXPORT_C void CStateMachine::Start( TRequestStatus* aClientStatus, CAsynchEvent* aErrorEvent, MStateMachineNotify* aStateMachineNotify )
+/** 
+ * Starts the state machine
+ *
+ * @param aClientStatus the client request to complete on completion
+ * @param aErrorEvent an error event to execute on error
+ * @param aStateMachineNotify a notifier to receive state achine events
+ */
+   {
+   //history is set beforehand
+   iLastError = KErrNone;
+   iClientStatus = aClientStatus;
+   if (iClientStatus != NULL)
+      *iClientStatus = KRequestPending;
+   iErrorEvent = aErrorEvent;
+   iSuspendRequest = EFalse;
+   iStateMachineNotify = aStateMachineNotify;
+   //jump to RunL
+   TRequestStatus* p=&iStatus;
+   if ( !IsActive() )
+   	{
+	   SetActive();
+   	}
+   User::RequestComplete( p, KErrNone );
+   }
+
+EXPORT_C void CStateMachine::Cancel( TInt aLastError )
+/** 
+ * Cancels the state machine with an error
+ *
+ * @param aLastError a desired error code. 
+ * if the last eror is KErrNone the state machine
+ * will be cancelled and client request will be completed with KErrCancel.
+ * In any other case the active event will become the error event and the 
+ * processing continues.
+ */
+   {
+   iSuspendRequest = EFalse;
+   if ( aLastError == KErrNone )
+      {
+      iErrorEvent = 0;
+      }
+   //cancel the current activity
+   CActive::Cancel();
+   iLastError = KErrCancel;
+   iActiveEvent = iErrorEvent;
+   if ( iActiveEvent )
+      {
+      //jump to RunL //!!This makes the cancel asynchronous
+      TRequestStatus* p=&iStatus;
+      SetActive();
+      User::RequestComplete( p, KErrNone );
+      }
+   }
+
+EXPORT_C void CStateMachine::DoCancel()
+/** 
+ * completes the cancel request
+ *
+ */
+   {
+   if ( !iErrorEvent ) //otherwise the "cancel" completes after the error event has been sent
+      {
+      OnCompletion();
+      }
+   }
+
+EXPORT_C void CStateMachine::OnError()
+/** 
+ * Called from ::RunL when an error occures
+ *
+ */
+   {
+   if ( iLastError != KErrNone )
+      {
+      if ( iActiveEvent != iErrorEvent )
+         {
+         iActiveEvent = 0;
+         }
+      }
+   else
+      {
+      iLastError = iStatus.Int();
+      iActiveEvent = iErrorEvent;
+      }
+   }
+
+EXPORT_C void CStateMachine::RunL()
+/** 
+ * Called on completion of one active event
+ *
+ */
+   {
+   if ( iStatus.Int() != KErrNone )
+      {//error
+      OnError();
+      }
+   if ( iActiveEvent )
+      {//process iActiveEvent if not iSuspendRequest
+      if ( iSuspendRequest )
+         {
+         if ( iStateMachineNotify )
+            {//return value ignored
+            iStateMachineNotify->OnCompletion( this );
+            }
+         }
+      else
+         {
+         SetActive();
+         iActiveEvent = iActiveEvent->ProcessL( iStatus );
+         }
+      }
+   else
+      {//complete the state machine task
+      OnCompletion();
+      }
+   }
+
+EXPORT_C TInt CStateMachine::RunError(TInt aError)
+/** 
+ * RunL left. Complete status with the aError and let RunL function to handle it
+ *
+ */
+   {
+   //if RunL (ProcessL) leaves the current request must not be completed
+   __ASSERT_DEBUG(IsActive(), User::Panic(KSpecAssert_ElemStateMachStM, 1));
+   iActiveEvent = 0;
+   TRequestStatus* p=&iStatus;
+   User::RequestComplete( p, aError );
+	return KErrNone; //no error propagation to central error handler
+   }
+
+EXPORT_C void CStateMachine::OnCompletion()
+/** 
+ * Called by RunL when the state machine has completed its task.
+ *
+ */
+   {
+   //!!!notifier cannot delete this
+   TBool bDelete = iStateMachineNotify ? iStateMachineNotify->OnCompletion( this ) : EFalse;
+   if ( iClientStatus )
+      {
+      User::RequestComplete( iClientStatus, iLastError );
+      }
+   if ( bDelete )
+      {
+      delete this;
+      }
+   }
+