net.nicholaswilliams.java.teamcity.plugin.buildNumber.SharedBuildNumberController.java Source code

Java tutorial

Introduction

Here is the source code for net.nicholaswilliams.java.teamcity.plugin.buildNumber.SharedBuildNumberController.java

Source

/*
 * SharedBuildNumberController.java from TeamCityPlugins modified Saturday, September 15, 2012 11:34:17 CDT (-0500).
 *
 * Copyright 2010-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.nicholaswilliams.java.teamcity.plugin.buildNumber;

import com.intellij.openapi.diagnostic.Logger;
import jetbrains.buildServer.controllers.BaseController;
import jetbrains.buildServer.controllers.admin.AdminPage;
import jetbrains.buildServer.serverSide.auth.AccessDeniedException;
import jetbrains.buildServer.serverSide.auth.AuthUtil;
import jetbrains.buildServer.users.SUser;
import jetbrains.buildServer.web.openapi.PagePlaces;
import jetbrains.buildServer.web.openapi.PluginDescriptor;
import jetbrains.buildServer.web.openapi.PositionConstraint;
import jetbrains.buildServer.web.openapi.WebControllerManager;
import jetbrains.buildServer.web.util.SessionUser;
import jetbrains.buildServer.web.util.WebAuthUtil;
import jetbrains.buildServer.web.util.WebUtil;
import net.nicholaswilliams.java.teamcity.plugin.buildNumber.pojo.SharedBuildNumber;
import org.apache.commons.lang.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.SortedSet;

/**
 * Handles the UI for managing shared build numbers.
 *
 * @author Nick Williams
 * @version 1.0.0
 * @since 1.0.0
 */
public class SharedBuildNumberController extends BaseController {
    private static final Logger logger = Logger
            .getInstance("jetbrains.buildServer.PLUGIN.sharedBuildNumber.CONTROLLER");

    private static final String FORM = "sharedBuildNumberForm";

    private static final String PREFIX = "sbnParameterPrefix";

    public static String TAB_ID = "sharedBuildNumbers";

    private PluginConfigurationService configurationService;

    private String listJspPagePath;

    private String addJspPagePath;

    private String editJspPagePath;

    public SharedBuildNumberController(@NotNull WebControllerManager controllerManager,
            @NotNull PluginDescriptor pluginDescriptor, @NotNull PagePlaces pagePlaces,
            @NotNull PluginConfigurationService configurationService) {
        SharedBuildNumberController.logger
                .info("Initializing shared build number controller; plugging in Administrative tab extension.");

        this.listJspPagePath = pluginDescriptor.getPluginResourcesPath("jsp/list.jsp");
        this.addJspPagePath = pluginDescriptor.getPluginResourcesPath("jsp/addBuildNumber.jsp");
        this.editJspPagePath = pluginDescriptor.getPluginResourcesPath("jsp/editBuildNumber.jsp");

        this.configurationService = configurationService;

        AdminTab tab = new AdminTab(pagePlaces, pluginDescriptor);
        tab.addCssFile(pluginDescriptor.getPluginResourcesPath("css/sharedBuildNumbers.css"));
        tab.addCssFile("/css/settingsBlock.css");
        tab.addJsFile(pluginDescriptor.getPluginResourcesPath("js/sharedBuildNumbers.js"));
        tab.setPluginName("sharedBuildNumbers");
        tab.setPosition(PositionConstraint.between(Arrays.asList("projects"), Arrays.asList("cleanup")));
        tab.register();

        controllerManager.registerController("/admin/adminSharedBuildNumbers.html", this);
    }

    @Override
    protected ModelAndView doHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
            throws ServletException, IOException {
        SUser user = SessionUser.getUser(request);

        if (this.hasAccess(user)) {
            String action = request.getParameter("action");
            if (action == null || action.trim().length() == 0)
                action = "list";
            else
                action = action.trim();

            boolean isPost = this.isPost(request);

            if (action.equals("list")) {
                return this.listBuildNumbers(request);
            } else if (action.equals("add")) {
                if (isPost)
                    return this.submitAddBuildNumber(request);
                return this.addBuildNumber();
            } else if (action.equals("edit")) {
                if (isPost)
                    return this.submitEditBuildNumber(request, response);
                return this.editBuildNumber(request, response);
            } else if (action.equals("delete") && isPost) {
                return this.submitDeleteBuildNumber(request, response);
            } else {
                SharedBuildNumberController.logger
                        .info("Unsupported action [" + action + "] in shared build number controller.");
                WebUtil.notFound(request, response, "The page you referenced does not exist.",
                        SharedBuildNumberController.logger);
                return null;
            }
        } else {
            SharedBuildNumberController.logger
                    .warn("Access denied to user [" + user.getUsername() + "] for shared build number UI.");
            WebAuthUtil.addAccessDeniedMessage(request,
                    new AccessDeniedException(user,
                            "You must be an System Administrator or Global Project Administrator to manage shared "
                                    + "build numbers."));
            return null;
        }
    }

