genericservices/taskscheduler/SCHSVR/SCHCLI.CPP
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/taskscheduler/SCHSVR/SCHCLI.CPP	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,410 @@
+// Copyright (c) 2004-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:
+//
+
+// System includes
+#include <logwraplimits.h>
+#include <logwrap.h>
+#include <schtask.h>
+
+
+// User includes
+#include "SCHCLI.H"
+#include "SchLogger.h"
+#include "SCHEXEC.H"
+#include "SCHLOG.h"
+
+
+// Constants
+#define KEllipsis 0x2026
+const TInt KTaskArrayGranularity = 1;
+_LIT(KTaskNameSeparator, ", ");
+
+
+
+//
+// CClientProxy
+//
+CClientProxy::CClientProxy(RFs& aFsSession, CSchLogManager& aLogManager)
+:	iFsSession(aFsSession), 
+	iTasks(CScheduledTask::Offset()),
+	iSchLogManager(aLogManager)
+	{
+	}
+
+CClientProxy::CClientProxy(RFs& aFsSession, TInt aPriority, CSchLogManager& aLogManager)
+:	iFsSession(aFsSession), 
+	iTasks(CScheduledTask::Offset()),
+	iSchLogManager(aLogManager)
+	{
+	iPriLink.iPriority = aPriority;
+	}
+
+CClientProxy::~CClientProxy()
+	{
+	LOGSTRING("CClientProxy::~CClientProxy - start");
+
+	TDblQueIter<CScheduledTask> taskIter(iTasks);
+	taskIter.SetToFirst();
+	CScheduledTask* task;
+	while ((task = taskIter++) != NULL)
+		{
+		RemoveTask(task);
+		}
+	delete iFileName;
+	LOGSTRING("CClientProxy::~CClientProxy - end");
+	} 
+
+void CClientProxy::ConstructL(const TDesC& aFileName)
+	{
+	iFileName = aFileName.AllocL();
+	}
+
+CClientProxy* CClientProxy::NewL(RFs& aFsSession, 
+								const TDesC& aFileName, 
+								TInt aPriority,
+								CSchLogManager& aLogManager)
+	{
+	CClientProxy* self = new(ELeave) CClientProxy(aFsSession, aPriority,aLogManager);
+	CleanupStack::PushL(self);
+	self->ConstructL(aFileName);
+	CleanupStack::Pop();
+	return self;
+	}
+
+CClientProxy* CClientProxy::NewL(RFs& aFsSession, 
+								RReadStream& aStream,
+								CSchLogManager& aLogManager)
+	{
+	CClientProxy* self = new(ELeave) CClientProxy(aFsSession,aLogManager);
+	CleanupStack::PushL(self);
+	aStream >> *self;
+	CleanupStack::Pop();
+	return self;
+	}
+
+TBool CClientProxy::IsEqual(const TDesC& aFilename, TInt aPriority) const
+	{
+	// Equality here means: same DLL filename, DLL ordinal & priority
+	return ((*iFileName == aFilename) && (iPriLink.iPriority == aPriority));
+	}
+
+void CClientProxy::AddTask(CScheduledTask& aTask)
+	{
+	LOGSTRING("CClientProxy::AddTask - start");
+	iTasks.Add(aTask);
+	iUsers++;
+	LOGSTRING("CClientProxy::AddTask - end");
+	}
+
+void CClientProxy::RemoveTask(CScheduledTask* aTask)
+	{
+	LOGSTRING("CClientProxy::RemoveTask - start");
+	iUsers--;
+	aTask->Remove();
+	delete aTask;
+	LOGSTRING("CClientProxy::RemoveTask - end");
+	}
+
+//
+static void BuildTaskErrorMessage(const CArrayPtr<CScheduledTask>& aTasks, TDes& aErrorMessage)
+//
+//	Establish the names of all the tasks that potentially might fail
+//	when executing the task. This is done *before* actually executing the
+//	tasks as its not possible to discern (at failure time) which tasks
+//	were actually executing (because we don't know at what time the task
+//	executor was spawned).
+//
+	{
+	const TInt count = aTasks.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		const TDesC& taskName = aTasks.At(i)->Info().iName;
+		if	(aErrorMessage.Length() + taskName.Length() > KLogMaxSubjectLength - KTaskNameSeparator().Length())
+			{
+			// The task name that still needs adding to the subject line (of the
+			// log entry) is too big to fit within KLogCallEventTypeUid characters.
+			// Trim the task name so that it will fit, and append the ellipsis
+			// character to indicate that more tasks were present but unable to be
+			// shown.
+			TInt lengthOfTaskNameToAccept = (KLogMaxSubjectLength - aErrorMessage.Length()) - KTaskNameSeparator().Length();
+			if	(lengthOfTaskNameToAccept <= 0)
+				break;
+			aErrorMessage += taskName.Left(lengthOfTaskNameToAccept);
+			aErrorMessage.Append(KEllipsis);
+			
+			// Exit the 'for' loop as there isn't any more room to hold subsequent
+			// tasks that potentially failed...
+			break;
+			}
+		else
+			{
+			aErrorMessage += taskName;
+			}
+
+		if	(i<count-1) // not the last taskName
+			{
+			// Append a comma
+			aErrorMessage += KTaskNameSeparator;
+			}
+		}
+	}
+	
+void CClientProxy::ExecuteTasks()
+	{
+	// generate an array of due tasks
+	CArrayPtr<CScheduledTask>* tasks = NULL;
+	TRAPD(err, tasks = DueTasksL());
+	if(err)
+		{
+		iSchLogManager.LogError(err);
+		return;
+		}
+	
+	// Create the task error message, just in case an error occurs
+	TBuf<KLogMaxSubjectLength> errorMessage;
+	BuildTaskErrorMessage(*tasks, errorMessage);
+
+	TInt error =DoExecuteTasks(*tasks, errorMessage);
+	if(error)
+		iSchLogManager.LogError(errorMessage,error);
+	delete tasks;
+	}
+
+TInt CClientProxy::DoExecuteTasks(const CArrayPtr<CScheduledTask>& aTasks,
+									const TDesC& aErrorMessage)
+	{
+	// Generate a unique task name
+	TTime timenow;
+	timenow.UniversalTime();
+	TBuf<24> filename; // 20 is the longest decimal char length of a 64-bit number + 4 for extension
+	filename.Format(_L("%Ld.tmp"),timenow.Int64());
+	
+	// Save & perform execution
+	TRAPD(error, DoExecuteTasksL(aTasks, filename, aErrorMessage));
+
+	if (error != KErrNone)
+		{
+		LOGSTRING2("CClientProxy::ExecuteTasksL - attempted to execute tasks, error was %d", error);
+		// Cleanup the file that was created if the execution fails in any way. Note
+		// that it might not have been created
+
+		// If a debug build - record error
+		TInt fileDeleteErr=iFsSession.Delete(filename);
+		if (fileDeleteErr != KErrNone)
+			{
+			LOGSTRING2("CClientProxy::DoExecuteTasks - Failed to delete file. Error = %d", fileDeleteErr);
+			}
+		}
+	return error;
+	}
+
+void CClientProxy::DoExecuteTasksL(const CArrayPtr<CScheduledTask>& aTasks, 
+									const TDesC& aFileName,
+									const TDesC& aErrorMessage)
+	{
+	// Save the tasks to disk
+	SaveTasksToFileL(aTasks, aFileName);
+	
+	// Spawn the task executor active object (deletes itself upon completion)
+	CTaskExecutor* executor = CTaskExecutor::NewLC(aErrorMessage,aFileName,*iFileName,iSchLogManager);
+	executor->ExecuteL();
+	CleanupStack::Pop(executor);
+	// Don't delete executor here as it does it itself once 
+	// the task has finished (delete this in its RunL() )
+	}
+
+
+CArrayPtr<CScheduledTask>* CClientProxy::DueTasksL()
+//
+//	Returns a copy of any due tasks
+//
+	{
+	CArrayPtrFlat<CScheduledTask>* tasks = new(ELeave)CArrayPtrFlat<CScheduledTask> (KTaskArrayGranularity);
+	CleanupStack::PushL(tasks);
+	TDblQueIter<CScheduledTask> taskIter(iTasks);
+	taskIter.SetToFirst();
+	CScheduledTask* task;
+	while ((task=taskIter++)!=NULL)
+		{
+		if (task->Due())
+			{
+			tasks->AppendL(task);
+			}
+		}
+	CleanupStack::Pop(tasks);
+	return tasks;
+	}
+	
+
+CFileStore* CClientProxy::CreateStoreL(const TDesC& aName,TUint aFileMode)
+//
+//	To make the code clearer - called within a trap frame that shouldn't leave anything 
+//	on cleanup stack.
+//
+	{
+	CFileStore* store = CDirectFileStore::CreateLC(iFsSession, aName, aFileMode);
+	CleanupStack::Pop(store);
+	return store;
+	}
+
+void CClientProxy::SaveTasksToFileL(const CArrayPtr<CScheduledTask>& aTasks, const TDesC& aFileName)
+	{
+	LOGSTRING("CClientProxy::SaveTasksToFileL - start");
+
+	// Create the file store
+	LOGSTRING("CClientProxy::SaveTasksToFileL - creating store");
+	CFileStore* store = CreateStoreL(aFileName, EFileWrite);
+	CleanupStack::PushL(store);
+
+	// Save the actual tasks to the store
+	LOGSTRING("CClientProxy::SaveTasksToFileL - saving tasks");
+	SaveTasksL(*store, aTasks);
+	CleanupStack::PopAndDestroy(store);
+
+	LOGSTRING("CClientProxy::SaveTasksToFileL - end");
+	}
+
+void CClientProxy::SaveTasksL(CFileStore& aStore, const CArrayPtr<CScheduledTask>& aTasks)
+	{
+	LOGSTRING("CClientProxy::SaveTasksL - start");
+	aStore.SetTypeL(KDirectFileStoreLayoutUid);	
+
+	// Save the tasks
+	RStoreWriteStream outstream;
+	TStreamId id = outstream.CreateLC(aStore);
+	const TInt count = aTasks.Count();
+	LOGSTRING2("CClientProxy::SaveTasksL - saving %d tasks", count);
+	outstream.WriteInt32L(count);
+	for (TInt i=0;i<count;i++)
+		{
+		CScheduledTask* task = aTasks.At(i);
+		task->ExternalizeL(outstream);
+		} 
+	outstream.CommitL();
+	CleanupStack::PopAndDestroy(); // outstream
+
+	aStore.SetRootL(id);							
+	aStore.CommitL();							
+	LOGSTRING("CClientProxy::SaveTasksL - end");
+	}
+
+void CClientProxy::RemoveDueTasks()
+	{
+	LOGSTRING("CClientProxy::RemoveDueTasks - start");
+
+	TDblQueIter<CScheduledTask> taskIter(iTasks);
+	taskIter.SetToFirst();
+	CScheduledTask* task;
+	//
+	while ((task=taskIter++)!=NULL)
+		{
+		if (task->Due())
+			{
+			LOGSTRING3("CClientProxy::RemoveDueTasks - found due task %S, %d", &task->Info().iName, task->Info().iTaskId);
+
+			if	(!task->Info().iRepeat)
+				{
+				LOGSTRING("CClientProxy::RemoveDueTasks - task has no repeats left - it's being removed");
+				RemoveTask(task);
+				}
+			else
+				{
+				LOGSTRING("CClientProxy::RemoveDueTasks - task still has some repeats, setting as 'no longer due'");
+				task->SetDue(EFalse);
+				}
+			}
+		}
+	iReadyToExecute = EFalse;
+	LOGSTRING("CClientProxy::RemoveDueTasks - end");
+	}
+
+void CClientProxy::TransferTasks(CClientProxy& aTargetClient)
+	{
+	TDblQueIter<CScheduledTask> taskIter(iTasks);
+	taskIter.SetToFirst();
+	CScheduledTask* task;
+	while ((task=taskIter++)!=NULL)
+		{
+		task->Remove();
+		aTargetClient.AddTask(*task);
+		}
+	}
+
+void CClientProxy::InternalizeL(RReadStream& aReadStream)
+	{
+	LOGSTRING("CClientProxy::InternalizeL - start");
+
+	HBufC* fileName = HBufC::NewL(aReadStream, KMaxFileName);
+	delete iFileName;
+	iFileName = fileName;
+	//
+	iPriLink.iPriority = aReadStream.ReadInt32L();
+
+	const TInt count = aReadStream.ReadInt32L();
+	for(TInt i=0; i<count; i++)
+		{
+		CScheduledTask* task = CScheduledTask::NewLC(aReadStream);
+		AddTask(*task);
+		CleanupStack::Pop(task);
+		}
+
+	LOGSTRING("CClientProxy::InternalizeL - end");
+	}
+
+void CClientProxy::ExternalizeL(RWriteStream& aWriteStream) const
+	{
+	LOGSTRING("CClientProxy::ExternalizeL - start");
+
+	aWriteStream << *iFileName;
+	aWriteStream.WriteInt32L(iPriLink.iPriority);
+
+	TDblQueIter<CScheduledTask> taskIter(const_cast<CClientProxy*>(this)->iTasks);
+	taskIter.SetToFirst();
+	CScheduledTask* task;
+
+	// Count tasks
+	TInt count = 0;
+	while ((task=taskIter++)!=NULL)
+		{
+		if(task->Persists())
+			{	
+			count++;
+			}
+		}
+
+	// Store leading count
+	aWriteStream.WriteInt32L(count);
+
+	// Store tasks
+	taskIter.SetToFirst();
+	while ((task=taskIter++)!=NULL)
+		{
+		if(task->Persists())
+		  {
+		  aWriteStream << *task;
+		  }
+		}
+
+	LOGSTRING("CClientProxy::ExternalizeL - end");
+	}
+
+
+TDblQueIter<CScheduledTask> CClientProxy::TaskIterator()
+	{
+	return TDblQueIter<CScheduledTask>(iTasks);
+	}
+
+
+