Search code examples
javajenkinshudsonjenkins-pluginsjelly

Dynamically create variables for Jelly checkboxes for Jenkins plugin


For anyone who is familiar with the Jelly tags for Jenkins plugins, you know that there is a specific getter/setter format used for the @checked value for the tag.

My plugin parses an XML with interface values, and I need to dynamically create checkboxes for each of the values in the XML on the project page (via floatingBox.jelly). I have the XML file being input from the config page, the plugin action parsing the xml and passing a list of strings to the jelly, wherein it currently generates checkboxes based on the list.

My dilemma is structuring my java/jelly relationship in a way that allows the plugin to communicate the @checked value to 1) pass the checked value to some unique dynamically created java boolean variable 2) hold the value in said variable and return.

I'm currently using a Hashtable to store my key,value pairs but am not able to set values and return values using a single method call successfully.

My floatingBox.jelly:

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt" xmlns:local="local">
<div class="test-trend-caption" style="color:red;text-align:center" >Select Build Interfaces</div>
    <div>
        <j:forEach var="i" items="${it.getActions().get(0).getInterfaces()}">
            <div style="text-align:left">
                <f:checkbox title="${i}" checked="${it.getActions().get(0).getCheckedInterfaces(i)}"/>
            </div>
            <br/>
        </j:forEach>       
    </div>

My Plugin Action code:

public boolean getCheckedInterfaces(String name) {
    for (Map.Entry entry : checkedInterfaces.entrySet()) {
        if (entry.getValue().equals(name)) {
            return (Boolean)entry.getKey();
        }
    }
    return false;
}

public void setCheckedInterfaces(String name) {
    checkedInterfaces.put(name, true);
}

public void parseInterfaces() throws IOException, InstantiationException, IllegalAccessException {
    if (getInterfacesPath()!=null || getInterfacesPath()!="") {
        GroovyClassLoader loader = new GroovyClassLoader();
        Class groovyClass = loader.parseClass(new File("C:\\...\\src\\main\\groovy\\xmlTest.groovy"));
        GroovyObject groovyObj = (GroovyObject)groovyClass.newInstance();
        final Object args = (Object)getInterfacesPath();
        ArrayList<String> temp = (ArrayList<String>)groovyObj.invokeMethod("parseXML", args);
        if (interfaces.isEmpty()) 
            interfaces.addAll(temp);
        else {
            interfaces.clear();
            interfaces.addAll(temp);
        }
    }

Is there another paradigm that I could try to initialize and manage these values so they operate like an explicitly declared boolean for the checkbox-java relationship?


Solution

  • I did eventually solve this issue. I created a JavaScript function that read the table checkbox values and assigned the output to a hidden input, which was made available to my Java code via @QueryParameter. See below.

    Jelly/HTML form to call the JS function and post Java:

    <form style="float:right" method="post" action="forcePromotion?name=${p.name}" onsubmit="saveChecksForce()">
      <f:submit value="${%Force promotion}" />
      <input id="ServerList" name="serverList" type="hidden" />
    </form>
    

    And the JS function:

    function saveChecksForce() {
      var c = window.document.getElementById("ServerChecklist").rows;
      var checkedservers = "";
      for (var i = 0; i & lt; c.length; i++) {
        if (c[i].cells[1] != null) {
          if (c[i].cells[1].children[0] != null) {
            if (c[i].cells[1].children[0].checked == true) {
              checkedservers = checkedservers + c[i].cells[0].innerHTML + ",";
            }
          }
        }
      }
      window.document.getElementById('ServerList').value = checkedservers;
    }
    

    Where "ServerChecklist" is my table Id with the checkboxes in a single column. Then the form executes the action, and calls the Java code:

     public HttpResponse doForcePromotion(@QueryParameter("name") String name, @QueryParameter("serverList") String serverList) throws IOException, InterruptedException {
        setEnvVars(serverList);
        this.getProject().checkPermission(Promotion.PROMOTE);
        ...
     }