package hudson.model.queue;
import hudson.console.ModelHyperlinkNote;
import hudson.model.Queue.Task;
import hudson.model.Node;
import hudson.model.Messages;
import hudson.model.Label;
import hudson.model.TaskListener;
import hudson.slaves.Cloud;
import org.jvnet.localizer.Localizable;
/**
* If something is blocked/vetoed, this object represents why.
*
* <p>
* Originally, this is added for {@link Task} stuck in the queue, but since then the use of this
* has expanded beyond queues.
*
* <h2>View</h2>
* <tt>summary.jelly</tt> should do one-line HTML rendering to be used showing the cause
* to the user. By default it simply renders {@link #getShortDescription()} text.
*
* <p>
* For queues, this is used while rendering the "build history" widget.
*
*
* @since 1.330
*/
public abstract class CauseOfBlockage {
/**
* Human readable description of why the build is blocked.
*/
public abstract String getShortDescription();
/**
* Report a line to the listener about this cause.
*/
public void print(TaskListener listener) {
listener.getLogger().println(getShortDescription());
}
/**
* Obtains a simple implementation backed by {@link Localizable}.
*/
public static CauseOfBlockage fromMessage(final Localizable l) {
return new CauseOfBlockage() {
public String getShortDescription() {
return l.toString();
}
};
}
@Override public String toString() {
return getShortDescription();
}
/**
* Marker interface to indicates that we can reasonably expect
* that adding a suitable executor/node will resolve this blockage.
*
* Primarily this is used by {@link Cloud} to see if it should
* consider provisioning new node.
*
* @since 1.427
*/
interface NeedsMoreExecutor {}
public static CauseOfBlockage createNeedsMoreExecutor(Localizable l) {
return new NeedsMoreExecutorImpl(l);
}
private static final class NeedsMoreExecutorImpl extends CauseOfBlockage implements NeedsMoreExecutor {
private final Localizable l;
private NeedsMoreExecutorImpl(Localizable l) {
this.l = l;
}
public String getShortDescription() {
return l.toString();
}
}
/**
* Build is blocked because a node is offline.
*/
public static final class BecauseNodeIsOffline extends CauseOfBlockage implements NeedsMoreExecutor {
public final Node node;
public BecauseNodeIsOffline(Node node) {
this.node = node;
}
public String getShortDescription() {
String name = (node.toComputer() != null) ? node.toComputer().getDisplayName() : node.getDisplayName();
return Messages.Queue_NodeOffline(name);
}
@Override
public void print(TaskListener listener) {
listener.getLogger().println(
Messages.Queue_NodeOffline(ModelHyperlinkNote.encodeTo(node)));
}
}
/**
* Build is blocked because all the nodes that match a given label is offline.
*/
public static final class BecauseLabelIsOffline extends CauseOfBlockage implements NeedsMoreExecutor {
public final Label label;
public BecauseLabelIsOffline(Label l) {
this.label = l;
}
public String getShortDescription() {
if (label.isEmpty()) {
return Messages.Queue_LabelHasNoNodes(label.getName());
} else {
return Messages.Queue_AllNodesOffline(label.getName());
}
}
}
/**
* Build is blocked because a node is fully busy
*/
public static final class BecauseNodeIsBusy extends CauseOfBlockage implements NeedsMoreExecutor {
public final Node node;
public BecauseNodeIsBusy(Node node) {
this.node = node;
}
public String getShortDescription() {
String name = (node.toComputer() != null) ? node.toComputer().getDisplayName() : node.getDisplayName();
return Messages.Queue_WaitingForNextAvailableExecutorOn(name);
}
@Override
public void print(TaskListener listener) {
listener.getLogger().println(Messages.Queue_WaitingForNextAvailableExecutorOn(ModelHyperlinkNote.encodeTo(node)));
}
}
/**
* Build is blocked because everyone that matches the specified label is fully busy
*/
public static final class BecauseLabelIsBusy extends CauseOfBlockage implements NeedsMoreExecutor {
public final Label label;
public BecauseLabelIsBusy(Label label) {
this.label = label;
}
public String getShortDescription() {
return Messages.Queue_WaitingForNextAvailableExecutorOn(label.getName());
}
}
}