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