天天看點

Google-Guava Concurrent包裡的Service架構淺析

<b>概述</b>

guava包裡的service接口用于封裝一個服務對象的運作狀态、包括start和stop等方法。例如web伺服器,rpc伺服器、計時器等可以實作這個接口。對此類服務的狀态管理并不輕松、需要對服務的開啟/關閉進行妥善管理、特别是在多線程環境下尤為複雜。guava包提供了一些基礎類幫助你管理複雜的狀态轉換邏輯和同步細節。

<b>使用一個服務</b>

一個服務正常生命周期有:

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/service.state.html#new">service.state.new</a>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/service.state.html#starting">service.state.starting</a>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/service.state.html#running">service.state.running</a>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/service.state.html#stopping">service.state.stopping</a>

<a href="http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/service.state.html#terminated">service.state.terminated</a>

service也提供了一些方法用于等待服務狀态轉換的完成:

<b>基礎實作類</b>

<b>abstractidleservice</b>

<code>1</code>

<code>protected</code> <code>void</code> <code>startup() {</code>

<code>2</code>

<code>servlets.add(</code><code>new</code> <code>gcstatsservlet());</code>

<code>3</code>

<code>}</code>

<code>4</code>

<code>protected</code> <code>void</code> <code>shutdown() {}</code>

如上面的例子、由于任何請求到gcstatsservlet時已經會有現成線程處理了,是以在服務運作時就不需要做什麼額外動作了。

<b>abstractexecutionthreadservice</b>

<code>public</code> <code>void</code> <code>run() {</code>

<code>  </code><code>while</code> <code>(isrunning()) {</code>

<code>    </code><code>// perform a unit of work</code>

<code>  </code><code>}</code>

<code>5</code>

重載startup()和shutdown()方法是可選的,不影響服務本身狀态的管理

<code>01</code>

<code>02</code>

<code>dispatcher.listenforconnections(port, queue);</code>

<code>03</code>

<code> </code><code>}</code>

<code>04</code>

