net.sourceforge.vulcan.web.struts.actions.ManualBuildAction.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.vulcan.web.struts.actions.ManualBuildAction.java

Source

/*
 * Vulcan Build Manager
 * Copyright (C) 2005-2012 Chris Eldredge
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package net.sourceforge.vulcan.web.struts.actions;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sourceforge.vulcan.ProjectManager;
import net.sourceforge.vulcan.RepositoryAdaptor;
import net.sourceforge.vulcan.StateManager;
import net.sourceforge.vulcan.core.BuildDetailCallback;
import net.sourceforge.vulcan.core.BuildManager;
import net.sourceforge.vulcan.core.DependencyBuildPolicy;
import net.sourceforge.vulcan.core.DependencyGroup;
import net.sourceforge.vulcan.dto.MetricDto;
import net.sourceforge.vulcan.dto.ProjectConfigDto;
import net.sourceforge.vulcan.dto.ProjectStatusDto;
import net.sourceforge.vulcan.dto.RepositoryTagDto;
import net.sourceforge.vulcan.exception.ConfigException;
import net.sourceforge.vulcan.exception.NoSuchProjectException;
import net.sourceforge.vulcan.exception.ProjectsLockedException;
import net.sourceforge.vulcan.scheduler.BuildDaemon;
import net.sourceforge.vulcan.web.struts.forms.ManualBuildForm;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

public final class ManualBuildAction extends Action {
    private BuildManager buildManager;
    private ProjectManager projectManager;
    private StateManager stateManager;

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        final String requestedBy;

        requestedBy = getRequestUsernameOrHostname(request);

        final ManualBuildForm buildForm = (ManualBuildForm) form;

        final String[] selectedTags = buildForm.getSelectedTags();

        final boolean chooseTags = buildForm.isChooseTags();
        if (chooseTags && selectedTags != null) {
            buildForm.applyTagNamesOnTargets();
            final DependencyGroup dg = buildForm.getDependencyGroup();
            dg.setName(requestedBy);
            buildManager.add(dg);
            //TODO: wake up build daemon(s) here too
            return mapping.findForward("dashboard");
        }

        final List<ProjectConfigDto> projects = new ArrayList<ProjectConfigDto>();

        for (String target : buildForm.getTargets()) {
            try {
                projects.add(projectManager.getProjectConfig(target));
            } catch (NoSuchProjectException e) {
                BaseDispatchAction.saveError(request, "targets",
                        new ActionMessage("errors.no.such.project", new String[] { target }));
                return mapping.getInputForward();
            }
        }

        final DependencyBuildPolicy policy = DependencyBuildPolicy.valueOf(buildForm.getDependencies());

        boolean buildOnNoUpdates = buildForm.isBuildOnNoUpdates();

        if (chooseTags) {
            buildOnNoUpdates = true;
        }

        final DependencyGroup dg;

        try {
            dg = projectManager.buildDependencyGroup(projects.toArray(new ProjectConfigDto[projects.size()]),
                    policy, buildForm.getWorkingCopyUpdateStrategy(), buildForm.isBuildOnDependencyFailure(),
                    buildOnNoUpdates);
        } catch (ProjectsLockedException e) {
            BaseDispatchAction.saveError(request, ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage("errors.projects.locked", StringUtils.join(e.getLockedProjectNames(), ", ")));
            return mapping.getInputForward();
        }

        if (dg.isEmpty()) {
            BaseDispatchAction.saveError(request, ActionMessages.GLOBAL_MESSAGE,
                    new ActionMessage("errors.projects.up.to.date"));
            return mapping.getInputForward();
        }

        dg.setName(requestedBy);
        dg.setManualBuild(true);

        if (chooseTags) {
            fetchAvailableTags(buildForm, request, dg);
            return mapping.findForward("chooseTags");
        }

        buildManager.add(dg);

        wakeUpBuildDaemons(projects.size());

        return mapping.findForward("dashboard");
    }

    public BuildManager getBuildManager() {
        return buildManager;
    }

    public void setBuildManager(BuildManager buildManager) {
        this.buildManager = buildManager;
    }

    public ProjectManager getProjectManager() {
        return projectManager;
    }

    public void setProjectManager(ProjectManager projectManager) {
        this.projectManager = projectManager;
    }

    public StateManager getStateManager() {
        return stateManager;
    }

    public void setStateManager(StateManager stateManager) {
        this.stateManager = stateManager;
    }

    static String getRequestUsernameOrHostname(HttpServletRequest request) {
        final Principal userPrincipal = request.getUserPrincipal();

        if (userPrincipal != null) {
            return userPrincipal.getName();
        }

        return request.getRemoteHost();
    }

    // Wake up an idle build daemon if one is found in order to show that
    // the project is building when the user is brought back to the dashboard.
    private void wakeUpBuildDaemons(int numProjects) {
        final List<BuildDaemon> buildDaemons = stateManager.getBuildDaemons();
        int count = 0;

        for (BuildDaemon bd : buildDaemons) {
            if (bd.isRunning() && !bd.isBuilding()) {
                bd.wakeUp();

                // sleep to allow buildDaemon a chance to fetch the target
                // before client is shown the dashboard.
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ignore) {
                    // propagate interrupt that is not intended for us.
                    Thread.currentThread().interrupt();
                }
                if (++count == numProjects) {
                    return;
                }
            }
        }
    }

    private void fetchAvailableTags(ManualBuildForm buildForm, HttpServletRequest request, DependencyGroup dg) {
        final List<ProjectConfigDto> targets = dg.getPendingProjects();

        final List<String> projectNames = new ArrayList<String>();
        final List<List<RepositoryTagDto>> tags = new ArrayList<List<RepositoryTagDto>>();
        final List<String> selectedTags = new ArrayList<String>();
        final List<String> workDirOverrides = new ArrayList<String>();

        for (ProjectConfigDto target : targets) {
            final String projectName = target.getName();
            projectNames.add(projectName);

            List<RepositoryTagDto> projectTags = null;

            try {
                final RepositoryAdaptor repository = projectManager.getRepositoryAdaptor(target);

                try {
                    repository.prepareRepository(new NoOpBuildDetailCallback());
                } catch (InterruptedException e) {
                    throw new ConfigException("errors.interrupted", null, e);
                }

                projectTags = repository.getAvailableTagsAndBranches();
            } catch (ConfigException e) {
                BaseDispatchAction.saveError(request, target.getName(), new ActionMessage(e.getKey(), e.getArgs()));

                projectTags = Collections.emptyList();
            }

            setPreviouslySelectedTag(selectedTags, projectName, projectTags);

            tags.add(projectTags);
            workDirOverrides.add(target.getWorkDir());
        }

        buildForm.populateTagChoices(projectNames, tags, workDirOverrides, dg);
        buildForm.setSelectedTags(selectedTags.toArray(new String[selectedTags.size()]));
    }

    private void setPreviouslySelectedTag(List<String> selectedTags, String projectName,
            List<RepositoryTagDto> projectTags) {
        final ProjectStatusDto latestStatus = buildManager.getLatestStatus(projectName);

        if (latestStatus != null) {
            final String previousTagName = latestStatus.getTagName();

            for (RepositoryTagDto tag : projectTags) {
                if (tag.getName().equals(previousTagName)) {
                    selectedTags.add(previousTagName);
                    return;
                }
            }
        }

        String tagName = "";

        if (projectTags.size() > 0) {
            tagName = projectTags.get(projectTags.size() - 1).getName();
        }

        selectedTags.add(tagName);
    }

    class NoOpBuildDetailCallback implements BuildDetailCallback {
        public void addMetric(MetricDto metric) {
        }

        public void reportError(String message, String file, Integer lineNumber, String code) {
        }

        public void reportWarning(String message, String file, Integer lineNumber, String code) {
        }

        public void setDetail(String detail) {
        }

        public void setDetailMessage(String messageKey, Object[] args) {
        }

        public void setPhaseMessageKey(String messageKey) {
        }
    }
}