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