<code> </code><code>protected</code> <code>void</code> <code>run() {</code>

<code>05</code>

<code>  </code><code>connection connection;</code>

<code>06</code>

<code>  </code><code>while</code> <code>((connection = queue.take() != poison)) {</code>

<code>07</code>

<code>    </code><code>process(connection);</code>

<code>08</code>

<code>09</code>

<code>10</code>

<code> </code><code>protected</code> <code>void</code> <code>triggershutdown() {</code>

<code>11</code>

<code>  </code><code>dispatcher.stoplisteningforconnections(queue);</code>

<code>12</code>

<code>  </code><code>queue.put(poison);</code>

<code>13</code>

start()内部會調用startup()方法,建立一個線程、然後線上程内調用run()方法。stop()會調用 triggershutdown()方法并且等待線程終止。

<b>abstractscheduledservice</b>

<b>abstractservice</b><b></b>

繼承abstractservice方法必須實作兩個方法.

dostart和dostop方法的實作需要考慮下性能,盡可能的低延遲。如果初始化的開銷較大,如讀檔案,打開網絡連接配接,或者其他任何可能引起阻塞的操作,建議移到另外一個單獨的線程去處理。

<b>使用servicemanager</b><b></b>

檢測類的方法有:

我們建議整個服務的生命周期都能通過servicemanager來管理,不過即使狀态轉換是通過其他機制觸發的、也不影響servicemanager方法的正确執行。例如:當一個服務不是通過startasync()、而是其他機制啟動時,listeners 仍然可以被正常調用、awaithealthy()也能夠正常工作。servicemanager 唯一強制的要求是當其被建立時所有的服務必須處于new狀态。

附:testcase、也可以作為練習demo

servicetest

<code>&lt;/pre&gt;</code>

<code>/*</code>

<code> </code><code>* copyright (c) 2013 the guava authors</code>

<code> </code><code>*</code>

<code> </code><code>* licensed under the apache license, version 2.0 (the "license");</code>

<code> </code><code>* you may not use this file except in compliance with the license.</code>

<code> </code><code>* you may obtain a copy of the license at</code>

<code> </code><code>* unless required by applicable law or agreed to in writing, software</code>

<code> </code><code>* distributed under the license is distributed on an "as is" basis,</code>

<code> </code><code>* without warranties or conditions of any kind, either express or implied.</code>

<code>14</code>

<code> </code><code>* see the license for the specific language governing permissions and</code>

<code>15</code>

<code> </code><code>* limitations under the license.</code>

<code>16</code>

<code> </code><code>*/</code>

<code>17</code>

<code>18</code>

<code>package com.google.common.util.concurrent;</code>

<code>19</code>

<code>20</code>

<code>import static com.google.common.util.concurrent.service.state.failed;</code>

<code>21</code>

<code>import static com.google.common.util.concurrent.service.state.new;</code>

<code>22</code>

<code>import static com.google.common.util.concurrent.service.state.running;</code>

<code>23</code>

<code>import static com.google.common.util.concurrent.service.state.starting;</code>

<code>24</code>

<code>import static com.google.common.util.concurrent.service.state.stopping;</code>

<code>25</code>

<code>import static com.google.common.util.concurrent.service.state.terminated;</code>

<code>26</code>

<code>27</code>

<code>import junit.framework.testcase;</code>

<code>28</code>

<code>29</code>

<code>/**</code>

<code>30</code>

<code> </code><code>* unit tests for {@link service}</code>

<code>31</code>

<code>32</code>

<code>public class servicetest extends testcase {</code>

<code>33</code>

<code>34</code>

<code>/** assert on the comparison ordering of the state enum since we guarantee it. */</code>

<code>35</code>

<code> </code><code>public</code> <code>void</code> <code>teststateordering() {</code>

<code>36</code>

<code> </code><code>// list every valid (direct) state transition.</code>

<code>37</code>

<code> </code><code>assertlessthan(new, starting);</code>

<code>38</code>

<code> </code><code>assertlessthan(new, terminated);</code>

<code>39</code>

<code>40</code>

<code> </code><code>assertlessthan(starting, running);</code>

<code>41</code>

<code> </code><code>assertlessthan(starting, stopping);</code>

<code>42</code>

<code> </code><code>assertlessthan(starting, failed);</code>

<code>43</code>

<code>44</code>

<code> </code><code>assertlessthan(running, stopping);</code>

<code>45</code>

<code> </code><code>assertlessthan(running, failed);</code>

<code>46</code>

<code>47</code>

<code> </code><code>assertlessthan(stopping, failed);</code>

<code>48</code>

<code> </code><code>assertlessthan(stopping, terminated);</code>

<code>49</code>

<code>50</code>

<code>51</code>

<code> </code><code>private</code> <code>static</code> <code>&lt;t</code><code>extends</code> <code>comparable&lt;?</code><code>super</code> <code>t&gt;&gt;</code><code>void</code> <code>assertlessthan(t a, t b) {</code>

<code>52</code>

<code> </code><code>if</code> <code>(a.compareto(b) &gt;=</code><code>0</code><code>) {</code>

<code>53</code>

<code> </code><code>fail(string.format(</code><code>"expected %s to be less than %s"</code><code>, a, b));</code>

<code>54</code>

<code>55</code>

<code>56</code>

<code>57</code>

<code>&lt;pre&gt;</code>

abstractidleservicetest

<code>001</code>

<code>002</code>

<code> </code><code>* copyright (c) 2009 the guava authors</code>

<code>003</code>

<code>004</code>

<code>005</code>

<code>006</code>

<code>007</code>

<code>008</code>

<code>009</code>

<code>010</code>

<code>011</code>

<code>012</code>

<code>013</code>

<code>014</code>

<code>015</code>

<code>016</code>

<code>017</code>

<code>018</code>

<code>019</code>

<code>import static org.truth0.truth.assert;</code>

<code>020</code>

<code>021</code>

<code>import com.google.common.collect.lists;</code>

<code>022</code>

<code>023</code>

<code>024</code>

<code>025</code>

<code>import java.util.list;</code>

<code>026</code>

<code>import java.util.concurrent.executor;</code>

<code>027</code>

<code>import java.util.concurrent.timeunit;</code>

<code>028</code>

<code>import java.util.concurrent.timeoutexception;</code>

<code>029</code>

<code>030</code>

<code>031</code>

<code> </code><code>* tests for {@link abstractidleservice}.</code>

<code>032</code>

<code>033</code>

<code> </code><code>* @author chris nokleberg</code>

<code>034</code>

<code> </code><code>* @author ben yu</code>

<code>035</code>

<code>036</code>

<code>public</code> <code>class</code> <code>abstractidleservicetest</code><code>extends</code> <code>testcase {</code>

<code>037</code>

<code>038</code>

<code>// functional tests using real thread. we only verify publicly visible state.</code>

<code>039</code>

<code> </code><code>// interaction assertions are done by the single-threaded unit tests.</code>

<code>040</code>

<code>041</code>

<code>public</code> <code>static</code> <code>class</code> <code>functionaltest</code><code>extends</code> <code>testcase {</code>

<code>042</code>

<code>043</code>

<code>private</code> <code>static</code> <code>class</code> <code>defaultservice</code><code>extends</code> <code>abstractidleservice {</code>

<code>044</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>startup()</code><code>throws</code> <code>exception {}</code>

<code>045</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>shutdown()</code><code>throws</code> <code>exception {}</code>

<code>046</code>

<code>047</code>

<code>048</code>

<code>public</code> <code>void</code> <code>testservicestartstop()</code><code>throws</code> <code>exception {</code>

<code>049</code>

<code> </code><code>abstractidleservice service =</code><code>new</code> <code>defaultservice();</code>

<code>050</code>

<code> </code><code>service.startasync().awaitrunning();</code>

<code>051</code>

<code> </code><code>assertequals(service.state.running, service.state());</code>

<code>052</code>

<code> </code><code>service.stopasync().awaitterminated();</code>

<code>053</code>

<code> </code><code>assertequals(service.state.terminated, service.state());</code>

<code>054</code>

<code>055</code>

<code>056</code>

<code>public</code> <code>void</code> <code>teststart_failed()</code><code>throws</code> <code>exception {</code>

<code>057</code>

<code> </code><code>final</code> <code>exception exception =</code><code>new</code> <code>exception(</code><code>"deliberate"</code><code>);</code>

<code>058</code>

<code> </code><code>abstractidleservice service =</code><code>new</code> <code>defaultservice() {</code>

<code>059</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>startup()</code><code>throws</code> <code>exception {</code>

<code>060</code>

<code> </code><code>throw</code> <code>exception;</code>

<code>061</code>

<code>062</code>

<code> </code><code>};</code>

<code>063</code>

<code> </code><code>try</code> <code>{</code>

<code>064</code>

<code>065</code>

<code> </code><code>fail();</code>

<code>066</code>

<code> </code><code>}</code><code>catch</code> <code>(runtimeexception e) {</code>

<code>067</code>

<code> </code><code>assertsame(exception, e.getcause());</code>

<code>068</code>

<code>069</code>

<code> </code><code>assertequals(service.state.failed, service.state());</code>

<code>070</code>

<code>071</code>

<code>072</code>

<code>public</code> <code>void</code> <code>teststop_failed()</code><code>throws</code> <code>exception {</code>

<code>073</code>

<code>074</code>

<code>075</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>shutdown()</code><code>throws</code> <code>exception {</code>

<code>076</code>

<code>077</code>

<code>078</code>

<code>079</code>

<code>080</code>

<code>081</code>

<code>082</code>

<code>083</code>

<code>084</code>

<code>085</code>

<code>086</code>

<code>087</code>

<code>088</code>

<code>089</code>

<code>090</code>

<code>public</code> <code>void</code> <code>teststart() {</code>

<code>091</code>

<code> </code><code>testservice service =</code><code>new</code> <code>testservice();</code>

<code>092</code>

<code> </code><code>assertequals(</code><code>0</code><code>, service.startupcalled);</code>

<code>093</code>

<code>094</code>

<code> </code><code>assertequals(</code><code>1</code><code>, service.startupcalled);</code>

<code>095</code>

<code>096</code>

<code> </code><code>assert.that(service.transitionstates).has().exactly(service.state.starting).inorder();</code>

<code>097</code>

<code>098</code>

<code>099</code>

<code>public</code> <code>void</code> <code>teststart_failed() {</code>

<code>100</code>

<code>101</code>

<code> </code><code>testservice service =</code><code>new</code> <code>testservice() {</code>

<code>102</code>

<code>103</code>

<code> </code><code>super</code><code>.startup();</code>

<code>104</code>

<code>105</code>

<code>106</code>

<code>107</code>

<code>108</code>

<code>109</code>

<code>110</code>

<code>111</code>

<code>112</code>

<code>113</code>

<code>114</code>

<code>115</code>

<code>116</code>

<code>117</code>

<code>118</code>

<code>119</code>

<code>public</code> <code>void</code> <code>teststop_withoutstart() {</code>

<code>120</code>

<code>121</code>

<code>122</code>

<code>123</code>

<code> </code><code>assertequals(</code><code>0</code><code>, service.shutdowncalled);</code>

<code>124</code>

<code>125</code>

<code> </code><code>assert.that(service.transitionstates).isempty();</code>

<code>126</code>

<code>127</code>

<code>128</code>

<code>public</code> <code>void</code> <code>teststop_afterstart() {</code>

<code>129</code>

<code>130</code>

<code>131</code>

<code>132</code>

<code>133</code>

<code>134</code>

<code>135</code>

<code> </code><code>assertequals(</code><code>1</code><code>, service.shutdowncalled);</code>

<code>136</code>

<code>137</code>

<code> </code><code>assert.that(service.transitionstates)</code>

<code>138</code>

<code> </code><code>.has().exactly(service.state.starting, service.state.stopping).inorder();</code>

<code>139</code>

<code>140</code>

<code>141</code>

<code>public</code> <code>void</code> <code>teststop_failed() {</code>

<code>142</code>

<code>143</code>

<code>144</code>

<code>145</code>

<code> </code><code>super</code><code>.shutdown();</code>

<code>146</code>

<code>147</code>

<code>148</code>

<code>149</code>

<code>150</code>

<code>151</code>

<code>152</code>

<code>153</code>

<code>154</code>

<code>155</code>

<code>156</code>

<code>157</code>

<code>158</code>

<code>159</code>

<code>160</code>

<code>161</code>

<code>162</code>

<code>163</code>

<code>164</code>

<code>165</code>

<code>public</code> <code>void</code> <code>testservicetostring() {</code>

<code>166</code>

<code> </code><code>abstractidleservice service =</code><code>new</code> <code>testservice();</code>

<code>167</code>

<code> </code><code>assertequals(</code><code>"testservice [new]"</code><code>, service.tostring());</code>

<code>168</code>

<code>169</code>

<code> </code><code>assertequals(</code><code>"testservice [running]"</code><code>, service.tostring());</code>

<code>170</code>

<code>171</code>

<code> </code><code>assertequals(</code><code>"testservice [terminated]"</code><code>, service.tostring());</code>

<code>172</code>

<code>173</code>

<code>174</code>

<code>public</code> <code>void</code> <code>testtimeout()</code><code>throws</code> <code>exception {</code>

<code>175</code>

<code> </code><code>// create a service whose executor will never run its commands</code>

<code>176</code>

<code> </code><code>service service =</code><code>new</code> <code>testservice() {</code>

<code>177</code>

<code> </code><code>@override</code> <code>protected</code> <code>executor executor() {</code>

<code>178</code>

<code> </code><code>return</code> <code>new</code> <code>executor() {</code>

<code>179</code>

<code> </code><code>@override</code> <code>public</code> <code>void</code> <code>execute(runnable command) {}</code>

<code>180</code>

<code>181</code>

<code>182</code>

<code>183</code>

<code>184</code>

<code> </code><code>service.startasync().awaitrunning(</code><code>1</code><code>, timeunit.milliseconds);</code>

<code>185</code>

<code> </code><code>fail(</code><code>"expected timeout"</code><code>);</code>

<code>186</code>

<code> </code><code>}</code><code>catch</code> <code>(timeoutexception e) {</code>

<code>187</code>

<code> </code><code>assert.that(e.getmessage()).contains(service.state.starting.tostring());</code>

<code>188</code>

<code>189</code>

<code>190</code>

<code>191</code>

<code>private</code> <code>static</code> <code>class</code> <code>testservice</code><code>extends</code> <code>abstractidleservice {</code>

<code>192</code>

<code> </code><code>int</code> <code>startupcalled =</code><code>0</code><code>;</code>

<code>193</code>

<code> </code><code>int</code> <code>shutdowncalled =</code><code>0</code><code>;</code>

<code>194</code>

<code> </code><code>final</code> <code>list&lt;state&gt; transitionstates = lists.newarraylist();</code>

<code>195</code>

<code>196</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>startup()</code><code>throws</code> <code>exception {</code>

<code>197</code>

<code> </code><code>assertequals(</code><code>0</code><code>, startupcalled);</code>

<code>198</code>

<code> </code><code>assertequals(</code><code>0</code><code>, shutdowncalled);</code>

<code>199</code>

<code> </code><code>startupcalled++;</code>

<code>200</code>

<code> </code><code>assertequals(state.starting, state());</code>

<code>201</code>

<code>202</code>

<code>203</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>shutdown()</code><code>throws</code> <code>exception {</code>

<code>204</code>

<code> </code><code>assertequals(</code><code>1</code><code>, startupcalled);</code>

<code>205</code>

<code>206</code>

<code> </code><code>shutdowncalled++;</code>

<code>207</code>

<code> </code><code>assertequals(state.stopping, state());</code>

<code>208</code>

<code>209</code>

<code>210</code>

<code>@override</code> <code>protected</code> <code>executor executor() {</code>

<code>211</code>

<code> </code><code>transitionstates.add(state());</code>

<code>212</code>

<code> </code><code>return</code> <code>moreexecutors.samethreadexecutor();</code>

<code>213</code>

<code>214</code>

<code>215</code>

<code>216</code>

<code>217</code>

abstractscheduledservicetest

<code> </code><code>* copyright (c) 2011 the guava authors</code>

<code>import com.google.common.util.concurrent.abstractscheduledservice.scheduler;</code>

<code>import com.google.common.util.concurrent.service.state;</code>

<code>import java.util.concurrent.countdownlatch;</code>

<code>import java.util.concurrent.cyclicbarrier;</code>

<code>import java.util.concurrent.executionexception;</code>

<code>import java.util.concurrent.executors;</code>

<code>import java.util.concurrent.future;</code>

<code>import java.util.concurrent.scheduledexecutorservice;</code>

<code>import java.util.concurrent.scheduledfuture;</code>

<code>import java.util.concurrent.scheduledthreadpoolexecutor;</code>

<code>import java.util.concurrent.atomic.atomicboolean;</code>

<code>import java.util.concurrent.atomic.atomicinteger;</code>

<code> </code><code>* unit test for {@link abstractscheduledservice}.</code>

<code> </code><code>* @author luke sandberg</code>

<code>public</code> <code>class</code> <code>abstractscheduledservicetest</code><code>extends</code> <code>testcase {</code>

<code>volatile</code> <code>scheduler configuration = scheduler.newfixeddelayschedule(</code><code>0</code><code>,</code><code>10</code><code>, timeunit.milliseconds);</code>

<code> </code><code>volatile</code> <code>scheduledfuture&lt;?&gt; future =</code><code>null</code><code>;</code>

<code>volatile</code> <code>boolean</code> <code>atfixedratecalled =</code><code>false</code><code>;</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>withfixeddelaycalled =</code><code>false</code><code>;</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>schedulecalled =</code><code>false</code><code>;</code>

<code>final</code> <code>scheduledexecutorservice executor =</code><code>new</code> <code>scheduledthreadpoolexecutor(</code><code>10</code><code>) {</code>

<code> </code><code>@override</code>

<code> </code><code>public</code> <code>scheduledfuture&lt;?&gt; schedulewithfixeddelay(runnable command,</code><code>long</code> <code>initialdelay,</code>

<code> </code><code>long</code> <code>delay, timeunit unit) {</code>

<code> </code><code>return</code> <code>future =</code><code>super</code><code>.schedulewithfixeddelay(command, initialdelay, delay, unit);</code>

<code> </code><code>nullservice service =</code><code>new</code> <code>nullservice();</code>

<code> </code><code>assertfalse(future.isdone());</code>

<code> </code><code>asserttrue(future.iscancelled());</code>

<code>private</code> <code>class</code> <code>nullservice</code><code>extends</code> <code>abstractscheduledservice {</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>runoneiteration()</code><code>throws</code> <code>exception {}</code>

<code> </code><code>@override</code> <code>protected</code> <code>scheduler scheduler() {</code><code>return</code> <code>configuration; }</code>

<code> </code><code>@override</code> <code>protected</code> <code>scheduledexecutorservice executor() {</code><code>return</code> <code>executor; }</code>

<code>public</code> <code>void</code> <code>testfailonexceptionfromrun()</code><code>throws</code> <code>exception {</code>

<code> </code><code>service.runexception =</code><code>new</code> <code>exception();</code>

<code> </code><code>service.runfirstbarrier.await();</code>

<code> </code><code>service.runsecondbarrier.await();</code>

<code> </code><code>future.get();</code>

<code> </code><code>}</code><code>catch</code> <code>(executionexception e) {</code>

<code> </code><code>// an execution exception holds a runtime exception (from throwables.propogate) that holds our</code>

<code> </code><code>// original exception.</code>

<code> </code><code>assertequals(service.runexception, e.getcause().getcause());</code>

<code> </code><code>assertequals(service.state(), service.state.failed);</code>

<code>public</code> <code>void</code> <code>testfailonexceptionfromstartup() {</code>

<code> </code><code>service.startupexception =</code><code>new</code> <code>exception();</code>

<code> </code><code>}</code><code>catch</code> <code>(illegalstateexception e) {</code>

<code> </code><code>assertequals(service.startupexception, e.getcause());</code>

<code> </code><code>assertequals(</code><code>0</code><code>, service.numberoftimesruncalled.get());</code>

<code>public</code> <code>void</code> <code>testfailonexceptionfromshutdown()</code><code>throws</code> <code>exception {</code>

<code> </code><code>service.shutdownexception =</code><code>new</code> <code>exception();</code>

<code> </code><code>service.stopasync();</code>

<code> </code><code>service.awaitterminated();</code>

<code> </code><code>assertequals(service.shutdownexception, e.getcause());</code>

<code>public</code> <code>void</code> <code>testrunoneiterationcalledmultipletimes()</code><code>throws</code> <code>exception {</code>

<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>1</code><code>; i &lt;</code><code>10</code><code>; i++) {</code>

<code> </code><code>assertequals(i, service.numberoftimesruncalled.get());</code>

<code>public</code> <code>void</code> <code>testexecutoronlycalledonce()</code><code>throws</code> <code>exception {</code>

<code> </code><code>// it should be called once during startup.</code>

<code> </code><code>assertequals(</code><code>1</code><code>, service.numberoftimesexecutorcalled.get());</code>

<code> </code><code>// only called once overall.</code>

<code>public</code> <code>void</code> <code>testdefaultexecutorisshutdownwhenserviceisstopped()</code><code>throws</code> <code>exception {</code>

<code> </code><code>final</code> <code>countdownlatch terminationlatch =</code><code>new</code> <code>countdownlatch(</code><code>1</code><code>);</code>

<code> </code><code>abstractscheduledservice service =</code><code>new</code> <code>abstractscheduledservice() {</code>

<code> </code><code>volatile</code> <code>scheduledexecutorservice executorservice;</code>

<code>@override</code> <code>protected</code> <code>scheduledexecutorservice executor() {</code>

<code> </code><code>if</code> <code>(executorservice ==</code><code>null</code><code>) {</code>

<code> </code><code>executorservice =</code><code>super</code><code>.executor();</code>

<code> </code><code>// add a listener that will be executed after the listener that shuts down the executor.</code>

<code> </code><code>addlistener(</code><code>new</code> <code>listener() {</code>

<code> </code><code>@override</code> <code>public</code> <code>void</code> <code>terminated(state from) {</code>

<code> </code><code>terminationlatch.countdown();</code>

<code> </code><code>}, moreexecutors.samethreadexecutor());</code>

<code> </code><code>return</code> <code>executorservice;</code>

<code>@override</code> <code>protected</code> <code>scheduler scheduler() {</code>

<code> </code><code>return</code> <code>scheduler.newfixeddelayschedule(</code><code>0</code><code>,</code><code>1</code><code>, timeunit.milliseconds);</code>

<code> </code><code>}};</code>

<code>service.startasync();</code>

<code> </code><code>assertfalse(service.executor().isshutdown());</code>

<code> </code><code>service.awaitrunning();</code>

<code> </code><code>terminationlatch.await();</code>

<code> </code><code>asserttrue(service.executor().isshutdown());</code>

<code> </code><code>asserttrue(service.executor().awaittermination(</code><code>100</code><code>, timeunit.milliseconds));</code>

<code>public</code> <code>void</code> <code>testdefaultexecutorisshutdownwhenservicefails()</code><code>throws</code> <code>exception {</code>

<code> </code><code>final</code> <code>countdownlatch failurelatch =</code><code>new</code> <code>countdownlatch(</code><code>1</code><code>);</code>

<code> </code><code>throw</code> <code>new</code> <code>exception(</code><code>"failed"</code><code>);</code>

<code> </code><code>@override</code> <code>public</code> <code>void</code> <code>failed(state from, throwable failure) {</code>

<code> </code><code>failurelatch.countdown();</code>

<code>try</code> <code>{</code>

<code> </code><code>fail(</code><code>"expected service to fail during startup"</code><code>);</code>

<code> </code><code>}</code><code>catch</code> <code>(illegalstateexception expected) {}</code>

<code> </code><code>failurelatch.await();</code>

<code>218</code>

<code>219</code>

<code>220</code>

<code>public</code> <code>void</code> <code>testscheduleronlycalledonce()</code><code>throws</code> <code>exception {</code>

<code>221</code>

<code>222</code>

<code>223</code>

<code>224</code>

<code> </code><code>assertequals(</code><code>1</code><code>, service.numberoftimesschedulercalled.get());</code>

<code>225</code>

<code>226</code>

<code>227</code>

<code>228</code>

<code>229</code>

<code>230</code>

<code>231</code>

<code>232</code>

<code>233</code>

<code>234</code>

<code>235</code>

<code>236</code>

<code>237</code>

<code>238</code>

<code>private</code> <code>class</code> <code>testservice</code><code>extends</code> <code>abstractscheduledservice {</code>

<code>239</code>

<code> </code><code>cyclicbarrier runfirstbarrier =</code><code>new</code> <code>cyclicbarrier(</code><code>2</code><code>);</code>

<code>240</code>

<code> </code><code>cyclicbarrier runsecondbarrier =</code><code>new</code> <code>cyclicbarrier(</code><code>2</code><code>);</code>

<code>241</code>

<code>242</code>

<code>volatile</code> <code>boolean</code> <code>startupcalled =</code><code>false</code><code>;</code>

<code>243</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>shutdowncalled =</code><code>false</code><code>;</code>

<code>244</code>

<code> </code><code>atomicinteger numberoftimesruncalled =</code><code>new</code> <code>atomicinteger(</code><code>0</code><code>);</code>

<code>245</code>

<code> </code><code>atomicinteger numberoftimesexecutorcalled =</code><code>new</code> <code>atomicinteger(</code><code>0</code><code>);</code>

<code>246</code>

<code> </code><code>atomicinteger numberoftimesschedulercalled =</code><code>new</code> <code>atomicinteger(</code><code>0</code><code>);</code>

<code>247</code>

<code> </code><code>volatile</code> <code>exception runexception =</code><code>null</code><code>;</code>

<code>248</code>

<code> </code><code>volatile</code> <code>exception startupexception =</code><code>null</code><code>;</code>

<code>249</code>

<code> </code><code>volatile</code> <code>exception shutdownexception =</code><code>null</code><code>;</code>

<code>250</code>

<code>251</code>

<code>@override</code>

<code>252</code>

<code> </code><code>protected</code> <code>void</code> <code>runoneiteration()</code><code>throws</code> <code>exception {</code>

<code>253</code>

<code> </code><code>asserttrue(startupcalled);</code>

<code>254</code>

<code> </code><code>assertfalse(shutdowncalled);</code>

<code>255</code>

<code> </code><code>numberoftimesruncalled.incrementandget();</code>

<code>256</code>

<code> </code><code>assertequals(state.running, state());</code>

<code>257</code>

<code> </code><code>runfirstbarrier.await();</code>

<code>258</code>

<code> </code><code>runsecondbarrier.await();</code>

<code>259</code>

<code> </code><code>if</code> <code>(runexception !=</code><code>null</code><code>) {</code>

<code>260</code>

<code> </code><code>throw</code> <code>runexception;</code>

<code>261</code>

<code>262</code>

<code>263</code>

<code>264</code>

<code>265</code>

<code> </code><code>protected</code> <code>void</code> <code>startup()</code><code>throws</code> <code>exception {</code>

<code>266</code>

<code> </code><code>assertfalse(startupcalled);</code>

<code>267</code>

<code>268</code>

<code> </code><code>startupcalled =</code><code>true</code><code>;</code>

<code>269</code>

<code>270</code>

<code> </code><code>if</code> <code>(startupexception !=</code><code>null</code><code>) {</code>

<code>271</code>

<code> </code><code>throw</code> <code>startupexception;</code>

<code>272</code>

<code>273</code>

<code>274</code>

<code>275</code>

<code>276</code>

<code> </code><code>protected</code> <code>void</code> <code>shutdown()</code><code>throws</code> <code>exception {</code>

<code>277</code>

<code>278</code>

<code>279</code>

<code> </code><code>shutdowncalled =</code><code>true</code><code>;</code>

<code>280</code>

<code> </code><code>if</code> <code>(shutdownexception !=</code><code>null</code><code>) {</code>

<code>281</code>

<code> </code><code>throw</code> <code>shutdownexception;</code>

<code>282</code>

<code>283</code>

<code>284</code>

<code>285</code>

<code>286</code>

<code> </code><code>protected</code> <code>scheduledexecutorservice executor() {</code>

<code>287</code>

<code> </code><code>numberoftimesexecutorcalled.incrementandget();</code>

<code>288</code>

<code> </code><code>return</code> <code>executor;</code>

<code>289</code>

<code>290</code>

<code>291</code>

<code>292</code>

<code> </code><code>protected</code> <code>scheduler scheduler() {</code>

<code>293</code>

<code> </code><code>numberoftimesschedulercalled.incrementandget();</code>

<code>294</code>

<code> </code><code>return</code> <code>configuration;</code>

<code>295</code>

<code>296</code>

<code>297</code>

<code>298</code>

<code>public</code> <code>static</code> <code>class</code> <code>schedulertest</code><code>extends</code> <code>testcase {</code>

<code>299</code>

<code> </code><code>// these constants are arbitrary and just used to make sure that the correct method is called</code>

<code>300</code>

<code> </code><code>// with the correct parameters.</code>

<code>301</code>

<code> </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>initialdelay =</code><code>10</code><code>;</code>

<code>302</code>

<code> </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>delay =</code><code>20</code><code>;</code>

<code>303</code>

<code> </code><code>private</code> <code>static</code> <code>final</code> <code>timeunit unit = timeunit.milliseconds;</code>

<code>304</code>

<code>305</code>

<code>// unique runnable object used for comparison.</code>

<code>306</code>

<code> </code><code>final</code> <code>runnable testrunnable =</code><code>new</code> <code>runnable() {</code><code>@override</code> <code>public</code> <code>void</code> <code>run() {}};</code>

<code>307</code>

<code> </code><code>boolean</code> <code>called =</code><code>false</code><code>;</code>

<code>308</code>

<code>309</code>

<code>private</code> <code>void</code> <code>assertsinglecallwithcorrectparameters(runnable command,</code><code>long</code> <code>initialdelay,</code>

<code>310</code>

<code>311</code>

<code> </code><code>assertfalse(called);</code><code>// only called once.</code>

<code>312</code>

<code> </code><code>called =</code><code>true</code><code>;</code>

<code>313</code>

<code> </code><code>assertequals(schedulertest.initialdelay, initialdelay);</code>

<code>314</code>

<code> </code><code>assertequals(schedulertest.delay, delay);</code>

<code>315</code>

<code> </code><code>assertequals(schedulertest.unit, unit);</code>

<code>316</code>

<code> </code><code>assertequals(testrunnable, command);</code>

<code>317</code>

<code>318</code>

<code>319</code>

<code>public</code> <code>void</code> <code>testfixedrateschedule() {</code>

<code>320</code>

<code> </code><code>scheduler schedule = scheduler.newfixedrateschedule(initialdelay, delay, unit);</code>

<code>321</code>

<code> </code><code>schedule.schedule(</code><code>null</code><code>,</code><code>new</code> <code>scheduledthreadpoolexecutor(</code><code>1</code><code>) {</code>

<code>322</code>

<code>323</code>

<code> </code><code>public</code> <code>scheduledfuture&lt;?&gt; scheduleatfixedrate(runnable command,</code><code>long</code> <code>initialdelay,</code>

<code>324</code>

<code> </code><code>long</code> <code>period, timeunit unit) {</code>

<code>325</code>

<code> </code><code>assertsinglecallwithcorrectparameters(command, initialdelay, delay, unit);</code>

<code>326</code>

<code> </code><code>return</code> <code>null</code><code>;</code>

<code>327</code>

<code>328</code>

<code> </code><code>}, testrunnable);</code>

<code>329</code>

<code> </code><code>asserttrue(called);</code>

<code>330</code>

<code>331</code>

<code>332</code>

<code>public</code> <code>void</code> <code>testfixeddelayschedule() {</code>

<code>333</code>

<code> </code><code>scheduler schedule = scheduler.newfixeddelayschedule(initialdelay, delay, unit);</code>

<code>334</code>

<code> </code><code>schedule.schedule(</code><code>null</code><code>,</code><code>new</code> <code>scheduledthreadpoolexecutor(</code><code>10</code><code>) {</code>

<code>335</code>

<code>336</code>

<code>337</code>

<code>338</code>

<code>339</code>

<code>340</code>

<code>341</code>

<code>342</code>

<code>343</code>

<code>344</code>

<code>345</code>

<code>private</code> <code>class</code> <code>testcustomscheduler</code><code>extends</code> <code>abstractscheduledservice.customscheduler {</code>

<code>346</code>

<code> </code><code>public</code> <code>atomicinteger schedulecounter =</code><code>new</code> <code>atomicinteger(</code><code>0</code><code>);</code>

<code>347</code>

<code>348</code>

<code> </code><code>protected</code> <code>schedule getnextschedule()</code><code>throws</code> <code>exception {</code>

<code>349</code>

<code> </code><code>schedulecounter.incrementandget();</code>

<code>350</code>

<code> </code><code>return</code> <code>new</code> <code>schedule(</code><code>0</code><code>, timeunit.seconds);</code>

<code>351</code>

<code>352</code>

<code>353</code>

<code>354</code>

<code>public</code> <code>void</code> <code>testcustomschedule_startstop()</code><code>throws</code> <code>exception {</code>

<code>355</code>

<code> </code><code>final</code> <code>cyclicbarrier firstbarrier =</code><code>new</code> <code>cyclicbarrier(</code><code>2</code><code>);</code>

<code>356</code>

<code> </code><code>final</code> <code>cyclicbarrier secondbarrier =</code><code>new</code> <code>cyclicbarrier(</code><code>2</code><code>);</code>

<code>357</code>

<code> </code><code>final</code> <code>atomicboolean shouldwait =</code><code>new</code> <code>atomicboolean(</code><code>true</code><code>);</code>

<code>358</code>

<code> </code><code>runnable task =</code><code>new</code> <code>runnable() {</code>

<code>359</code>

<code> </code><code>@override</code> <code>public</code> <code>void</code> <code>run() {</code>

<code>360</code>

<code>361</code>

<code> </code><code>if</code> <code>(shouldwait.get()) {</code>

<code>362</code>

<code> </code><code>firstbarrier.await();</code>

<code>363</code>

<code> </code><code>secondbarrier.await();</code>

<code>364</code>

<code>365</code>

<code> </code><code>}</code><code>catch</code> <code>(exception e) {</code>

<code>366</code>

<code> </code><code>throw</code> <code>new</code> <code>runtimeexception(e);</code>

<code>367</code>

<code>368</code>

<code>369</code>

<code>370</code>

<code> </code><code>testcustomscheduler scheduler =</code><code>new</code> <code>testcustomscheduler();</code>

<code>371</code>

<code> </code><code>future&lt;?&gt; future = scheduler.schedule(</code><code>null</code><code>, executors.newscheduledthreadpool(</code><code>10</code><code>), task);</code>

<code>372</code>

<code>373</code>

<code> </code><code>assertequals(</code><code>1</code><code>, scheduler.schedulecounter.get());</code>

<code>374</code>

<code>375</code>

<code>376</code>

<code> </code><code>assertequals(</code><code>2</code><code>, scheduler.schedulecounter.get());</code>

<code>377</code>

<code> </code><code>shouldwait.set(</code><code>false</code><code>);</code>

<code>378</code>

<code>379</code>

<code> </code><code>future.cancel(</code><code>false</code><code>);</code>

<code>380</code>

<code>381</code>

<code>382</code>

<code>public</code> <code>void</code> <code>testcustomschedulerservicestop()</code><code>throws</code> <code>exception {</code>

<code>383</code>

<code> </code><code>testabstractscheduledcustomservice service =</code><code>new</code> <code>testabstractscheduledcustomservice();</code>

<code>384</code>

<code>385</code>

<code> </code><code>service.firstbarrier.await();</code>

<code>386</code>

<code> </code><code>assertequals(</code><code>1</code><code>, service.numiterations.get());</code>

<code>387</code>

<code>388</code>

<code> </code><code>service.secondbarrier.await();</code>

<code>389</code>

<code>390</code>

<code> </code><code>// sleep for a while just to ensure that our task wasn't called again.</code>

<code>391</code>

<code> </code><code>thread.sleep(unit.tomillis(</code><code>3</code> <code>* delay));</code>

<code>392</code>

<code>393</code>

<code>394</code>

<code>395</code>

<code>public</code> <code>void</code> <code>testbig()</code><code>throws</code> <code>exception {</code>

<code>396</code>

<code> </code><code>testabstractscheduledcustomservice service =</code><code>new</code> <code>testabstractscheduledcustomservice() {</code>

<code>397</code>

<code> </code><code>@override</code> <code>protected</code> <code>scheduler scheduler() {</code>

<code>398</code>

<code> </code><code>return</code> <code>new</code> <code>abstractscheduledservice.customscheduler() {</code>

<code>399</code>

<code>400</code>

<code>401</code>

<code> </code><code>// explicitly yield to increase the probability of a pathological scheduling.</code>

<code>402</code>

<code> </code><code>thread.yield();</code>

<code>403</code>

<code>404</code>

<code>405</code>

<code>406</code>

<code>407</code>

<code>408</code>

<code> </code><code>service.usebarriers =</code><code>false</code><code>;</code>

<code>409</code>

<code>410</code>

<code> </code><code>thread.sleep(</code><code>50</code><code>);</code>

<code>411</code>

<code> </code><code>service.usebarriers =</code><code>true</code><code>;</code>

<code>412</code>

<code>413</code>

<code> </code><code>int</code> <code>numiterations = service.numiterations.get();</code>

<code>414</code>

<code>415</code>

<code>416</code>

<code>417</code>

<code> </code><code>assertequals(numiterations, service.numiterations.get());</code>

<code>418</code>

<code>419</code>

<code>420</code>

<code>private</code> <code>static</code> <code>class</code> <code>testabstractscheduledcustomservice</code><code>extends</code> <code>abstractscheduledservice {</code>

<code>421</code>

<code> </code><code>final</code> <code>atomicinteger numiterations =</code><code>new</code> <code>atomicinteger(</code><code>0</code><code>);</code>

<code>422</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>usebarriers =</code><code>true</code><code>;</code>

<code>423</code>

<code>424</code>

<code>425</code>

<code>426</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>runoneiteration()</code><code>throws</code> <code>exception {</code>

<code>427</code>

<code> </code><code>numiterations.incrementandget();</code>

<code>428</code>

<code> </code><code>if</code> <code>(usebarriers) {</code>

<code>429</code>

<code>430</code>

<code>431</code>

<code>432</code>

<code>433</code>

<code>434</code>

<code>435</code>

<code> </code><code>// use a bunch of threads so that weird overlapping schedules are more likely to happen.</code>

<code>436</code>

<code> </code><code>return</code> <code>executors.newscheduledthreadpool(</code><code>10</code><code>);</code>

<code>437</code>

<code>438</code>

<code>439</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>startup()</code><code>throws</code> <code>exception {}</code>

<code>440</code>

<code>441</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>shutdown()</code><code>throws</code> <code>exception {}</code>

<code>442</code>

<code>443</code>

<code>444</code>

<code> </code><code>return</code> <code>new</code> <code>customscheduler() {</code>

<code>445</code>

<code>446</code>

<code>447</code>

<code> </code><code>return</code> <code>new</code> <code>schedule(delay, unit);</code>

<code>448</code>

<code>449</code>

<code>450</code>

<code>451</code>

<code>452</code>

<code>public</code> <code>void</code> <code>testcustomschedulerfailure()</code><code>throws</code> <code>exception {</code>

<code>453</code>

<code> </code><code>testfailingcustomscheduledservice service =</code><code>new</code> <code>testfailingcustomscheduledservice();</code>

<code>454</code>

<code>455</code>

<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>1</code><code>; i &lt;</code><code>4</code><code>; i++) {</code>

<code>456</code>

<code>457</code>

<code> </code><code>assertequals(i, service.numiterations.get());</code>

<code>458</code>

<code>459</code>

<code>460</code>

<code> </code><code>thread.sleep(</code><code>1000</code><code>);</code>

<code>461</code>

<code>462</code>

<code> </code><code>service.stopasync().awaitterminated(</code><code>100</code><code>, timeunit.seconds);</code>

<code>463</code>

<code>464</code>

<code>465</code>

<code> </code><code>assertequals(state.failed, service.state());</code>

<code>466</code>

<code>467</code>

<code>468</code>

<code>469</code>

<code>private</code> <code>static</code> <code>class</code> <code>testfailingcustomscheduledservice</code><code>extends</code> <code>abstractscheduledservice {</code>

<code>470</code>

<code>471</code>

<code>472</code>

<code>473</code>

<code>474</code>

<code>475</code>

<code>476</code>

<code>477</code>

<code>478</code>

<code>479</code>

<code>480</code>

<code>481</code>

<code>482</code>

<code>483</code>

<code>484</code>

<code>485</code>

<code>486</code>

<code>487</code>

<code>488</code>

<code>489</code>

<code> </code><code>if</code> <code>(numiterations.get() &gt;</code><code>2</code><code>) {</code>

<code>490</code>

<code> </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"failed"</code><code>);</code>

<code>491</code>

<code>492</code>

<code>493</code>

<code>494</code>

<code>495</code>

<code>496</code>

<code>497</code>

<code>498</code>

abstractservicetest

<code>import static java.lang.thread.currentthread;</code>

<code>import static java.util.concurrent.timeunit.seconds;</code>

<code>import com.google.common.collect.immutablelist;</code>

<code>import com.google.common.collect.iterables;</code>

<code>import com.google.common.util.concurrent.service.listener;</code>

<code>import java.lang.thread.uncaughtexceptionhandler;</code>

<code>import java.util.concurrent.atomic.atomicreference;</code>

<code>import javax.annotation.concurrent.guardedby;</code>

<code> </code><code>* unit test for {@link abstractservice}.</code>

<code> </code><code>* @author jesse wilson</code>

<code>public class abstractservicetest extends testcase {</code>

<code>private thread executionthread;</code>

<code> </code><code>private throwable thrownbyexecutionthread;</code>

<code>public void testnoopservicestartstop() throws exception {</code>

<code> </code><code>noopservice service = new noopservice();</code>

<code> </code><code>recordinglistener listener = recordinglistener.record(service);</code>

<code>assertequals(state.new, service.state());</code>

<code> </code><code>assertfalse(service.isrunning());</code>

<code> </code><code>assertfalse(service.running);</code>

<code> </code><code>assertequals(state.running, service.state());</code>

<code> </code><code>asserttrue(service.isrunning());</code>

<code> </code><code>asserttrue(service.running);</code>

<code>service.stopasync();</code>

<code> </code><code>assertequals(state.terminated, service.state());</code>

<code> </code><code>assertequals(</code>

<code> </code><code>immutablelist.of(</code>

<code> </code><code>state.starting,</code>

<code> </code><code>state.running,</code>

<code> </code><code>state.stopping,</code>

<code> </code><code>state.terminated),</code>

<code> </code><code>listener.getstatehistory());</code>

<code>public void testnoopservicestartandwaitstopandwait() throws exception {</code>

<code>service.startasync().awaitrunning();</code>

<code>service.stopasync().awaitterminated();</code>

<code>public void testnoopservicestartasyncandawaitstopasyncandawait() throws exception {</code>

<code>public void testnoopservicestopidempotence() throws exception {</code>

<code>public void testnoopservicestopidempotenceafterwait() throws exception {</code>

<code>public void testnoopservicestopidempotencedoublewait() throws exception {</code>

<code>public void testnoopservicestartstopandwaituninterruptible()</code>

<code> </code><code>throws exception {</code>

<code>currentthread().interrupt();</code>

<code> </code><code>try {</code>

<code>asserttrue(currentthread().isinterrupted());</code>

<code> </code><code>} finally {</code>

<code> </code><code>thread.interrupted(); // clear interrupt for future tests</code>

<code>private static class noopservice extends abstractservice {</code>

<code> </code><code>boolean running = false;</code>

<code>@override protected void dostart() {</code>

<code> </code><code>assertfalse(running);</code>

<code> </code><code>running = true;</code>

<code> </code><code>notifystarted();</code>

<code>@override protected void dostop() {</code>

<code> </code><code>asserttrue(running);</code>

<code> </code><code>running = false;</code>

<code> </code><code>notifystopped();</code>

<code>public void testmanualservicestartstop() throws exception {</code>

<code> </code><code>manualswitchedservice service = new manualswitchedservice();</code>

<code> </code><code>assertequals(state.starting, service.state());</code>

<code> </code><code>asserttrue(service.dostartcalled);</code>

<code>service.notifystarted(); // usually this would be invoked by another thread</code>

<code> </code><code>assertequals(state.stopping, service.state());</code>

<code> </code><code>asserttrue(service.dostopcalled);</code>

<code>service.notifystopped(); // usually this would be invoked by another thread</code>

<code>public void testmanualservicenotifystoppedwhilerunning() throws exception {</code>

<code> </code><code>service.notifystarted();</code>

<code> </code><code>service.notifystopped();</code>

<code> </code><code>assertfalse(service.dostopcalled);</code>

<code>assertequals(</code>

<code>public void testmanualservicestopwhilestarting() throws exception {</code>

<code>service.notifystarted();</code>

<code>service.notifystopped();</code>

<code> </code><code>* this tests for a bug where if {@link service#stopasync()} was called while the service was</code>

<code> </code><code>* {@link state#starting} more than once, the {@link listener#stopping(state)} callback would get</code>

<code> </code><code>* called multiple times.</code>

<code> </code><code>public void testmanualservicestopmultipletimeswhilestarting() throws exception {</code>

<code> </code><code>final atomicinteger stopppingcount = new atomicinteger();</code>

<code> </code><code>service.addlistener(new listener() {</code>

<code> </code><code>@override public void stopping(state from) {</code>

<code> </code><code>stopppingcount.incrementandget();</code>

<code> </code><code>assertequals(1, stopppingcount.get());</code>

<code>public void testmanualservicestopwhilenew() throws exception {</code>

<code> </code><code>assertfalse(service.dostartcalled);</code>

<code> </code><code>assertequals(immutablelist.of(state.terminated), listener.getstatehistory());</code>

<code>public void testmanualservicefailwhilestarting() throws exception {</code>

<code> </code><code>service.startasync();</code>

<code> </code><code>service.notifyfailed(exception);</code>

<code> </code><code>assertequals(immutablelist.of(state.starting, state.failed), listener.getstatehistory());</code>

<code>public void testmanualservicefailwhilerunning() throws exception {</code>

<code> </code><code>assertequals(immutablelist.of(state.starting, state.running, state.failed),</code>

<code>public void testmanualservicefailwhilestopping() throws exception {</code>

<code> </code><code>assertequals(immutablelist.of(state.starting, state.running, state.stopping, state.failed),</code>

<code>public void testmanualserviceunrequestedstop() {</code>

<code> </code><code>* the user of this service should call {@link #notifystarted} and {@link</code>

<code> </code><code>* #notifystopped} after calling {@link #startasync} and {@link #stopasync}.</code>

<code> </code><code>private static class manualswitchedservice extends abstractservice {</code>

<code> </code><code>boolean dostartcalled = false;</code>

<code> </code><code>boolean dostopcalled = false;</code>

<code> </code><code>assertfalse(dostartcalled);</code>

<code> </code><code>dostartcalled = true;</code>

<code> </code><code>assertfalse(dostopcalled);</code>

<code> </code><code>dostopcalled = true;</code>

<code>public void testawaitterminated() throws exception {</code>

<code> </code><code>final noopservice service = new noopservice();</code>

<code> </code><code>thread waiter = new thread() {</code>

<code> </code><code>@override public void run() {</code>

<code> </code><code>waiter.start();</code>

<code> </code><code>waiter.join(100); // ensure that the await in the other thread is triggered</code>

<code> </code><code>assertfalse(waiter.isalive());</code>

<code>public void testawaitterminated_failedservice() throws exception {</code>

<code> </code><code>final manualswitchedservice service = new manualswitchedservice();</code>

<code> </code><code>final atomicreference&lt;throwable&gt; exception = atomics.newreference();</code>

<code> </code><code>fail("expected an illegalstateexception");</code>

<code> </code><code>} catch (throwable t) {</code>

<code> </code><code>exception.set(t);</code>

<code> </code><code>waiter.join(100);</code>

<code> </code><code>asserttrue(exception.get() instanceof illegalstateexception);</code>

<code> </code><code>assertequals(exception, exception.get().getcause());</code>

<code>public void testthreadedservicestartandwaitstopandwait() throws throwable {</code>

<code> </code><code>threadedservice service = new threadedservice();</code>

<code>service.awaitrunchecks();</code>

<code>throwifset(thrownbyexecutionthread);</code>

<code>public void testthreadedservicestopidempotence() throws throwable {</code>

<code>public void testthreadedservicestopidempotenceafterwait()</code>

<code> </code><code>throws throwable {</code>

<code>executionthread.join();</code>

<code>public void testthreadedservicestopidempotencedoublewait()</code>

<code>public void testmanualservicefailureidempotence() {</code>

<code> </code><code>recordinglistener.record(service);</code>

<code> </code><code>service.notifyfailed(new exception("1"));</code>

<code> </code><code>service.notifyfailed(new exception("2"));</code>

<code> </code><code>assertequals("1", service.failurecause().getmessage());</code>

<code> </code><code>} catch (illegalstateexception e) {</code>

<code> </code><code>assertequals("1", e.getcause().getmessage());</code>

<code>private class threadedservice extends abstractservice {</code>

<code> </code><code>final countdownlatch hasconfirmedisrunning = new countdownlatch(1);</code>

<code> </code><code>* the main test thread tries to stop() the service shortly after</code>

<code> </code><code>* confirming that it is running. meanwhile, the service itself is trying</code>

<code> </code><code>* to confirm that it is running. if the main thread's stop() call happens</code>

<code> </code><code>* before it has the chance, the test will fail. to avoid this, the main</code>

<code> </code><code>* thread calls this method, which waits until the service has performed</code>

<code> </code><code>* its own "running" check.</code>

<code> </code><code>void</code> <code>awaitrunchecks()</code><code>throws</code> <code>interruptedexception {</code>

<code> </code><code>asserttrue(</code><code>"service thread hasn't finished its checks. "</code>

<code> </code><code>+</code><code>"exception status (possibly stale): "</code> <code>+ thrownbyexecutionthread,</code>

<code> </code><code>hasconfirmedisrunning.await(</code><code>10</code><code>, seconds));</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>dostart() {</code>

<code> </code><code>invokeonexecutionthreadfortest(</code><code>new</code> <code>runnable() {</code>

<code> </code><code>hasconfirmedisrunning.countdown();</code>

<code> </code><code>});</code>

<code>499</code>

<code>500</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>dostop() {</code>

<code>501</code>

<code>502</code>

<code>503</code>

<code>504</code>

<code>505</code>

<code>506</code>

<code> </code><code>assertequals(state.terminated, state());</code>

<code>507</code>

<code>508</code>

<code>509</code>

<code>510</code>

<code>511</code>

<code>512</code>

<code>private</code> <code>void</code> <code>invokeonexecutionthreadfortest(runnable runnable) {</code>

<code>513</code>

<code> </code><code>executionthread =</code><code>new</code> <code>thread(runnable);</code>

<code>514</code>

<code> </code><code>executionthread.setuncaughtexceptionhandler(</code><code>new</code> <code>uncaughtexceptionhandler() {</code>

<code>515</code>

<code>516</code>

<code> </code><code>public</code> <code>void</code> <code>uncaughtexception(thread thread, throwable e) {</code>

<code>517</code>

<code> </code><code>thrownbyexecutionthread = e;</code>

<code>518</code>

<code>519</code>

<code>520</code>

<code> </code><code>executionthread.start();</code>

<code>521</code>

<code>522</code>

<code>523</code>

<code>private</code> <code>static</code> <code>void</code> <code>throwifset(throwable t)</code><code>throws</code> <code>throwable {</code>

<code>524</code>

<code> </code><code>if</code> <code>(t !=</code><code>null</code><code>) {</code>

<code>525</code>

<code> </code><code>throw</code> <code>t;</code>

<code>526</code>

<code>527</code>

<code>528</code>

<code>529</code>

<code>public</code> <code>void</code> <code>teststopunstartedservice()</code><code>throws</code> <code>exception {</code>

<code>530</code>

<code> </code><code>noopservice service =</code><code>new</code> <code>noopservice();</code>

<code>531</code>

<code>532</code>

<code>533</code>

<code>534</code>

<code>535</code>

<code>536</code>

<code>537</code>

<code>538</code>

<code>539</code>

<code>540</code>

<code> </code><code>assertequals(state.terminated, iterables.getonlyelement(listener.getstatehistory()));</code>

<code>541</code>

<code>542</code>

<code>543</code>

<code>public</code> <code>void</code> <code>testfailingservicestartandwait()</code><code>throws</code> <code>exception {</code>

<code>544</code>

<code> </code><code>startfailingservice service =</code><code>new</code> <code>startfailingservice();</code>

<code>545</code>

<code>546</code>

<code>547</code>

<code>548</code>

<code>549</code>

<code>550</code>

<code>551</code>

<code> </code><code>assertequals(exception, service.failurecause());</code>

<code>552</code>

<code> </code><code>assertequals(exception, e.getcause());</code>

<code>553</code>

<code>554</code>

<code>555</code>

<code>556</code>

<code>557</code>

<code> </code><code>state.failed),</code>

<code>558</code>

<code>559</code>

<code>560</code>

<code>561</code>

<code>public</code> <code>void</code> <code>testfailingservicestopandwait_stopfailing()</code><code>throws</code> <code>exception {</code>

<code>562</code>

<code> </code><code>stopfailingservice service =</code><code>new</code> <code>stopfailingservice();</code>

<code>563</code>

<code>564</code>

<code>565</code>

<code>566</code>

<code>567</code>

<code>568</code>

<code>569</code>

<code>570</code>

<code>571</code>

<code>572</code>

<code>573</code>

<code>574</code>

<code>575</code>

<code>576</code>

<code>577</code>

<code>578</code>

<code>579</code>

<code>580</code>

<code>581</code>

<code>582</code>

<code>public</code> <code>void</code> <code>testfailingservicestopandwait_runfailing()</code><code>throws</code> <code>exception {</code>

<code>583</code>

<code> </code><code>runfailingservice service =</code><code>new</code> <code>runfailingservice();</code>

<code>584</code>

<code>585</code>

<code>586</code>

<code>587</code>

<code>588</code>

<code>589</code>

<code>590</code>

<code>591</code>

<code>592</code>

<code>593</code>

<code>594</code>

<code>595</code>

<code>596</code>

<code>597</code>

<code>598</code>

<code>599</code>

<code>600</code>

<code>601</code>

<code>602</code>

<code>public</code> <code>void</code> <code>testthrowingservicestartandwait()</code><code>throws</code> <code>exception {</code>

<code>603</code>

<code> </code><code>startthrowingservice service =</code><code>new</code> <code>startthrowingservice();</code>

<code>604</code>

<code>605</code>

<code>606</code>

<code>607</code>

<code>608</code>

<code>609</code>

<code>610</code>

<code> </code><code>assertequals(service.exception, service.failurecause());</code>

<code>611</code>

<code> </code><code>assertequals(service.exception, e.getcause());</code>

<code>612</code>

<code>613</code>

<code>614</code>

<code>615</code>

<code>616</code>

<code>617</code>

<code>618</code>

<code>619</code>

<code>620</code>

<code>public</code> <code>void</code> <code>testthrowingservicestopandwait_stopthrowing()</code><code>throws</code> <code>exception {</code>

<code>621</code>

<code> </code><code>stopthrowingservice service =</code><code>new</code> <code>stopthrowingservice();</code>

<code>622</code>

<code>623</code>

<code>624</code>

<code>625</code>

<code>626</code>

<code>627</code>

<code>628</code>

<code>629</code>

<code>630</code>

<code>631</code>

<code>632</code>

<code>633</code>

<code>634</code>

<code>635</code>

<code>636</code>

<code>637</code>

<code>638</code>

<code>639</code>

<code>640</code>

<code>641</code>

<code>public</code> <code>void</code> <code>testthrowingservicestopandwait_runthrowing()</code><code>throws</code> <code>exception {</code>

<code>642</code>

<code> </code><code>runthrowingservice service =</code><code>new</code> <code>runthrowingservice();</code>

<code>643</code>

<code>644</code>

<code>645</code>

<code>646</code>

<code>647</code>

<code>648</code>

<code>649</code>

<code>650</code>

<code>651</code>

<code>652</code>

<code>653</code>

<code>654</code>

<code>655</code>

<code>656</code>

<code>657</code>

<code>658</code>

<code>659</code>

<code>660</code>

<code>661</code>

<code>public</code> <code>void</code> <code>testfailurecause_throwsifnotfailed() {</code>

<code>662</code>

<code>663</code>

<code>664</code>

<code> </code><code>service.failurecause();</code>

<code>665</code>

<code>666</code>

<code>667</code>

<code> </code><code>// expected</code>

<code>668</code>

<code>669</code>

<code>670</code>

<code>671</code>

<code>672</code>

<code>673</code>

<code>674</code>

<code>675</code>

<code>676</code>

<code>677</code>

<code>678</code>

<code>679</code>

<code>680</code>

<code>681</code>

<code>682</code>

<code>683</code>

<code>684</code>

<code>685</code>

<code>public</code> <code>void</code> <code>testaddlistenerafterfailuredoesntcausedeadlock()</code><code>throws</code> <code>interruptedexception {</code>

<code>686</code>

<code> </code><code>final</code> <code>startfailingservice service =</code><code>new</code> <code>startfailingservice();</code>

<code>687</code>

<code>688</code>

<code>689</code>

<code> </code><code>service.addlistener(</code><code>new</code> <code>recordinglistener(service), moreexecutors.samethreadexecutor());</code>

<code>690</code>

<code> </code><code>thread thread =</code><code>new</code> <code>thread() {</code>

<code>691</code>

<code>692</code>

<code> </code><code>// internally stopasync() grabs a lock, this could be any such method on abstractservice.</code>

<code>693</code>

<code>694</code>

<code>695</code>

<code>696</code>

<code> </code><code>thread.start();</code>

<code>697</code>

<code> </code><code>thread.join(</code><code>100</code><code>);</code>

<code>698</code>

<code> </code><code>assertfalse(thread +</code><code>" is deadlocked"</code><code>, thread.isalive());</code>

<code>699</code>

<code>700</code>

<code>701</code>

<code>public</code> <code>void</code> <code>testlistenerdoesntdeadlockonstartandwaitfromrunning()</code><code>throws</code> <code>exception {</code>

<code>702</code>

<code> </code><code>final</code> <code>noopthreadedservice service =</code><code>new</code> <code>noopthreadedservice();</code>

<code>703</code>

<code> </code><code>service.addlistener(</code><code>new</code> <code>listener() {</code>

<code>704</code>

<code> </code><code>@override</code> <code>public</code> <code>void</code> <code>running() {</code>

<code>705</code>

<code>706</code>

<code>707</code>

<code>708</code>

<code> </code><code>service.startasync().awaitrunning(</code><code>10</code><code>, timeunit.milliseconds);</code>

<code>709</code>

<code>710</code>

<code>711</code>

<code>712</code>

<code>public</code> <code>void</code> <code>testlistenerdoesntdeadlockonstopandwaitfromterminated()</code><code>throws</code> <code>exception {</code>

<code>713</code>

<code>714</code>

<code>715</code>

<code>716</code>

<code>717</code>

<code>718</code>

<code>719</code>

<code>720</code>

<code>721</code>

<code>thread thread =</code><code>new</code> <code>thread() {</code>

<code>722</code>

<code>723</code>

<code>724</code>

<code>725</code>

<code>726</code>

<code>727</code>

<code>728</code>

<code>729</code>

<code>730</code>

<code>731</code>

<code>private</code> <code>static</code> <code>class</code> <code>noopthreadedservice</code><code>extends</code> <code>abstractexecutionthreadservice {</code>

<code>732</code>

<code> </code><code>final</code> <code>countdownlatch latch =</code><code>new</code> <code>countdownlatch(</code><code>1</code><code>);</code>

<code>733</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>run()</code><code>throws</code> <code>exception {</code>

<code>734</code>

<code> </code><code>latch.await();</code>

<code>735</code>

<code>736</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>triggershutdown() {</code>

<code>737</code>

<code> </code><code>latch.countdown();</code>

<code>738</code>

<code>739</code>

<code>740</code>

<code>741</code>

<code>private</code> <code>static</code> <code>class</code> <code>startfailingservice</code><code>extends</code> <code>abstractservice {</code>

<code>742</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>dostart() {</code>

<code>743</code>

<code> </code><code>notifyfailed(exception);</code>

<code>744</code>

<code>745</code>

<code>746</code>

<code>747</code>

<code>748</code>

<code>749</code>

<code>750</code>

<code>751</code>

<code>private</code> <code>static</code> <code>class</code> <code>runfailingservice</code><code>extends</code> <code>abstractservice {</code>

<code>752</code>

<code>753</code>

<code>754</code>

<code>755</code>

<code>756</code>

<code>757</code>

<code>758</code>

<code>759</code>

<code>760</code>

<code>761</code>

<code>762</code>

<code>private</code> <code>static</code> <code>class</code> <code>stopfailingservice</code><code>extends</code> <code>abstractservice {</code>

<code>763</code>

<code>764</code>

<code>765</code>

<code>766</code>

<code>767</code>

<code>768</code>

<code>769</code>

<code>770</code>

<code>771</code>

<code>772</code>

<code>private</code> <code>static</code> <code>class</code> <code>startthrowingservice</code><code>extends</code> <code>abstractservice {</code>

<code>773</code>

<code>774</code>

<code>final</code> <code>runtimeexception exception =</code><code>new</code> <code>runtimeexception(</code><code>"deliberate"</code><code>);</code>

<code>775</code>

<code>776</code>

<code>777</code>

<code>778</code>

<code>779</code>

<code>780</code>

<code>781</code>

<code>782</code>

<code>783</code>

<code>784</code>

<code>785</code>

<code>private</code> <code>static</code> <code>class</code> <code>runthrowingservice</code><code>extends</code> <code>abstractservice {</code>

<code>786</code>

<code>787</code>

<code>788</code>

<code>789</code>

<code>790</code>

<code>791</code>

<code>792</code>

<code>793</code>

<code>794</code>

<code>795</code>

<code>796</code>

<code>797</code>

<code>798</code>

<code>799</code>

<code>private</code> <code>static</code> <code>class</code> <code>stopthrowingservice</code><code>extends</code> <code>abstractservice {</code>

<code>800</code>

<code>801</code>

<code>802</code>

<code>803</code>

<code>804</code>

<code>805</code>

<code>806</code>

<code>807</code>

<code>808</code>

<code>809</code>

<code>810</code>

<code>811</code>

<code>812</code>

<code>private</code> <code>static</code> <code>class</code> <code>recordinglistener</code><code>extends</code> <code>listener {</code>

<code>813</code>

<code> </code><code>static</code> <code>recordinglistener record(service service) {</code>

<code>814</code>

<code> </code><code>recordinglistener listener =</code><code>new</code> <code>recordinglistener(service);</code>

<code>815</code>

<code> </code><code>service.addlistener(listener, moreexecutors.samethreadexecutor());</code>

<code>816</code>

<code> </code><code>return</code> <code>listener;</code>

<code>817</code>

<code>818</code>

<code>819</code>

<code>final</code> <code>service service;</code>

<code>820</code>

<code>821</code>

<code>recordinglistener(service service) {</code>

<code>822</code>

<code> </code><code>this</code><code>.service = service;</code>

<code>823</code>

<code>824</code>

<code>825</code>

<code>@guardedby</code><code>(</code><code>"this"</code><code>)</code>

<code>826</code>

<code> </code><code>final</code> <code>list&lt;state&gt; statehistory = lists.newarraylist();</code>

<code>827</code>

<code> </code><code>final</code> <code>countdownlatch completionlatch =</code><code>new</code> <code>countdownlatch(</code><code>1</code><code>);</code>

<code>828</code>

<code>829</code>

<code>immutablelist&lt;state&gt; getstatehistory()</code><code>throws</code> <code>exception {</code>

<code>830</code>

<code> </code><code>completionlatch.await();</code>

<code>831</code>

<code> </code><code>synchronized</code> <code>(</code><code>this</code><code>) {</code>

<code>832</code>

<code> </code><code>return</code> <code>immutablelist.copyof(statehistory);</code>

<code>833</code>

<code>834</code>

<code>835</code>

<code>836</code>

<code>@override</code> <code>public</code> <code>synchronized</code> <code>void</code> <code>starting() {</code>

<code>837</code>

<code> </code><code>asserttrue(statehistory.isempty());</code>

<code>838</code>

<code> </code><code>assertnotsame(state.new, service.state());</code>

<code>839</code>

<code> </code><code>statehistory.add(state.starting);</code>

<code>840</code>

<code>841</code>

<code>842</code>

<code>@override</code> <code>public</code> <code>synchronized</code> <code>void</code> <code>running() {</code>

<code>843</code>

<code> </code><code>assertequals(state.starting, iterables.getonlyelement(statehistory));</code>

<code>844</code>

<code> </code><code>statehistory.add(state.running);</code>

<code>845</code>

<code>846</code>

<code> </code><code>assertnotsame(state.starting, service.state());</code>

<code>847</code>

<code>848</code>

<code>849</code>

<code>@override</code> <code>public</code> <code>synchronized</code> <code>void</code> <code>stopping(state from) {</code>

<code>850</code>

<code> </code><code>assertequals(from, iterables.getlast(statehistory));</code>

<code>851</code>

<code> </code><code>statehistory.add(state.stopping);</code>

<code>852</code>

<code> </code><code>if</code> <code>(from == state.starting) {</code>

<code>853</code>

<code>854</code>

<code>855</code>

<code>856</code>

<code> </code><code>}</code><code>catch</code> <code>(illegalstateexception expected) {</code>

<code>857</code>

<code> </code><code>assertnull(expected.getcause());</code>

<code>858</code>

<code> </code><code>asserttrue(expected.getmessage().equals(</code>

<code>859</code>

<code> </code><code>"expected the service to be running, but was stopping"</code><code>));</code>

<code>860</code>

<code>861</code>

<code>862</code>

<code> </code><code>assertnotsame(from, service.state());</code>

<code>863</code>

<code>864</code>

<code>865</code>

<code>@override</code> <code>public</code> <code>synchronized</code> <code>void</code> <code>terminated(state from) {</code>

<code>866</code>

<code> </code><code>assertequals(from, iterables.getlast(statehistory, state.new));</code>

<code>867</code>

<code> </code><code>statehistory.add(state.terminated);</code>

<code>868</code>

<code>869</code>

<code> </code><code>if</code> <code>(from == state.new) {</code>

<code>870</code>

<code>871</code>

<code>872</code>

<code>873</code>

<code>874</code>

<code>875</code>

<code>876</code>

<code> </code><code>"expected the service to be running, but was terminated"</code><code>));</code>

<code>877</code>

<code>878</code>

<code>879</code>

<code> </code><code>completionlatch.countdown();</code>

<code>880</code>

<code>881</code>

<code>882</code>

<code>@override</code> <code>public</code> <code>synchronized</code> <code>void</code> <code>failed(state from, throwable failure) {</code>

<code>883</code>

<code>884</code>

<code> </code><code>statehistory.add(state.failed);</code>

<code>885</code>

<code>886</code>

<code> </code><code>assertequals(failure, service.failurecause());</code>

<code>887</code>

<code>888</code>

<code>889</code>

<code>890</code>

<code>891</code>

<code>892</code>

<code> </code><code>assertequals(failure, e.getcause());</code>

<code>893</code>

<code>894</code>

<code>895</code>

<code>896</code>

<code>897</code>

<code>898</code>

<code>899</code>

<code>900</code>

<code>901</code>

<code>902</code>

<code>903</code>

<code>904</code>

<code>905</code>

<code>public</code> <code>void</code> <code>testnotifystartedwhennotstarting() {</code>

<code>906</code>

<code> </code><code>abstractservice service =</code><code>new</code> <code>defaultservice();</code>

<code>907</code>

<code>908</code>

<code>909</code>

<code>910</code>

<code>911</code>

<code>912</code>

<code>913</code>

<code>public</code> <code>void</code> <code>testnotifystoppedwhennotrunning() {</code>

<code>914</code>

<code>915</code>

<code>916</code>

<code>917</code>

<code>918</code>

<code>919</code>

<code>920</code>

<code>921</code>

<code>public</code> <code>void</code> <code>testnotifyfailedwhennotstarted() {</code>

<code>922</code>

<code>923</code>

<code>924</code>

<code> </code><code>service.notifyfailed(</code><code>new</code> <code>exception());</code>

<code>925</code>

<code>926</code>

<code>927</code>

<code>928</code>

<code>929</code>

<code>public</code> <code>void</code> <code>testnotifyfailedwhenterminated() {</code>

<code>930</code>

<code>931</code>

<code>932</code>

<code>933</code>

<code>934</code>

<code>935</code>

<code>936</code>

<code>937</code>

<code>938</code>

<code>939</code>

<code>private</code> <code>static</code> <code>class</code> <code>defaultservice</code><code>extends</code> <code>abstractservice {</code>

<code>940</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>dostart() {}</code>

<code>941</code>

<code> </code><code>@override</code> <code>protected</code> <code>void</code> <code>dostop() {}</code>

<code>942</code>

<code>943</code>

<code>944</code>

<code>private</code> <code>static</code> <code>final</code> <code>exception exception =</code><code>new</code> <code>exception();</code>

<code>945</code>

<code>946</code>

servicemanagertest

<code> </code><code>* copyright (c) 2012 the guava authors</code>

<code>import static java.util.arrays.aslist;</code>

<code>import com.google.common.collect.immutablemap;</code>

<code>import com.google.common.collect.immutableset;</code>

<code>import com.google.common.collect.sets;</code>

<code>import com.google.common.testing.nullpointertester;</code>

<code>import com.google.common.testing.testloghandler;</code>

<code>import com.google.common.util.concurrent.servicemanager.listener;</code>

<code>import java.util.arrays;</code>

<code>import java.util.collection;</code>

<code>import java.util.set;</code>

<code>import java.util.logging.formatter;</code>

<code>import java.util.logging.level;</code>

<code>import java.util.logging.logrecord;</code>

<code>import java.util.logging.logger;</code>

<code> </code><code>* tests for {@link servicemanager}.</code>

<code>public class servicemanagertest extends testcase {</code>

<code> </code><code>@override protected void dostart() {</code>

<code> </code><code>* a noop service that will delay the startup and shutdown notification for a configurable amount</code>

<code> </code><code>* of time.</code>

<code> </code><code>private static class noopdelayedserivce extends noopservice {</code>

<code> </code><code>private long delay;</code>

<code>public noopdelayedserivce(long delay) {</code>

<code> </code><code>this.delay = delay;</code>

<code> </code><code>new thread() {</code>

<code> </code><code>uninterruptibles.sleepuninterruptibly(delay, timeunit.milliseconds);</code>

<code> </code><code>}.start();</code>

<code>private static class failstartservice extends noopservice {</code>

<code> </code><code>notifyfailed(new illegalstateexception("failed"));</code>

<code>private static class failrunservice extends noopservice {</code>

<code> </code><code>super.dostart();</code>

<code>private static class failstopservice extends noopservice {</code>

<code> </code><code>@override protected void dostop() {</code>

<code>public void testservicestartuptimes() {</code>

<code> </code><code>service a = new noopdelayedserivce(150);</code>

<code> </code><code>service b = new noopdelayedserivce(353);</code>

<code> </code><code>servicemanager servicemanager = new servicemanager(aslist(a, b));</code>

<code> </code><code>servicemanager.startasync().awaithealthy();</code>

<code> </code><code>immutablemap&lt;service, long&gt; startuptimes = servicemanager.startuptimes();</code>

<code> </code><code>assertequals(2, startuptimes.size());</code>

<code> </code><code>asserttrue(startuptimes.get(a) &gt;= 150);</code>

<code> </code><code>asserttrue(startuptimes.get(b) &gt;= 353);</code>

<code>public void testservicestartstop() {</code>

<code> </code><code>service a = new noopservice();</code>

<code> </code><code>service b = new noopservice();</code>

<code> </code><code>servicemanager manager = new servicemanager(aslist(a, b));</code>

<code> </code><code>recordinglistener listener = new recordinglistener();</code>

<code> </code><code>manager.addlistener(listener);</code>

<code> </code><code>assertstate(manager, service.state.new, a, b);</code>

<code> </code><code>assertfalse(manager.ishealthy());</code>

<code> </code><code>manager.startasync().awaithealthy();</code>

<code> </code><code>assertstate(manager, service.state.running, a, b);</code>

<code> </code><code>asserttrue(manager.ishealthy());</code>

<code> </code><code>asserttrue(listener.healthycalled);</code>

<code> </code><code>assertfalse(listener.stoppedcalled);</code>

<code> </code><code>asserttrue(listener.failedservices.isempty());</code>

<code> </code><code>manager.stopasync().awaitstopped();</code>

<code> </code><code>assertstate(manager, service.state.terminated, a, b);</code>

<code> </code><code>asserttrue(listener.stoppedcalled);</code>

<code>public void testfailstart() throws exception {</code>

<code> </code><code>service b = new failstartservice();</code>

<code> </code><code>service c = new noopservice();</code>

<code> </code><code>service d = new failstartservice();</code>

<code> </code><code>service e = new noopservice();</code>

<code> </code><code>servicemanager manager = new servicemanager(aslist(a, b, c, d, e));</code>

<code> </code><code>assertstate(manager, service.state.new, a, b, c, d, e);</code>

<code> </code><code>} catch (illegalstateexception expected) {</code>

<code> </code><code>assertfalse(listener.healthycalled);</code>

<code> </code><code>assertstate(manager, service.state.running, a, c, e);</code>

<code> </code><code>assertequals(immutableset.of(b, d), listener.failedservices);</code>

<code> </code><code>assertstate(manager, service.state.failed, b, d);</code>

<code>manager.stopasync().awaitstopped();</code>

<code>public void testfailrun() throws exception {</code>

<code> </code><code>service b = new failrunservice();</code>

<code> </code><code>assertequals(immutableset.of(b), listener.failedservices);</code>

<code> </code><code>assertstate(manager, service.state.failed, b);</code>

<code> </code><code>assertstate(manager, service.state.terminated, a);</code>

<code>asserttrue(listener.stoppedcalled);</code>

<code>public void testfailstop() throws exception {</code>

<code> </code><code>service b = new failstopservice();</code>

<code> </code><code>servicemanager manager = new servicemanager(aslist(a, b, c));</code>

<code>manager.startasync().awaithealthy();</code>

<code> </code><code>assertstate(manager, service.state.terminated, a, c);</code>

<code>public void testtostring() throws exception {</code>

<code> </code><code>string tostring = manager.tostring();</code>

<code> </code><code>asserttrue(tostring.contains("noopservice"));</code>

<code> </code><code>asserttrue(tostring.contains("failstartservice"));</code>

<code>public void testtimeouts() throws exception {</code>

<code> </code><code>service a = new noopdelayedserivce(50);</code>

<code> </code><code>servicemanager manager = new servicemanager(aslist(a));</code>

<code> </code><code>manager.startasync();</code>

<code> </code><code>manager.awaithealthy(1, timeunit.milliseconds);</code>

<code> </code><code>} catch (timeoutexception expected) {</code>

<code> </code><code>manager.awaithealthy(100, timeunit.milliseconds); // no exception thrown</code>

<code>manager.stopasync();</code>

<code> </code><code>manager.awaitstopped(1, timeunit.milliseconds);</code>

<code> </code><code>manager.awaitstopped(100, timeunit.milliseconds); // no exception thrown</code>

<code> </code><code>* this covers a case where if the last service to stop failed then the stopped callback would</code>

<code> </code><code>* never be called.</code>

<code> </code><code>public void testsinglefailedservicecallsstopped() {</code>

<code> </code><code>service a = new failstartservice();</code>

<code> </code><code>* this covers a bug where listener.healthy would get called when a single service failed during</code>

<code> </code><code>* startup (it occurred in more complicated cases also).</code>

<code> </code><code>public void testfailstart_singleservicecallshealthy() {</code>

<code> </code><code>* this covers a bug where if a listener was installed that would stop the manager if any service</code>

<code> </code><code>* fails and something failed during startup before service.start was called on all the services,</code>

<code> </code><code>* then awaitstopped would deadlock due to an illegalstateexception that was thrown when trying to</code>

<code> </code><code>* stop the timer(!).</code>

<code> </code><code>public void testfailstart_stopothers() throws timeoutexception {</code>

<code> </code><code>final servicemanager manager = new servicemanager(aslist(a, b));</code>

<code> </code><code>manager.addlistener(new listener() {</code>

<code> </code><code>@override public void failure(service service) {</code>

<code> </code><code>manager.stopasync();</code>

<code> </code><code>}});</code>

<code> </code><code>manager.awaitstopped(10, timeunit.milliseconds);</code>

<code>private static void assertstate(</code>

<code> </code><code>servicemanager manager, service.state state, service... services) {</code>

<code> </code><code>collection&lt;service&gt; managerservices = manager.servicesbystate().get(state);</code>

<code> </code><code>for (service service : services) {</code>

<code> </code><code>assertequals(service.tostring(), state, service.state());</code>

<code> </code><code>assertequals(service.tostring(), service.isrunning(), state == service.state.running);</code>

<code> </code><code>asserttrue(managerservices + " should contain " + service, managerservices.contains(service));</code>

<code> </code><code>* this is for covering a case where the servicemanager would behave strangely if constructed</code>

<code> </code><code>* with no service under management. listeners would never fire because the servicemanager was</code>

<code> </code><code>* healthy and stopped at the same time. this test ensures that listeners fire and ishealthy</code>

<code> </code><code>* makes sense.</code>

<code> </code><code>public void testemptyservicemanager() {</code>

<code> </code><code>logger logger = logger.getlogger(servicemanager.class.getname());</code>

<code> </code><code>logger.setlevel(level.finest);</code>

<code> </code><code>testloghandler loghandler = new testloghandler();</code>

<code> </code><code>logger.addhandler(loghandler);</code>

<code> </code><code>servicemanager manager = new servicemanager(arrays.&lt;service&gt;aslist());</code>

<code> </code><code>manager.addlistener(listener, moreexecutors.samethreadexecutor());</code>

<code> </code><code>// check that our noopservice is not directly observable via any of the inspection methods or</code>

<code> </code><code>// via logging.</code>

<code> </code><code>assertequals("servicemanager{services=[]}", manager.tostring());</code>

<code> </code><code>asserttrue(manager.servicesbystate().isempty());</code>

<code> </code><code>asserttrue(manager.startuptimes().isempty());</code>

<code> </code><code>formatter logformatter = new formatter() {</code>

<code> </code><code>@override public string format(logrecord record) {</code>

<code> </code><code>return formatmessage(record);</code>

<code> </code><code>for (logrecord record : loghandler.getstoredlogrecords()) {</code>

<code> </code><code>assertfalse(logformatter.format(record).contains("noopservice"));</code>

<code> </code><code>* this is for a case where a long running listener using the samethreadlistener could deadlock</code>

<code> </code><code>* another thread calling stopasync().</code>

<code>public void testlistenerdeadlock() throws interruptedexception {</code>

<code> </code><code>final countdownlatch failenter = new countdownlatch(1);</code>

<code> </code><code>service failrunservice = new abstractservice() {</code>

<code> </code><code>notifyfailed(new exception("boom"));</code>

<code> </code><code>final servicemanager manager = new servicemanager(</code>

<code> </code><code>arrays.aslist(failrunservice, new noopservice()));</code>

<code> </code><code>manager.addlistener(new servicemanager.listener() {</code>

<code> </code><code>failenter.countdown();</code>

<code> </code><code>// block forever!</code>

<code> </code><code>uninterruptibles.awaituninterruptibly(new countdownlatch(1));</code>

<code> </code><code>// we do not call awaithealthy because, due to races, that method may throw an exception. but</code>

<code> </code><code>// we really just want to wait for the thread to be in the failure callback so we wait for that</code>

<code> </code><code>// explicitly instead.</code>

<code> </code><code>failenter.await();</code>

<code> </code><code>assertfalse("state should be updated before calling listeners", manager.ishealthy());</code>

<code> </code><code>// now we want to stop the services.</code>

<code> </code><code>thread stoppingthread = new thread() {</code>

<code> </code><code>stoppingthread.start();</code>

<code> </code><code>// this should be super fast since the only non stopped service is a noopservice</code>

<code> </code><code>stoppingthread.join(1000);</code>

<code> </code><code>assertfalse("stopasync has deadlocked!.", stoppingthread.isalive());</code>

<code> </code><code>* catches a bug where when constructing a service manager failed, later interactions with the</code>

<code> </code><code>* service could cause illegalstateexceptions inside the partially constructed servicemanager.</code>

<code> </code><code>* this ise wouldn't actually bubble up but would get logged by executionqueue. this obfuscated</code>

<code> </code><code>* the original error (which was not constructing servicemanager correctly).</code>

<code> </code><code>public void testpartiallyconstructedmanager() {</code>

<code> </code><code>logger logger = logger.getlogger("global");</code>

<code> </code><code>new servicemanager(arrays.aslist(service));</code>

<code> </code><code>} catch (illegalargumentexception expected) {}</code>

<code> </code><code>// nothing was logged!</code>

<code> </code><code>assertequals(0, loghandler.getstoredlogrecords().size());</code>

<code>public void testpartiallyconstructedmanager_transitionafteraddlistenerbeforestateisready() {</code>

<code> </code><code>// ensure that if weird things happen during construction then we get exceptions.</code>

<code> </code><code>final noopservice service1 = new noopservice();</code>

<code> </code><code>// this service will start service1 when addlistener is called. this simulates service1 being</code>

<code> </code><code>// started asynchronously.</code>

<code> </code><code>service service2 = new service() {</code>

<code> </code><code>final noopservice delegate = new noopservice();</code>

<code> </code><code>@override public final void addlistener(listener listener, executor executor) {</code>

<code> </code><code>service1.startasync();</code>

<code> </code><code>delegate.addlistener(listener, executor);</code>

<code> </code><code>// delegates from here on down</code>

<code> </code><code>@override public final service startasync() {</code>

<code> </code><code>return delegate.startasync();</code>

<code>@override public final service stopasync() {</code>

<code> </code><code>return delegate.stopasync();</code>

<code>@override public final listenablefuture&lt;state&gt; start() {</code>

<code> </code><code>return delegate.start();</code>

<code>@override public final listenablefuture&lt;state&gt; stop() {</code>

<code> </code><code>return delegate.stop();</code>

<code>@override public state startandwait() {</code>

<code> </code><code>return delegate.startandwait();</code>

<code>@override public state stopandwait() {</code>

<code> </code><code>return delegate.stopandwait();</code>

<code>@override public final void awaitrunning() {</code>

<code> </code><code>delegate.awaitrunning();</code>

<code>@override public final void awaitrunning(long timeout, timeunit unit)</code>

<code> </code><code>throws timeoutexception {</code>

<code> </code><code>delegate.awaitrunning(timeout, unit);</code>

<code>@override public final void awaitterminated() {</code>

<code> </code><code>delegate.awaitterminated();</code>

<code>@override public final void awaitterminated(long timeout, timeunit unit)</code>

<code> </code><code>delegate.awaitterminated(timeout, unit);</code>

<code>@override public final boolean isrunning() {</code>

<code> </code><code>return delegate.isrunning();</code>

<code>@override public final state state() {</code>

<code> </code><code>return delegate.state();</code>

<code>@override public final throwable failurecause() {</code>

<code> </code><code>return delegate.failurecause();</code>

<code> </code><code>new servicemanager(arrays.aslist(service1, service2));</code>

<code> </code><code>} catch (illegalargumentexception expected) {</code>

<code> </code><code>asserttrue(expected.getmessage().contains("started transitioning asynchronously"));</code>

<code> </code><code>* this test is for a case where two service.listener callbacks for the same service would call</code>

<code> </code><code>* transitionservice in the wrong order due to a race. due to the fact that it is a race this</code>

<code> </code><code>* test isn't guaranteed to expose the issue, but it is at least likely to become flaky if the</code>

<code> </code><code>* race sneaks back in, and in this case flaky means something is definitely wrong.</code>

<code> </code><code>* &lt;p&gt;before the bug was fixed this test would fail at least 30% of the time.</code>

<code>public void testtransitionrace() throws timeoutexception {</code>

<code> </code><code>for (int k = 0; k &lt; 1000; k++) {</code>

<code> </code><code>list&lt;service&gt; services = lists.newarraylist();</code>

<code> </code><code>for (int i = 0; i &lt; 5; i++) {</code>

<code> </code><code>services.add(new snappyshutdownservice(i));</code>

<code> </code><code>servicemanager manager = new servicemanager(services);</code>

<code> </code><code>manager.stopasync().awaitstopped(1, timeunit.seconds);</code>

<code> </code><code>* this service will shutdown very quickly after stopasync is called and uses a background thread</code>

<code> </code><code>* so that we know that the stopping() listeners will execute on a different thread than the</code>

<code> </code><code>* terminated() listeners.</code>

<code> </code><code>private</code> <code>static</code> <code>class</code> <code>snappyshutdownservice</code><code>extends</code> <code>abstractexecutionthreadservice {</code>

<code> </code><code>final</code> <code>int</code> <code>index;</code>

<code>snappyshutdownservice(</code><code>int</code> <code>index) {</code>

<code> </code><code>this</code><code>.index = index;</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>run()</code><code>throws</code> <code>exception {</code>

<code>@override</code> <code>protected</code> <code>void</code> <code>triggershutdown() {</code>

<code>@override</code> <code>protected</code> <code>string servicename() {</code>

<code> </code><code>return</code> <code>this</code><code>.getclass().getsimplename() +</code><code>"["</code> <code>+ index +</code><code>"]"</code><code>;</code>

<code>public</code> <code>void</code> <code>testnulls() {</code>

<code> </code><code>servicemanager manager =</code><code>new</code> <code>servicemanager(arrays.&lt;service&gt;aslist());</code>

<code> </code><code>new</code> <code>nullpointertester()</code>

<code> </code><code>.setdefault(servicemanager.listener.</code><code>class</code><code>,</code><code>new</code> <code>recordinglistener())</code>

<code> </code><code>.testallpublicinstancemethods(manager);</code>

<code>private</code> <code>static</code> <code>final</code> <code>class</code> <code>recordinglistener</code><code>extends</code> <code>servicemanager.listener {</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>healthycalled;</code>

<code> </code><code>volatile</code> <code>boolean</code> <code>stoppedcalled;</code>

<code> </code><code>final</code> <code>set&lt;service&gt; failedservices = sets.newconcurrenthashset();</code>

<code>@override</code> <code>public</code> <code>void</code> <code>healthy() {</code>

<code> </code><code>healthycalled =</code><code>true</code><code>;</code>

<code>@override</code> <code>public</code> <code>void</code> <code>stopped() {</code>

<code> </code><code>stoppedcalled =</code><code>true</code><code>;</code>

<code>@override</code> <code>public</code> <code>void</code> <code>failure(service service) {</code>

<code> </code><code>failedservices.add(service);</code>