Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JENKINS-19494] Call Descriptor#newInstance to instantiate enclosing …
…Publishers.
  • Loading branch information
ikedam committed Sep 12, 2013
1 parent d921267 commit afa9d8c
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 11 deletions.
Expand Up @@ -39,16 +39,21 @@
import hudson.model.Hudson;
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.BuildStep;
import net.sf.json.JSONObject;

import org.jenkins_ci.plugins.run_condition.BuildStepRunner;
import org.jenkins_ci.plugins.run_condition.RunCondition;
import org.jenkins_ci.plugins.run_condition.core.AlwaysRun;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import jenkins.model.Jenkins;

public class ConditionalPublisher implements Describable<ConditionalPublisher>, DependecyDeclarer {

private final RunCondition condition;
Expand All @@ -64,6 +69,15 @@ public ConditionalPublisher(final RunCondition condition, final BuildStep publis
this(condition, publisher, runner, false, null, null);
}

/**
* @param condition
* @param publisher
* @param runner
* @param configuredAggregation
* @param aggregationCondition
* @param aggregationRunner
* @see ConditionalPublisherDescriptor#newInstance(StaplerRequest, JSONObject)
*/
@DataBoundConstructor
public ConditionalPublisher(final RunCondition condition, final BuildStep publisher, final BuildStepRunner runner,
boolean configuredAggregation, final RunCondition aggregationCondition, final BuildStepRunner aggregationRunner) {
Expand Down Expand Up @@ -164,6 +178,95 @@ public Descriptor<? extends BuildStep> getDefaultPublisher() {
public boolean isMatrixProject(Object it) {
return (it instanceof MatrixProject);
}

/**
* Build a new instance from parameters a user input in a configuration page.
*
* Usually, it is done by {@link StaplerRequest#bindJSON(Class, JSONObject)},
* and {@link DataBoundConstructor} of classes of posted objects.
*
* But we have to use {@link Descriptor#newInstance(StaplerRequest, JSONObject)}
* for classes without {@link DataBoundConstructor} (such as {@link hudson.tasks.Mailer})
* and classes with {@link Descriptor#newInstance(StaplerRequest, JSONObject)}
* doing different from their constructors with {@link DataBoundConstructor}
* (such as {@link hudson.tasks.junit.JUnitResultArchiver}).
*
* @param req
* @param formData
* @return
* @throws hudson.model.Descriptor.FormException
* @see hudson.model.Descriptor#newInstance(org.kohsuke.stapler.StaplerRequest, net.sf.json.JSONObject)
* @see ConditionalPublisher#ConditionalPublisher(RunCondition, BuildStep, BuildStepRunner, boolean, RunCondition, BuildStepRunner)
*/
@Override
public ConditionalPublisher newInstance(StaplerRequest req, JSONObject formData)
throws hudson.model.Descriptor.FormException {
RunCondition condition = null;
BuildStepRunner runner = null;
BuildStep publisher = null;
boolean configuredAggregation = false;
RunCondition aggregationCondition = null;
BuildStepRunner aggregationRunner = null;

if (formData != null) {
condition = req.bindJSON(RunCondition.class, formData.getJSONObject("condition"));
runner = req.bindJSON(BuildStepRunner.class, formData.getJSONObject("runner"));
if (formData.has("configuredAggregation")) {
configuredAggregation = formData.getBoolean("configuredAggregation");
aggregationCondition = req.bindJSON(RunCondition.class, formData.getJSONObject("aggregationCondition"));
aggregationRunner = req.bindJSON(BuildStepRunner.class, formData.getJSONObject("aggregationRunner"));
}

publisher = bindJSONWithDescriptor(req, formData, "publisher");
}
return new ConditionalPublisher(
condition,
publisher,
runner,
configuredAggregation,
aggregationCondition,
aggregationRunner
);
}

/**
* Construct an object from parameters input by a user.
*
* Not using {@link DataBoundConstructor},
* but using {@link Descriptor#newInstance(StaplerRequest, JSONObject)}.
*
* @param req
* @param formData
* @param fieldName
* @return
* @throws hudson.model.Descriptor.FormException
*/
private BuildStep bindJSONWithDescriptor(StaplerRequest req, JSONObject formData, String fieldName)
throws hudson.model.Descriptor.FormException {
formData = formData.getJSONObject(fieldName);
if (formData == null || formData.isNullObject()) {
return null;
}
if (!formData.has("stapler-class")) {
throw new FormException("No stapler-class is specified", fieldName);
}
String clazzName = formData.getString("stapler-class");
if (clazzName == null) {
throw new FormException("No stapler-class is specified", fieldName);
}
try {
@SuppressWarnings("unchecked")
Class<? extends Describable<?>> clazz = (Class<? extends Describable<?>>)Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass(clazzName);
Descriptor<?> d = Jenkins.getInstance().getDescriptorOrDie(clazz);
return (BuildStep)d.newInstance(req, formData);
} catch(ClassNotFoundException e) {
throw new FormException(
String.format("Failed to instantiate %s", clazz),
e,
fieldName
);
}
}
}

@SuppressWarnings("rawtypes")
Expand Down
Expand Up @@ -33,7 +33,6 @@
import hudson.tasks.Publisher;
import org.kohsuke.stapler.DataBoundConstructor;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand All @@ -57,8 +56,7 @@ public List<? extends Descriptor<? extends BuildStep>> getAllowedPublishers(Abst
BuildStepDescriptor<? extends Publisher> buildStepDescriptor = (BuildStepDescriptor<? extends Publisher>) descriptor;
// would be nice to refuse if needsToRunAfterFinalized - but that's on the publisher which does not yet exist!
if (buildStepDescriptor.isApplicable(project.getClass())) {
if (hasDbc(buildStepDescriptor.clazz))
publishers.add(buildStepDescriptor);
publishers.add(buildStepDescriptor);
}
}
return publishers;
Expand All @@ -68,14 +66,6 @@ public DescriptorImpl getDescriptor() {
return Hudson.getInstance().getDescriptorByType(DescriptorImpl.class);
}

private boolean hasDbc(final Class<?> clazz) {
for (Constructor<?> constructor : clazz.getConstructors()) {
if (constructor.isAnnotationPresent(DataBoundConstructor.class))
return true;
}
return false;
}

@Extension
public static class DescriptorImpl extends Descriptor<PublisherDescriptorLister> {

Expand Down
Expand Up @@ -43,6 +43,7 @@
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.jenkins_ci.plugins.run_condition.RunCondition;
Expand All @@ -57,12 +58,18 @@
import java.util.List;
import java.util.Set;

import jenkins.model.Jenkins;

public class FlexiblePublisher extends Recorder implements DependecyDeclarer, MatrixAggregatable{

public static final String PROMOTION_JOB_TYPE = "hudson.plugins.promoted_builds.PromotionProcess";

private List<ConditionalPublisher> publishers;

/**
* @param publishers
* @see FlexiblePublisherDescriptor#newInstance(StaplerRequest, JSONObject)
*/
@DataBoundConstructor
public FlexiblePublisher(final List<ConditionalPublisher> publishers) {
this.publishers = publishers;
Expand Down Expand Up @@ -170,6 +177,43 @@ public Object readResolve() {
return this;
}

/**
* Build a new instance from parameters a user input in a configuration page.
*
* Usually, it is done by {@link StaplerRequest#bindJSON(Class, JSONObject)},
* and {@link DataBoundConstructor} of classes of posted objects.
*
* But we have to use {@link Descriptor#newInstance(StaplerRequest, JSONObject)}
* for classes without {@link DataBoundConstructor} (such as {@link hudson.tasks.Mailer})
* and classes with {@link Descriptor#newInstance(StaplerRequest, JSONObject)}
* doing different from their constructors with {@link DataBoundConstructor}
* (such as {@link hudson.tasks.junit.JUnitResultArchiver}).
*
* @param req
* @param formData
* @return
* @throws hudson.model.Descriptor.FormException
* @see hudson.model.Descriptor#newInstance(org.kohsuke.stapler.StaplerRequest, net.sf.json.JSONObject)
* @see FlexiblePublisher#FlexiblePublisher(List)
*/
@Override
public FlexiblePublisher newInstance(StaplerRequest req, JSONObject formData)
throws hudson.model.Descriptor.FormException {
List<ConditionalPublisher> publishers = null;
if (formData != null) {
JSONArray a = JSONArray.fromObject(formData.get("publishers"));
if (a != null && !a.isEmpty()) {
@SuppressWarnings("unchecked")
Descriptor<ConditionalPublisher> d = Jenkins.getInstance().getDescriptorOrDie(ConditionalPublisher.class);
publishers = new ArrayList<ConditionalPublisher>(a.size());
for(int idx = 0; idx < a.size(); ++idx) {
publishers.add(d.newInstance(req, a.getJSONObject(idx)));
}
}
}

return new FlexiblePublisher(publishers);
}
}

@SuppressWarnings("rawtypes")
Expand Down

0 comments on commit afa9d8c

Please sign in to comment.