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