#region CPL License /* Nuclex Framework Copyright (C) 2002-2008 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; namespace Nuclex.Support.Tracking { /// Extended type of progression that is able to fail /// /// /// If the background process fails, the exception that caused it to fail is /// communicated to all parties waiting on the progression through the /// Exception property. Implementers should place their code in try..catch /// blocks and call SetException() to temporarily store the exception for /// retrieval by the caller(s). /// /// /// As with all progressions, the interface contract still requires you to call /// OnAsyncEnded(), no matter what the outcome of your background operation is. /// /// public abstract class Request : Waitable { #region class EndedDummyRequest /// Dummy request that is always in the ended state private class EndedDummyRequest : Request { /// Creates a new successfully completed dummy request public EndedDummyRequest() : this(null) { } /// Creates a new failed dummy request /// Exception that caused the dummy to fail public EndedDummyRequest(Exception exception) { this.exception = exception; OnAsyncEnded(); } /// /// Allows the specific request implementation to re-throw an exception if /// the background process finished unsuccessfully /// protected override void ReraiseExceptions() { if(this.exception != null) throw this.exception; } /// Exception that supposedly caused the request to fail private Exception exception; } #endregion // EndedDummyRequest /// Creates a new failed dummy request /// Exception that supposedly caused the request to fail /// /// A failed request that reports the provided exception as cause for its failure /// public static Request CreateFailedDummy(Exception exception) { return new EndedDummyRequest(exception); } /// Waits for the background operation to end /// /// Any exceptions raised in the background operation will be thrown /// in this method. If you decide to override this method, you should /// call End() first (and let any possible exception through to your /// caller). /// public virtual void Join() { // If the progression itself hasn't ended yet, block the caller until it has. // We could just use WaitHandle.WaitOne() here, but since the WaitHandle is created // on-the-fly only when it is requested, we can avoid the WaitHandle creation in // case the request is already finished! if(!Ended) Wait(); // Allow the implementor to throw an exception in case an error has occured ReraiseExceptions(); } /// /// Allows the specific request implementation to re-throw an exception if /// the background process finished unsuccessfully /// protected virtual void ReraiseExceptions() { } } /// Request providing a result that can be passed to the caller /// /// Type of the result being provided by the request /// public abstract class Request : Request { #region class EndedDummyRequest /// Dummy request that is always in the ended state private class EndedDummyRequest : Request { /// Creates a new failed dummy request /// Exception that caused the dummy to fail public EndedDummyRequest(Exception exception) { this.exception = exception; OnAsyncEnded(); } /// /// Allows the specific request implementation to re-throw an exception if /// the background process finished unsuccessfully /// protected override ResultType GatherResults() { throw this.exception; } /// Exception that supposedly caused the request to fail private Exception exception; } #endregion // EndedDummyRequest /// Creates a new failed dummy request /// Exception that supposedly caused the request to fail /// /// A failed request that reports the provided exception as cause for its failure /// public static new Request CreateFailedDummy(Exception exception) { return new EndedDummyRequest(exception); } /// Waits for the background operation to end /// /// Any exceptions raised in the background operation will be thrown /// in this method. If you decide to override this method, you should /// call End() first (and let any possible exception through to your /// caller). /// public new ResultType Join() { base.Join(); // Return the results of the request return GatherResults(); } /// /// Allows the specific request implementation to re-throw an exception if /// the background process finished unsuccessfully /// protected abstract ResultType GatherResults(); } } // namespace Nuclex.Support.Tracking