/*******************************************************************************
*
* Copyright (c) 2004-2009, Oracle Corporation
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
*
*
*
*******************************************************************************/
package hudson.model;
/**
* Provides a mechanism for synchronizing build executions in the face of
* concurrent builds.
*
* <p> At certain points of a build, {@link BuildStep}s and other extension
* points often need to refer to what happened in its earlier build. For
* example, a {@link SCM} check out can run concurrently, but the changelog
* computation requires that the check out of the earlier build has completed.
* Or if Hudson is sending out an e-mail, he needs to know the result of the
* previous build, so that he can decide an e-mail is necessary or not.
*
* <p> Check pointing is a primitive mechanism to provide this sort of
* synchronization. These methods can be only invoked from {@link Executor}
* threads.
*
* <p> Each {@link CheckPoint} instance represents unique check points.
* {@link CheckPoint} instances are normally created as a static instance,
* because two builds of the same project needs to refer to the same check point
* instance for synchronization to happen properly.
*
* <p> This class defines a few well-known check point instances. plugins can
* define their additional check points for their own use.
*
* <h2>Example</h2> <p> {@link JUnitResultArchiver} provides a good example of
* how a {@link Recorder} can depend on its earlier result.
*
* @author Kohsuke Kawaguchi
* @see BuildStep#getRequiredMonitorService()
* @since 1.319
*/
public final class CheckPoint {
private final Object identity;
private final String internalName;
/**
* For advanced uses. Creates a check point that uses the given object as
* its identity.
*/
public CheckPoint(String internalName, Object identity) {
this.internalName = internalName;
this.identity = identity;
}
/**
* @param internalName Name of this check point that's used in the logging,
* stack traces, debug messages, and so on. This is not displayed to users.
* No need for i18n.
*/
public CheckPoint(String internalName) {
this(internalName, new Object());
}
@Override
public boolean equals(Object that) {
if (that == null || getClass() != that.getClass()) {
return false;
}
return identity == ((CheckPoint) that).identity;
}
@Override
public int hashCode() {
return identity.hashCode();
}
@Override
public String toString() {
return "Check point " + internalName;
}
/**
* Records that the execution of the build has reached to a check point,
* idenified by the given identifier.
*
* <p> If the successive builds are
* {@linkplain #block() waiting for this check point}, they'll be released.
*
* <p> This method can be only called from an {@link Executor} thread.
*/
public void report() {
Run.reportCheckpoint(this);
}
/**
* Waits until the previous build in progress reaches a check point,
* identified by the given identifier, or until the current executor becomes
* the youngest build in progress.
*
* <p> Note that "previous build in progress" should be interpreted as
* "previous (build in progress)" instead of "(previous build) if it's in
* progress". This makes a difference around builds that are aborted or
* failed very early without reporting the check points. Imagine the
* following time sequence:
*
* <ol> <li>Build #1, #2, and #3 happens around the same time <li>Build #3
* waits for check point {@link JUnitResultArchiver} <li>Build #2 aborts
* before getting to that check point <li>Build #1 finally checks in
* {@link JUnitResultArchiver} </ol>
*
* <p> Using this method, build #3 correctly waits until the step 4. Because
* of this behavior, the {@link #report()}/{@link #block()} pair can
* normally be used without a try/finally block.
*
* <p> This method can be only called from an {@link Executor} thread.
*
* @throws InterruptedException If the build (represented by the calling
* executor thread) is aborted while it's waiting.
*/
public void block() throws InterruptedException {
Run.waitForCheckpoint(this);
}
/**
* {@link CheckPoint} that indicates that
* {@link AbstractBuild#getCulprits()} is computed.
*/
public static final CheckPoint CULPRITS_DETERMINED = new CheckPoint("CULPRITS_DETERMINED");
/**
* {@link CheckPoint} that indicates that the build is completed.
* ({@link AbstractBuild#isBuilding()}==false)
*/
public static final CheckPoint COMPLETED = new CheckPoint("COMPLETED");
/**
* {@link CheckPoint} that indicates that the build has finished executing
* the "main" portion ({@link Builder}s in case of {@link FreeStyleProject})
* and now moving on to the post-build steps.
*/
public static final CheckPoint MAIN_COMPLETED = new CheckPoint("MAIN_COMPLETED");
}