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