Instruction:
作为 Java 安全专家，检测此代码中的安全漏洞：
## 内容1
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritManagement.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.config.Config;
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig;
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.PluginConfig;
import com.sonyericsson.hudson.plugins.gerrit.trigger.diagnostics.Diagnostics;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritAdministrativeMonitor;
import com.sonymobile.tools.gerrit.gerritevents.GerritSendCommandQueue;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.Functions;
import hudson.model.AdministrativeMonitor;
import hudson.model.AutoCompletionCandidates;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Failure;
import hudson.model.ManagementLink;
import hudson.model.Saveable;
import hudson.security.Permission;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithContextMenu;
import jenkins.security.stapler.StaplerDispatchable;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.CharEncoding;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import javax.servlet.ServletException;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil.PLUGIN_IMAGES_URL;

/**
 * Management link for configuring the global configuration of this trigger.
 *
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
@Extension
public class GerritManagement extends ManagementLink implements StaplerProxy, Describable<GerritManagement>,
        Saveable, ModelObjectWithContextMenu {

    /**
     * The relative url name for this management link.
     * As returned by {@link #getUrlName()}.
     */
    public static final String URL_NAME = "gerrit-trigger";

    private static final Logger logger = LoggerFactory.getLogger(GerritManagement.class);

    private static final Diagnostics DIAGNOSTICS = new Diagnostics();

    @Override
    public String getIconFileName() {
        return PLUGIN_IMAGES_URL + "icon.png";
    }

    @Override
    public String getUrlName() {
        return URL_NAME;
    }

    @Override
    public String getDisplayName() {
        return Messages.DisplayName();
    }

    @Override
    public String getDescription() {
        return Messages.PluginDescription();
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return Jenkins.get().getDescriptorByType(DescriptorImpl.class);
    }

    @Override
    public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
        checkPermission();
        Jenkins jenkins = Jenkins.get();
        ContextMenu menu = new ContextMenu();
        menu.add("newServer", Functions.joinPath(jenkins.getRootUrl(), Functions.getResourcePath(),
                                                 "images", "24x24", "new-package.png"), Messages.AddNewServer());
        for (GerritServer server : getServers()) {
            menu.add(server);
        }
        MenuItem item = new MenuItem()
                .withUrl("diagnostics")
                .withDisplayName(DIAGNOSTICS)
                .withStockIcon("folder.png");
        item.subMenu = DIAGNOSTICS.getContextMenu("diagnostics");
        menu.add(item);
        return menu;
    }

    /**
     * A sub page displaying some diagnostic views.
     *
     * @return the diagnostics page.
     */
    public Diagnostics getDiagnostics() {
        return DIAGNOSTICS;
    }

    /**
     * Descriptor is only used for UI form bindings.
     */
    @Extension
    public static final class DescriptorImpl extends Descriptor<GerritManagement> {

        @Override
        public String getDisplayName() {
            return ""; // unused
        }

        /**
         * Returns the list containing the GerritServer descriptor.
         *
         * @return the list of descriptors containing GerritServer's descriptor.
         */
        public static DescriptorExtensionList<GerritServer, GerritServer.DescriptorImpl> serverDescriptorList() {
            Jenkins jenkins = Jenkins.get();
            return jenkins.getDescriptorList(GerritServer.class);
        }

        /**
         * Auto-completion for the "copy from" field in the new server page.
         *
         * @param value the value that the user has typed in the textbox.
         * @return the list of server names, depending on the current value in the textbox.
         */
        public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value) {
            final AutoCompletionCandidates r = new AutoCompletionCandidates();

            PluginImpl plugin = PluginImpl.getInstance();
            if (plugin != null) {
                for (String s : plugin.getServerNames()) {
                    if (s.startsWith(value)) {
                        r.add(s);
                    }
                }
            }
            return r;
        }
    }

    /**
     * Gets the list of GerritServer.
     *
     * @return the list of GerritServer.
     */
    @StaplerDispatchable @SuppressWarnings("unused") //Called from Jelly
    public List<GerritServer> getServers() {
        checkPermission();
        PluginImpl plugin = PluginImpl.getInstance();
        if (plugin == null) {
            return Collections.emptyList();
        }
        return plugin.getServers();
    }

    /**
     * Used when redirected to a server.
     *
     * @param encodedServerName the server name encoded by URLEncoder.encode(name,"UTF-8").
     * @return the GerritServer object.
     */
    @StaplerDispatchable @SuppressWarnings("unused") //Called from Jelly
    public GerritServer getServer(String encodedServerName) {
        checkPermission();
        String serverName;
        try {
            serverName = URLDecoder.decode(encodedServerName, CharEncoding.UTF_8);
        } catch (Exception ex) {
            serverName = URLDecoder.decode(encodedServerName);
        }
        PluginImpl plugin = PluginImpl.getInstance();
        if (plugin == null) {
            return null;
        }
        return plugin.getServer(serverName);
    }

    /**
     * Used when getting server status from JavaScript.
     *
     * @return the json array of server status.
     */
    @JavaScriptMethod
    public JSONObject getServerStatuses() {
        JSONObject root = new JSONObject();
        JSONArray array = new JSONArray();
        JSONObject obj;

        for (GerritServer server : PluginImpl.getServers_()) {
            String status;
            if (server.isConnected()) {
                status = "up";
            } else {
                status = "down";
            }

            obj = new JSONObject();
            obj.put("name", server.getName());
            obj.put("frontEndUrl", server.getConfig().getGerritFrontEndUrl());
            obj.put("serverUrl", server.getUrlName());
            obj.put("version", server.getGerritVersion());
            obj.put("status", status);
            obj.put("hasErrors", server.hasErrors());
            obj.put("hasWarnings", server.hasWarnings());
            array.add(obj);
        }

        root.put("servers", array);
        return root;
    }

    /**
     * Add a new server.
     *
     * @param req the StaplerRequest
     * @param rsp the StaplerResponse
     * @return the new GerritServer
     * @throws IOException when error sending redirect back to the list of servers
     */
    @RequirePOST
    public GerritServer doAddNewServer(StaplerRequest req, StaplerResponse rsp) throws IOException {
        checkPermission();
        String serverName = req.getParameter("name");
        PluginImpl plugin = PluginImpl.getInstance();
        assert plugin != null;
        if (plugin.containsServer(serverName)) {
            throw new Failure("A server already exists with the name '" + serverName + "'");
        } else if (GerritServer.ANY_SERVER.equals(serverName)) {
            throw new Failure("Illegal server name '" + serverName + "'");
        }
        GerritServer server = new GerritServer(serverName);
        PluginConfig pluginConfig = plugin.getPluginConfig();
        server.getConfig().setNumberOfSendingWorkerThreads(pluginConfig.getNumberOfSendingWorkerThreads());

        String mode = req.getParameter("mode");
        if (mode != null && mode.equals("copy")) { //"Copy Existing Server Configuration" has been chosen
            String from = req.getParameter("from");
            GerritServer fromServer = plugin.getServer(from);
            if (fromServer != null) {
                server.setConfig(new Config(fromServer.getConfig()));
                plugin.addServer(server);
                server.start();
            } else {
                throw new Failure("Server '" + from + "' does not exist!");
            }
        } else {
            plugin.addServer(server);
            server.start();
        }
        plugin.save();

        rsp.sendRedirect("./server/" + URLEncoder.encode(serverName, CharEncoding.UTF_8));
        return server;
    }

    @Override
    public Object getTarget() {
        Jenkins jenkins = Jenkins.get();
        jenkins.checkPermission(Jenkins.ADMINISTER);
        return this;
    }

    @Override
    public void save() throws IOException {
        logger.debug("SAVE!!!");
    }

    /**
     * Returns this singleton.
     *
     * @return the single loaded instance if this class.
     */
    public static GerritManagement get() {
        return ManagementLink.all().get(GerritManagement.class);
    }

    /**
     * Get the plugin config.
     *
     * @return the plugin config.
     */
    @CheckForNull
    public static PluginConfig getPluginConfig() {
        PluginImpl plugin = PluginImpl.getInstance();
        if (plugin == null) {
            return null;
        }
        return plugin.getPluginConfig();
    }

    /**
     * Get the config of a server.
     *
     * @param serverName the name of the server for which we want to get the config.
     * @return the config.
     * @see GerritServer#getConfig()
     */
    public static IGerritHudsonTriggerConfig getConfig(String serverName) {
        GerritServer server = PluginImpl.getServer_(serverName);
        if (server != null) {
            return server.getConfig();
        } else {
            logger.error("Could not find the Gerrit Server: {}", serverName);
            return null;
        }
    }

    /**
     * The AdministrativeMonitor related to Gerrit.
     * convenience method for the jelly page.
     *
     * @return the monitor if it could be found, or null otherwise.
     */
    @SuppressWarnings("unused") //Called from Jelly
    public GerritAdministrativeMonitor getAdministrativeMonitor() {
        for (AdministrativeMonitor monitor : AdministrativeMonitor.all()) {
            if (monitor instanceof GerritAdministrativeMonitor) {
                return (GerritAdministrativeMonitor)monitor;
            }
        }
        return null;
    }

    /**
     * Convenience method for jelly. Get the list of Gerrit server names.
     *
     * @return the list of server names as a list.
     */
    public List<String> getServerNames() {
        PluginImpl plugin = PluginImpl.getInstance();
        if (plugin == null) {
            return Collections.emptyList();
        }
        return plugin.getServerNames();
    }

    /**
     * Checks whether server name already exists.
     *
     * @param value the value of the name field.
     * @return ok or error.
     */
    public FormValidation doNameFreeCheck(@QueryParameter("value") final String value) {
        checkPermission();
        PluginImpl plugin = PluginImpl.getInstance();
        assert plugin != null;
        if (plugin.containsServer(value)) {
            return FormValidation.error("The server name " + value + " is already in use!");
        } else if (GerritServer.ANY_SERVER.equals(value)) {
            return FormValidation.error("Illegal name " + value + "!");
        } else {
            return FormValidation.ok();
        }
    }

    /**
     * Saves the form to the configuration and disk.
     *
     * @param req StaplerRequest
     * @param rsp StaplerResponse
     * @throws ServletException     if something unfortunate happens.
     * @throws IOException          if something unfortunate happens.
     * @throws InterruptedException if something unfortunate happens.
     */
    @RequirePOST
    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws ServletException,
            IOException,
            InterruptedException {
        checkPermission();
        if (logger.isDebugEnabled()) {
            logger.debug("submit {}", req.toString());
        }
        JSONObject form = req.getSubmittedForm();
        PluginConfig pluginConfig = PluginImpl.getPluginConfig_();
        if (pluginConfig != null) {
            pluginConfig.setValues(form);
            PluginImpl.save_();
            GerritSendCommandQueue.configure(pluginConfig);
        }
        //TODO reconfigure the incoming worker threads as well

        rsp.sendRedirect(".");
    }

    /**
     * Checks that the current user has {@link #getRequiredPermission()} permission.
     * If Jenkins is currently active.
     */
    private void checkPermission() {
        final Jenkins jenkins = Jenkins.getInstanceOrNull();
        if (jenkins != null) {
            jenkins.checkPermission(getRequiredPermission());
        }
    }

    /**
     * {@link Jenkins#ADMINISTER} permission.
     * Also used by Jelly
     *
     * @return the permission
     */
    @Override
    public Permission getRequiredPermission() {
        return Jenkins.ADMINISTER;
    }

}

