001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.batch;
021    
022    import com.google.common.collect.Lists;
023    import com.google.common.collect.Maps;
024    import org.apache.commons.lang.ObjectUtils;
025    import org.slf4j.LoggerFactory;
026    import org.sonar.api.batch.bootstrap.ProjectBuilder;
027    import org.sonar.api.batch.bootstrap.ProjectDefinition;
028    import org.sonar.api.batch.bootstrap.ProjectReactor;
029    import org.sonar.api.resources.Project;
030    import org.sonar.batch.bootstrap.ProjectFilter;
031    
032    import java.io.IOException;
033    import java.util.Iterator;
034    import java.util.List;
035    import java.util.Map;
036    
037    public class ProjectTree {
038    
039      private ProjectConfigurator configurator;
040      private ProjectReactor projectReactor;
041    
042      private List<Project> projects;
043      private Map<ProjectDefinition, Project> projectsByDef;
044      private ProjectFilter projectFilter;
045    
046      public ProjectTree(ProjectReactor projectReactor, //NOSONAR the unused parameter 'builders' is used for the startup order of components
047                         ProjectConfigurator projectConfigurator,
048                         ProjectFilter projectFilter,
049                         /* Must be executed after ProjectBuilders */ ProjectBuilder[] builders) {
050        this(projectReactor, projectConfigurator, projectFilter);
051      }
052    
053      public ProjectTree(ProjectReactor projectReactor, //NOSONAR the unused parameter 'builders' is used for the startup order of components
054                         ProjectConfigurator projectConfigurator,
055                         ProjectFilter projectFilter) {
056        this.projectReactor = projectReactor;
057        this.configurator = projectConfigurator;
058        this.projectFilter = projectFilter;
059      }
060    
061      ProjectTree(ProjectConfigurator configurator) {
062        this.configurator = configurator;
063      }
064    
065      public void start() throws IOException {
066        doStart(projectReactor.getProjects());
067      }
068    
069      void doStart(List<ProjectDefinition> definitions) {
070        projects = Lists.newArrayList();
071        projectsByDef = Maps.newHashMap();
072    
073        for (ProjectDefinition def : definitions) {
074          Project project = configurator.create(def);
075          projectsByDef.put(def, project);
076          projects.add(project);
077        }
078    
079        for (Map.Entry<ProjectDefinition, Project> entry : projectsByDef.entrySet()) {
080          ProjectDefinition def = entry.getKey();
081          Project project = entry.getValue();
082          for (ProjectDefinition module : def.getSubProjects()) {
083            projectsByDef.get(module).setParent(project);
084          }
085        }
086    
087        // Configure
088        for (Project project : projects) {
089          configurator.configure(project);
090        }
091    
092        applyExclusions();
093      }
094    
095      void applyExclusions() {
096        for (Iterator<Project> it = projects.iterator(); it.hasNext(); ) {
097          Project project = it.next();
098          if (projectFilter.isExcluded(project)) {
099            project.setExcluded(true);
100            LoggerFactory.getLogger(getClass()).info("Project {} excluded", project.getName());
101            project.removeFromParent();
102            it.remove();
103          }
104        }
105      }
106    
107      public List<Project> getProjects() {
108        return projects;
109      }
110    
111      public Project getRootProject() {
112        for (Project project : projects) {
113          if (project.getParent() == null) {
114            return project;
115          }
116        }
117        throw new IllegalStateException("Can not find the root project from the list of Maven modules");
118      }
119    
120      public ProjectDefinition getProjectDefinition(Project project) {
121        for (Map.Entry<ProjectDefinition, Project> entry : projectsByDef.entrySet()) {
122          if (ObjectUtils.equals(entry.getValue(), project)) {
123            return entry.getKey();
124          }
125        }
126        throw new IllegalStateException("Can not find ProjectDefinition for " + project);
127      }
128    }