/hudson-core/src/main/java/hudson/model/ViewJob.java

http://github.com/hudson/hudson · Java · 211 lines · 105 code · 25 blank · 81 comment · 9 complexity · 0a81848f2a64bc4bbcc92e3617183c65 MD5 · raw file

  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package hudson.model;
  25. import org.kohsuke.stapler.StaplerRequest;
  26. import org.kohsuke.stapler.StaplerResponse;
  27. import javax.servlet.ServletException;
  28. import java.io.IOException;
  29. import java.util.LinkedHashSet;
  30. import java.util.SortedMap;
  31. import hudson.model.Descriptor.FormException;
  32. /**
  33. * {@link Job} that monitors activities that happen outside Hudson,
  34. * which requires occasional batch reload activity to obtain the up-to-date information.
  35. *
  36. * <p>
  37. * This can be used as a base class to derive custom {@link Job} type.
  38. *
  39. * @author Kohsuke Kawaguchi
  40. */
  41. public abstract class ViewJob<JobT extends ViewJob<JobT,RunT>, RunT extends Run<JobT,RunT>>
  42. extends Job<JobT,RunT> {
  43. /**
  44. * We occasionally update the list of {@link Run}s from a file system.
  45. * The next scheduled update time.
  46. */
  47. private transient long nextUpdate = 0;
  48. /**
  49. * All {@link Run}s. Copy-on-write semantics.
  50. */
  51. protected transient /*almost final*/ RunMap<RunT> runs = new RunMap<RunT>();
  52. private transient boolean notLoaded = true;
  53. /**
  54. * If the reloading of runs are in progress (in another thread,
  55. * set to true.)
  56. */
  57. private transient volatile boolean reloadingInProgress;
  58. /**
  59. * {@link ExternalJob}s that need to be reloaded.
  60. *
  61. * This is a set, so no {@link ExternalJob}s are scheduled twice, yet
  62. * it's order is predictable, avoiding starvation.
  63. */
  64. private static final LinkedHashSet<ViewJob> reloadQueue = new LinkedHashSet<ViewJob>();
  65. /*package*/ static final Thread reloadThread = new ReloadThread();
  66. static {
  67. reloadThread.start();
  68. }
  69. /**
  70. * @deprecated as of 1.390
  71. */
  72. protected ViewJob(Hudson parent, String name) {
  73. super(parent,name);
  74. }
  75. protected ViewJob(ItemGroup parent, String name) {
  76. super(parent,name);
  77. }
  78. public boolean isBuildable() {
  79. return false;
  80. }
  81. @Override
  82. public void onLoad(ItemGroup<? extends Item> parent, String name) throws IOException {
  83. super.onLoad(parent, name);
  84. notLoaded = true;
  85. }
  86. protected SortedMap<Integer,RunT> _getRuns() {
  87. if(notLoaded || runs==null) {
  88. // if none is loaded yet, do so immediately.
  89. synchronized(this) {
  90. if(runs==null)
  91. runs = new RunMap<RunT>();
  92. if(notLoaded) {
  93. notLoaded = false;
  94. _reload();
  95. }
  96. }
  97. }
  98. if(nextUpdate<System.currentTimeMillis()) {
  99. if(!reloadingInProgress) {
  100. // schedule a new reloading operation.
  101. // we don't want to block the current thread,
  102. // so reloading is done asynchronously.
  103. reloadingInProgress = true;
  104. synchronized(reloadQueue) {
  105. reloadQueue.add(this);
  106. reloadQueue.notify();
  107. }
  108. }
  109. }
  110. return runs;
  111. }
  112. public void removeRun(RunT run) {
  113. // reload the info next time
  114. nextUpdate = 0;
  115. }
  116. private void _reload() {
  117. try {
  118. reload();
  119. } finally {
  120. reloadingInProgress = false;
  121. nextUpdate = reloadPeriodically ? System.currentTimeMillis()+1000*60 : Long.MAX_VALUE;
  122. }
  123. }
  124. /**
  125. * Reloads the list of {@link Run}s. This operation can take a long time.
  126. *
  127. * <p>
  128. * The loaded {@link Run}s should be set to {@link #runs}.
  129. */
  130. protected abstract void reload();
  131. @Override
  132. protected void submit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, FormException {
  133. super.submit(req,rsp);
  134. // make sure to reload to reflect this config change.
  135. nextUpdate = 0;
  136. }
  137. /**
  138. * Thread that reloads the {@link Run}s.
  139. */
  140. private static final class ReloadThread extends Thread {
  141. private ReloadThread() {
  142. setName("ViewJob reload thread");
  143. }
  144. private ViewJob getNext() throws InterruptedException {
  145. synchronized(reloadQueue) {
  146. // reload operations might eat InterruptException,
  147. // so check the status every so often
  148. while(reloadQueue.isEmpty() && !terminating())
  149. reloadQueue.wait(60*1000);
  150. if(terminating())
  151. throw new InterruptedException(); // terminate now
  152. ViewJob job = reloadQueue.iterator().next();
  153. reloadQueue.remove(job);
  154. return job;
  155. }
  156. }
  157. private boolean terminating() {
  158. return Hudson.getInstance().isTerminating();
  159. }
  160. @Override
  161. public void run() {
  162. while (!terminating()) {
  163. try {
  164. getNext()._reload();
  165. } catch (InterruptedException e) {
  166. // treat this as a death signal
  167. return;
  168. } catch (Throwable t) {
  169. // otherwise ignore any error
  170. t.printStackTrace();
  171. }
  172. }
  173. }
  174. }
  175. // private static final Logger logger = Logger.getLogger(ViewJob.class.getName());
  176. /**
  177. * In the very old version of Hudson, an external job submission was just creating files on the file system,
  178. * so we needed to periodically reload the jobs from a file system to pick up new records.
  179. *
  180. * <p>
  181. * We then switched to submission via HTTP, so this reloading is no longer necessary, so only do this
  182. * when explicitly requested.
  183. *
  184. */
  185. public static boolean reloadPeriodically = Boolean.getBoolean(ViewJob.class.getName()+".reloadPeriodically");
  186. }