crashanalysercmd/Libraries/Engine/CrashItemLib/Engine/CIEngine.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/Libraries/Engine/CrashItemLib/Engine/CIEngine.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,567 @@
+/*
+* Copyright (c) 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:
+*
+*/
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using SymbianDebugLib.Engine;
+using SymbianUtils;
+using SymbianUtils.Tracer;
+using SymbianUtils.Threading;
+using SymbianUtils.FileSystem;
+using CrashItemLib.Crash.Base;
+using CrashItemLib.Crash.Container;
+using CrashItemLib.Engine.Interfaces;
+using CrashItemLib.Engine.Operations;
+using CrashItemLib.Engine.Primer;
+using CrashItemLib.Engine.ProblemDetectors;
+using CrashItemLib.Engine.Sources;
+using CrashItemLib.PluginAPI;
+using CrashItemLib.Sink;
+
+namespace CrashItemLib.Engine
+{
+    public class CIEngine : DisposableObject, IEnumerable<CIContainer>, ITracer
+    {
+        #region Enumerations
+        public enum TState
+        {
+            // We've started to process the crash sources
+            EStateProcessingStarted = 0,
+
+            // Engine is idle & fully ready for display & output
+            EStateProcessingComplete
+        }
+
+        public enum TSourceEvent
+        {
+            EEventSourceReady = 0,
+            EEventSourceProgress,
+            EEventSourceStateChanged
+        }
+
+        public enum TCrashEvent
+        {
+            EEventCrashAdded = 0,
+            EEventCrashRemoved,
+            EEventCrashRemovedAll
+        }
+        #endregion
+
+        #region Delegates & events
+        public delegate void CIEngineStateHandler( TState aEvent );
+        public event CIEngineStateHandler StateChanged = delegate( TState aState ) { };
+
+        public delegate void CIEngineSourceObserver( TSourceEvent aEvent, CIEngineSource aSource, object aParameter );
+        public event CIEngineSourceObserver SourceObservers = delegate( TSourceEvent aEvent, CIEngineSource aSource, object aParameter ) { };
+
+        public delegate void CIEngineCrashObserver( TCrashEvent aEvent, CIContainer aContainer );
+        public event CIEngineCrashObserver CrashObservers;
+
+        public delegate void CIExceptionHandler( Exception aException );
+        public event CIExceptionHandler ExceptionHandlers = delegate( Exception aException ) { };
+        #endregion
+
+        #region Constructors
+        public CIEngine( DbgEngine aDebugEngine, ICIEngineUI aUI )
+        {
+            iUI = aUI;
+            iDebugEngine = aDebugEngine;
+            //
+            iPrimer = new CIEnginePrimer( this );
+            iPlugins = new CFFPluginRegistry( this );
+            iSinkManager = new CISinkManager( this );
+            iSources = new CIEngineSourceCollection( this );
+            iContainerIndex = new CIContainerIndex( this );
+            iContainerCollection = new CIContainerCollection();
+            iOperationManager = new CIEngineOperationManager( this );
+            iProblemDetectorManager = new CIProblemDetectorManager( this );
+        }
+        #endregion
+
+        #region API
+        public void ClearAll()
+        {
+            lock ( iSources )
+            {
+                iSources.Clear();
+            }
+            ClearCrashes();
+        }
+
+        public void ClearCrashes()
+        {
+            bool notify = true;
+            lock ( iContainerCollection )
+            {
+                notify = iContainerCollection.Count > 0;
+                iContainerCollection.Clear();
+            }
+            //
+            if ( notify )
+            {
+                OnContainerRemovedAll();
+            }
+        }
+
+        public bool Prime( FileInfo aFile )
+        {
+            bool success = false;
+            //
+            try
+            {
+                success = iPrimer.Prime( aFile );
+            }
+            catch ( Exception )
+            {
+            }
+            //
+            return success;
+        }
+
+        public bool Prime( DirectoryInfo aDirectory )
+        {
+            bool success = false;
+            //
+            try
+            {
+                iPrimer.Prime( aDirectory );
+                success = true;
+            }
+            catch ( Exception )
+            {
+            }
+            //
+            return success;
+        }
+
+        public bool PrimeRecursive( DirectoryInfo aDirectory )
+        {
+            bool success = false;
+            //
+            try
+            {
+                iPrimer.PrimeRecursive( aDirectory );
+                success = true;
+            }
+            catch ( Exception )
+            {
+            }
+            //
+            return success;
+        }
+
+        public void IdentifyCrashes( TSynchronicity aSynchronicity )
+        {
+            // If we must operate in synchronous mode, that is, we must not
+            // return until the all the crash item containers are prepared,
+            // then we created a blocking object that will be signalled when
+            // all the asynchronous operations are complete.
+            DestroyBlocker();
+            if ( aSynchronicity == TSynchronicity.ESynchronous )
+            {
+                iSynchronousBlocker = new ManualResetEvent( false );
+            }
+
+            // Next, we start processing the source files in order to create
+            // crash containers.
+            DestroySourceProcessor();
+            iSourceProcessor = new CIEngineSourceProcessor( iSources );
+            iSourceProcessor.EventHandler += new CIEngineSourceProcessor.ProcessorEventHandler( SourceProcessor_EventHandler );
+            iSourceProcessor.Start( TSynchronicity.EAsynchronous );
+
+            // Now we operate asynchronously. When the source processor has read
+            // all of the CIEngineSource objects, it will trigger and event
+            // callback (SourceProcessor_EventHandler) which will cause us to start
+            // the serialized operation manager.
+            //
+            // When the serialized operation manager completes, it will again indicate
+            // this via an event callback at which point we will trigger the manual
+            // reset event (blocker) and therefore resume this main thread.
+            if ( aSynchronicity == TSynchronicity.ESynchronous )
+            {
+                // Now wait. 
+                using ( iSynchronousBlocker )
+                {
+                    iSynchronousBlocker.WaitOne();
+                }
+                iSynchronousBlocker = null;
+            }
+        }
+        #endregion
+
+        #region Properties
+        public int Count
+        {
+            get
+            {
+                lock ( iContainerCollection )
+                {
+                    return iContainerCollection.Count;
+                }
+            }
+        }
+
+        public CIContainer this[ int aIndex ]
+        {
+            get
+            {
+                lock ( iContainerCollection )
+                {
+                    return iContainerCollection[ aIndex ];
+                }
+            }
+        }
+
+        public DbgEngine DebugEngine
+        {
+            get { return iDebugEngine; }
+        }
+
+        public CISinkManager SinkManager
+        {
+            get { return iSinkManager; }
+        }
+
+        public CFFPluginRegistry PluginRegistry
+        {
+            get { return iPlugins; }
+        }
+
+        public CIEngineSourceCollection Sources
+        {
+            get { return iSources; }
+        }
+        #endregion
+
+        #region Event handlers
+        private void SourceProcessor_EventHandler( CIEngineSourceProcessor.TEvent aEvent )
+        {
+            this.Trace( "[CIEngine] SourceProcessor_EventHandler() - START - aEvent: {0}", aEvent );
+            //
+            if ( aEvent == CIEngineSourceProcessor.TEvent.EEventStarting )
+            {
+                OnStateChanged( TState.EStateProcessingStarted );
+                ClearCrashes();
+            }
+            else if ( aEvent == CIEngineSourceProcessor.TEvent.EEventCompleted )
+            {
+                DestroySourceProcessor();
+                //
+                DestroyIndexProcessor();
+                iIndexProcessor = new CIContainerIndexProcessor( iContainerIndex, this );
+                iIndexProcessor.EventHandler += new CIContainerIndexProcessor.ProcessorEventHandler( IndexProcessor_EventHandler );
+                iIndexProcessor.Start( TSynchronicity.EAsynchronous );
+            }
+            //
+            this.Trace( "[CIEngine] SourceProcessor_EventHandler() - END - aEvent: {0}", aEvent );
+        }
+
+        private void IndexProcessor_EventHandler( CIContainerIndexProcessor.TEvent aEvent )
+        {
+            this.Trace( "[CIEngine] IndexProcessor_EventHandler() - START - aEvent: {0}", aEvent );
+            //
+            if ( aEvent == CIContainerIndexProcessor.TEvent.EEventStarting )
+            {
+            }
+            else if ( aEvent == CIContainerIndexProcessor.TEvent.EEventCompleted )
+            {
+                DestroyIndexProcessor();
+   
+                // All the sources have been processed. Create any problem detectors.
+                iProblemDetectorManager.EventHandler += new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler );
+                iProblemDetectorManager.Start( TSynchronicity.EAsynchronous );
+            }
+            //
+            this.Trace( "[CIEngine] IndexProcessor_EventHandler() - END - aEvent: {0}", aEvent );
+        }
+
+        private void ProblemDetectorManager_EventHandler( MultiThreadedProcessor<CIProblemDetector>.TEvent aEvent )
+        {
+            this.Trace( "[CIEngine] ProblemDetectorManager_EventHandler() - START - aEvent: {0}", aEvent );
+            //
+            if ( aEvent == MultiThreadedProcessor<CIProblemDetector>.TEvent.EEventStarting )
+            {
+            }
+            else if ( aEvent == MultiThreadedProcessor<CIProblemDetector>.TEvent.EEventCompleted )
+            {
+                iProblemDetectorManager.EventHandler -= new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler );
+
+                // Run any serialized operations
+                iOperationManager.StateHandler += new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler );
+                iOperationManager.Start();
+            }
+            //
+            this.Trace( "[CIEngine] ProblemDetectorManager_EventHandler() - END - aEvent: {0}", aEvent );
+        }
+     
+        private void OperationManager_StateHandler( CIEngineOperationManager.TState aState )
+        {
+            this.Trace( "[CIEngine] OperationManager_StateHandler() - START - aState: {0}", aState );
+            //
+            if ( aState == SymbianUtils.SerializedOperations.SerializedOperationManager.TState.EStateOperationsCompleted )
+            {
+                iOperationManager.StateHandler -= new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler );
+                //
+                IdentifyCrashesComplete();
+            }
+            //
+            this.Trace( "[CIEngine] OperationManager_StateHandler() - END - aState: {0}", aState );
+        }
+        #endregion
+
+        #region Internal delegates
+        private delegate void VoidHandler();
+        #endregion
+
+        #region Internal methods
+        internal void Add( CIContainer aContainer )
+        {
+            string fileName = aContainer.Source.MasterFileName;
+            if ( string.IsNullOrEmpty( fileName ) )
+            {
+                throw new ArgumentException( "Container source file name cannot be empty" );
+            }
+            //
+            lock ( iContainerCollection )
+            {
+                iContainerCollection.Add( aContainer );
+            }
+            //
+            if ( CrashObservers != null )
+            {
+                CrashObservers( TCrashEvent.EEventCrashAdded, aContainer );
+            }
+        }
+
+        internal int GetNextElementId()
+        {
+            return iIdProvider.GetNextId();
+        }
+        
+        internal void QueueOperation( CIEngineOperation aOperation )
+        {
+            this.Trace( "[CIEngine] QueueOperation() - aOperation: {0} ({1})", aOperation, aOperation.GetType() );
+            iOperationManager.Queue( aOperation );
+        }
+
+        internal void OnSourceStateChanged( CIEngineSource aSource )
+        {
+            this.Trace( "[CIEngine] OnSourceStateChanged() - START - aSource: {0}, aSource.IsReady: {1}, aSource.State: {2}", aSource.FileName, aSource.IsReady, aSource.State );
+            
+            SourceObservers( TSourceEvent.EEventSourceStateChanged, aSource, null );
+            if ( aSource.IsReady )
+            {
+                SourceObservers( TSourceEvent.EEventSourceReady, aSource, null );
+            }
+
+            this.Trace( "[CIEngine] OnSourceStateChanged() - END - aSource: {0}, aSource.IsReady: {1}, aSource.State: {2}", aSource.FileName, aSource.IsReady, aSource.State );
+        }
+
+        internal void OnSourceProgress( CIEngineSource aSource, int aProgress )
+        {
+            this.Trace( "[CIEngine] OnSourceProgress() - START - aSource: {0}, aSource.IsReady: {1}, aProgress: {2}", aSource.FileName, aSource.IsReady, aProgress );
+
+            SourceObservers( TSourceEvent.EEventSourceProgress, aSource, aProgress );
+
+            this.Trace( "[CIEngine] OnSourceProgress() - END - aSource: {0}, aSource.IsReady: {1}, aProgress: {2}", aSource.FileName, aSource.IsReady, aProgress );
+        }
+
+        internal void OnException( Exception aException )
+        {
+            this.Trace( "[CIEngine] OnException() - {0} / {1}", aException.Message, aException.StackTrace );
+            ExceptionHandlers( aException );
+        }
+
+        internal void OnContainerRemovedAll()
+        {
+            if ( CrashObservers != null )
+            {
+                CrashObservers( TCrashEvent.EEventCrashRemovedAll, null );
+            }
+        }
+
+        private void Remove( CIContainer aContainer )
+        {
+            lock ( iContainerCollection )
+            {
+                if ( iContainerCollection.Contains( aContainer ) )
+                {
+                    iContainerCollection.Remove( aContainer );
+                    if ( CrashObservers != null )
+                    {
+                        CrashObservers( TCrashEvent.EEventCrashRemoved, aContainer );
+                    }
+                }
+            }
+        }
+
+        private void OnStateChanged( TState aEvent )
+        {
+            this.Trace( "[CIEngine] OnStateChanged() - START - aEvent: {0}", aEvent );
+            if ( StateChanged != null )
+            {
+                StateChanged( aEvent );
+            }
+            this.Trace( "[CIEngine] OnStateChanged() - END - aEvent: {0}", aEvent );
+        }
+
+        private void IdentifyCrashesComplete()
+        {
+            this.Trace( "[CIEngine] IdentifyCrashesComplete()" );
+            OnStateChanged( TState.EStateProcessingComplete );
+            //
+            ReleaseBlocker();
+        }
+
+        private void DestroyBlocker()
+        {
+            if ( iSynchronousBlocker != null )
+            {
+                iSynchronousBlocker.Close();
+                iSynchronousBlocker = null;
+            }
+        }
+
+        private void ReleaseBlocker()
+        {
+            if ( iSynchronousBlocker != null )
+            {
+                iSynchronousBlocker.Set();
+            }
+        }
+
+        private void DestroySourceProcessor()
+        {
+            if ( iSourceProcessor != null )
+            {
+                iSourceProcessor.EventHandler -= new CIEngineSourceProcessor.ProcessorEventHandler( SourceProcessor_EventHandler );
+                iSourceProcessor.Dispose();
+                iSourceProcessor = null;
+            }
+        }
+
+        private void DestroyIndexProcessor()
+        {
+            if ( iIndexProcessor != null )
+            {
+                iIndexProcessor.EventHandler -= new CIContainerIndexProcessor.ProcessorEventHandler( IndexProcessor_EventHandler );
+                iIndexProcessor = null;
+            }
+        }
+
+        private void DestroyProblemDetectorManager()
+        {
+            if ( iProblemDetectorManager != null )
+            {
+                iProblemDetectorManager.EventHandler -= new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler );
+                iProblemDetectorManager.Dispose();
+            }
+        }
+
+        private void DestroyOperationManager()
+        {
+            if ( iOperationManager != null )
+            {
+                iOperationManager.StateHandler -= new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler );
+                iOperationManager.Dispose();
+            }
+        }
+        #endregion
+
+        #region Internal properties
+        internal ICIEngineUI UI
+        {
+            get { return iUI; }
+        }
+        #endregion
+
+        #region From System.Object
+        #endregion
+
+        #region From ITracer 
+        public void Trace( string aMessage )
+        {
+            UI.CITrace( aMessage );
+        }
+
+        public void Trace( string aFormat, params object[] aParams )
+        {
+            UI.CITrace( aFormat, aParams );
+        }
+        #endregion
+
+        #region From IEnumerable<CIContainer>
+        public IEnumerator<CIContainer> GetEnumerator()
+        {
+            lock ( iContainerCollection )
+            {
+                foreach ( CIContainer container in iContainerCollection )
+                {
+                    yield return container;
+                }
+            }
+        }
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            lock ( iContainerCollection )
+            {
+                foreach ( CIContainer container in iContainerCollection )
+                {
+                    yield return container;
+                }
+            }
+        }
+        #endregion
+
+        #region From DisposableObject
+        protected override void CleanupManagedResources()
+        {
+            try
+            {
+                base.CleanupManagedResources();
+            }
+            finally
+            {
+                DestroyIndexProcessor();
+                DestroySourceProcessor();
+                DestroyProblemDetectorManager();
+                DestroyOperationManager();
+                DestroyBlocker();
+            }
+        }
+        #endregion
+
+        #region Data members
+        private readonly DbgEngine iDebugEngine;
+        private readonly ICIEngineUI iUI;
+        private readonly CIEnginePrimer iPrimer;
+        private readonly CISinkManager iSinkManager;
+        private readonly CFFPluginRegistry iPlugins;
+        private readonly CIEngineSourceCollection iSources;
+        private readonly CIContainerCollection iContainerCollection;
+        private readonly CIEngineOperationManager iOperationManager;
+        private readonly CIProblemDetectorManager iProblemDetectorManager;
+        private readonly CIContainerIndex iContainerIndex;
+        private ManualResetEvent iSynchronousBlocker = null;
+        private CIEngineSourceProcessor iSourceProcessor = null;
+        private CIContainerIndexProcessor  iIndexProcessor = null;
+        private CIElementIdProvider iIdProvider = new CIElementIdProvider();
+		#endregion
+    }
+}