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 */ 020package org.sonar.api.resources; 021 022import com.google.common.collect.ImmutableList; 023import com.google.common.collect.Lists; 024import org.apache.commons.configuration.Configuration; 025import org.apache.commons.lang.StringUtils; 026import org.apache.commons.lang.builder.ToStringBuilder; 027import org.apache.maven.project.MavenProject; 028import org.sonar.api.CoreProperties; 029import org.sonar.api.component.Component; 030 031import java.util.ArrayList; 032import java.util.Date; 033import java.util.List; 034 035/** 036 * A class that manipulates Projects in the Sonar way. 037 * 038 * @since 1.10 039 */ 040public 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}