##// END OF EJS Templates
working on runnable component
working on runnable component

File last commit:

r184:d6a8cba73acc ref20160224
r184:d6a8cba73acc ref20160224
Show More
RunnableComponent.cs
195 lines | 5.5 KiB | text/x-csharp | CSharpLexer
using System;
using Implab.Formats;
namespace Implab.Components {
public class RunnableComponent : Disposable, IRunnable, IInitializable {
enum Commands {
Ok = 0,
Fail,
Init,
Start,
Stop,
Dispose,
Last = Dispose
}
class StateMachine {
static readonly ExecutionState[,] _transitions;
static StateMachine() {
_transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
Edge(ExecutionState.Created, ExecutionState.Ready, Commands.Ok);
Edge(ExecutionState.Created, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose);
}
static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
_transitions[(int)s1, (int)cmd] = s2;
}
public ExecutionState State {
get;
private set;
}
public StateMachine(ExecutionState initial) {
State = initial;
}
public bool Move(Commands cmd) {
var next = _transitions[(int)State, (int)cmd];
if (next == ExecutionState.Undefined)
return false;
State = next;
return true;
}
}
IPromise m_pending;
Exception m_lastError;
readonly StateMachine m_stateMachine;
protected RunnableComponent(bool initialized) {
m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
}
void ThrowInvalidCommand(Commands cmd) {
throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
}
protected void Move(Commands cmd) {
lock (m_stateMachine)
if (!m_stateMachine.Move(cmd))
ThrowInvalidCommand(cmd);
}
protected void Fail(Exception err) {
lock (m_stateMachine) {
if (!m_stateMachine.Move(Commands.Fail))
ThrowInvalidCommand(Commands.Fail);
m_lastError = err;
}
}
protected void Success() {
Move(Commands.Ok);
}
protected void Invoke(Commands cmd, Action action) {
Move(cmd);
try {
action();
Move(Commands.Ok);
} catch (Exception err) {
Fail(err);
throw;
}
}
protected IPromise InvokeAsync(Commands cmd, Func<IPromise> action) {
Move(cmd);
var medium = new Promise();
IPromise promise = null;
promise = medium.Then(
() => {
lock(m_stateMachine) {
if (m_pending == promise) {
m_pending = null;
Move(Commands.Ok);
}
}
}, e => {
if (m_pending == promise) {
m_pending = null;
Fail(
}
}
);
return Safe.InvokePromise(action).Then(
Success,
Fail
);
}
void AddPending(IPromise result) {
}
#region IInitializable implementation
public void Init() {
Invoke(Commands.Init, OnInitialize);
}
protected virtual void OnInitialize() {
}
#endregion
#region IRunnable implementation
public IPromise Start() {
Move(Commands.Start);
return Safe.InvokePromise(OnStart).Then(
() => {
Move(Commands.Ok);
Run();
},
() => {
Move(Commands.Fail);
}
);
}
protected virtual IPromise OnStart() {
return Promise.SUCCESS;
}
protected virtual void Run() {
}
public IPromise Stop() {
throw new NotImplementedException();
}
public ExecutionState State {
get {
throw new NotImplementedException();
}
}
public Exception LastError {
get {
throw new NotImplementedException();
}
}
#endregion
}
}