001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 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 org.apache.commons.lang.StringUtils;
023    import org.apache.commons.lang.builder.ToStringBuilder;
024    import org.apache.maven.project.MavenProject;
025    import org.sonar.api.CoreProperties;
026    import org.sonar.api.component.Component;
027    import org.sonar.api.config.Settings;
028    
029    import javax.annotation.Nullable;
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      /**
043       * Internal use
044       */
045      public static final Language NONE_LANGUAGE = new AbstractLanguage("none", "None") {
046        @Override
047        public String[] getFileSuffixes() {
048          return new String[0];
049        }
050      };
051    
052      static final String MAVEN_KEY_FORMAT = "%s:%s";
053      private static final String BRANCH_KEY_FORMAT = "%s:%s";
054    
055      public static final String SCOPE = Scopes.PROJECT;
056    
057      /**
058       * Enumerates the type of possible analysis
059       * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report.
060       */
061      @Deprecated
062      public enum AnalysisType {
063        STATIC, DYNAMIC, REUSE_REPORTS;
064    
065        /**
066         * @param includeReuseReportMode whether to count report reuse as dynamic or not
067         * @return whether this a dynamic analysis
068         */
069        public boolean isDynamic(boolean includeReuseReportMode) {
070          return equals(Project.AnalysisType.DYNAMIC) ||
071            (equals(Project.AnalysisType.REUSE_REPORTS) && includeReuseReportMode);
072        }
073      }
074    
075      private MavenProject pom;
076      private String branch;
077      private ProjectFileSystem fileSystem;
078      private String name;
079      private String description;
080      private String packaging;
081      private Language language;
082      private Date analysisDate;
083      private AnalysisType analysisType;
084      private String analysisVersion;
085      private Settings settings;
086    
087      // modules tree
088      private Project parent;
089      private List<Project> modules = new ArrayList<Project>();
090    
091      public Project(String key) {
092        setKey(key);
093        setDeprecatedKey(key);
094        setEffectiveKey(key);
095      }
096    
097      public Project(String key, String branch, String name) {
098        if (StringUtils.isNotBlank(branch)) {
099          setKey(String.format(BRANCH_KEY_FORMAT, key, branch));
100          this.name = String.format("%s %s", name, branch);
101        } else {
102          setKey(key);
103          this.name = name;
104        }
105        setDeprecatedKey(getKey());
106        setEffectiveKey(getKey());
107        this.branch = branch;
108      }
109    
110      public String getBranch() {
111        return branch;
112      }
113    
114      /**
115       * For internal use only.
116       */
117      public Project setBranch(String branch) {
118        this.branch = branch;
119        return this;
120      }
121    
122      /**
123       * For internal use only.
124       */
125      public final Project setPom(MavenProject pom) {
126        this.pom = pom;
127        return this;
128      }
129    
130      /**
131       * @return the project's packaging
132       * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341
133       */
134      @Deprecated
135      public String getPackaging() {
136        return packaging;
137      }
138    
139      @Override
140      public String getName() {
141        return name;
142      }
143    
144      @Override
145      public String getLongName() {
146        return name;
147      }
148    
149      @Override
150      public String getDescription() {
151        return description;
152      }
153    
154      /**
155       * For internal use only.
156       */
157      public Project setName(String name) {
158        this.name = name;
159        return this;
160      }
161    
162      /**
163       * For internal use only.
164       */
165      public Project setDescription(String description) {
166        this.description = description;
167        return this;
168      }
169    
170      /**
171       * For internal use only.
172       *
173       * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341
174       */
175      @Deprecated
176      public Project setPackaging(String packaging) {
177        this.packaging = packaging;
178        return this;
179      }
180    
181      /**
182       * @return whether the current project is root project
183       */
184      public boolean isRoot() {
185        return getParent() == null;
186      }
187    
188      public Project getRoot() {
189        return parent == null ? this : parent.getRoot();
190      }
191    
192      /**
193       * @return whether the current project is a module
194       */
195      public boolean isModule() {
196        return !isRoot();
197      }
198    
199      /**
200       * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report.
201       */
202      @Deprecated
203      public AnalysisType getAnalysisType() {
204        return analysisType;
205      }
206    
207      /**
208       * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report.
209       */
210      @Deprecated
211      public Project setAnalysisType(AnalysisType at) {
212        this.analysisType = at;
213        return this;
214      }
215    
216      /**
217       * whether it's the latest analysis done on this project (displayed in sonar dashboard) or an analysis on a past revision.
218       *
219       * @since 2.0
220       * @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
221       */
222      @Deprecated
223      public boolean isLatestAnalysis() {
224        return true;
225      }
226    
227      /**
228       * For internal use only.
229       *
230       * @deprecated in 3.6. It's not possible to analyze a project before the latest known quality snapshot.
231       * See http://jira.codehaus.org/browse/SONAR-4334
232       */
233      @Deprecated
234      public Project setLatestAnalysis(boolean b) {
235        if (!b) {
236          throw new UnsupportedOperationException("The analysis is always the latest one. " +
237            "Past analysis must be done in a chronological order.");
238        }
239        return this;
240      }
241    
242      /**
243       * @return the project language when there is only one language
244       * @deprecated since 4.2 use {@link org.sonar.api.batch.fs.FileSystem#languages()}
245       */
246      @Deprecated
247      @Override
248      public Language getLanguage() {
249        return language;
250      }
251    
252      /**
253       * Internal use
254       */
255      public Project setLanguage(Language language) {
256        this.language = language;
257        return this;
258      }
259    
260      /**
261       * @return the language key or empty if no language is specified
262       * @deprecated since 4.2 use {@link org.sonar.api.batch.fs.FileSystem#languages()}
263       */
264      @Deprecated
265      public String getLanguageKey() {
266        if (settings == null) {
267          throw new IllegalStateException("Project is not yet initialized");
268        }
269        return StringUtils.defaultIfEmpty(settings.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY), "");
270      }
271    
272      /**
273       * Internal use
274       */
275      public Project setSettings(Settings settings) {
276        this.settings = settings;
277        return this;
278      }
279    
280      /**
281       * Internal use for backward compatibility. Settings should be retrieved as an IoC dependency.
282       * @deprecated since 5.0
283       */
284      @Deprecated
285      public Settings getSettings() {
286        return settings;
287      }
288    
289      /**
290       * For internal use only.
291       */
292      public Project setAnalysisDate(Date analysisDate) {
293        this.analysisDate = analysisDate;
294        return this;
295      }
296    
297      /**
298       * For internal use only.
299       */
300      public Project setAnalysisVersion(String analysisVersion) {
301        this.analysisVersion = analysisVersion;
302        return this;
303      }
304    
305      /**
306       * @return the scope of the current object
307       */
308      @Override
309      public String getScope() {
310        return Scopes.PROJECT;
311      }
312    
313      /**
314       * @return the qualifier of the current object
315       */
316      @Override
317      public String getQualifier() {
318        return isRoot() ? Qualifiers.PROJECT : Qualifiers.MODULE;
319      }
320    
321      @Override
322      public boolean matchFilePattern(String antPattern) {
323        return false;
324      }
325    
326      @Override
327      public Project getParent() {
328        return parent;
329      }
330    
331      /**
332       * For internal use only.
333       */
334      public Project setParent(Project parent) {
335        this.parent = parent;
336        if (parent != null) {
337          parent.modules.add(this);
338        }
339        return this;
340      }
341    
342      /**
343       * For internal use only.
344       */
345      public void removeFromParent() {
346        if (parent != null) {
347          parent.modules.remove(this);
348        }
349      }
350    
351      /**
352       * @return the list of modules
353       */
354      public List<Project> getModules() {
355        return modules;
356      }
357    
358      /**
359       * @return the current version of the project
360       */
361      public String getAnalysisVersion() {
362        return analysisVersion;
363      }
364    
365      /**
366       * @return the analysis date, i.e. the date that will be used to store the snapshot
367       */
368      public Date getAnalysisDate() {
369        return analysisDate;
370      }
371    
372      /**
373       * Note: it's better to get a reference on ProjectFileSystem as an IoC dependency (constructor parameter)
374       * @deprecated replaced by {@link org.sonar.api.scan.filesystem.ModuleFileSystem} in 3.5
375       */
376      @Deprecated
377      public ProjectFileSystem getFileSystem() {
378        return fileSystem;
379      }
380    
381      /**
382       * For internal use only.
383       *
384       * @deprecated since 2.6. See http://jira.codehaus.org/browse/SONAR-2126
385       */
386      @Deprecated
387      public Project setFileSystem(ProjectFileSystem fs) {
388        this.fileSystem = fs;
389        return this;
390      }
391    
392      /**
393       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
394       */
395      @Deprecated
396      public String getGroupId() {
397        return pom.getGroupId();
398      }
399    
400      /**
401       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011
402       */
403      @Deprecated
404      public String getArtifactId() {
405        return pom.getArtifactId();
406      }
407    
408      /**
409       * @return the underlying Maven project
410       * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 ,
411       *             MavenProject can be retrieved as an IoC dependency
412       */
413      @Deprecated
414      public MavenProject getPom() {
415        return pom;
416      }
417    
418      public static Project createFromMavenIds(String groupId, String artifactId) {
419        return createFromMavenIds(groupId, artifactId, null);
420      }
421    
422      public static Project createFromMavenIds(String groupId, String artifactId, @Nullable String branch) {
423        return new Project(String.format(MAVEN_KEY_FORMAT, groupId, artifactId), branch, "");
424      }
425    
426      @Override
427      public String toString() {
428        return new ToStringBuilder(this)
429          .append("id", getId())
430          .append("key", getKey())
431          .append("qualifier", getQualifier())
432          .toString();
433      }
434    
435      @Override
436      public String key() {
437        return getKey();
438      }
439    
440      @Override
441      public String name() {
442        return getName();
443      }
444    
445      @Override
446      public String path() {
447        return getPath();
448      }
449    
450      @Override
451      public String longName() {
452        return getLongName();
453      }
454    
455      @Override
456      public String qualifier() {
457        return getQualifier();
458      }
459    }