001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2013 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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 License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.api.resources;
021    
022    import com.google.common.collect.ImmutableList;
023    import com.google.common.collect.Lists;
024    import org.apache.commons.configuration.Configuration;
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.commons.lang.builder.ToStringBuilder;
027    import org.apache.maven.project.MavenProject;
028    import org.sonar.api.CoreProperties;
029    import org.sonar.api.component.Component;
030    
031    import java.util.ArrayList;
032    import java.util.Date;
033    import java.util.List;
034    
035    /**
036     * A class that manipulates Projects in the Sonar way.
037     *
038     * @since 1.10
039     */
040    public class Project extends Resource implements Component {
041    
042      private static final String MAVEN_KEY_FORMAT = "%s:%s";
043      private static final String BRANCH_KEY_FORMAT = "%s:%s";
044    
045      public static final String SCOPE = Scopes.PROJECT;
046    
047      /**
048       * @deprecated since version 1.11. Constant moved to CoreProperties
049       */
050      @Deprecated
051      public static final String PARAM_REUSE_RULES_CONFIG = CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY;
052    
053      /**
054       * Enumerates the type of possible analysis
055       */
056      public enum AnalysisType {
057        STATIC, DYNAMIC, REUSE_REPORTS;
058    
059        /**
060         * @param includeReuseReportMode whether to count report reuse as dynamic or not
061         * @return whether this a dynamic analysis
062         */
063        public boolean isDynamic(boolean includeReuseReportMode) {
064          return equals(Project.AnalysisType.DYNAMIC) ||
065            (equals(Project.AnalysisType.REUSE_REPORTS) && includeReuseReportMode);
066        }
067      }
068    
069      private MavenProject pom;
070      private String branch;
071      private ProjectFileSystem fileSystem;
072      private Configuration configuration;
073      private String name;
074      private String description;
075      private String packaging;
076      private Language language;
077      private Date analysisDate;
078      private AnalysisType analysisType;
079      private String analysisVersion;
080    
081      // modules tree
082      private Project parent;
083      private List<Project> modules = new ArrayList<Project>();
084    
085      public Project(String key) {
086        setKey(key);
087        setEffectiveKey(key);
088      }
089    
090      public Project(String key, String branch, String name) {
091        if (StringUtils.isNotBlank(branch)) {
092          setKey(String.format(BRANCH_KEY_FORMAT, key, branch));
093          this.name = String.format("%s %s", name, branch);
094        } else {
095          setKey(key);
096          this.name = name;
097        }
098        setEffectiveKey(getKey());
099        this.branch = branch;
100      }
101    
102      public String getBranch() {
103        return branch;
104      }
105    
106      /**
107       * For internal use only.
108       */
109      public Project setBranch(String branch) {
110        this.branch = branch;
111        return this;
112      }
113    
114      /**
115       * For internal use only.
116       */
117      public final Project setPom(MavenProject pom) {
118        this.pom = pom;
119        return this;
120      }
121    
122      /**
123       * @return the project's packaging
124       * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341
125       */
126      @Deprecated
127      public String getPackaging() {
128        return packaging;
129      }
130    
131      @Override
132      public String getName() {
133        return name;
134      }
135    
136      @Override
137      public String getLongName() {
138        return name;
139      }
140    
141      @Override
142      public String getDescription() {
143        return description;
144      }
145    
146      /**
147       * For internal use only.
148       */
149      public Project setName(String name) {
150        this.name = name;
151        return this;
152      }
153    
154      /**
155       * For internal use only.
156       */
157      public Project setDescription(String description) {
158        this.description = description;
159        return this;
160      }
161    
162      /**
163       * For internal use only.
164       *
165       * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341
166       */
167      @Deprecated
168      public Project setPackaging(String packaging) {
169        this.packaging = packaging;
170        return this;
171      }
172    
173      /**
174       * @return whether the current project is root project
175       */
176      public boolean isRoot() {
177        return getParent() == null;
178      }
179    
180      public Project getRoot() {
181        return parent==null ? this : parent.getRoot();
182      }
183    
184      /**
185       * @return whether the current project is a module
186       */
187      public boolean isModule() {
188        return !isRoot();
189      }
190    
191      /**
192       * @return the type of analysis of the project
193       */
194      public AnalysisType getAnalysisType() {
195        return analysisType;
196      }
197    
198      public Project setAnalysisType(AnalysisType at) {
199        this.analysisType = at;
200        return this;
201      }
202    
203      /**
204       * whether it's the latest analysis done on this project (displayed in sonar dashboard) or an analysis on a past revision.
205       *
206       * @since 2.0
207       * @deprecated in 3.6. The analysis is now always the latest one (past analysis must be done in a chronological order). See http://jira.codehaus.org/browse/SONAR-4334
208       */
209      @Deprecated
210      public boolean isLatestAnalysis() {
211        return true;
212      }
213    
214      /**
215       * For internal use only.
216       *
217       * @deprecated in 3.6. It's not possible to analyze a project before the latest known quality snapshot.
218       * See http://jira.codehaus.org/browse/SONAR-4334
219       */
220      @Deprecated
221      public Project setLatestAnalysis(boolean b) {
222        if (!b) {
223          throw new UnsupportedOperationException("The analysis is always the latest one. " +
224            "Past analysis must be done in a chronological order.");
225        }
226        return this;
227      }
228    
229      /**
230       * @return the project language
231       */
232      @Override
233      public Language getLanguage() {
234        return language;
235      }
236    
237      public Project setLanguage(Language language) {
238        this.language = language;
239        return this;
240      }
241    
242      /**
243       * @return the language key
244       */
245      public String getLanguageKey() {
246        return configuration.getString("sonar.language", Java.KEY);
247      }
248    
249      /**
250       * For internal use only.
251       */
252      public Project setAnalysisDate(Date analysisDate) {
253        this.analysisDate = analysisDate;
254        return this;
255      }
256    
257      /**
258       * For internal use only.
259       */
260      public Project setAnalysisVersion(String analysisVersion) {
261        this.analysisVersion = analysisVersion;
262        return this;
263      }
264    
265      /**
266       * @return the scope of the current object
267       */
268      @Override
269      public String getScope() {
270        return Scopes.PROJECT;
271      }
272    
273      /**
274       * @return the qualifier of the current object
275       */
276      @Override
277      public String getQualifier() {
278        return isRoot() ? Qualifiers.PROJECT : Qualifiers.MODULE;
279      }
280    
281      @Override
282      public boolean matchFilePattern(String antPattern) {
283        return false;
284      }
285    
286      @Override
287      public Project getParent() {
288        return parent;
289      }
290    
291      /**
292       * For internal use only.
293       */
294      public Project setParent(Project parent) {
295        this.parent = parent;
296        if (parent != null) {
297          parent.modules.add(this);
298        }
299        return this;
300      }
301    
302      /**
303       * For internal use only.
304       */
305      public void removeFromParent() {
306        if (parent != null) {
307          parent.modules.remove(this);
308        }
309      }
310    
311      /**
312       * @return the list of modules
313       */
314      public List<Project> getModules() {
315        return modules;
316      }
317    
318      /**
319       * @return whether to use external source for rules configuration
320       * @deprecated since 2.5. See discussion from http://jira.codehaus.org/browse/SONAR-1873
321       */
322      @Deprecated
323      public boolean getReuseExistingRulesConfig() {
324        return configuration!=null && configuration.getBoolean(CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY, false);
325      }
326    
327      /**
328       * @return the current version of the project
329       */
330      public String getAnalysisVersion() {
331        return analysisVersion;
332      }
333    
334      /**
335       * @return the analysis date, i.e. the date that will be used to store the snapshot
336       */
337      public Date getAnalysisDate() {
338        return analysisDate;
339      }
340    
341      /**
342       * Patterns of resource exclusion as defined in project settings page.
343       *
344       * @since 3.3 also applies exclusions in general settings page and global exclusions.
345       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
346       */
347      @Deprecated
348      public String[] getExclusionPatterns() {
349        return trimExclusions(ImmutableList.<String> builder()
350          .add(configuration.getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY))
351          .add(configuration.getStringArray(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY)).build());
352      }
353    
354      /**
355       * Patterns of test exclusion as defined in project settings page.
356       * Also applies exclusions in general settings page and global exclusions.
357       *
358       * @since 3.3
359       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
360       */
361      @Deprecated
362      public String[] getTestExclusionPatterns() {
363        String[] globalTestExclusions = configuration.getStringArray(CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY);
364        if (globalTestExclusions.length == 0) {
365          globalTestExclusions = new String[] {CoreProperties.GLOBAL_TEST_EXCLUSIONS_DEFAULT};
366        }
367    
368        return trimExclusions(ImmutableList.<String> builder()
369            .add(configuration.getStringArray(CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY))
370            .add(globalTestExclusions).build());
371      }
372    
373      // http://jira.codehaus.org/browse/SONAR-2261 - exclusion must be trimmed
374      private static String[] trimExclusions(List<String> exclusions) {
375        List<String> trimmed = Lists.newArrayList();
376        for (String exclusion : exclusions) {
377          trimmed.add(StringUtils.trim(exclusion));
378        }
379        return trimmed.toArray(new String[trimmed.size()]);
380      }
381    
382      /**
383       * Set exclusion patterns. Configuration is not saved, so this method must be used ONLY IN UNIT TESTS.
384       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
385       */
386      @Deprecated
387      public Project setExclusionPatterns(String[] s) {
388        throw new UnsupportedOperationException("deprecated in 3.5");
389      }
390    
391      /**
392       * Note: it's better to get a reference on ProjectFileSystem as an IoC dependency (constructor parameter)
393       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.ModuleFileSystem} in 3.5
394       */
395      @Deprecated
396      public ProjectFileSystem getFileSystem() {
397        return fileSystem;
398      }
399    
400      /**
401       * For internal use only.
402       *
403       * @deprecated since 2.6. See http://jira.codehaus.org/browse/SONAR-2126
404       */
405      @Deprecated
406      public Project setFileSystem(ProjectFileSystem fs) {
407        this.fileSystem = fs;
408        return this;
409      }
410    
411      /**
412       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
413       */
414      @Deprecated
415      public String getGroupId() {
416        return pom.getGroupId();
417      }
418    
419      /**
420       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
421       */
422      @Deprecated
423      public String getArtifactId() {
424        return pom.getArtifactId();
425      }
426    
427      /**
428       * @return the underlying Maven project
429       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 ,
430       *             MavenProject can be retrieved as an IoC dependency
431       */
432      @Deprecated
433      public MavenProject getPom() {
434        return pom;
435      }
436    
437      /**
438       * @return the project configuration
439       * @deprecated since 2.12. The component org.sonar.api.config.Settings must be used.
440       */
441      @Deprecated
442      public Configuration getConfiguration() {
443        return configuration;
444      }
445    
446      /**
447       * For internal use only.
448       */
449      public final Project setConfiguration(Configuration configuration) {
450        this.configuration = configuration;
451        return this;
452      }
453    
454      /**
455       * @deprecated since 3.6. Replaced by {@link org.sonar.api.config.Settings}.
456       */
457      @Deprecated
458      public Object getProperty(String key) {
459        return configuration != null ? configuration.getProperty(key) : null;
460      }
461    
462      public static Project createFromMavenIds(String groupId, String artifactId) {
463        return new Project(String.format(MAVEN_KEY_FORMAT, groupId, artifactId));
464      }
465    
466      @Override
467      public String toString() {
468        return new ToStringBuilder(this)
469            .append("id", getId())
470            .append("key", getKey())
471            .append("qualifier", getQualifier())
472            .toString();
473      }
474    
475      @Override
476      public String key() {
477        return getKey();
478      }
479    
480      @Override
481      public String name() {
482        return getName();
483      }
484    
485      @Override
486      public String longName() {
487        return getLongName();
488      }
489    
490      @Override
491      public String qualifier() {
492        return getQualifier();
493      }
494    }