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      public static final String SCOPE = Scopes.PROJECT;
043    
044      /**
045       * @deprecated since version 1.11. Constant moved to CoreProperties
046       */
047      @Deprecated
048      public static final String PARAM_REUSE_RULES_CONFIG = CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY;
049    
050      /**
051       * Enumerates the type of possible analysis
052       */
053      public enum AnalysisType {
054        STATIC, DYNAMIC, REUSE_REPORTS;
055    
056        /**
057         * @param includeReuseReportMode whether to count report reuse as dynamic or not
058         * @return whether this a dynamic analysis
059         */
060        public boolean isDynamic(boolean includeReuseReportMode) {
061          return equals(Project.AnalysisType.DYNAMIC) ||
062            (equals(Project.AnalysisType.REUSE_REPORTS) && includeReuseReportMode);
063        }
064      }
065    
066      private MavenProject pom;
067      private String branch;
068      private ProjectFileSystem fileSystem;
069      private Configuration configuration;
070      private String name;
071      private String description;
072      private String packaging;
073      private Language language;
074      private Date analysisDate;
075      private AnalysisType analysisType;
076      private String analysisVersion;
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       * @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
205       */
206      @Deprecated
207      public boolean isLatestAnalysis() {
208        return true;
209      }
210    
211      /**
212       * For internal use only.
213       *
214       * @deprecated in 3.6. It's not possible to analyze a project before the latest known quality snapshot.
215       * See http://jira.codehaus.org/browse/SONAR-4334
216       */
217      @Deprecated
218      public Project setLatestAnalysis(boolean b) {
219        if (!b) {
220          throw new UnsupportedOperationException("The analysis is always the latest one. " +
221            "Past analysis must be done in a chronological order.");
222        }
223        return this;
224      }
225    
226      /**
227       * @return the project language
228       */
229      @Override
230      public Language getLanguage() {
231        return language;
232      }
233    
234      public Project setLanguage(Language language) {
235        this.language = language;
236        return this;
237      }
238    
239      /**
240       * @return the language key
241       */
242      public String getLanguageKey() {
243        return configuration.getString("sonar.language", Java.KEY);
244      }
245    
246      /**
247       * For internal use only.
248       */
249      public Project setAnalysisDate(Date analysisDate) {
250        this.analysisDate = analysisDate;
251        return this;
252      }
253    
254      /**
255       * For internal use only.
256       */
257      public Project setAnalysisVersion(String analysisVersion) {
258        this.analysisVersion = analysisVersion;
259        return this;
260      }
261    
262      /**
263       * @return the scope of the current object
264       */
265      @Override
266      public String getScope() {
267        return Scopes.PROJECT;
268      }
269    
270      /**
271       * @return the qualifier of the current object
272       */
273      @Override
274      public String getQualifier() {
275        return isRoot() ? Qualifiers.PROJECT : Qualifiers.MODULE;
276      }
277    
278      @Override
279      public boolean matchFilePattern(String antPattern) {
280        return false;
281      }
282    
283      @Override
284      public Project getParent() {
285        return parent;
286      }
287    
288      /**
289       * For internal use only.
290       */
291      public Project setParent(Project parent) {
292        this.parent = parent;
293        if (parent != null) {
294          parent.modules.add(this);
295        }
296        return this;
297      }
298    
299      /**
300       * For internal use only.
301       */
302      public void removeFromParent() {
303        if (parent != null) {
304          parent.modules.remove(this);
305        }
306      }
307    
308      /**
309       * @return the list of modules
310       */
311      public List<Project> getModules() {
312        return modules;
313      }
314    
315      /**
316       * @return whether to use external source for rules configuration
317       * @deprecated since 2.5. See discussion from http://jira.codehaus.org/browse/SONAR-1873
318       */
319      @Deprecated
320      public boolean getReuseExistingRulesConfig() {
321        return (configuration != null && configuration.getBoolean(CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY, false));
322      }
323    
324      /**
325       * @return the current version of the project
326       */
327      public String getAnalysisVersion() {
328        return analysisVersion;
329      }
330    
331      /**
332       * @return the analysis date, i.e. the date that will be used to store the snapshot
333       */
334      public Date getAnalysisDate() {
335        return analysisDate;
336      }
337    
338      /**
339       * Patterns of resource exclusion as defined in project settings page.
340       *
341       * @since 3.3 also applies exclusions in general settings page and global exclusions.
342       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
343       */
344      @Deprecated
345      public String[] getExclusionPatterns() {
346        return trimExclusions(ImmutableList.<String> builder()
347          .add(configuration.getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY))
348          .add(configuration.getStringArray(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY)).build());
349      }
350    
351      /**
352       * Patterns of test exclusion as defined in project settings page.
353       * Also applies exclusions in general settings page and global exclusions.
354       *
355       * @since 3.3
356       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
357       */
358      @Deprecated
359      public String[] getTestExclusionPatterns() {
360        String[] globalTestExclusions = configuration.getStringArray(CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY);
361        if (globalTestExclusions.length == 0) {
362          globalTestExclusions = new String[] {CoreProperties.GLOBAL_TEST_EXCLUSIONS_DEFAULT};
363        }
364    
365        return trimExclusions(ImmutableList.<String> builder()
366            .add(configuration.getStringArray(CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY))
367            .add(globalTestExclusions).build());
368      }
369    
370      // http://jira.codehaus.org/browse/SONAR-2261 - exclusion must be trimmed
371      private static String[] trimExclusions(List<String> exclusions) {
372        List<String> trimmed = Lists.newArrayList();
373        for (String exclusion : exclusions) {
374          trimmed.add(StringUtils.trim(exclusion));
375        }
376        return trimmed.toArray(new String[trimmed.size()]);
377      }
378    
379      /**
380       * Set exclusion patterns. Configuration is not saved, so this method must be used ONLY IN UNIT TESTS.
381       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5
382       */
383      @Deprecated
384      public Project setExclusionPatterns(String[] s) {
385        throw new UnsupportedOperationException("deprecated in 3.5");
386      }
387    
388      /**
389       * Note: it's better to get a reference on ProjectFileSystem as an IoC dependency (constructor parameter)
390       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.ModuleFileSystem} in 3.5
391       */
392      @Deprecated
393      public ProjectFileSystem getFileSystem() {
394        return fileSystem;
395      }
396    
397      /**
398       * For internal use only.
399       * 
400       * @deprecated since 2.6. See http://jira.codehaus.org/browse/SONAR-2126
401       */
402      @Deprecated
403      public Project setFileSystem(ProjectFileSystem fs) {
404        this.fileSystem = fs;
405        return this;
406      }
407    
408      /**
409       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
410       */
411      @Deprecated
412      public String getGroupId() {
413        return pom.getGroupId();
414      }
415    
416      /**
417       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
418       */
419      @Deprecated
420      public String getArtifactId() {
421        return pom.getArtifactId();
422      }
423    
424      /**
425       * @return the underlying Maven project
426       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 ,
427       *             MavenProject can be retrieved as an IoC dependency
428       */
429      @Deprecated
430      public MavenProject getPom() {
431        return pom;
432      }
433    
434      /**
435       * @return the project configuration
436       * @deprecated since 2.12. The component org.sonar.api.config.Settings must be used.
437       */
438      @Deprecated
439      public Configuration getConfiguration() {
440        return configuration;
441      }
442    
443      /**
444       * For internal use only.
445       */
446      public final Project setConfiguration(Configuration configuration) {
447        this.configuration = configuration;
448        return this;
449      }
450    
451      /**
452       * @deprecated since 3.6. Replaced by {@link org.sonar.api.config.Settings}.
453       */
454      @Deprecated
455      public Object getProperty(String key) {
456        return configuration != null ? configuration.getProperty(key) : null;
457      }
458    
459      public static Project createFromMavenIds(String groupId, String artifactId) {
460        return new Project(String.format("%s:%s", groupId, artifactId));
461      }
462    
463      @Override
464      public String toString() {
465        return new ToStringBuilder(this)
466            .append("id", getId())
467            .append("key", getKey())
468            .append("qualifier", getQualifier())
469            .toString();
470      }
471    
472      @Override
473      public String key() {
474        return getKey();
475      }
476    
477      @Override
478      public String name() {
479        return getName();
480      }
481    
482      @Override
483      public String longName() {
484        return getLongName();
485      }
486    
487      @Override
488      public String qualifier() {
489        return getQualifier();
490      }
491    }