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