##// END OF EJS Templates
Code review for RunnableComponent...
cin -
r210:5dc21f6a3222 v2
parent child
Show More
@@ -0,0 +1,52
1 using System;
2 using System.Reflection;
3 using System.Threading;
4 using Implab.Parallels;
5 using Implab.Components;
6
7 #if MONO
8
9 using NUnit.Framework;
10 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
11 using TestMethodAttribute = NUnit.Framework.TestAttribute;
12 using AssertFailedException = NUnit.Framework.AssertionException;
13 #else
14
15 using Microsoft.VisualStudio.TestTools.UnitTesting;
16
17 #endif
18 namespace Implab.Fx.Test {
19 [TestClass]
20 public class StaApartmentTests {
21 [TestMethod]
22 public void CreateDestroyApartment() {
23 var apartment = new StaApartment();
24 try {
25 Assert.IsNotNull(apartment.SyncContext);
26 Assert.Fail();
27 } catch (InvalidOperationException) {
28 // OK
29 }
30
31 apartment.Start().Join();
32 Assert.AreEqual(apartment.State, ExecutionState.Running);
33
34 Assert.IsNotNull(apartment.SyncContext);
35 apartment.Stop().Join();
36
37 Assert.IsTrue(apartment.State == ExecutionState.Disposed);
38 }
39
40 [TestMethod]
41 public void InvokeInApartment() {
42 var apartment = new StaApartment();
43
44 apartment.Start().Join();
45
46 var apType = apartment.Invoke(() => { return Thread.CurrentThread.GetApartmentState(); }).Join();
47 Assert.AreEqual(apType, ApartmentState.STA);
48
49 apartment.Stop().Join();
50 }
51 }
52 }
@@ -0,0 +1,188
1 using Implab.Components;
2 using Implab.Diagnostics;
3 using Implab.Parallels;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Text;
8 using System.Threading;
9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11
12 namespace Implab.Fx {
13 public class StaApartment : RunnableComponent {
14 readonly Thread m_worker;
15 SynchronizationContext m_syncContext;
16 readonly Promise m_threadStarted;
17 readonly Promise m_threadTerminated;
18
19 public StaApartment() : base(true) {
20 m_threadStarted = new Promise();
21 m_threadTerminated = new Promise();
22
23 m_worker = new Thread(WorkerEntry);
24 m_worker.SetApartmentState(ApartmentState.STA);
25 m_worker.IsBackground = true;
26 m_worker.Name = "STA managed aparment";
27 }
28
29 public SynchronizationContext SyncContext {
30 get {
31 if (m_syncContext == null)
32 throw new InvalidOperationException();
33 return m_syncContext;
34 }
35 }
36
37 public IPromise Invoke(Action<ICancellationToken> action) {
38 Safe.ArgumentNotNull(action, "action");
39
40 if (m_syncContext == null)
41 throw new InvalidOperationException();
42 var p = new Promise();
43 var lop = TraceContext.Instance.CurrentOperation;
44
45 m_syncContext.Post(x => {
46 TraceContext.Instance.EnterLogicalOperation(lop, false);
47 try {
48 if (p.CancelOperationIfRequested())
49 return;
50
51 action(p);
52 p.Resolve();
53 } catch (Exception e) {
54 p.Reject(e);
55 } finally {
56 TraceContext.Instance.Leave();
57 }
58 }, null);
59
60 return p;
61 }
62
63 public IPromise<T> Invoke<T>(Func<ICancellationToken, T> action) {
64 Safe.ArgumentNotNull(action, "action");
65
66 if (m_syncContext == null)
67 throw new InvalidOperationException();
68 var p = new Promise<T>();
69 var lop = TraceContext.Instance.CurrentOperation;
70
71 m_syncContext.Post(x => {
72 TraceContext.Instance.EnterLogicalOperation(lop, false);
73 try {
74 if (p.CancelOperationIfRequested())
75 return;
76 p.Resolve(action(p));
77 } catch (Exception e) {
78 p.Reject(e);
79 } finally {
80 TraceContext.Instance.Leave();
81 }
82 }, null);
83
84 return p;
85 }
86
87 public IPromise Invoke(Action action) {
88 Safe.ArgumentNotNull(action, "action");
89
90 if (m_syncContext == null)
91 throw new InvalidOperationException();
92 var p = new Promise();
93 var lop = TraceContext.Instance.CurrentOperation;
94
95 m_syncContext.Post(x => {
96 TraceContext.Instance.EnterLogicalOperation(lop, false);
97 try {
98 if (p.CancelOperationIfRequested())
99 return;
100 action();
101 p.Resolve();
102 } catch (Exception e) {
103 p.Reject(e);
104 } finally {
105 TraceContext.Instance.Leave();
106 }
107 }, null);
108
109 return p;
110 }
111
112 public IPromise<T> Invoke<T>(Func<T> action) {
113 Safe.ArgumentNotNull(action, "action");
114
115 if (m_syncContext == null)
116 throw new InvalidOperationException();
117 var p = new Promise<T>();
118 var lop = TraceContext.Instance.CurrentOperation;
119
120 m_syncContext.Post(x => {
121 TraceContext.Instance.EnterLogicalOperation(lop, false);
122 try {
123 if (p.CancelOperationIfRequested())
124 return;
125 p.Resolve(action());
126 } catch (Exception e) {
127 p.Reject(e);
128 } finally {
129 TraceContext.Instance.Leave();
130 }
131 }, null);
132
133 return p;
134 }
135
136
137 /// <summary>
138 /// Starts the apartment thread
139 /// </summary>
140 /// <returns>Promise which will be fullfiled when the syncronization
141 /// context will be ready to accept tasks.</returns>
142 protected override IPromise OnStart() {
143 m_worker.Start();
144 return m_threadStarted;
145 }
146
147 /// <summary>
148 /// Posts quit message to the message loop of the apartment
149 /// </summary>
150 /// <returns>Promise</returns>
151 protected override IPromise OnStop() {
152 m_syncContext.Post(x => Application.ExitThread(), null);
153 return m_threadTerminated;
154 }
155
156 void WorkerEntry() {
157 m_syncContext = new WindowsFormsSynchronizationContext();
158 SynchronizationContext.SetSynchronizationContext(m_syncContext);
159
160 m_threadStarted.Resolve();
161
162 Application.OleRequired();
163 Application.Run();
164
165 try {
166 OnShutdown();
167 m_threadTerminated.Resolve();
168 } catch(Exception err) {
169 m_threadTerminated.Reject(err);
170 }
171 }
172
173 /// <summary>
174 /// Called from the STA apartment after the message loop is terminated, override this
175 /// method to handle apartment cleanup.
176 /// </summary>
177 protected virtual void OnShutdown() {
178 }
179
180 protected override void Dispose(bool disposing) {
181 if (disposing) {
182 if (!m_threadTerminated.IsResolved)
183 m_syncContext.Post(x => Application.ExitThread(), null);
184 }
185 base.Dispose(disposing);
186 }
187 }
188 }
@@ -1,114 +1,115
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{2F31E405-E267-4195-A05D-574093C21209}</ProjectGuid>
8 <ProjectGuid>{2F31E405-E267-4195-A05D-574093C21209}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Implab.Fx.Test</RootNamespace>
11 <RootNamespace>Implab.Fx.Test</RootNamespace>
12 <AssemblyName>Implab.Fx.Test</AssemblyName>
12 <AssemblyName>Implab.Fx.Test</AssemblyName>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
14 <FileAlignment>512</FileAlignment>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16 <TargetFrameworkProfile />
16 <TargetFrameworkProfile />
17 </PropertyGroup>
17 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 <DebugSymbols>true</DebugSymbols>
19 <DebugSymbols>true</DebugSymbols>
20 <DebugType>full</DebugType>
20 <DebugType>full</DebugType>
21 <Optimize>false</Optimize>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
25 <WarningLevel>4</WarningLevel>
26 <Prefer32Bit>false</Prefer32Bit>
26 <Prefer32Bit>false</Prefer32Bit>
27 </PropertyGroup>
27 </PropertyGroup>
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 <DebugType>pdbonly</DebugType>
29 <DebugType>pdbonly</DebugType>
30 <Optimize>true</Optimize>
30 <Optimize>true</Optimize>
31 <OutputPath>bin\Release\</OutputPath>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>false</Prefer32Bit>
35 <Prefer32Bit>false</Prefer32Bit>
36 </PropertyGroup>
36 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 <DebugSymbols>true</DebugSymbols>
38 <DebugSymbols>true</DebugSymbols>
39 <DebugType>full</DebugType>
39 <DebugType>full</DebugType>
40 <Optimize>false</Optimize>
40 <Optimize>false</Optimize>
41 <OutputPath>bin\Debug\</OutputPath>
41 <OutputPath>bin\Debug\</OutputPath>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 <ErrorReport>prompt</ErrorReport>
43 <ErrorReport>prompt</ErrorReport>
44 <WarningLevel>4</WarningLevel>
44 <WarningLevel>4</WarningLevel>
45 <Prefer32Bit>false</Prefer32Bit>
45 <Prefer32Bit>false</Prefer32Bit>
46 </PropertyGroup>
46 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
48 <DebugType>pdbonly</DebugType>
48 <DebugType>pdbonly</DebugType>
49 <Optimize>true</Optimize>
49 <Optimize>true</Optimize>
50 <OutputPath>bin\Release\</OutputPath>
50 <OutputPath>bin\Release\</OutputPath>
51 <DefineConstants>TRACE</DefineConstants>
51 <DefineConstants>TRACE</DefineConstants>
52 <ErrorReport>prompt</ErrorReport>
52 <ErrorReport>prompt</ErrorReport>
53 <WarningLevel>4</WarningLevel>
53 <WarningLevel>4</WarningLevel>
54 <Prefer32Bit>false</Prefer32Bit>
54 <Prefer32Bit>false</Prefer32Bit>
55 </PropertyGroup>
55 </PropertyGroup>
56 <ItemGroup>
56 <ItemGroup>
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
58 <Reference Include="System" />
58 <Reference Include="System" />
59 <Reference Include="System.Core">
59 <Reference Include="System.Core">
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
61 </Reference>
61 </Reference>
62 <Reference Include="System.Data" />
62 <Reference Include="System.Data" />
63 <Reference Include="System.Drawing" />
63 <Reference Include="System.Drawing" />
64 <Reference Include="System.Windows.Forms" />
64 <Reference Include="System.Windows.Forms" />
65 <Reference Include="System.Xml" />
65 <Reference Include="System.Xml" />
66 <Reference Include="WindowsBase" />
66 <Reference Include="WindowsBase" />
67 </ItemGroup>
67 </ItemGroup>
68 <ItemGroup>
68 <ItemGroup>
69 <Compile Include="Properties\AssemblyInfo.cs" />
69 <Compile Include="Properties\AssemblyInfo.cs" />
70 <Compile Include="OverlayTest.cs" />
70 <Compile Include="OverlayTest.cs" />
71 <Compile Include="Sample\MainForm.cs">
71 <Compile Include="Sample\MainForm.cs">
72 <SubType>Form</SubType>
72 <SubType>Form</SubType>
73 </Compile>
73 </Compile>
74 <Compile Include="Sample\MainForm.Designer.cs">
74 <Compile Include="Sample\MainForm.Designer.cs">
75 <DependentUpon>MainForm.cs</DependentUpon>
75 <DependentUpon>MainForm.cs</DependentUpon>
76 </Compile>
76 </Compile>
77 <Compile Include="Sample\OverlayForm.cs">
77 <Compile Include="Sample\OverlayForm.cs">
78 <SubType>Form</SubType>
78 <SubType>Form</SubType>
79 </Compile>
79 </Compile>
80 <Compile Include="Sample\OverlayForm.Designer.cs">
80 <Compile Include="Sample\OverlayForm.Designer.cs">
81 <DependentUpon>OverlayForm.cs</DependentUpon>
81 <DependentUpon>OverlayForm.cs</DependentUpon>
82 </Compile>
82 </Compile>
83 <Compile Include="StaApartmentTests.cs" />
83 </ItemGroup>
84 </ItemGroup>
84 <ItemGroup>
85 <ItemGroup>
85 <EmbeddedResource Include="Sample\MainForm.resx">
86 <EmbeddedResource Include="Sample\MainForm.resx">
86 <DependentUpon>MainForm.cs</DependentUpon>
87 <DependentUpon>MainForm.cs</DependentUpon>
87 <LogicalName>
88 <LogicalName>
88 </LogicalName>
89 </LogicalName>
89 </EmbeddedResource>
90 </EmbeddedResource>
90 <EmbeddedResource Include="Sample\OverlayForm.resx">
91 <EmbeddedResource Include="Sample\OverlayForm.resx">
91 <DependentUpon>OverlayForm.cs</DependentUpon>
92 <DependentUpon>OverlayForm.cs</DependentUpon>
92 <LogicalName>
93 <LogicalName>
93 </LogicalName>
94 </LogicalName>
94 </EmbeddedResource>
95 </EmbeddedResource>
95 </ItemGroup>
96 </ItemGroup>
96 <ItemGroup>
97 <ItemGroup>
97 <ProjectReference Include="..\Implab.Fx\Implab.Fx.csproj">
98 <ProjectReference Include="..\Implab.Fx\Implab.Fx.csproj">
98 <Project>{06E706F8-6881-43EB-927E-FFC503AF6ABC}</Project>
99 <Project>{06E706F8-6881-43EB-927E-FFC503AF6ABC}</Project>
99 <Name>Implab.Fx</Name>
100 <Name>Implab.Fx</Name>
100 </ProjectReference>
101 </ProjectReference>
101 <ProjectReference Include="..\Implab\Implab.csproj">
102 <ProjectReference Include="..\Implab\Implab.csproj">
102 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
103 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
103 <Name>Implab</Name>
104 <Name>Implab</Name>
104 </ProjectReference>
105 </ProjectReference>
105 </ItemGroup>
106 </ItemGroup>
106 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
107 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
107 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
108 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
108 Other similar extension points exist, see Microsoft.Common.targets.
109 Other similar extension points exist, see Microsoft.Common.targets.
109 <Target Name="BeforeBuild">
110 <Target Name="BeforeBuild">
110 </Target>
111 </Target>
111 <Target Name="AfterBuild">
112 <Target Name="AfterBuild">
112 </Target>
113 </Target>
113 -->
114 -->
114 </Project> No newline at end of file
115 </Project>
@@ -1,88 +1,89
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{06E706F8-6881-43EB-927E-FFC503AF6ABC}</ProjectGuid>
8 <ProjectGuid>{06E706F8-6881-43EB-927E-FFC503AF6ABC}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Implab.Fx</RootNamespace>
11 <RootNamespace>Implab.Fx</RootNamespace>
12 <AssemblyName>Implab.Fx</AssemblyName>
12 <AssemblyName>Implab.Fx</AssemblyName>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
14 <FileAlignment>512</FileAlignment>
15 <ReleaseVersion>0.2</ReleaseVersion>
15 <ReleaseVersion>0.2</ReleaseVersion>
16 <TargetFrameworkProfile />
16 <TargetFrameworkProfile />
17 </PropertyGroup>
17 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 <DebugSymbols>true</DebugSymbols>
19 <DebugSymbols>true</DebugSymbols>
20 <DebugType>full</DebugType>
20 <DebugType>full</DebugType>
21 <Optimize>false</Optimize>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
25 <WarningLevel>4</WarningLevel>
26 <Prefer32Bit>false</Prefer32Bit>
26 <Prefer32Bit>false</Prefer32Bit>
27 </PropertyGroup>
27 </PropertyGroup>
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 <DebugType>pdbonly</DebugType>
29 <DebugType>pdbonly</DebugType>
30 <Optimize>true</Optimize>
30 <Optimize>true</Optimize>
31 <OutputPath>bin\Release\</OutputPath>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>false</Prefer32Bit>
35 <Prefer32Bit>false</Prefer32Bit>
36 </PropertyGroup>
36 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 <DebugSymbols>true</DebugSymbols>
38 <DebugSymbols>true</DebugSymbols>
39 <DebugType>full</DebugType>
39 <DebugType>full</DebugType>
40 <Optimize>false</Optimize>
40 <Optimize>false</Optimize>
41 <OutputPath>bin\Debug\</OutputPath>
41 <OutputPath>bin\Debug\</OutputPath>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 <ErrorReport>prompt</ErrorReport>
43 <ErrorReport>prompt</ErrorReport>
44 <WarningLevel>4</WarningLevel>
44 <WarningLevel>4</WarningLevel>
45 <Prefer32Bit>false</Prefer32Bit>
45 <Prefer32Bit>false</Prefer32Bit>
46 </PropertyGroup>
46 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
48 <DebugType>pdbonly</DebugType>
48 <DebugType>pdbonly</DebugType>
49 <Optimize>true</Optimize>
49 <Optimize>true</Optimize>
50 <OutputPath>bin\Release\</OutputPath>
50 <OutputPath>bin\Release\</OutputPath>
51 <DefineConstants>TRACE</DefineConstants>
51 <DefineConstants>TRACE</DefineConstants>
52 <ErrorReport>prompt</ErrorReport>
52 <ErrorReport>prompt</ErrorReport>
53 <WarningLevel>4</WarningLevel>
53 <WarningLevel>4</WarningLevel>
54 <Prefer32Bit>false</Prefer32Bit>
54 <Prefer32Bit>false</Prefer32Bit>
55 </PropertyGroup>
55 </PropertyGroup>
56 <ItemGroup>
56 <ItemGroup>
57 <Reference Include="System" />
57 <Reference Include="System" />
58 <Reference Include="System.Core" />
58 <Reference Include="System.Core" />
59 <Reference Include="System.Drawing" />
59 <Reference Include="System.Drawing" />
60 <Reference Include="System.Windows.Forms" />
60 <Reference Include="System.Windows.Forms" />
61 <Reference Include="System.Xml.Linq" />
61 <Reference Include="System.Xml.Linq" />
62 <Reference Include="System.Data.DataSetExtensions" />
62 <Reference Include="System.Data.DataSetExtensions" />
63 <Reference Include="Microsoft.CSharp" />
63 <Reference Include="Microsoft.CSharp" />
64 <Reference Include="System.Data" />
64 <Reference Include="System.Data" />
65 <Reference Include="System.Xml" />
65 <Reference Include="System.Xml" />
66 </ItemGroup>
66 </ItemGroup>
67 <ItemGroup>
67 <ItemGroup>
68 <Compile Include="Animation.cs" />
68 <Compile Include="Animation.cs" />
69 <Compile Include="AnimationHelpers.cs" />
69 <Compile Include="AnimationHelpers.cs" />
70 <Compile Include="PromiseHelpers.cs" />
70 <Compile Include="PromiseHelpers.cs" />
71 <Compile Include="Properties\AssemblyInfo.cs" />
71 <Compile Include="Properties\AssemblyInfo.cs" />
72 <Compile Include="ControlBoundPromise.cs" />
72 <Compile Include="ControlBoundPromise.cs" />
73 <Compile Include="StaApartment.cs" />
73 </ItemGroup>
74 </ItemGroup>
74 <ItemGroup>
75 <ItemGroup>
75 <ProjectReference Include="..\Implab\Implab.csproj">
76 <ProjectReference Include="..\Implab\Implab.csproj">
76 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
77 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
77 <Name>Implab</Name>
78 <Name>Implab</Name>
78 </ProjectReference>
79 </ProjectReference>
79 </ItemGroup>
80 </ItemGroup>
80 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
81 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
81 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
82 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
82 Other similar extension points exist, see Microsoft.Common.targets.
83 Other similar extension points exist, see Microsoft.Common.targets.
83 <Target Name="BeforeBuild">
84 <Target Name="BeforeBuild">
84 </Target>
85 </Target>
85 <Target Name="AfterBuild">
86 <Target Name="AfterBuild">
86 </Target>
87 </Target>
87 -->
88 -->
88 </Project> No newline at end of file
89 </Project>
@@ -1,84 +1,90
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Implab.Test</RootNamespace>
11 <RootNamespace>Implab.Test</RootNamespace>
12 <AssemblyName>Implab.Test</AssemblyName>
12 <AssemblyName>Implab.Test</AssemblyName>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
14 <FileAlignment>512</FileAlignment>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16 <TargetFrameworkProfile />
16 <TargetFrameworkProfile />
17 </PropertyGroup>
17 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 <DebugSymbols>true</DebugSymbols>
19 <DebugSymbols>true</DebugSymbols>
20 <DebugType>full</DebugType>
20 <DebugType>full</DebugType>
21 <Optimize>false</Optimize>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
25 <WarningLevel>4</WarningLevel>
26 <Prefer32Bit>false</Prefer32Bit>
26 <Prefer32Bit>false</Prefer32Bit>
27 </PropertyGroup>
27 </PropertyGroup>
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 <DebugType>pdbonly</DebugType>
29 <DebugType>pdbonly</DebugType>
30 <Optimize>true</Optimize>
30 <Optimize>true</Optimize>
31 <OutputPath>bin\Release\</OutputPath>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>false</Prefer32Bit>
35 <Prefer32Bit>false</Prefer32Bit>
36 </PropertyGroup>
36 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 <DebugSymbols>true</DebugSymbols>
38 <DebugSymbols>true</DebugSymbols>
39 <DebugType>full</DebugType>
39 <DebugType>full</DebugType>
40 <Optimize>false</Optimize>
40 <Optimize>false</Optimize>
41 <OutputPath>bin\Debug\</OutputPath>
41 <OutputPath>bin\Debug\</OutputPath>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 <ErrorReport>prompt</ErrorReport>
43 <ErrorReport>prompt</ErrorReport>
44 <WarningLevel>4</WarningLevel>
44 <WarningLevel>4</WarningLevel>
45 <Prefer32Bit>false</Prefer32Bit>
45 <Prefer32Bit>false</Prefer32Bit>
46 </PropertyGroup>
46 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
48 <DebugType>pdbonly</DebugType>
48 <DebugType>pdbonly</DebugType>
49 <Optimize>true</Optimize>
49 <Optimize>true</Optimize>
50 <OutputPath>bin\Release\</OutputPath>
50 <OutputPath>bin\Release\</OutputPath>
51 <DefineConstants>TRACE</DefineConstants>
51 <DefineConstants>TRACE</DefineConstants>
52 <ErrorReport>prompt</ErrorReport>
52 <ErrorReport>prompt</ErrorReport>
53 <WarningLevel>4</WarningLevel>
53 <WarningLevel>4</WarningLevel>
54 <Prefer32Bit>false</Prefer32Bit>
54 <Prefer32Bit>false</Prefer32Bit>
55 </PropertyGroup>
55 </PropertyGroup>
56 <ItemGroup>
56 <ItemGroup>
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
58 <Reference Include="System" />
58 <Reference Include="System" />
59 <Reference Include="System.Core">
59 <Reference Include="System.Core">
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
61 </Reference>
61 </Reference>
62 </ItemGroup>
62 </ItemGroup>
63 <ItemGroup>
63 <ItemGroup>
64 <Compile Include="AsyncTests.cs" />
64 <Compile Include="AsyncTests.cs" />
65 <Compile Include="CancelationTests.cs" />
65 <Compile Include="CancelationTests.cs" />
66 <Compile Include="Mock\MockPollingComponent.cs" />
67 <Compile Include="Mock\MockRunnableComponent.cs" />
68 <Compile Include="PollingComponentTests.cs" />
66 <Compile Include="PromiseHelper.cs" />
69 <Compile Include="PromiseHelper.cs" />
67 <Compile Include="Properties\AssemblyInfo.cs" />
70 <Compile Include="Properties\AssemblyInfo.cs" />
68 <Compile Include="RunnableComponentTests.cs" />
71 <Compile Include="RunnableComponentTests.cs" />
69 </ItemGroup>
72 </ItemGroup>
70 <ItemGroup>
73 <ItemGroup>
71 <ProjectReference Include="..\Implab\Implab.csproj">
74 <ProjectReference Include="..\Implab\Implab.csproj">
72 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
75 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
73 <Name>Implab</Name>
76 <Name>Implab</Name>
74 </ProjectReference>
77 </ProjectReference>
75 </ItemGroup>
78 </ItemGroup>
79 <ItemGroup>
80 <Folder Include="Implab.Format.Test\" />
81 </ItemGroup>
76 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
82 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
77 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
83 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
78 Other similar extension points exist, see Microsoft.Common.targets.
84 Other similar extension points exist, see Microsoft.Common.targets.
79 <Target Name="BeforeBuild">
85 <Target Name="BeforeBuild">
80 </Target>
86 </Target>
81 <Target Name="AfterBuild">
87 <Target Name="AfterBuild">
82 </Target>
88 </Target>
83 -->
89 -->
84 </Project> No newline at end of file
90 </Project>
@@ -1,368 +1,411
1 using System;
1 using System;
2 using System.Diagnostics.CodeAnalysis;
2 using System.Diagnostics.CodeAnalysis;
3
3
4 namespace Implab.Components {
4 namespace Implab.Components {
5 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
5 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
6 enum Commands {
6 enum Commands {
7 Ok = 0,
7 Ok = 0,
8 Fail,
8 Fail,
9 Init,
9 Init,
10 Start,
10 Start,
11 Stop,
11 Stop,
12 Dispose,
12 Dispose,
13 Reset,
13 Reset,
14 Last = Reset
14 Last = Reset
15 }
15 }
16
16
17 class StateMachine {
17 class StateMachine {
18 static readonly ExecutionState[,] _transitions;
18 public static readonly ExecutionState[,] ReusableTransitions;
19 public static readonly ExecutionState[,] NonreusableTransitions;
20
21 class StateBuilder {
22 readonly ExecutionState[,] m_states;
23
24 public ExecutionState[,] States {
25 get { return m_states; }
26 }
27 public StateBuilder(ExecutionState[,] states) {
28 m_states = states;
29 }
30
31 public StateBuilder() {
32 m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
33 }
34
35 public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
36 m_states[(int)s1, (int)cmd] = s2;
37 return this;
38 }
39
40 public StateBuilder Clone() {
41 return new StateBuilder((ExecutionState[,])m_states.Clone());
42 }
43 }
19
44
20 static StateMachine() {
45 static StateMachine() {
21 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
46 ReusableTransitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
22
47
23 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init);
48 var common = new StateBuilder()
24 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose);
49 .Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init)
50 .Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose)
25
51
26 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok);
52 .Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok)
27 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail);
53 .Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail)
28
54
29 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
55 .Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start)
30 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
56 .Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose)
57
58 .Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok)
59 .Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail)
60 .Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop)
61 .Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose)
31
62
32 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
63 .Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail)
33 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
64 .Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop)
34 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
65 .Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose)
35 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
66
67 .Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose)
68 .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset)
69
70 .Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail)
71 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose)
72
73 .Edge(ExecutionState.Disposed, ExecutionState.Disposed, Commands.Dispose);
36
74
37 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
75 var reusable = common
38 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
76 .Clone()
39 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
77 .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
40
78
41 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
79 var nonreusable = common
42 Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
80 .Clone()
43 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose);
81 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
44
82
45 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose);
83 NonreusableTransitions = nonreusable.States;
46 Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset);
84 ReusableTransitions = reusable.States;
85
47 }
86 }
48
87
49 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
88 readonly ExecutionState[,] m_states;
50 _transitions[(int)s1, (int)cmd] = s2;
51 }
52
89
53 public ExecutionState State {
90 public ExecutionState State {
54 get;
91 get;
55 private set;
92 private set;
56 }
93 }
57
94
58 public StateMachine(ExecutionState initial) {
95 public StateMachine(ExecutionState[,] states, ExecutionState initial) {
59 State = initial;
96 State = initial;
97 m_states = states;
60 }
98 }
61
99
62 public bool Move(Commands cmd) {
100 public bool Move(Commands cmd) {
63 var next = _transitions[(int)State, (int)cmd];
101 var next = m_states[(int)State, (int)cmd];
64 if (next == ExecutionState.Undefined)
102 if (next == ExecutionState.Undefined)
65 return false;
103 return false;
66 State = next;
104 State = next;
67 return true;
105 return true;
68 }
106 }
69 }
107 }
70
108
71 IPromise m_pending;
109 IPromise m_pending;
72 Exception m_lastError;
110 Exception m_lastError;
73
111
74 readonly StateMachine m_stateMachine;
112 readonly StateMachine m_stateMachine;
75 readonly bool m_reusable;
113 readonly bool m_reusable;
76 public event EventHandler<StateChangeEventArgs> StateChanged;
114 public event EventHandler<StateChangeEventArgs> StateChanged;
77
115
78 /// <summary>
116 /// <summary>
79 /// Initializes component state.
117 /// Initializes component state.
80 /// </summary>
118 /// </summary>
81 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
119 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
82 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
120 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
83 protected RunnableComponent(bool initialized, bool reusable) {
121 protected RunnableComponent(bool initialized, bool reusable) {
84 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
122 m_stateMachine = new StateMachine(
123 reusable ? StateMachine.ReusableTransitions : StateMachine.NonreusableTransitions,
124 initialized ? ExecutionState.Ready : ExecutionState.Created
125 );
85 m_reusable = reusable;
126 m_reusable = reusable;
86 DisposeTimeout = 10000;
87 }
127 }
88
128
89 /// <summary>
129 /// <summary>
90 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
130 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
91 /// </summary>
131 /// </summary>
92 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
132 /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
93 protected RunnableComponent(bool initialized) : this(initialized, false) {
133 protected RunnableComponent(bool initialized) : this(initialized, false) {
94 }
134 }
95
135
96 /// <summary>
97 /// Gets or sets the timeout to wait for the pending operation to complete. If the pending operation doesn't finish than the component will be disposed anyway.
98 /// </summary>
99 protected int DisposeTimeout {
100 get;
101 set;
102 }
103
104 void ThrowInvalidCommand(Commands cmd) {
136 void ThrowInvalidCommand(Commands cmd) {
105 if (m_stateMachine.State == ExecutionState.Disposed)
137 if (m_stateMachine.State == ExecutionState.Disposed)
106 throw new ObjectDisposedException(ToString());
138 throw new ObjectDisposedException(ToString());
107
139
108 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
140 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
109 }
141 }
110
142
111 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) {
143 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) {
112 ExecutionState prev, current;
144 ExecutionState prev, current;
113 lock (m_stateMachine) {
145 lock (m_stateMachine) {
114 if (m_stateMachine.State != state)
146 if (m_stateMachine.State != state)
115 return false;
147 return false;
116
148
117 prev = m_stateMachine.State;
149 prev = m_stateMachine.State;
118 if (!m_stateMachine.Move(cmd))
150 if (!m_stateMachine.Move(cmd))
119 ThrowInvalidCommand(cmd);
151 ThrowInvalidCommand(cmd);
120 current = m_stateMachine.State;
152 current = m_stateMachine.State;
121
153
122 m_pending = pending;
154 m_pending = pending;
123 m_lastError = error;
155 m_lastError = error;
124 }
156 }
125 if (prev != current)
157 if (prev != current)
126 OnStateChanged(prev, current, error);
158 OnStateChanged(prev, current, error);
127 return true;
159 return true;
128 }
160 }
129
161
130 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) {
162 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) {
131 ExecutionState prev, current;
163 ExecutionState prev, current;
132 lock (m_stateMachine) {
164 lock (m_stateMachine) {
133 if (m_pending != expected)
165 if (m_pending != expected)
134 return false;
166 return false;
135 prev = m_stateMachine.State;
167 prev = m_stateMachine.State;
136 if (!m_stateMachine.Move(cmd))
168 if (!m_stateMachine.Move(cmd))
137 ThrowInvalidCommand(cmd);
169 ThrowInvalidCommand(cmd);
138 current = m_stateMachine.State;
170 current = m_stateMachine.State;
139 m_pending = pending;
171 m_pending = pending;
140 m_lastError = error;
172 m_lastError = error;
141 }
173 }
142 if (prev != current)
174 if (prev != current)
143 OnStateChanged(prev, current, error);
175 OnStateChanged(prev, current, error);
144 return true;
176 return true;
145 }
177 }
146
178
147 IPromise Move(Commands cmd, IPromise pending, Exception error) {
179 IPromise Move(Commands cmd, IPromise pending, Exception error) {
148 ExecutionState prev, current;
180 ExecutionState prev, current;
149 IPromise ret;
181 IPromise ret;
150 lock (m_stateMachine) {
182 lock (m_stateMachine) {
151 prev = m_stateMachine.State;
183 prev = m_stateMachine.State;
152 if (!m_stateMachine.Move(cmd))
184 if (!m_stateMachine.Move(cmd))
153 ThrowInvalidCommand(cmd);
185 ThrowInvalidCommand(cmd);
154 current = m_stateMachine.State;
186 current = m_stateMachine.State;
155
187
156 ret = m_pending;
188 ret = m_pending;
157 m_pending = pending;
189 m_pending = pending;
158 m_lastError = error;
190 m_lastError = error;
159
191
160 }
192 }
161 if(prev != current)
193 if (prev != current)
162 OnStateChanged(prev, current, error);
194 OnStateChanged(prev, current, error);
163 return ret;
195 return ret;
164 }
196 }
165
197
198 /// <summary>
199 /// Handles the state of the component change event, raises the <see cref="StateChanged"/> event, handles
200 /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method).
201 /// </summary>
202 /// <param name="previous">The previous state</param>
203 /// <param name="current">The current state</param>
204 /// <param name="error">The last error if any.</param>
205 /// <remarks>
206 /// <para>
207 /// If the previous state and the current state are same this method isn't called, such situiation is treated
208 /// as the component hasn't changed it's state.
209 /// </para>
210 /// <para>
211 /// When overriding this method ensure the call is made to the base implementation, otherwise it will lead to
212 /// the wrong behavior of the component.
213 /// </para>
214 /// </remarks>
166 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
215 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
167 var h = StateChanged;
216 StateChanged.DispatchEvent(
168 if (h != null)
217 this,
169 h(this, new StateChangeEventArgs {
218 new StateChangeEventArgs {
170 State = current,
219 State = current,
171 LastError = error
220 LastError = error
172 });
221 }
222 );
223 if (current == ExecutionState.Disposed) {
224 GC.SuppressFinalize(this);
225 Dispose(true);
226 }
173 }
227 }
174
228
175 /// <summary>
229 /// <summary>
176 /// Moves the component from running to failed state.
230 /// Moves the component from running to failed state.
177 /// </summary>
231 /// </summary>
178 /// <param name="error">The exception which is describing the error.</param>
232 /// <param name="error">The exception which is describing the error.</param>
179 protected bool Fail(Exception error) {
233 protected bool Fail(Exception error) {
180 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
234 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
181 }
235 }
182
236
183 /// <summary>
237 /// <summary>
184 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
238 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
185 /// </summary>
239 /// </summary>
186 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't
240 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't
187 /// in <see cref="ExecutionState.Failed"/> state.</returns>
241 /// in <see cref="ExecutionState.Failed"/> state.</returns>
188 /// <remarks>
242 /// <remarks>
189 /// This method checks the current state of the component and if it's in <see cref="ExecutionState.Failed"/>
243 /// This method checks the current state of the component and if it's in <see cref="ExecutionState.Failed"/>
190 /// moves component to <see cref="ExecutionState.Initializing"/>.
244 /// moves component to <see cref="ExecutionState.Initializing"/>.
191 /// The <see cref="OnResetState()"/> is called and if this method completes succesfully the component moved
245 /// The <see cref="OnResetState()"/> is called and if this method completes succesfully the component moved
192 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/>
246 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/>
193 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller.
247 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller.
194 /// </remarks>
248 /// </remarks>
195 protected bool ResetState() {
249 protected bool ResetState() {
196 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
250 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
197 return false;
251 return false;
198
252
199 try {
253 try {
200 OnResetState();
254 OnResetState();
201 Move(Commands.Ok, null, null);
255 Move(Commands.Ok, null, null);
202 return true;
256 return true;
203 } catch (Exception err) {
257 } catch (Exception err) {
204 Move(Commands.Fail, null, err);
258 Move(Commands.Fail, null, err);
205 throw;
259 throw;
206 }
260 }
207 }
261 }
208
262
209 /// <summary>
263 /// <summary>
210 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
264 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
211 /// </summary>
265 /// </summary>
212 /// <remarks>
266 /// <remarks>
213 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component
267 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component
214 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state.
268 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state.
215 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state.
269 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state.
216 /// </remarks>
270 /// </remarks>
217 protected virtual void OnResetState() {
271 protected virtual void OnResetState() {
218 throw new NotImplementedException();
272 throw new NotImplementedException();
219 }
273 }
220
274
221 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
275 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
222 IPromise promise = null;
276 IPromise promise = null;
223 IPromise prev;
277 IPromise prev;
224
278
225 var task = new ActionChainTask(action, null, null, true);
279 var task = new ActionChainTask(action, null, null, true);
226
280
227 Action<Exception> errorOrCancel = e => {
281 Action<Exception> errorOrCancel = e => {
228 if (e == null)
282 if (e == null)
229 e = new OperationCanceledException();
283 e = new OperationCanceledException();
230 MoveIfPending(Commands.Fail, null, e, promise);
284 MoveIfPending(Commands.Fail, null, e, promise);
231 throw new PromiseTransientException(e);
285 throw new PromiseTransientException(e);
232 };
286 };
233
287
234 promise = task.Then(
288 promise = task.Then(
235 () => MoveIfPending(Commands.Ok, null, null, promise),
289 () => MoveIfPending(Commands.Ok, null, null, promise),
236 errorOrCancel,
290 errorOrCancel,
237 errorOrCancel
291 errorOrCancel
238 );
292 );
239
293
240 prev = Move(cmd, promise, null);
294 prev = Move(cmd, promise, null);
241
295
242 if (prev == null)
296 if (prev == null)
243 task.Resolve();
297 task.Resolve();
244 else
298 else
245 chain(prev, task);
299 chain(prev, task);
246
300
247 return promise;
301 return promise;
248 }
302 }
249
303
250
304
251 #region IInitializable implementation
305 #region IInitializable implementation
252
306
253 public void Initialize() {
307 public void Initialize() {
254 Move(Commands.Init, null, null);
308 Move(Commands.Init, null, null);
255
309
256 try {
310 try {
257 OnInitialize();
311 OnInitialize();
258 Move(Commands.Ok, null, null);
312 Move(Commands.Ok, null, null);
259 } catch (Exception err) {
313 } catch (Exception err) {
260 Move(Commands.Fail, null, err);
314 Move(Commands.Fail, null, err);
261 throw;
315 throw;
262 }
316 }
263 }
317 }
264
318
265 protected virtual void OnInitialize() {
319 protected virtual void OnInitialize() {
266 }
320 }
267
321
268 #endregion
322 #endregion
269
323
270 #region IRunnable implementation
324 #region IRunnable implementation
271
325
272 public IPromise Start() {
326 public IPromise Start() {
273 return InvokeAsync(Commands.Start, OnStart, null);
327 return InvokeAsync(Commands.Start, OnStart, null);
274 }
328 }
275
329
276 protected virtual IPromise OnStart() {
330 protected virtual IPromise OnStart() {
277 return Promise.Success;
331 return Promise.Success;
278 }
332 }
279
333
280 public IPromise Stop() {
334 public IPromise Stop() {
281 var pending = InvokeAsync(Commands.Stop, OnStop, StopPending);
335 return InvokeAsync(Commands.Stop, OnStop, StopPending);
282 return m_reusable ? pending : pending.Then(Dispose);
283 }
336 }
284
337
285 protected virtual IPromise OnStop() {
338 protected virtual IPromise OnStop() {
286 return Promise.Success;
339 return Promise.Success;
287 }
340 }
288
341
289 /// <summary>
342 /// <summary>
290 /// Stops the current operation if one exists.
343 /// Stops the current operation if one exists.
291 /// </summary>
344 /// </summary>
292 /// <param name="current">Current.</param>
345 /// <param name="current">Current.</param>
293 /// <param name="stop">Stop.</param>
346 /// <param name="stop">Stop.</param>
294 protected virtual void StopPending(IPromise current, IDeferred stop) {
347 protected virtual void StopPending(IPromise current, IDeferred stop) {
295 if (current == null) {
348 if (current == null) {
296 stop.Resolve();
349 stop.Resolve();
297 } else {
350 } else {
298 // связваСм Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ с ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠ΅ΠΉ остановки
351 // связваСм Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ с ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠ΅ΠΉ остановки
299 current.On(
352 current.On(
300 stop.Resolve, // Ссли тСкущая опСрация Π·Π°Π²Π΅Ρ€Ρ‰ΠΈΠ»Π°ΡΡŒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ остановку
353 stop.Resolve, // Ссли тСкущая опСрация Π·Π°Π²Π΅Ρ€Ρ‰ΠΈΠ»Π°ΡΡŒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ остановку
301 stop.Reject, // Ссли тСкущая опСрация Π΄Π°Π»Π° ΠΎΡˆΠΈΠ±ΠΊΡƒ - Ρ‚ΠΎ всС ΠΏΠ»ΠΎΡ…ΠΎ, нСльзя ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ
354 stop.Reject, // Ссли тСкущая опСрация Π΄Π°Π»Π° ΠΎΡˆΠΈΠ±ΠΊΡƒ - Ρ‚ΠΎ всС ΠΏΠ»ΠΎΡ…ΠΎ, нСльзя ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ
302 e => stop.Resolve() // Ссли тСкущая ΠΎΡ‚ΠΌΠ΅Π½ΠΈΠ»Π°ΡΡŒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ остановку
355 e => stop.Resolve() // Ссли тСкущая ΠΎΡ‚ΠΌΠ΅Π½ΠΈΠ»Π°ΡΡŒ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒ остановку
303 );
356 );
304 // посылаСм Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ сигнал остановки
357 // посылаСм Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ сигнал остановки
305 current.Cancel();
358 current.Cancel();
306 }
359 }
307 }
360 }
308
361
309 public ExecutionState State {
362 public ExecutionState State {
310 get {
363 get {
311 return m_stateMachine.State;
364 return m_stateMachine.State;
312 }
365 }
313 }
366 }
314
367
315 public Exception LastError {
368 public Exception LastError {
316 get {
369 get {
317 return m_lastError;
370 return m_lastError;
318 }
371 }
319 }
372 }
320
373
321 #endregion
374 #endregion
322
375
323 #region IDisposable implementation
376 #region IDisposable implementation
324
377
325 /// <summary>
378 /// <summary>
326 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object.
379 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object.
327 /// </summary>
380 /// </summary>
328 /// <remarks>
381 /// <remarks>
329 /// <para>Will not try to stop the component, it will just release all resources.
382 /// <para>Will not try to stop the component, it will just release all resources.
330 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para>
383 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para>
331 /// <para>
384 /// <para>
332 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/>
385 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/>
333 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors,
386 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors,
334 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may
387 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may
335 /// lead to the data loss by the component.
388 /// lead to the data loss by the component.
336 /// </para></remarks>
389 /// </para></remarks>
337 [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
390 [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
338 public void Dispose() {
391 public void Dispose() {
339 IPromise pending;
340
341 lock (m_stateMachine) {
342 if (m_stateMachine.State == ExecutionState.Disposed)
343 return;
344 Move(Commands.Dispose, null, null);
392 Move(Commands.Dispose, null, null);
345 }
393 }
346
394
347 GC.SuppressFinalize(this);
348 Dispose(true);
349 }
350
351 ~RunnableComponent() {
395 ~RunnableComponent() {
352 Dispose(false);
396 Dispose(false);
353 }
397 }
354
398
355 #endregion
399 #endregion
356
400
357 /// <summary>
401 /// <summary>
358 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
402 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
359 /// </summary>
403 /// </summary>
360 /// <param name="disposing">true if this method is called during normal dispose process.</param>
404 /// <param name="disposing">true if this method is called during normal dispose process.</param>
361 /// <param name="pending">The operation which is currenty pending</param>
405 /// <param name="pending">The operation which is currenty pending</param>
362 protected virtual void Dispose(bool disposing) {
406 protected virtual void Dispose(bool disposing) {
363
364 }
407 }
365
408
366 }
409 }
367 }
410 }
368
411
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now