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