Created
September 19, 2012 18:04
-
-
Save whitelynx/3751181 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Deferred<T> | |
{ | |
protected Logger logger = null; | |
protected EventWaitHandle waitForResult = null; | |
protected HashSet<Deferred<T>> dependentDeferreds = null; | |
public string name | |
{ | |
get | |
{ | |
return _name; | |
} // end get | |
set | |
{ | |
_name = value; | |
if(_name != null) | |
{ | |
logger = LogManager.GetLogger(String.Format("Deferred[{0}]", _name)); | |
} | |
else | |
{ | |
logger = LogManager.GetLogger("Deferred"); | |
} // end if | |
} // end set | |
} // end name | |
private string _name = null; | |
public bool isfinished | |
{ | |
get | |
{ | |
return waitForResult.WaitOne(0); | |
} // end get | |
} // end iserror | |
protected Boolean iserror_ = false; | |
public bool iserror | |
{ | |
get | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
return iserror_; | |
} | |
else | |
{ | |
return false; | |
} // end if | |
} // end get | |
} // end iserror | |
public bool issuccess | |
{ | |
get | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
return !iserror_; | |
} | |
else | |
{ | |
return false; | |
} // end if | |
} // end get | |
} // end issuccess | |
public DeferredStatus status | |
{ | |
get | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
if(iserror_) | |
{ | |
return DeferredStatus.Failed; | |
} | |
else | |
{ | |
return DeferredStatus.Succeeded; | |
} // end if | |
} | |
else | |
{ | |
return DeferredStatus.InProgress; | |
} // end if | |
} // end get | |
} // end status | |
public T result | |
{ | |
get | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
lock(waitForResult) | |
{ | |
return result_; | |
} // end lock | |
} | |
else | |
{ | |
return default(T); | |
} // end if | |
} // end get | |
} // end result | |
protected T result_ = default(T); | |
public string message | |
{ | |
get | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
lock(waitForResult) | |
{ | |
return message_; | |
} // end lock | |
} | |
else | |
{ | |
return null; | |
} // end if | |
} // end get | |
} // end message | |
protected string message_ = ""; | |
protected virtual event EventHandler<DeferredEventArgs<T>> callback_ = delegate { }; | |
protected virtual event EventHandler<DeferredEventArgs<T>> errback_ = delegate { }; | |
public event EventHandler<DeferredEventArgs<T>> callback | |
{ | |
add | |
{ | |
callback_ += value; | |
if(waitForResult.WaitOne(0) && !iserror) | |
{ | |
value(this, new DeferredEventArgs<T>(this)); | |
} // end if | |
} // end add | |
remove | |
{ | |
callback_ -= value; | |
} // end remove | |
} // end callback | |
public event EventHandler<DeferredEventArgs<T>> errback | |
{ | |
add | |
{ | |
errback_ += value; | |
if(waitForResult.WaitOne(0) && iserror) | |
{ | |
value(this, new DeferredEventArgs<T>(this)); | |
} // end if | |
} // end add | |
remove | |
{ | |
errback_ -= value; | |
} // end remove | |
} // end errback | |
public event EventHandler<DeferredEventArgs<T>> onFinished | |
{ | |
add | |
{ | |
callback += value; | |
errback += value; | |
} // end add | |
remove | |
{ | |
callback -= value; | |
errback -= value; | |
} // end remove | |
} // end onFinished | |
public Deferred() : this(null) | |
{ | |
} // end Deferred | |
public Deferred(string name, params object[] args) : this(new HashSet<Deferred<T>>(), name, args) | |
{ | |
} // end Deferred | |
protected Deferred(HashSet<Deferred<T>> dependentDeferredSet, string name, params object[] args) | |
{ | |
this.name = name; | |
if(args.Length > 0) | |
{ | |
this.name = String.Format(name, args); | |
} // end if | |
waitForResult = new ManualResetEvent(false); | |
dependentDeferreds = dependentDeferredSet; | |
} // end Deferred | |
public static Deferred<T> createSucceeded(T val, string message = null) | |
{ | |
Deferred<T> def = new Deferred<T>(); | |
return def.succeed(val, message); | |
} // end createSucceeded | |
public static Deferred<T> createFailed(string message) | |
{ | |
Deferred<T> def = new Deferred<T>(); | |
return def.fail(message); | |
} // end createFailed | |
public void succeedOn(Deferred<T> other) | |
{ | |
other.callback += chainCallback; | |
other.errback += chainErrback; | |
} // end succeedOn | |
public void allOf(params Deferred<T>[] others) | |
{ | |
// First, add each deferred to our list of dependencies. | |
lock(dependentDeferreds) | |
{ | |
foreach(Deferred<T> other in others) | |
{ | |
dependentDeferreds.Add(other); | |
} // end foreach | |
} // end lock | |
// Next, add callbacks to each so we get notified when they succeed or fail. | |
//NOTE: We don't want to do this in the above foreach, because otherwise we might succeed early if any | |
// Deferred other than the last has already succeeded. | |
foreach(Deferred<T> other in others) | |
{ | |
try | |
{ | |
logger.Debug("allOf: Adding Deferred {0} to list of dependencies.", other); | |
other.callback += checkDependencies; | |
other.errback += chainErrback; | |
} | |
catch(NullReferenceException ex) | |
{ | |
logger.ErrorException("Got null Deferred<T> while adding dependencies!", ex); | |
throw; | |
} // end catch | |
} // end foreach | |
} // end allOf | |
public void chainCallback(object source, DeferredEventArgs<T> args) | |
{ | |
succeed(args.deferred.result, args.deferred.message); | |
} // end chainCallback | |
public void chainErrback(object source, DeferredEventArgs<T> args) | |
{ | |
fail(args.deferred.message); | |
} // end chainErrback | |
public virtual Deferred<T> succeed(T result, string message = null) | |
{ | |
lock(waitForResult) | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
logger.Error("Deferred already finished! Ignoring succeed({0}, {1}) call.", result, message); | |
return this; | |
} // end if | |
logger.Debug("succeed({0}, {1})", result, message); | |
message_ = message; | |
result_ = result; | |
iserror_ = false; | |
waitForResult.Set(); | |
} // end lock | |
//TODO: Threading? | |
callback_(this, new DeferredEventArgs<T>(this)); | |
return this; | |
} // end succeed | |
public virtual Deferred<T> fail(string message) | |
{ | |
lock(waitForResult) | |
{ | |
if(waitForResult.WaitOne(0)) | |
{ | |
logger.Error("Deferred already finished! Ignoring fail({0}) call.", message); | |
return this; | |
} // end if | |
logger.Debug("fail({0})", message); | |
message_ = message; | |
iserror_ = true; | |
waitForResult.Set(); | |
} // end lock | |
//TODO: Threading? | |
errback_(this, new DeferredEventArgs<T>(this)); | |
return this; | |
} // end fail | |
public override string ToString() | |
{ | |
if(name == null) | |
{ | |
return String.Format("{0}<{1}>", GetType(), GetHashCode()); | |
} | |
else | |
{ | |
return String.Format("{0}[{1}]<{2}>", GetType(), name, GetHashCode()); | |
} // end if | |
} // end ToString | |
public bool waitForSuccess() | |
{ | |
if(waitForResult.WaitOne()) | |
{ | |
return !iserror_; | |
} | |
else | |
{ | |
return false; | |
} // end if | |
} // end issuccess | |
public bool waitForSuccess(TimeSpan timeout) | |
{ | |
if(waitForResult.WaitOne(timeout)) | |
{ | |
return !iserror_; | |
} | |
else | |
{ | |
return false; | |
} // end if | |
} // end issuccess | |
private void checkDependencies(object source, DeferredEventArgs<T> args) | |
{ | |
lock(dependentDeferreds) | |
{ | |
foreach(Deferred<T> def in dependentDeferreds) | |
{ | |
switch(def.status) | |
{ | |
case DeferredStatus.Failed: | |
logger.Debug("{0}.checkDependencies: {1} failed.", this, def); | |
return; | |
case DeferredStatus.InProgress: | |
logger.Debug("{0}.checkDependencies: {1} is not yet finished.", this, def); | |
return; | |
case DeferredStatus.Succeeded: | |
default: | |
break; | |
} // end switch | |
} // end foreach | |
} // end lock | |
if(args != null) | |
{ | |
succeed(args.deferred.result, args.deferred.message); | |
} | |
else | |
{ | |
succeed(default(T)); | |
} // end if | |
} // end checkDependencies | |
} // end Deferred |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment