File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\triggers\Trigger.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Jean-Baptiste Quenot, Stephen Connolly, Tom Huybrechts
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.triggers;
25
26 import static hudson.init.InitMilestone.JOB_LOADED;
27 import hudson.DependencyRunner;
28 import hudson.DependencyRunner.ProjectRunnable;
29 import hudson.DescriptorExtensionList;
30 import hudson.Extension;
31 import hudson.ExtensionPoint;
32 import hudson.init.Initializer;
33 import hudson.model.AbstractProject;
34 import hudson.model.Action;
35 import hudson.model.AperiodicWork;
36 import hudson.model.Build;
37 import hudson.model.ComputerSet;
38 import hudson.model.Describable;
39 import hudson.scheduler.Hash;
40 import jenkins.model.Jenkins;
41 import hudson.model.Item;
42 import hudson.model.PeriodicWork;
43 import hudson.model.Project;
44 import hudson.model.TopLevelItem;
45 import hudson.model.TopLevelItemDescriptor;
46 import hudson.scheduler.CronTab;
47 import hudson.scheduler.CronTabList;
48 import hudson.util.DoubleLaunchChecker;
49
50 import java.io.InvalidObjectException;
51 import java.io.ObjectStreamException;
52 import java.util.ArrayList;
53 import java.util.Calendar;
54 import java.util.Collection;
55 import java.util.Collections;
56 import java.util.Date;
57 import java.util.GregorianCalendar;
58 import java.util.List;
59 import java.util.Timer;
60 import java.util.concurrent.Future;
61 import java.util.logging.Level;
62 import java.util.logging.Logger;
63
64 import antlr.ANTLRException;
65 import javax.annotation.CheckForNull;
66 import edu.umd.cs.findbugs.annotations.SuppressWarnings;
67
68 /**
69 * Triggers a {@link Build}.
70 *
71 * <p>
72 * To register a custom {@link Trigger} from a plugin,
73 * put {@link Extension} on your {@link TriggerDescriptor} class.
74 *
75 * @author Kohsuke Kawaguchi
76 */
77 public abstract class Trigger<J extends Item> implements Describable<Trigger<?>>, ExtensionPoint {
78
79 /**
80 * Called when a {@link Trigger} is loaded into memory and started.
81 *
82 * @param project
83 * given so that the persisted form of this object won't have to have a back pointer.
84 * @param newInstance
85 * True if this may be a newly created trigger first attached to the {@link Project} (generally if the project is being created or configured).
86 * False if this is invoked for a {@link Project} loaded from disk.
87 */
88 public void start(J project, boolean newInstance) {
89 this.job = project;
90
91 try {// reparse the tabs with the job as the hash
92 this.tabs = CronTabList.create(spec, Hash.from(project.getFullName()));
93 } catch (ANTLRException e) {
94 // this shouldn't fail because we've already parsed stuff in the constructor,
95 // so if it fails, use whatever 'tabs' that we already have.
96 LOGGER.log(Level.FINE, "Failed to parse crontab spec: "+spec,e);
97 }
98 }
99
100 /**
101 * Executes the triggered task.
102 *
103 * This method is invoked when {@link #Trigger(String)} is used
104 * to create an instance, and the crontab matches the current time.
105 */
106 public void run() {}
107
108 /**
109 * Called before a {@link Trigger} is removed.
110 * Under some circumstances, this may be invoked more than once for
111 * a given {@link Trigger}, so be prepared for that.
112 *
113 * <p>
114 * When the configuration is changed for a project, all triggers
115 * are removed once and then added back.
116 */
117 public void stop() {}
118
119 /**
120 * Returns an action object if this {@link Trigger} has an action
121 * to contribute to a {@link Project}.
122 *
123 * @deprecated as of 1.341
124 * Use {@link #getProjectActions()} instead.
125 */
126 public Action getProjectAction() {
127 return null;
128 }
129
130 /**
131 * {@link Action}s to be displayed in the job page.
132 *
133 * @return
134 * can be empty but never null
135 * @since 1.341
136 */
137 public Collection<? extends Action> getProjectActions() {
138 // delegate to getJobAction (singular) for backward compatible behavior
139 Action a = getProjectAction();
140 if (a==null) return Collections.emptyList();
141 return Collections.singletonList(a);
142 }
143
144 public TriggerDescriptor getDescriptor() {
145 return (TriggerDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass());
146 }
147
148
149
150 protected final String spec;
151 protected transient CronTabList tabs;
152 protected transient J job;
153
154 /**
155 * Creates a new {@link Trigger} that gets {@link #run() run}
156 * periodically. This is useful when your trigger does
157 * some polling work.
158 */
159 protected Trigger(String cronTabSpec) throws ANTLRException {
160 this.spec = cronTabSpec;
161 this.tabs = CronTabList.create(cronTabSpec);
162 }
163
164 /**
165 * Creates a new {@link Trigger} without using cron.
166 */
167 protected Trigger() {
168 this.spec = "";
169 this.tabs = new CronTabList(Collections.<CronTab>emptyList());
170 }
171
172 /**
173 * Gets the crontab specification.
174 *
175 * If you are not using cron service, just ignore it.
176 */
177 public final String getSpec() {
178 return spec;
179 }
180
181 protected Object readResolve() throws ObjectStreamException {
182 try {
183 tabs = CronTabList.create(spec);
184 } catch (ANTLRException e) {
185 InvalidObjectException x = new InvalidObjectException(e.getMessage());
186 x.initCause(e);
187 throw x;
188 }
189 return this;
190 }
191
192
193 /**
194 * Runs every minute to check {@link TimerTrigger} and schedules build.
195 */
196 @Extension
197 public static class Cron extends PeriodicWork {
198 private final Calendar cal = new GregorianCalendar();
199
200 public long getRecurrencePeriod() {
201 return MIN;
202 }
203
204 public void doRun() {
205 while(new Date().getTime()-cal.getTimeInMillis()>1000) {
206 LOGGER.fine("cron checking "+cal.getTime().toLocaleString());
207
208 try {
209 checkTriggers(cal);
210 } catch (Throwable e) {
211 LOGGER.log(Level.WARNING,"Cron thread throw an exception",e);
212 // bug in the code. Don't let the thread die.
213 e.printStackTrace();
214 }
215
216 cal.add(Calendar.MINUTE,1);
217 }
218 }
219 }
220
221 private static Future previousSynchronousPolling;
222
223 public static void checkTriggers(final Calendar cal) {
224 Jenkins inst = Jenkins.getInstance();
225
226 // Are we using synchronous polling?
227 SCMTrigger.DescriptorImpl scmd = inst.getDescriptorByType(SCMTrigger.DescriptorImpl.class);
228 if (scmd.synchronousPolling) {
229 LOGGER.fine("using synchronous polling");
230
231 // Check that previous synchronous polling job is done to prevent piling up too many jobs
232 if (previousSynchronousPolling == null || previousSynchronousPolling.isDone()) {
233 // Process SCMTriggers in the order of dependencies. Note that the crontab spec expressed per-project is
234 // ignored, only the global setting is honored. The polling job is submitted only if the previous job has
235 // terminated.
236 // FIXME allow to set a global crontab spec
237 previousSynchronousPolling = scmd.getExecutor().submit(new DependencyRunner(new ProjectRunnable() {
238 public void run(AbstractProject p) {
239 for (Trigger t : (Collection<Trigger>) p.getTriggers().values()) {
240 if (t instanceof SCMTrigger) {
241 LOGGER.fine("synchronously triggering SCMTrigger for project " + t.job.getName());
242 t.run();
243 }
244 }
245 }
246 }));
247 } else {
248 LOGGER.fine("synchronous polling has detected unfinished jobs, will not trigger additional jobs.");
249 }
250 }
251
252 // Process all triggers, except SCMTriggers when synchronousPolling is set
253 for (AbstractProject<?,?> p : inst.getAllItems(AbstractProject.class)) {
254 for (Trigger t : p.getTriggers().values()) {
255 if (! (t instanceof SCMTrigger && scmd.synchronousPolling)) {
256 LOGGER.fine("cron checking "+p.getName());
257
258 if (t.tabs.check(cal)) {
259 LOGGER.config("cron triggered "+p.getName());
260 try {
261 t.run();
262 } catch (Throwable e) {
263 // t.run() is a plugin, and some of them throw RuntimeException and other things.
264 // don't let that cancel the polling activity. report and move on.
265 LOGGER.log(Level.WARNING, t.getClass().getName()+".run() failed for "+p.getName(),e);
266 }
267 }
268 }
269 }
270 }
271 }
272
273 private static final Logger LOGGER = Logger.getLogger(Trigger.class.getName());
274
275 /**
276 * This timer is available for all the components inside Hudson to schedule
277 * some work.
278 *
279 * Initialized and cleaned up by {@link jenkins.model.Jenkins}, but value kept here for compatibility.
280 *
281 * If plugins want to run periodic jobs, they should implement {@link PeriodicWork}.
282 */
283 @SuppressWarnings("MS_SHOULD_BE_FINAL")
284 public static @CheckForNull Timer timer;
285
286 @Initializer(after=JOB_LOADED)
287 public static void init() {
288 new DoubleLaunchChecker().schedule();
289
290 Timer _timer = timer;
291 if (_timer != null) {
292 // start all PeridocWorks
293 for(PeriodicWork p : PeriodicWork.all()) {
294 _timer.scheduleAtFixedRate(p,p.getInitialDelay(),p.getRecurrencePeriod());
295 }
296
297 // start all AperidocWorks
298 for(AperiodicWork p : AperiodicWork.all()) {
299 _timer.schedule(p,p.getInitialDelay());
300 }
301
302 // start monitoring nodes, although there's no hurry.
303 _timer.schedule(new SafeTimerTask() {
304 public void doRun() {
305 ComputerSet.initialize();
306 }
307 }, 1000*10);
308 }
309 }
310
311 /**
312 * Returns all the registered {@link Trigger} descriptors.
313 */
314 public static DescriptorExtensionList<Trigger<?>,TriggerDescriptor> all() {
315 return (DescriptorExtensionList) Jenkins.getInstance().getDescriptorList(Trigger.class);
316 }
317
318 /**
319 * Returns a subset of {@link TriggerDescriptor}s that applys to the given item.
320 */
321 public static List<TriggerDescriptor> for_(Item i) {
322 List<TriggerDescriptor> r = new ArrayList<TriggerDescriptor>();
323 for (TriggerDescriptor t : all()) {
324 if(!t.isApplicable(i)) continue;
325
326 if (i instanceof TopLevelItem) {// ugly
327 TopLevelItemDescriptor tld = ((TopLevelItem) i).getDescriptor();
328 // tld shouldn't be really null in contract, but we often write test Describables that
329 // doesn't have a Descriptor.
330 if(tld!=null && !tld.isApplicable(t)) continue;
331 }
332
333 r.add(t);
334 }
335 return r;
336 }
337 }
338