## 内容2
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/hudsontrigger/GerritTriggerDescriptor.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer;
import com.sonyericsson.hudson.plugins.gerrit.trigger.Messages;
import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl;
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.Config;
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.ReplicationConfig;
import com.sonyericsson.hudson.plugins.gerrit.trigger.dependency.DependencyQueueTaskDispatcher;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.CompareType;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.GerritSlave;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.events.PluginGerritEvent;
import com.sonymobile.tools.gerrit.gerritevents.dto.rest.Notify;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.Util;
import hudson.model.AbstractProject;
import hudson.model.AutoCompletionCandidates;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.triggers.TriggerDescriptor;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;

import org.jenkinsci.Symbol;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.QueryParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer.ANY_SERVER;

/**
 * The Descriptor for the Trigger.
 */
@Extension
@Symbol("gerrit")
public final class GerritTriggerDescriptor extends TriggerDescriptor {

    private static final Logger logger = LoggerFactory.getLogger(GerritTriggerDescriptor.class);

    /**
     * Checks if the provided job type can support {@link GerritTrigger#getBuildUnsuccessfulFilepath()}.
     * I.e. if the job is an {@link AbstractProject}.
     *
     * @param job the job to check.
     * @return true if so.
     */
    public boolean isUnsuccessfulMessageFileSupported(Job job) {
        return job instanceof AbstractProject;
    }

    /**
     * Checks that the provided parameter is an empty string or an integer.
     *
     * @param value the value.
     * @return {@link FormValidation#validatePositiveInteger(String)}
     */
    public FormValidation doEmptyOrIntegerCheck(
            @QueryParameter("value")
            final String value) {
        if (value == null || value.length() <= 0) {
            return FormValidation.ok();
        } else {
            try {
                Integer.parseInt(value);
                return FormValidation.ok();
            } catch (NumberFormatException e) {
                return FormValidation.error(Messages.NotANumber());
            }
        }
    }

    /**
     * Provides auto-completion candidates for dependency jobs names.
     *
     * @param value the value.
     * @param self the current instance.
     * @param container the container.
     * @return {@link AutoCompletionCandidates}
     */
    public AutoCompletionCandidates doAutoCompleteDependencyJobsNames(@QueryParameter String value,
                                                                      @AncestorInPath Item self,
                                                                      @AncestorInPath ItemGroup container) {
        return AutoCompletionCandidates.ofJobNames(Job.class, value, self, container);
    }

    /**
     * Validates that the dependency jobs are legitimate and do not create cycles.
     *
     * @param value the string value.
     * @param project the current project.
     * @return {@link FormValidation}
     */
    public FormValidation doCheckDependencyJobsNames(@AncestorInPath Item project, @QueryParameter String value) {
        StringTokenizer tokens = new StringTokenizer(Util.fixNull(value), ",");
        // Check that all jobs are legit, actual projects.
        while (tokens.hasMoreTokens()) {
            String projectName = tokens.nextToken().trim();
            if (!projectName.equals("")) {
                Jenkins jenkins = Jenkins.get();
                Item item = jenkins.getItem(projectName, project, Item.class);
                if ((item == null) || !(item instanceof Job)) {
                    AbstractProject nearest = AbstractProject.findNearest(projectName);
                    String path = "<null>";
                    if (nearest != null) {
                        path = nearest.getFullName();
                    }
                    return FormValidation.error(
                            Messages.NoSuchJobExists(
                                    projectName,
                                    path));
                }
            }
        }
        //Check there are no cycles in the dependencies, by exploring all dependencies recursively
        //Only way of creating a cycle is if this project is in the dependencies somewhere.
        Set<Job> explored = new HashSet<Job>();
        List<Job> directDependencies = DependencyQueueTaskDispatcher.getProjectsFromString(value,
                project);
        if (directDependencies == null) {
            // no dependencies
            return FormValidation.ok();
        }
        for (Job directDependency : directDependencies) {
            if (directDependency.getFullName().equals(project.getFullName())) {
                return FormValidation.error(Messages.CannotAddSelfAsDependency());
            }
            java.util.Queue<Job> toExplore = new LinkedList<Job>();
            toExplore.add(directDependency);
            while (toExplore.size() > 0) {
                Job currentlyExploring = toExplore.remove();
                explored.add(currentlyExploring);
                GerritTrigger currentTrigger = GerritTrigger.getTrigger(currentlyExploring);
                if (currentTrigger == null) {
                    continue;
                }
                String currentDependenciesString = GerritTrigger.getTrigger(currentlyExploring).getDependencyJobsNames();
                List<Job> currentDependencies = DependencyQueueTaskDispatcher.getProjectsFromString(
                        currentDependenciesString, project);
                if (currentDependencies == null) {
                    continue;
                }
                for (Job dependency : currentDependencies) {
                    if (dependency.getFullName().equals(project.getFullName())) {
                        return FormValidation.error(Messages.AddingDependentProjectWouldCreateLoop(
                                directDependency.getFullName(), currentlyExploring.getFullName()));
                    }
                    if (!explored.contains(dependency)) {
                        toExplore.add(dependency);
                    }
                }
            }
        }
        return FormValidation.ok();
    }

