/*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.model;
import hudson.ExtensionPoint;
import hudson.Launcher;
import hudson.model.Descriptor.FormException;
import hudson.model.queue.SubTask;
import hudson.tasks.BuildStep;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.tasks.BuildStepMonitor;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import jenkins.model.Jenkins;
import jenkins.model.OptionalJobProperty;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.export.ExportedBean;
import javax.annotation.Nonnull;
/**
* Extensible property of {@link Job}.
*
* <p>
* Plugins can extend this to define custom properties
* for {@link Job}s. {@link JobProperty}s show up in the user
* configuration screen, and they are persisted with the job object.
*
* <p>
* Configuration screen should be defined in <tt>config.jelly</tt>.
* Within this page, the {@link JobProperty} instance is available
* as <tt>instance</tt> variable (while <tt>it</tt> refers to {@link Job}.
*
* <p>
* Starting 1.150, {@link JobProperty} implements {@link BuildStep},
* meaning it gets the same hook as {@link Publisher} and {@link Builder}.
* The primary intention of this mechanism is so that {@link JobProperty}s
* can add actions to the new build. The {@link #perform(AbstractBuild, Launcher, BuildListener)}
* and {@link #prebuild(AbstractBuild, BuildListener)} are invoked after those
* of {@link Publisher}s.
*
* <p>Consider extending {@link OptionalJobProperty} instead.
*
* @param <J>
* When you restrict your job property to be only applicable to a certain
* subtype of {@link Job}, you can use this type parameter to improve
* the type signature of this class. See {@link JobPropertyDescriptor#isApplicable(Class)}.
*
* @author Kohsuke Kawaguchi
* @see JobPropertyDescriptor
* @since 1.72
*/
@ExportedBean
public abstract class JobProperty<J extends Job<?,?>> implements ReconfigurableDescribable<JobProperty<?>>, BuildStep, ExtensionPoint {
/**
* The {@link Job} object that owns this property.
* This value will be set by the Hudson code.
* Derived classes can expect this value to be always set.
*/
protected transient J owner;
/**
* Hook for performing post-initialization action.
*
* <p>
* This method is invoked in two cases. One is when the {@link Job} that owns
* this property is loaded from disk, and the other is when a job is re-configured
* and all the {@link JobProperty} instances got re-created.
*/
protected void setOwner(J owner) {
this.owner = owner;
}
/**
* {@inheritDoc}
*/
@Override
public JobPropertyDescriptor getDescriptor() {
return (JobPropertyDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass());
}
/**
* @deprecated
* as of 1.341. Override {@link #getJobActions(Job)} instead.
*/
@Deprecated
public Action getJobAction(J job) {
return null;
}
/**
* {@link Action}s to be displayed in the job page.
*
* <p>
* Returning actions from this method allows a job property to add them
* to the left navigation bar in the job page.
*
* <p>
* {@link Action} can implement additional marker interface to integrate
* with the UI in different ways.
*
* @param job
* Always the same as {@link #owner} but passed in anyway for backward compatibility (I guess.)
* You really need not use this value at all.
* @return
* can be empty but never null.
* @since 1.341
* @see ProminentProjectAction
* @see PermalinkProjectAction
*/
@Nonnull
public Collection<? extends Action> getJobActions(J job) {
// delegate to getJobAction (singular) for backward compatible behavior
Action a = getJobAction(job);
if (a==null) return Collections.emptyList();
return Collections.singletonList(a);
}
//
// default no-op implementation
//
public boolean prebuild(AbstractBuild<?,?> build, BuildListener listener) {
return true;
}
/**
* {@inheritDoc}
*
* <p>
* Invoked after {@link Publisher}s have run.
*/
@Override
public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
return true;
}
/**
* Returns {@link BuildStepMonitor#NONE} by default, as {@link JobProperty}s normally don't depend
* on its previous result.
*/
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
public final Action getProjectAction(AbstractProject<?,?> project) {
return getJobAction((J)project);
}
@Nonnull
public final Collection<? extends Action> getProjectActions(AbstractProject<?,?> project) {
return getJobActions((J)project);
}
/** @see Job#getOverrides */
public Collection<?> getJobOverrides() {
return Collections.emptyList();
}
public JobProperty<?> reconfigure(StaplerRequest req, JSONObject form) throws FormException {
return form==null ? null : getDescriptor().newInstance(req,form);
}
/**
* Contributes {@link SubTask}s to {@link AbstractProject#getSubTasks()}
*
* @since 1.377
*/
public Collection<? extends SubTask> getSubTasks() {
return Collections.emptyList();
}
}