    protected ModelAndView listBuildNumbers(HttpServletRequest request) {
        ModelAndView modelAndView = new ModelAndView(this.listJspPagePath);

        boolean descending = "desc".equalsIgnoreCase(request.getParameter("direction"));

        SortedSet<SharedBuildNumber> set;
        if ("name".equalsIgnoreCase(request.getParameter("sort"))) {
            set = this.configurationService.getAllSharedBuildNumbersSortedByName(descending);
            modelAndView.getModel().put("sortedBy", "name");
        } else {
            set = this.configurationService.getAllSharedBuildNumbersSortedById(descending);
            modelAndView.getModel().put("sortedBy", "id");
        }

        modelAndView.getModel().put(SharedBuildNumberController.PREFIX,
                BuildNumberPropertiesProvider.PARAMETER_PREFIX);
        modelAndView.getModel().put("numResults", set.size());
        modelAndView.getModel().put("buildNumbers", set);
        modelAndView.getModel().put("sortClass", descending ? "sortedDesc" : "sortedAsc");
        modelAndView.getModel().put("sortChange", descending ? "asc" : "desc");

        return modelAndView;
    }

    protected ModelAndView addBuildNumber() {
        ModelAndView modelAndView = new ModelAndView(this.addJspPagePath);

        SharedBuildNumber form = new SharedBuildNumber(0);
        form.setFormat("{0}");
        form.setDateFormat("yyyyMMddHHmmss");

        modelAndView.getModel().put(SharedBuildNumberController.FORM, form);

        return modelAndView;
    }

    protected ModelAndView submitAddBuildNumber(HttpServletRequest request) throws IOException {
        SharedBuildNumber form = new SharedBuildNumber(0);
        BindingResult result = new BeanPropertyBindingResult(form, SharedBuildNumberController.FORM);
        this.bindAndValidateForm(request, result);

        if (result.hasErrors()) {
            ModelAndView modelAndView = new ModelAndView(this.addJspPagePath);

            modelAndView.getModel().put(BindingResult.MODEL_KEY_PREFIX + SharedBuildNumberController.FORM, result);
            modelAndView.getModel().put(SharedBuildNumberController.FORM, form);

            return modelAndView;
        }

        SharedBuildNumber buildNumber = new SharedBuildNumber(this.configurationService.getNextBuildNumberId());
        this.copyFormToBuildNumber(form, buildNumber);
        this.configurationService.saveSharedBuildNumber(buildNumber);

        return this.returnRedirectView("/admin/admin.html?item=sharedBuildNumbers");
    }

    protected ModelAndView editBuildNumber(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        Integer id = this.getId(request);
        if (id != null) {
            SharedBuildNumber form = this.configurationService.getSharedBuildNumber(id);
            if (form != null) {
                ModelAndView modelAndView = new ModelAndView(this.editJspPagePath);

                modelAndView.getModel().put(SharedBuildNumberController.PREFIX,
                        BuildNumberPropertiesProvider.PARAMETER_PREFIX);
                modelAndView.getModel().put(SharedBuildNumberController.FORM, form);

                return modelAndView;
            }
        }

        SharedBuildNumberController.logger.info("Edit requested for non-existent shared build number.");
        WebUtil.notFound(request, response, "The shared build number you are trying to edit does not exist.",
                SharedBuildNumberController.logger);
        return null;
    }

