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 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}