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