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