    /**
     * Fill the server dropdown with the list of servers configured globally.
     *
     * @return list of servers.
     */
    public ListBoxModel doFillServerNameItems() {
        ListBoxModel items = new ListBoxModel();
        items.add(Messages.AnyServer(), ANY_SERVER);
        List<String> serverNames = PluginImpl.getServerNames_();
        for (String s : serverNames) {
            items.add(s);
        }
        return items;
    }

    /**
     * Whether slave selection in jobs should be allowed.
     * If so, the user will see one more dropdown on the job config page, right under server selection dropdown.
     * @return true if so.
     */
    public boolean isSlaveSelectionAllowedInJobs() {
        //since we cannot create/remove drop down when the server is selected,
        //as soon as one of the server allow slave selection, we must display it.
        for (GerritServer server : PluginImpl.getServers_()) {
            ReplicationConfig replicationConfig = server.getConfig().getReplicationConfig();
            if (replicationConfig != null && replicationConfig.isEnableSlaveSelectionInJobs()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Fill the Gerrit slave dropdown with the list of slaves configured with the selected server.
     * Expected to be called only when slave config is enabled at job level.
     *
     * @param serverName the name of the selected server.
     * @return list of slaves.
     */
    public ListBoxModel doFillGerritSlaveIdItems(@QueryParameter("serverName") final String serverName) {
        ListBoxModel items = new ListBoxModel();
        if (ANY_SERVER.equals(serverName)) {
            items.add(Messages.SlaveSelectionNotAllowedAnyServer(Messages.AnyServer()), "");
            return items;
        }
        GerritServer server = PluginImpl.getServer_(serverName);
        if (server == null) {
            logger.warn(Messages.CouldNotFindServer(serverName));
            items.add(Messages.CouldNotFindServer(serverName), "");
            return items;
        }
        ReplicationConfig replicationConfig = server.getConfig().getReplicationConfig();
        if (replicationConfig == null) {
            items.add(Messages.ReplicationNotConfigured(), "");
            return items;
        } else if (!replicationConfig.isEnableReplication()) {
            items.add(Messages.ReplicationNotConfigured(), "");
            return items;
        } else if (!replicationConfig.isEnableSlaveSelectionInJobs()) {
            items.add(Messages.SlaveSelectionInJobsDisabled(), "");
            return items;
        }
        for (GerritSlave slave : replicationConfig.getGerritSlaves()) {
            //if GerritTrigger.gerritSlaveId is configured, the selected value will be the good one because of
            //the stapler/jelly magic. The problem is when job was not saved since replication was configured,
            //we want the selected slave to be the default slave defined at admin level but I did not find a way
            //to do this. Jelly support default value returned by a descriptor method but I did not find a way to
            //pass the selected server to this method.
            //To work around the issue, we always put the default slave first in the list.
            if (slave.getId().equals(replicationConfig.getDefaultSlaveId())) {
                items.add(0, new ListBoxModel.Option(slave.getName(), slave.getId()));
            } else {
                items.add(slave.getName(), slave.getId());
            }
        }
        return items;
    }

    /**
     * Checks that the provided parameter is nonempty and a valid URL.
     *
     * @param value the value.
     * @return {@link FormValidation#ok()}
     */
    public FormValidation doUrlCheck(
            @QueryParameter("value")
            final String value) {
        if (value == null || value.isEmpty()) {
            return FormValidation.error(Messages.EmptyError());
        }
        try {
            URL url = new URL(value); // Check for protocol errors
            url.toURI(); // Perform some extra checking
            return FormValidation.ok();
        } catch (MalformedURLException | URISyntaxException e) {
            return FormValidation.error(Messages.BadUrlError());
        }
    }

    /**
     * Fill the dropdown for notification levels.
     * @param serverName the server name.
     * @return the values.
     */
    public ListBoxModel doFillNotificationLevelItems(@QueryParameter("serverName") final String serverName) {
        Map<Notify, String> levelTextsById = GerritServer.notificationLevelTextsById();
        ListBoxModel items = new ListBoxModel(levelTextsById.size() + 1);
        items.add(getOptionForNotificationLevelDefault(serverName, levelTextsById));
        for (Map.Entry<Notify, String> level : levelTextsById.entrySet()) {
            items.add(new ListBoxModel.Option(level.getValue(), level.getKey().toString()));
        }
        return items;
    }

    /**
     * Reads the default option for the notification level, usually from the server config.
     *
     * @param serverName the server name.
     * @param levelTextsById a map with the localized level texts.
     * @return the default option.
     */
    private static ListBoxModel.Option getOptionForNotificationLevelDefault(
            final String serverName, Map<Notify, String> levelTextsById) {
        if (ANY_SERVER.equals(serverName)) {
            // We do not know which server is selected, so we cannot tell the
            // currently active default value.  It might be the global default,
            // but also a different value.
            return new ListBoxModel.Option(Messages.NotificationLevel_DefaultValue(), "");
        } else if (serverName != null) {
            GerritServer server = PluginImpl.getServer_(serverName);
            if (server != null) {
                Notify level = server.getConfig().getNotificationLevel();
                if (level != null) {
                    String levelText = levelTextsById.get(level);
                    if (levelText == null) { // new/unknown value
                        levelText = level.toString();
                    }
                    return new ListBoxModel.Option(Messages.NotificationLevel_DefaultValueFromServer(levelText), "");
                }
            }
        }

        // fall back to global default
        String defaultText = levelTextsById.get(Config.DEFAULT_NOTIFICATION_LEVEL);
        return new ListBoxModel.Option(Messages.NotificationLevel_DefaultValueFromServer(defaultText), "");
    }

    /**
     * Default Constructor.
     */
    public GerritTriggerDescriptor() {
        super(GerritTrigger.class);
    }

    @Override
    public boolean isApplicable(Item item) {
        return (item instanceof ParameterizedJobMixIn.ParameterizedJob);
    }

    @Override
    public String getDisplayName() {
        return Messages.TriggerDisplayName();
    }

    @Override
    public String getHelpFile() {
        return "/plugin/gerrit-trigger/help-whatIsGerritTrigger.html";
    }

    /**
     * A list of CompareTypes for the UI.
     *
     * @return A list of CompareTypes
     */
    public CompareType[] getCompareTypes() {
        return CompareType.values();
    }

    /**
     * Getter for the list of PluginGerritEventDescriptors.
     * @return the list.
     */
    public List<PluginGerritEvent.PluginGerritEventDescriptor> getGerritEventDescriptors() {
        ExtensionList<PluginGerritEvent.PluginGerritEventDescriptor> extensionList =
                Jenkins.get().getExtensionList(PluginGerritEvent.PluginGerritEventDescriptor.class);
        return extensionList;
    }
}

## 内容3
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/hudsontrigger/actions/RetriggerAction.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.actions;

import com.sonyericsson.hudson.plugins.gerrit.trigger.Messages;
import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl;
import com.sonyericsson.hudson.plugins.gerrit.trigger.gerritnotifier.ToGerritRunListener;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTrigger;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.TriggerContext;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.TriggeredItemEntity;
import hudson.model.Action;
import java.io.IOException;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil.getPluginImageUrl;

/**
 * Action that retriggers one build with the same event parameters as the build this trigger is in.
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
public class RetriggerAction implements Action {

    private TriggerContext context;

    /**
     * Standard Constructor.
     * @param context the original GerritCause's context.
     */
    public RetriggerAction(TriggerContext context) {
        this.context = context;
    }

    /**
     * Default constructor.
     * <strong>Only use this if you are a serializer.</strong>
     */
    public RetriggerAction() {
    }

    @Override
    public String getIconFileName() {
        if (!hasPermission() || isBuilding()) {
            return null;
        } else {
            return getPluginImageUrl("icon_retrigger24.png");
        }
    }

    @Override
    public String getDisplayName() {
        if (!hasPermission() || isBuilding()) {
            return null;
        } else {
            return Messages.Retrigger();
        }
    }

    @Override
    public String getUrlName() {
        if (!hasPermission() || isBuilding()) {
            return null;
        } else {
            return "gerrit-trigger-retrigger-this";
        }
    }

    /**
     * Checks the current "memory" if the project is currently building this event.
     * @return true if so.
     */
    private boolean isBuilding() {
        if (context == null || context.getThisBuild() == null || context.getEvent() == null) {
            return false;
        } else {
            ToGerritRunListener listener = ToGerritRunListener.getInstance();
            if (listener == null) {
                return context.getThisBuild().getBuild().isBuilding();
            }
            return context.getThisBuild().getBuild().isBuilding()
                    || listener.isBuilding(context.getThisBuild().getProject(), context.getEvent());
        }
    }

    /**
     * checks if the current user has permission to build/retrigger the project.
     * @return true if so.
     */
    private boolean hasPermission() {
        if (context == null || context.getThisBuild() == null || context.getThisBuild().getProject() == null) {
            return false;
        } else {
            return context.getThisBuild().getProject().hasPermission(PluginImpl.RETRIGGER);
        }
    }

    /**
     * Handles the request to re-trigger and redirects back to the page that called.
     * @param request StaplerRequest the request.
     * @param response StaplerResponse the response handler.
     * @throws IOException in case of Stapler issues
     */
    public void doIndex(StaplerRequest request, StaplerResponse response) throws IOException {

        if (context == null || context.getThisBuild() == null) {
            return;
        }

        if (!hasPermission()) {
            //TODO Access denied message to user?
            return;
        }

        if (isBuilding()) {
            //TODO show error to user?
            return;
        }

        TriggeredItemEntity entity = context.getThisBuild();
        GerritTrigger trigger = GerritTrigger.getTrigger(entity.getProject());
        if (trigger == null) {
            //TODO show config error to user?
            return;
        }

        trigger.retriggerThisBuild(context);
        response.sendRedirect2(entity.getProject().getAbsoluteUrl());
    }
}

## 内容4
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/hudsontrigger/actions/RetriggerAllAction.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.actions;

import com.sonyericsson.hudson.plugins.gerrit.trigger.Messages;
import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl;
import com.sonyericsson.hudson.plugins.gerrit.trigger.gerritnotifier.ToGerritRunListener;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTrigger;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.TriggerContext;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.TriggeredItemEntity;
import hudson.model.Action;
import java.io.IOException;

import hudson.model.Job;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil.getPluginImageUrl;

/**
 * Action that retriggers all builds in one event with the same event parameters as the build this trigger is in.
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
public class RetriggerAllAction implements Action {

    private TriggerContext context;

    /**
     * Standard Constructor.
     * @param context the original GerritCause's context.
     */
    public RetriggerAllAction(TriggerContext context) {
        this.context = context;
    }

    /**
     * Default constructor.
     * <strong>Only use this if you are a serialize.r</strong>
     */
    public RetriggerAllAction() {
    }

    @Override
    public String getIconFileName() {
        if (!hasPermission() || isBuilding() || !hasOthers()) {
            return null;
        } else {
            return getPluginImageUrl("icon_retrigger24.png");
        }
    }

    @Override
    public String getDisplayName() {
        if (!hasPermission() || isBuilding() || !hasOthers()) {
            return null;
        } else {
            return Messages.RetriggerAll();
        }
    }

    @Override
    public String getUrlName() {
        if (!hasPermission() || isBuilding() || !hasOthers()) {
            return null;
        } else {
            return "gerrit-trigger-retrigger-all";
        }
    }

    /**
     * Checks {@link TriggerContext#hasOthers()} if the context exists.
     * It does a null check on the context before calling.
     * @return true if there are any other builds in the context.
     */
    private boolean hasOthers() {
        if (context != null) {
            return context.hasOthers();
        } else {
            return false;
        }
    }

    /**
     * Checks the current "memory" if the event is currently building.
     * @return true if so.
     */
    private boolean isBuilding() {
        if (context != null) {
            ToGerritRunListener listener = ToGerritRunListener.getInstance();
            if (listener == null) {
                return context.getThisBuild().getBuild().isBuilding();
            }
            return context.getThisBuild().getBuild().isBuilding()
                    || listener.isBuilding(context.getEvent());
        } else {
            //The correct answer here should be null, but hasPermission takes care of a more "correct" answer.
            return false;
        }
    }

    /**
     * checks if the current user has permission to build/retrigger this and the other projects.
     * @return true if so.
     */
    private boolean hasPermission() {
        if (context == null || context.getThisBuild() == null || context.getThisBuild().getProject() == null) {
            return false;
        }
        if (context.getThisBuild().getProject().hasPermission(PluginImpl.RETRIGGER)) {
            for (Job project : context.getOtherProjects()) {
                if (!project.hasPermission(PluginImpl.RETRIGGER)) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * Handles the request to re-trigger and redirects back to the page that called.
     * @param request StaplerRequest the request.
     * @param response StaplerResponse the response handler.
     * @throws IOException in case of Stapler issues
     */
    public void doIndex(StaplerRequest request, StaplerResponse response) throws IOException {

        if (context == null || context.getThisBuild() == null) {
            return;
        }

        if (!hasPermission()) {
            //TODO Access denied message to user?
            return;
        }

        if (isBuilding()) {
            //TODO show error to user?
            return;
        }

        if (!context.hasOthers()) {
            //There is no reason to run this action on a lonely project.
            return;
        }

        TriggeredItemEntity entity = context.getThisBuild();
        GerritTrigger trigger = GerritTrigger.getTrigger(entity.getProject());
        if (trigger == null) {
            //TODO show config error to user?
            return;
        }

        trigger.retriggerAllBuilds(context);
        response.sendRedirect2(entity.getProject().getAbsoluteUrl());
    }
}

## 内容5
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/hudsontrigger/actions/manual/ManualTriggerAction.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.actions.manual;

import com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer;
import com.sonyericsson.hudson.plugins.gerrit.trigger.Messages;
import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl;
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig;
import com.sonyericsson.hudson.plugins.gerrit.trigger.events.ManualPatchsetCreated;
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTriggerParameters;
import com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil;
import com.sonymobile.tools.gerrit.gerritevents.GerritDefaultValues;
import com.sonymobile.tools.gerrit.gerritevents.GerritQueryException;
import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandler;
import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Change;
import com.sonymobile.tools.gerrit.gerritevents.dto.attr.PatchSet;
import com.sonymobile.tools.gerrit.gerritevents.dto.attr.Provider;
import com.sonymobile.tools.gerrit.gerritevents.dto.events.PatchsetCreated;
import hudson.Extension;
import hudson.model.ParameterValue;
import hudson.model.RootAction;
import hudson.security.Permission;
import jenkins.model.Jenkins;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil.getPluginImageUrl;

/**
 * RootAction for manually triggering a "Gerrit-build".
 *
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
@Extension
public class ManualTriggerAction implements RootAction {

    /**
     * The expected number of parts separated by _ in a generated id.
     * Each part is actually another id.
     *
     * @see #generateTheId(net.sf.json.JSONObject, net.sf.json.JSONObject)
     */
    public static final int EXPECTED_NR_OF_PARTS_IN_A_GENERATED_ID = 3;

    private static final String SESSION_RESULT = "result";
    private static final String SESSION_SEARCH_ERROR = "error_search";
    private static final String SESSION_BUILD_ERROR = "error_build";
    private static final String SESSION_TRIGGER_MONITOR = "trigger_monitor";
    private static final Logger logger = LoggerFactory.getLogger(ManualTriggerAction.class);
    /**
     * The char that separates the different id components in a search-result-row.
     */
    public static final String ID_SEPARATOR = ":";
    /**
     * The maximum length of a change subject to display.
     */
    private static final int MAX_SUBJECT_STR_LENGTH = 65;

    @Override
    public String getIconFileName() {
        if (hasEnabledServers() && Jenkins.get().hasPermission(PluginImpl.MANUAL_TRIGGER)) {
            return getPluginImageUrl("icon_retrigger24.png");
        } else {
            return null;
        }
    }

    @Override
    public String getDisplayName() {
        if (hasEnabledServers() && Jenkins.get().hasPermission(PluginImpl.MANUAL_TRIGGER)) {
            return Messages.ManualGerritTrigger();
        } else {
        return null;
        }
    }

    @Override
    public String getUrlName() {
        return "gerrit_manual_trigger";
    }

    /**
     * If this page/link is enabled or not, depending on whether at least one server is enabled.
     *
     * @return true if at least one server is enabled, false otherwise.
     * @see com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig#isEnableManualTrigger()
     */
    public boolean hasEnabledServers() {
        for (GerritServer s : PluginImpl.getServers_()) {
            if (s.getConfig().isEnableManualTrigger()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check whether a server is allowed to be queried and manually triggered.
     *
     * @param serverName the name of the server selected in the dropdown.
     * @return true if server exists and manual trigger is enabled.
     * @see com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig#isEnableManualTrigger()
     */
    private boolean isServerEnabled(String serverName) {
        if (getServerConfig(serverName) != null) {
            return getServerConfig(serverName).isEnableManualTrigger();
        } else {
            return false;
        }
    }

    /**
     * Get the server config.
     *
     * @param serverName the name of the server.
     * @return the config of the server or null if config not found.
     */
    private IGerritHudsonTriggerConfig getServerConfig(String serverName) {
        GerritServer server = PluginImpl.getServer_(serverName);
        if (server != null) {
            IGerritHudsonTriggerConfig config = server.getConfig();
            if (config != null) {
                return config;
            } else {
                logger.error("Could not find the config of server: {}", serverName);
            }
        } else {
            logger.error("Could not find server {}", serverName);
        }
        return null;
    }

    /**
     * Return the front end url of selected server, or first enabled server if
     * selected doesn't exists (happens when serverName is null also). First
     *
     * @param serverName the name of the GerritServer or null.
     * @return url to the frontend
     */
    @SuppressWarnings("unused")
    //called from jelly
    public String getFrontEndUrl(String serverName) {
        IGerritHudsonTriggerConfig serverConfig = getServerConfig(serverName);
        if (serverConfig != null) {
            return serverConfig.getGerritFrontEndUrl();
        } else {
            ArrayList<String> enabledServers = getEnabledServers();
            if (!enabledServers.isEmpty()) {
                return getServerConfig(enabledServers.get(0)).getGerritFrontEndUrl();
            }
        }
        return null;
    }

    /**
     * Returns the list of servers allowed to be queried and manually triggered.
     *
     * @return the enabled server names
     *
     */
    public ArrayList<String> getEnabledServers() {
        ArrayList<String> enabledServers = new ArrayList<String>();
        for (GerritServer s : PluginImpl.getServers_()) {
            if (s.getConfig().isEnableManualTrigger()) {
                enabledServers.add(s.getName());
            }
        }
        if (enabledServers.isEmpty()) {
            logger.trace("No enabled server for manual triggering found.");
        }
        return enabledServers;
    }

    /**
     * Serves the permission required to perform this action.
     * Used by index.jelly
     *
     * @return the permission.
     */
    @SuppressWarnings("unused")
    public Permission getRequiredPermission() {
        return PluginImpl.MANUAL_TRIGGER;
    }

    /**
     * Gets the full path to the provided javascript file.
     * For use by jelly files to give to the client browser.
     *
     * @param jsName the javascript filename.
     * @return the full path from the web-context root.
     */
    @SuppressWarnings("unused")
    //called from jelly
    public String getJsUrl(String jsName) {
        return StringUtil.getPluginJsUrl(jsName);
    }

    /**
     * Finds the highest and lowest code review vote for the provided patch set.
     *
     * @param res the patch set.
     * @return the highest and lowest code review vote for the patch set.
     */
    @Deprecated
    public HighLow getCodeReview(JSONObject res) {
        return getCodeReview(res, 0);
    }

    /**
     * Finds the highest and lowest code review vote for the provided patch set.
     *
     * @param res the patch set.
     * @param patchSetNumber the patch set number.
     * @return the highest and lowest code review vote for the patch set.
     */
    public HighLow getCodeReview(JSONObject res, int patchSetNumber) {
        return Approval.CODE_REVIEW.getApprovals(res, patchSetNumber);
    }

    /**
     * Finds the lowest and highest verified vote for the provided patch set.
     *
     * @param res the patch-set.
     * @return the highest and lowest verified vote.
     */
    @Deprecated
    public HighLow getVerified(JSONObject res) {
        return getVerified(res, 0);
    }

    /**
     * Finds the lowest and highest verified vote for the provided patch set.
     *
     * @param res the patch-set.
     * @param patchSetNumber the patch set number.
     * @return the highest and lowest verified vote.
     */
    public HighLow getVerified(JSONObject res, int patchSetNumber) {
        return Approval.VERIFIED.getApprovals(res, patchSetNumber);
    }

    /**
     * Cuts the string to a max length of {@link #MAX_SUBJECT_STR_LENGTH}.
     *
     * @param subject the string to fix if needed.
     * @return the fixed string.
     */
    @SuppressWarnings("unused")
    //Called from jelly
    public String toReadableHtml(String subject) {
        if (subject != null && subject.length() > MAX_SUBJECT_STR_LENGTH) {
            subject = subject.substring(0, MAX_SUBJECT_STR_LENGTH);
        }
        if (subject != null) {
            return subject;
        } else {
            return "";
        }
    }

    /**
     * Does a search.
     *
     * @param queryString the query to send to Gerrit.
     * @param request     the request.
     * @param selectedServer the selected Gerrit server.
     * @param allPatchSets if the result includes all patchsets in a change.
     * @param response    the response.
     * @throws IOException if the query fails.
     */
    @SuppressWarnings("unused")
    //Called from jelly
    public void doGerritSearch(@QueryParameter("queryString") final String queryString,
        @QueryParameter("selectedServer") final String selectedServer,
        @QueryParameter("allPatchSets") final boolean allPatchSets, StaplerRequest request,
                               StaplerResponse response) throws IOException {

        HttpSession session = request.getSession();
        // Create session if nothing.
        if (session == null) {
            session = request.getSession(true);
        }
        session.setAttribute("allPatchSets", allPatchSets);
        session.setAttribute("selectedServer", selectedServer);
        if (!isServerEnabled(selectedServer)) {
            response.sendRedirect2(".");
            return;
        }
        Jenkins jenkins = Jenkins.get();
        jenkins.checkPermission(PluginImpl.MANUAL_TRIGGER);
        IGerritHudsonTriggerConfig config = getServerConfig(selectedServer);

        if (config != null) {
            GerritQueryHandler handler = new GerritQueryHandler(config);
            clearSessionData(session);
            session.setAttribute("queryString", queryString);

            try {
                List<JSONObject> json = handler.queryJava(queryString, allPatchSets, true, false, true);
                if (!allPatchSets) {
                    for (JSONObject j : json) {
                        if (j.containsKey("id")) {
                            JSONArray jsonArray = new JSONArray();
                            jsonArray.add(j.getJSONObject("currentPatchSet"));
                            j.put("patchSets", jsonArray);
                        }
                    }
                }
                session.setAttribute(SESSION_RESULT, json);
                //TODO Implement some smart default selection.
                //That can notice that a specific revision is searched or that there is only one result etc.
            } catch (GerritQueryException gqe) {
                logger.debug("Bad query {}", gqe);
                session.setAttribute(SESSION_SEARCH_ERROR, gqe);
            } catch (Exception ex) {
                logger.warn("Could not query Gerrit for [" + queryString + "]", ex);
                session.setAttribute(SESSION_SEARCH_ERROR, ex);
            }
            response.sendRedirect2(".");
        } else {
            logger.error("Could not find config for the server {}", selectedServer);
        }
    }

    /**
     * Builds the selected patch-set(s).
     *
     * @param selectedIds the selected rows in the form's search-result separated by "[]".
     * @param request     the request.
     * @param response    the response.
     * @throws IOException if the query fails.
     */
    @SuppressWarnings("unused")
    //Called from jelly
    public void doBuild(@QueryParameter("selectedIds") String selectedIds, StaplerRequest request,
                        StaplerResponse response) throws IOException {

        HttpSession session = request.getSession();
        if (session == null) {
            logger.debug("Session alreay closed.");
            session = request.getSession(true);
            session.setAttribute(SESSION_BUILD_ERROR, Messages.ErrorSessionAlreadyClosed());
            response.sendRedirect2(".");
            return;
        }

        String selectedServer = (String)session.getAttribute("selectedServer");
        if (!isServerEnabled(selectedServer)) {
            response.sendRedirect2(".");
            return;
        }
        Jenkins.get().checkPermission(PluginImpl.MANUAL_TRIGGER);

        session.removeAttribute(SESSION_BUILD_ERROR);
        String[] selectedRows = null;
        if (selectedIds != null && selectedIds.length() > 0) {
            selectedRows = selectedIds.split("\\[\\]");
        }
        if (selectedRows == null || selectedRows.length <= 0) {
            logger.debug("No builds selected.");
            session.setAttribute(SESSION_BUILD_ERROR, Messages.ErrorSelectSomethingToBuild());
            response.sendRedirect2(".");
        } else {
            logger.debug("Something to build.");
            List<JSONObject> result = (List<JSONObject>)session.getAttribute(SESSION_RESULT);
            TriggerMonitor monitor = new TriggerMonitor();
            logger.trace("Putting monitor into session.");
            session.setAttribute(SESSION_TRIGGER_MONITOR, monitor);
            logger.trace("Calling to index the search result.");
            HashMap<String, JSONObject> indexed = indexResult(result);
            logger.debug("Creating and triggering events.");
            for (String rowId : selectedRows) {
                ManualPatchsetCreated event = findAndCreatePatchSetEvent(rowId, indexed);
                logger.debug("Created event: {}", event);
                if (event != null) {
                    if (event.getProvider() == null || event.getProvider().getName() == null) {
                        event.setProvider(createProviderFromGerritServer(selectedServer));
                    }
                    monitor.add(event);
                    logger.trace("Triggering event: {}", event);
                    triggerEvent(event);
                }
            }
            logger.debug("Sending redirect.");
            response.sendRedirect2(".");
        }
    }

    /**
     * Clears the HTTP session from search and manual-trigger related data.
     *
     * @param session the HTTP session.
     */
    private void clearSessionData(HttpSession session) {
        session.removeAttribute(SESSION_SEARCH_ERROR);
        session.removeAttribute(SESSION_BUILD_ERROR);
        session.removeAttribute(SESSION_RESULT);
        session.removeAttribute(SESSION_TRIGGER_MONITOR);
    }

    /**
     * Generates a "unique" id for the change and/or patch.
     * So it can be identified as a single row in the search result.
     *
     * @param change the change.
     * @param patch  the patch-set in the change.
     * @return the generated id.
     */
    public String generateTheId(JSONObject change, JSONObject patch) {
        StringBuilder theId = new StringBuilder(change.getString("id"));
        if (patch != null) {
            theId.append(ID_SEPARATOR);
            theId.append(patch.getString("revision"));
        }
        theId.append(ID_SEPARATOR);
        theId.append(change.getString("number"));
        if (patch != null) {
            theId.append(ID_SEPARATOR);
            theId.append(patch.getString("number"));
        }
        return theId.toString();
    }

    /**
     * Indexes the search result based on each change and patchset's rowId.
     *
     * @param result the search result.
     * @return an indexed map where the rowId is the key.
     * @see #generateTheId(net.sf.json.JSONObject, net.sf.json.JSONObject)
     */
    @Restricted(NoExternalUse.class)
    HashMap<String, JSONObject> indexResult(List<JSONObject> result) {
        HashMap<String, JSONObject> map = new HashMap<String, JSONObject>();
        for (JSONObject res : result) {
            if (!res.has("type")) {
                String changeId = generateTheId(res, null);
                map.put(changeId, res);
                JSONArray arr = res.getJSONArray("patchSets");
                for (Object obj : arr) {
                    if (obj instanceof JSONObject) {
                        JSONObject patch = (JSONObject)obj;
                        String theId = generateTheId(res, patch);
                        map.put(theId, patch);
                    }
                }
            }
        }
        return map;
    }

    /**
     * Create event Provider from GerritServer.
     *
     * @param serverName the name of the GerritServer
     * @return the Provider with info from the GerritServer, or an empty provider if server not found
     */
    @Restricted(NoExternalUse.class)
    public static Provider createProviderFromGerritServer(String serverName) {
        GerritServer server = PluginImpl.getServer_(serverName);
        if (server == null) {
            logger.warn("Could not find GerritServer: {}", serverName);
        }
        return createProvider(server);
    }

    /**
     * Create event Provider from GerritServer.
     *
     * @param server the GerritServer to create the provider for
     * @return the Provider with info from the GerritServer, or an empty provider if server is null
     */
    @Restricted(NoExternalUse.class)
    public static Provider createProvider(GerritServer server) {
        if (server != null) {
            return new Provider(
                    server.getName(),
                    server.getConfig().getGerritHostName(),
                    String.valueOf(server.getConfig().getGerritSshPort()),
                    GerritDefaultValues.DEFAULT_GERRIT_SCHEME,
                    server.getConfig().getGerritFrontEndUrl(),
                    server.getGerritVersion()
            );
        } else {
            return new Provider();
        }
    }

    /**
     * Creates a list of the parameters as they would be in a scheduled build.
     * Without escaped quotes.
     *
     * @param jsonChange   the JSON data for the change.
     * @param jsonPatchSet the JSON data for the patch-set.
     * @param serverName the name of the GerritServer from the current session.
     * @return a list of the parameters.
     */
    @SuppressWarnings("unused") //called from jelly.
    public List<ParameterValue> getParametersForPatchSet(
            JSONObject jsonChange,
            JSONObject jsonPatchSet,
            String serverName) {
        List<ParameterValue> parameters = new LinkedList<ParameterValue>();
        Change change = new Change(jsonChange);
        PatchSet patchSet = new PatchSet(jsonPatchSet);
        PatchsetCreated event = new PatchsetCreated();
        Provider provider = createProviderFromGerritServer(serverName);
        event.setChange(change);
        event.setPatchset(patchSet);
        event.setProvider(provider);
        GerritTriggerParameters.setOrCreateParameters(event, parameters);
        return parameters;
    }

    /**
     * Returns {@link ParameterValue} for parameter with name {@link GerritTriggerParameters#GERRIT_CHANGE_URL}
     * or <code>null</code> if such parameter is not present.
     *
     * @param jsonChange   the JSON data for the change.
     * @param jsonPatchSet the JSON data for the patch-set.
     * @param serverName the name of the GerritServer from the current session.
     * @return ParameterValue or <code>null</code>
     */
    @SuppressWarnings("unused") //called from jelly.
    public ParameterValue getChangeUrlParamForPatchSet(
            JSONObject jsonChange,
            JSONObject jsonPatchSet,
            String serverName) {
        List<ParameterValue> parameters = getParametersForPatchSet(jsonChange, jsonPatchSet, serverName);
        for (ParameterValue parameterValue : parameters) {
            if (hasUrl(parameterValue)) {
                return parameterValue;
            }
        }
        return null;
    }

    /**
     * Tells if the given parameter should have a URL or not.
     * i.e. if the parameter represents {@link GerritTriggerParameters#GERRIT_CHANGE_URL}.
     *
     * @param parameterValue the parameter.
     * @return true if so.
     */
    @SuppressWarnings("unused") //called from jelly.
    public boolean hasUrl(ParameterValue parameterValue) {
        return GerritTriggerParameters.GERRIT_CHANGE_URL.name().equals(parameterValue.getName());
    }

    /**
     * Generates the URL to the provided change in Gerrit
     * If the change already has a URL provided, that URL will be used.
     *
     * @param change the change to link to.
     * @param serverName the name of the selected Gerrit server.
     * @return the URL to the change.
     */
    public String getGerritUrl(JSONObject change, String serverName) {
        String url = change.optString("url", null);
        if (url != null && url.length() > 0) {
            return url;
        } else if (change.optString("number", "").length() > 0) {
            if (getServerConfig(serverName) != null) {
                return getServerConfig(serverName).getGerritFrontEndUrlFor(
                    change.getString("number"), "1");
            } else {
                logger.error("Could not get config for the server: {}", serverName);
            }
        } else {
            return "";
        }
        return " ";
    }

    /**
     * Finds the patch-set in the indexed search result and creates a {@link ManualPatchsetCreated} from its data.
     *
     * @param rowId   the generated rowId in the search result.
     * @param indexed the indexed search result.
     * @return the event, or null if there is no patch-set in the search result.
     */
    private ManualPatchsetCreated findAndCreatePatchSetEvent(String rowId,
                                                             HashMap<String, JSONObject> indexed) {
        logger.trace("Searching for {}", rowId);
        String[] ids = rowId.split(ID_SEPARATOR);
        if (ids.length >= EXPECTED_NR_OF_PARTS_IN_A_GENERATED_ID) {
            logger.debug("Correct nr of ids: {}", ids.length);
            JSONObject patch = indexed.get(rowId);
            if (patch != null) {
                logger.debug("Found the patch: {}", patch);
                String changeId = ids[0] + ID_SEPARATOR + ids[2];
                logger.debug("ChangeId calculated to: {}", changeId);
                JSONObject change = indexed.get(changeId);
                if (change != null) {
                    logger.debug("Found the change: {}", change);
                    return new ManualPatchsetCreated(change, patch, Jenkins.getAuthentication().getName());
                } else {
                    logger.trace("No change found with id {}", changeId);
                    return null;
                }
            } else {
                logger.trace("No patch found for id {}", rowId);
                return null;
            }
        } else {
            logger.trace("Bad nr of ids.");
            return null;
        }
    }

    /**
     * Triggers the event by putting it into the event queue.
     *
     * @param event the event to trigger.
     * @see GerritServer#triggerEvent(com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent)
     */
    private void triggerEvent(ManualPatchsetCreated event) {
        logger.trace("Going to trigger event: {}", event);
        String serverName = event.getProvider().getName(); //null handled by caller method doBuild
        GerritServer server = PluginImpl.getServer_(serverName);
        if (server != null) {
            server.triggerEvent(event);
        } else {
            logger.error("Could not find Gerrit server {}", serverName);
        }

    }

    /**
     * A tuple of a high and a low number.
     */
    public static class HighLow {

        private final int high;
        private final int low;

        /**
         * Standard constructor.
         *
         * @param high the highest number.
         * @param low  the lowest number.
         */
        public HighLow(int high, int low) {
            this.high = high;
            this.low = low;
        }

        /**
         * Get the High number.
         *
         * @return the high number.
         */
        public int getHigh() {
            return high;
        }

        /**
         * Get the Low number.
         *
         * @return the low number.
         */
        public int getLow() {
            return low;
        }

        @Override
        public String toString() {
            return "HighLow(" + high + "," + low + ")";
        }
    }

    /**
     * Represents a "vote"-type or Approval of a change in the JSON structure.
     */
    public static enum Approval {
        /**
         * A Code Review Approval type <i>Code-Review</i>.
         */
        CODE_REVIEW("Code-Review"),
        /**
         * A Verified Approval type <i>Verified</i>.
         */
        VERIFIED("Verified");
        private String type;

        /**
         * Standard constructor.
         *
         * @param type the approval type.
         */
        Approval(String type) {
            this.type = type;
        }

        /**
         * Finds the highest and lowest approval value of the approval's type for the specified change.
         *
         * @param res the change.
         * @return the highest and lowest value. Or 0,0 if there are no values.
         */
        @Deprecated
        public HighLow getApprovals(JSONObject res) {
            return getApprovals(res, 0);
        }

        /**
         * Finds the highest and lowest approval value of the approval's type for the specified change.
         *
         * @param res the change.
         * @param patchSetNumber the patch set number.
         * @return the highest and lowest value. Or 0,0 if there are no values.
         */
        public HighLow getApprovals(JSONObject res, int patchSetNumber) {
            logger.trace("Get Approval: {} {}", type, res);
            int highValue = Integer.MIN_VALUE;
            int lowValue = Integer.MAX_VALUE;
            if (res.has("currentPatchSet")) {
                logger.trace("Has currentPatchSet");
                JSONObject patchSet = res.getJSONObject("currentPatchSet");
                if (patchSet.has("number") && patchSet.has("approvals")) {
                    if (patchSet.getInt("number") == patchSetNumber) {
                        JSONArray approvals = patchSet.getJSONArray("approvals");
                        logger.trace("Approvals: {}", approvals);
                        for (Object o : approvals) {
                            JSONObject ap = (JSONObject)o;
                            if (type.equalsIgnoreCase(ap.optString("type"))) {
                                logger.trace("A {}", type);
                                try {
                                    int approval = Integer.parseInt(ap.getString("value"));
                                    highValue = Math.max(highValue, approval);
                                    lowValue = Math.min(lowValue, approval);
                                } catch (NumberFormatException nfe) {
                                    logger.warn("Gerrit is bad at giving me Approval-numbers! {}", nfe);
                                }
                            }
                        }
                    }
                }
            }
            if (highValue == Integer.MIN_VALUE && lowValue == Integer.MAX_VALUE) {
                logger.debug("Returning all 0");
                return new HighLow(0, 0);
            } else {
                HighLow r = new HighLow(highValue, lowValue);
                logger.debug("Returning something {}", r);
                return r;
            }
        }
    }
}

## 内容6
### 文件路径：
src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/hudsontrigger/data/GerritProject.java
### 代码内容：
package com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data;

import static com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer.ANY_SERVER;
import hudson.Extension;
import hudson.RelativePath;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.util.ComboBoxModel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;

import jenkins.model.Jenkins;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer;
import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl;

/**
 * Base settings for one matcher rule of a Gerrit project.
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
public class GerritProject implements Describable<GerritProject> {
    /** Magical file name which represents the commit message. */
    private static final String MAGIC_FILE_NAME_COMMIT_MSG = "/COMMIT_MSG";
    /** Magical file name which represents the merge list of a merge commit. */
    private static final String MAGIC_FILE_NAME_MERGE_LIST = "/MERGE_LIST";
    /** Magical file name which doesn't represent a file. Used specifically for patchset-level comments. */
    private static final String MAGIC_FILE_NAME_PATCHSET_LEVEL = "/PATCHSET_LEVEL";

    private CompareType compareType;
    private String pattern;
    private List<Branch> branches;
    private List<FilePath> filePaths;
    private List<Topic> topics;
    private List<FilePath> forbiddenFilePaths;
    private boolean disableStrictForbiddenFileVerification;

    /**
     * Default empty constructor.
     */
    public GerritProject() {

    }

    /**
     * DataBound Constructor.
     * @param compareType the compareType
     * @param pattern the project-name pattern
     * @param branches the branch-rules
     * @param topics the topic-rules
     * @param filePaths the file-path rules.
     * @param forbiddenFilePaths the forbidden file-path rules.
     * @param disableStrictForbiddenFileVerification whether to be strict or not.
     */
    @DataBoundConstructor
    public GerritProject(
            CompareType compareType,
            String pattern,
            List<Branch> branches,
            List<Topic> topics,
            List<FilePath> filePaths,
            List<FilePath> forbiddenFilePaths,
            boolean disableStrictForbiddenFileVerification) {

        this.compareType = compareType;
        this.pattern = pattern;
        this.branches = branches;
        this.topics = topics;
        this.filePaths = filePaths;
        this.forbiddenFilePaths = forbiddenFilePaths;
        this.disableStrictForbiddenFileVerification = disableStrictForbiddenFileVerification;
    }

    /**
     * Whether to disable strict verification of forbidden files.
     * @return true if disabled.
     */
    public boolean isDisableStrictForbiddenFileVerification() {
        return disableStrictForbiddenFileVerification;
    }

    /**
     * Set whether to disable strict verification of forbidden files.
     * @param disableStrictForbiddenFileVerification true to disable.
     */
    public void setDisableStrictForbiddenFileVerification(boolean disableStrictForbiddenFileVerification) {
        this.disableStrictForbiddenFileVerification = disableStrictForbiddenFileVerification;
    }

    /**
     * Which algorithm-type to use with the pattern.
     * @return the compareType
     */
    public CompareType getCompareType() {
        return compareType;
    }

    /**
     * Which algorithm-type to use with the pattern.
     * @param compareType the compareType
     */
    public void setCompareType(CompareType compareType) {
        this.compareType = compareType;
    }

    /**
     * The pattern for the project-name to match on.
     * @return the pattern
     */
    public String getPattern() {
        return pattern;
    }

    /**
     * The pattern for the project-name to match on.
     * @param pattern the pattern
     */
    public void setPattern(String pattern) {
        this.pattern = pattern;
    }

    /**
     * The list of branch-rules.
     * @return the branch-rules
     */
    public List<Branch> getBranches() {
        return branches;
    }

    /**
     * The list of branch-rules.
     * @param branches the branch-rules
     */
    public void setBranches(List<Branch> branches) {
        this.branches = branches;
    }

    /**
     * The list of filepath-rules.
     * @return the filepath-rules
     */
    public List<FilePath> getFilePaths() {
        return filePaths;
    }

    /**
     * The list of filepath-rules.
     * @param filePaths the filepath-rules
     */
    public void setFilePaths(List<FilePath> filePaths) {
        this.filePaths = filePaths;
    }

    /**
     * The list of topic-rules.
     * @return the topic-rules
     */
    public List<Topic> getTopics() {
        return topics;
    }

    /**
     * The list of topic-rules.
     * @param topics the topic-rules
     */
    public void setTopics(List<Topic> topics) {
        this.topics = topics;
    }

    /**
     * The list of the forbidden file-path rules.
     * @return the forbidden file-path rules.
     */
    public List<FilePath> getForbiddenFilePaths() {
        return forbiddenFilePaths;
    }

    /**
     * The list of the forbidden file-path rules.
     * @param forbiddenFilePaths the forbidden file-path rules.
     */
    public void setForbiddenFilePaths(List<FilePath> forbiddenFilePaths) {
        this.forbiddenFilePaths = forbiddenFilePaths;
    }

    /**
     * Compares the project, branch and files to see if the rules specified is a match.
     * @param project the Gerrit project
     * @param branch the branch.
     * @param topic the topic.
     * @param files a closure which returns the list of files in the change.
     * @return true is the rules match.
     */
    public boolean isInteresting(String project, String branch, String topic, Supplier<List<String>> files) {
        if (isInteresting(project, branch, topic)) {
            return isInterestingFile(files.get());
        }
        return false;
    }

    /**
     * Compares the project and branch to see if the rules specified is a match.
     * @param project the Gerrit project
     * @param branch the branch.
     * @param topic the topic.
     * @return true is the rules match.
     */
    public boolean isInteresting(String project, String branch, String topic) {
        if (compareType.matches(pattern, project)) {
            for (Branch b : branches) {
                if (b.isInteresting(branch)) {
                    return isInterestingTopic(topic);
                }
            }
        }
        return false;
    }

    /**
     * Compare topics to see if the rules specified is a match.
     *
     * @param topic the topic.
     * @return true if the rules match or no rules.
     */
    private boolean isInterestingTopic(String topic) {
        if (topics != null && topics.size() > 0) {
            for (Topic t : topics) {
                if (t.isInteresting(topic)) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    /**
     * Compare files to see if the rules specified is a match.
     *
     * @param files the files.
     * @return true if the rules match or no rules.
     */
    private boolean isInterestingFile(List<String> files) {
        List<String> tmpFiles = new ArrayList<String>(files);
        tmpFiles.remove(MAGIC_FILE_NAME_COMMIT_MSG);
        tmpFiles.remove(MAGIC_FILE_NAME_MERGE_LIST);
        tmpFiles.remove(MAGIC_FILE_NAME_PATCHSET_LEVEL);

        boolean foundInterestingForbidden = false;
        if (forbiddenFilePaths != null) {
            Iterator<String> i = tmpFiles.iterator();
            while (i.hasNext()) {
                String file = i.next();
                for (FilePath ffp : forbiddenFilePaths) {
                    if (ffp.isInteresting(file)) {
                        if (!disableStrictForbiddenFileVerification) {
                            return false;
                        } else {
                            foundInterestingForbidden = true;
                            i.remove();
                            break;
                        }
                    }
                }
            }
        }
        if (foundInterestingForbidden && tmpFiles.isEmpty()) {
            // All changed files are forbidden, so this is not interesting
            return false;
        }

        if (filePaths != null && filePaths.size() > 0) {
            for (FilePath f : filePaths) {
                if (f.isInteresting(tmpFiles)) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    @Override
    public Descriptor<GerritProject> getDescriptor() {
        return Jenkins.get().getDescriptor(getClass());
    }

    /**
     * Descriptor allowing for communication within the Repeatable.
     * Necessary for editable combobox.
     */
    @Extension
    public static final class DescriptorImpl extends Descriptor<GerritProject> {

        /**
         * Used to fill the project pattern combobox with AJAX.
         * The filled values will depend on the server that the user has chosen from the dropdown.
         *
         * @param serverName the name of the server that the user has chosen.
         * @return ComboBoxModels containing a list of all Gerrit Projects found on that server.
         */
        public ComboBoxModel doFillPatternItems(@QueryParameter("serverName")
                @RelativePath("..") final String serverName) {
            Collection<String> projects = new HashSet<String>();

            if (serverName != null && !serverName.isEmpty()) {
                if (ANY_SERVER.equals(serverName)) {
                    for (GerritServer server : PluginImpl.getServers_()) {
                        projects.addAll(server.getGerritProjects());
                    }
                } else {
                    GerritServer server = PluginImpl.getServer_(serverName);
                    if (server != null) {
                        projects.addAll(server.getGerritProjects());
                    }
                }
            }
            return new ComboBoxModel(projects);
        }
        @Override
        public String getDisplayName() {
            return "";
        }
    }
}

Output:
【漏洞类型】权限检查不足
【严重性】High
【漏洞摘要】在多个方法中，权限检查不充分或缺失，导致未授权用户可能执行敏感操作，如手动触发构建、重新触发构建等。具体表现为未在关键操作前进行充分的权限检查。例如，在`GerritManagement.java`的`doAutoCompleteCopyNewItemFrom`方法中，未对用户进行权限检查；在`GerritTriggerDescriptor.java`的`doFillServerNameItems`方法中，未对项目级别的权限进行检查。
【关键代码模式】
- `doAutoCompleteCopyNewItemFrom`方法中缺少`Jenkins.get().checkPermission(Jenkins.ADMINISTER);`
- `doFillServerNameItems`方法中缺少对项目级别的`Item.CONFIGURE`权限检查
- `doIndex`方法中缺少`@POST`注解和对`hasPermission`方法的调用
- `doBuild`方法中缺少`@POST`注解和对`hasPermission`方法的调用
- `doFillPatternItems`方法中缺少对项目级别的`Item.CONFIGURE`权限检查
【修复方法说明】在关键操作前添加充分的权限检查，并使用`@POST`注解确保操作为POST请求。