    protected ModelAndView submitEditBuildNumber(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        Integer id = this.getId(request);
        if (id != null) {
            SharedBuildNumber buildNumber = this.configurationService.getSharedBuildNumber(id);
            if (buildNumber != null) {
                SharedBuildNumber form = new SharedBuildNumber(id);
                BindingResult result = new BeanPropertyBindingResult(form, SharedBuildNumberController.FORM);
                this.bindAndValidateForm(request, result);

                if (result.hasErrors()) {
                    ModelAndView modelAndView = new ModelAndView(this.editJspPagePath);

                    modelAndView.getModel().put(BindingResult.MODEL_KEY_PREFIX + SharedBuildNumberController.FORM,
                            result);
                    modelAndView.getModel().put(SharedBuildNumberController.PREFIX,
                            BuildNumberPropertiesProvider.PARAMETER_PREFIX);
                    modelAndView.getModel().put(SharedBuildNumberController.FORM, form);

                    return modelAndView;
                }

                this.copyFormToBuildNumber(form, buildNumber);
                this.configurationService.saveSharedBuildNumber(buildNumber);

                return this.returnRedirectView("/admin/admin.html?item=sharedBuildNumbers");
            }
        }

        SharedBuildNumberController.logger.info("Edit requested for non-existent shared build number.");
        WebUtil.notFound(request, response, "The shared build number you are trying to edit does not exist.",
                SharedBuildNumberController.logger);
        return null;
    }

    protected ModelAndView submitDeleteBuildNumber(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        Integer id = this.getId(request);
        if (id != null) {
            this.configurationService.deleteSharedBuildNumber(id);

            return this.returnRedirectView("/admin/admin.html?item=sharedBuildNumbers");
        }

        SharedBuildNumberController.logger.info("Delete requested for non-existent shared build number.");
        WebUtil.notFound(request, response, "The shared build number you are trying to delete does not exist.",
                SharedBuildNumberController.logger);
        return null;
    }

    private void bindAndValidateForm(HttpServletRequest request, BindingResult result) {
        SharedBuildNumber form = (SharedBuildNumber) result.getTarget();

        form.setName(request.getParameter("name"));
        form.setDescription(request.getParameter("description"));
        form.setFormat(request.getParameter("format"));
        form.setDateFormat(request.getParameter("dateFormat"));

        String counterString = request.getParameter("counter");
        if (NumberUtils.isDigits(counterString)) {
            form.setCounter(Integer.parseInt(counterString));
            if (form.getCounter() < 1)
                form.setCounter(1);
        } else {
            result.rejectValue("counter", "counter.not.integer", "The counter must be a positive integer.");
        }

        if (form.getName() == null || form.getName().trim().length() < 5 || form.getName().trim().length() > 60) {
            result.rejectValue("name", "name.length", "The name must be between 5 and 60 characters long.");
        }

        if (form.getFormat() == null || form.getFormat().trim().length() < 3) {
            result.rejectValue("format", "format.length",
                    "The build number format must be at least 3 characters long.");
        } else if (form.getFormat().toLowerCase().contains("{d}")
                && (form.getDateFormat() == null || form.getDateFormat().trim().length() < 3)) {
            result.rejectValue("dateFormat", "dateFormat.length",
                    "The date format must be at least 3 characters long.");
        }
    }

    private void copyFormToBuildNumber(SharedBuildNumber form, SharedBuildNumber buildNumber) {
        buildNumber.setName(form.getName());
        buildNumber.setDescription(form.getDescription());
        buildNumber.setFormat(form.getFormat());
        buildNumber.setDateFormat(form.getDateFormat());
        buildNumber.setCounter(form.getCounter());
    }

    private Integer getId(HttpServletRequest request) {
        String idString = request.getParameter("id");
        if (NumberUtils.isDigits(idString)) {
            return Integer.parseInt(idString);
        }
        return null;
    }

    private ModelAndView returnRedirectView(String url) {
        return new ModelAndView(new RedirectView(url, true));
    }

    private boolean hasAccess(HttpServletRequest request) {
        SUser user = SessionUser.getUser(request);
        return this.hasAccess(user);
    }

    private boolean hasAccess(SUser user) {
        return AuthUtil.isSystemAdmin(user) || AuthUtil.hasPermissionToManageAllProjects(user);
    }

    private class AdminTab extends AdminPage {
        public AdminTab(@NotNull PagePlaces pagePlaces, @NotNull PluginDescriptor pluginDescriptor) {
            super(pagePlaces, SharedBuildNumberController.TAB_ID,
                    pluginDescriptor.getPluginResourcesPath("jsp/adminTab.jsp"), "Shared Build Numbers");
        }

        @Override
        public boolean isAvailable(@NotNull HttpServletRequest request) {
            return super.isAvailable(request) && SharedBuildNumberController.this.hasAccess(request);
        }

        @NotNull
        @Override
        public String getGroup() {
            return "Project-related Settings";
        }
    }
}