##// END OF EJS Templates
working on runnable component
cin -
r184:d6a8cba73acc ref20160224
parent child
Show More
@@ -1,88 +1,88
1 1 using NUnit.Framework;
2 2 using System;
3 3 using Implab.Formats.JSON;
4 4 using Implab.Automaton;
5 5
6 6 namespace Implab.Format.Test {
7 7 [TestFixture]
8 8 public class JsonTests {
9 9 [Test]
10 10 public void TestScannerValidTokens() {
11 11 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
12 12
13 Tuple<JsonTokenType,object>[] expexted = new [] {
13 Tuple<JsonTokenType,object>[] expexted = {
14 14 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
15 15 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
16 16 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
17 17 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
18 18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
19 19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
20 20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
21 21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
22 22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
23 23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
24 24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
25 25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
26 26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
27 27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
28 28 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
29 29 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
30 30 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
31 31 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
32 32 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
33 33 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
34 34 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
35 35 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
36 36 };
37 37
38 38 object value;
39 39 JsonTokenType tokenType;
40 40 for (var i = 0; i < expexted.Length; i++) {
41 41
42 42 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
43 43 Assert.AreEqual(expexted[i].Item1, tokenType);
44 44 Assert.AreEqual(expexted[i].Item2, value);
45 45 }
46 46
47 47 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
48 48 }
49 49 }
50 50
51 51 [Test]
52 52 public void TestScannerBadTokens() {
53 53 var bad = new [] {
54 54 " 1",
55 55 " literal",
56 56 " \"",
57 57 "\"unclosed string",
58 58 "1.bad",
59 59 "001", // should be read as three numbers
60 60 "--10",
61 61 "+10",
62 62 "1.0.0",
63 63 "1e1.0",
64 64 "l1teral0",
65 65 ".123",
66 66 "-.123"
67 67 };
68 68
69 69 foreach (var json in bad)
70 70 using (var scanner = new JSONScanner(json)) {
71 71 try {
72 72 object value;
73 73 JsonTokenType token;
74 74 scanner.ReadToken(out value, out token);
75 75 if (!Object.Equals(value,json)) {
76 76 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
77 77 continue;
78 78 }
79 79 Assert.Fail("Token '{0}' shouldn't pass", json);
80 80 } catch (ParserException e) {
81 81 Console.WriteLine(e.Message);
82 82 }
83 83 }
84 84
85 85 }
86 86 }
87 87 }
88 88
@@ -1,14 +1,24
1 1 namespace Implab.Components {
2 2
3 3 public enum ExecutionState {
4 Reserved = 0,
5 Uninitialized,
4 Undefined = 0,
5
6 Created,
7
8 Initializing,
9
6 10 Ready,
11
7 12 Starting,
13
8 14 Running,
15
9 16 Stopping,
10 Stopped,
17
18 Failed,
19
11 20 Disposed,
12 Failed
21
22 Last = Disposed
13 23 }
14 24 } No newline at end of file
@@ -1,21 +1,21
1 1 using System;
2 2
3 3 namespace Implab.Components {
4 4 /// <summary>
5 5 /// Initializable components are created and initialized in two steps, first we have create the component,
6 6 /// then we have to complete it's creation by calling an <see cref="Init()"/> method. All parameters needed
7 7 /// to complete the initialization must be passed before the calling <see cref="Init()"/>
8 8 /// </summary>
9 9 public interface IInitializable {
10 10 /// <summary>
11 11 /// Completes initialization.
12 12 /// </summary>
13 13 /// <remarks>
14 /// Normally virtual shouldn't be called from the constructor, due to the incomplete object state, but
14 /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but
15 15 /// they can be called from this method. This method is also usefull when we constructing a complex grpah
16 16 /// of components where cyclic references may take place.
17 17 /// </remarks>
18 18 void Init();
19 19 }
20 20 }
21 21
@@ -1,58 +1,195
1 1 using System;
2 2 using Implab.Formats;
3 3
4 4 namespace Implab.Components {
5 5 public class RunnableComponent : Disposable, IRunnable, IInitializable {
6
6 enum Commands {
7 Ok = 0,
8 Fail,
9 Init,
10 Start,
11 Stop,
12 Dispose,
13 Last = Dispose
14 }
15
16 class StateMachine {
17 static readonly ExecutionState[,] _transitions;
18
19 static StateMachine() {
20 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
21
22 Edge(ExecutionState.Created, ExecutionState.Ready, Commands.Ok);
23 Edge(ExecutionState.Created, ExecutionState.Failed, Commands.Fail);
24
25 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
26 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
27
28 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
29 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
30 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
31 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
32
33 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
34 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
35 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
36
37 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
38 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
39 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose);
40 }
41
42 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
43 _transitions[(int)s1, (int)cmd] = s2;
44 }
45
46 public ExecutionState State {
47 get;
48 private set;
49 }
50
51 public StateMachine(ExecutionState initial) {
52 State = initial;
53 }
54
55 public bool Move(Commands cmd) {
56 var next = _transitions[(int)State, (int)cmd];
57 if (next == ExecutionState.Undefined)
58 return false;
59 State = next;
60 return true;
61 }
62 }
63
64 IPromise m_pending;
65 Exception m_lastError;
66
67 readonly StateMachine m_stateMachine;
68
69 protected RunnableComponent(bool initialized) {
70 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
71 }
72
73 void ThrowInvalidCommand(Commands cmd) {
74 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
75 }
76
77 protected void Move(Commands cmd) {
78 lock (m_stateMachine)
79 if (!m_stateMachine.Move(cmd))
80 ThrowInvalidCommand(cmd);
81 }
82
83 protected void Fail(Exception err) {
84 lock (m_stateMachine) {
85 if (!m_stateMachine.Move(Commands.Fail))
86 ThrowInvalidCommand(Commands.Fail);
87
88 m_lastError = err;
89 }
90 }
91
92 protected void Success() {
93 Move(Commands.Ok);
94 }
95
96 protected void Invoke(Commands cmd, Action action) {
97 Move(cmd);
98 try {
99 action();
100 Move(Commands.Ok);
101 } catch (Exception err) {
102 Fail(err);
103 throw;
104 }
105 }
106
107 protected IPromise InvokeAsync(Commands cmd, Func<IPromise> action) {
108 Move(cmd);
109 var medium = new Promise();
110
111 IPromise promise = null;
112
113 promise = medium.Then(
114 () => {
115 lock(m_stateMachine) {
116 if (m_pending == promise) {
117 m_pending = null;
118 Move(Commands.Ok);
119 }
120 }
121 }, e => {
122 if (m_pending == promise) {
123 m_pending = null;
124 Fail(
125 }
126 }
127 );
7 128
8 129
9 130
10
11 IPromise m_pending;
12 Exception m_lastError;
131 return Safe.InvokePromise(action).Then(
132 Success,
133 Fail
134 );
135 }
13 136
14 protected RunnableComponent(bool initialized) {
15
137 void AddPending(IPromise result) {
138
16 139 }
17 140
141
18 142 #region IInitializable implementation
19 143
20 144 public void Init() {
21
145 Invoke(Commands.Init, OnInitialize);
146 }
147
148 protected virtual void OnInitialize() {
22 149 }
23 150
24 151 #endregion
25 152
26 153 #region IRunnable implementation
27 154
28 155 public IPromise Start() {
29 throw new NotImplementedException();
156 Move(Commands.Start);
157
158 return Safe.InvokePromise(OnStart).Then(
159 () => {
160 Move(Commands.Ok);
161 Run();
162 },
163 () => {
164 Move(Commands.Fail);
165 }
166 );
30 167 }
31 168
32 169 protected virtual IPromise OnStart() {
33 170 return Promise.SUCCESS;
34 171 }
35 172
36 173 protected virtual void Run() {
37 174 }
38 175
39 176 public IPromise Stop() {
40 177 throw new NotImplementedException();
41 178 }
42 179
43 180 public ExecutionState State {
44 181 get {
45 182 throw new NotImplementedException();
46 183 }
47 184 }
48 185
49 186 public Exception LastError {
50 187 get {
51 188 throw new NotImplementedException();
52 189 }
53 190 }
54 191
55 192 #endregion
56 193 }
57 194 }
58 195
General Comments 0
You need to be logged in to leave comments. Login now