001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2009 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar 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 * Sonar 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 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.api.resources; 021 022 import org.apache.commons.configuration.Configuration; 023 import org.apache.commons.configuration.MapConfiguration; 024 import org.apache.commons.lang.StringUtils; 025 import org.apache.commons.lang.time.DateUtils; 026 import org.apache.maven.project.MavenProject; 027 import org.sonar.api.CoreProperties; 028 import org.sonar.api.database.model.Snapshot; 029 import org.sonar.api.utils.SonarException; 030 031 import java.text.DateFormat; 032 import java.text.ParseException; 033 import java.text.SimpleDateFormat; 034 import java.util.ArrayList; 035 import java.util.Date; 036 import java.util.List; 037 038 /** 039 * A class that manipulates Projects in the Sonar way, i.e. mixing MavenProjects with the way it should be analyzed 040 * 041 * @since 1.10 042 */ 043 public class Project implements Resource { 044 045 /** 046 * @deprecated since version 1.11. Constant moved to CoreProperties 047 */ 048 @Deprecated 049 public static final String PARAM_DEPRECATED_BRANCH = "branch"; 050 051 /** 052 * @deprecated since version 1.11. Constant moved to CoreProperties 053 */ 054 @Deprecated 055 public static final String PARAM_BRANCH = "sonar.branch"; 056 057 /** 058 * @deprecated since version 1.11. Constant moved to CoreProperties 059 */ 060 @Deprecated 061 public static final String PARAM_VERSION = "sonar.projectVersion"; 062 063 /** 064 * @deprecated since version 1.11. Constant moved to CoreProperties 065 */ 066 @Deprecated 067 public static final String PARAM_DATE = "sonar.projectDate"; 068 069 /** 070 * @deprecated since version 1.11. Constant moved to CoreProperties 071 */ 072 @Deprecated 073 public static final String PARAM_LANGUAGE = "sonar.language"; 074 075 /** 076 * @deprecated since version 1.11. Constant moved to CoreProperties 077 */ 078 @Deprecated 079 public static final String PARAM_DYNAMIC_ANALYSIS = "sonar.dynamicAnalysis"; 080 081 /** 082 * @deprecated since version 1.11. Constant moved to CoreProperties 083 */ 084 @Deprecated 085 public static final String PARAM_EXCLUSIONS = "sonar.exclusions"; 086 087 /** 088 * @deprecated since version 1.11. Constant moved to CoreProperties 089 */ 090 @Deprecated 091 public static final String PARAM_REUSE_RULES_CONFIG = "sonar.reuseExistingRulesConfiguration"; 092 093 /** 094 * Enumerates the type of possible analysis 095 */ 096 public enum AnalysisType { 097 STATIC, DYNAMIC, REUSE_REPORTS; 098 099 /** 100 * @param includeReuseReportMode whether to count report reuse as dynamic or not 101 * @return whether this a dynamic analysis 102 */ 103 public boolean isDynamic(boolean includeReuseReportMode) { 104 return equals(Project.AnalysisType.DYNAMIC) || 105 (equals(Project.AnalysisType.REUSE_REPORTS) && includeReuseReportMode); 106 } 107 } 108 109 private MavenProject mavenProject; 110 private DefaultProjectFileSystem fileSystem; 111 private Configuration configuration; 112 private String key; 113 private String name; 114 private String packaging; 115 private String description; 116 private boolean isNew =true; 117 118 // modules tree 119 private Project root; 120 private Project parent; 121 private List<Project> modules = new ArrayList<Project>(); 122 123 // internal use 124 private Snapshot snapshot; 125 private Integer id; 126 private Languages languages; 127 128 129 /** 130 * Creates a Project from a MavenProject (pom) 131 */ 132 public Project(MavenProject mavenProject) { 133 this(mavenProject, new MapConfiguration(mavenProject.getProperties())); 134 } 135 136 /** 137 * Creates a project from MavenProject and a configuration 138 */ 139 public Project(MavenProject pom, Configuration configuration) { 140 this.mavenProject = pom; 141 this.fileSystem = new DefaultProjectFileSystem(this); 142 this.configuration = configuration; 143 144 String branch = getBranch(configuration); 145 this.key = getMavenKey(pom, branch); 146 this.name = getMavenName(pom, branch); 147 this.packaging = pom.getPackaging(); 148 this.description = pom.getDescription(); 149 } 150 151 /** 152 * Creates a Project from key, name, packaging and configuration 153 */ 154 public Project(String key, String name, String packaging, Configuration conf) { 155 this.key = key; 156 this.name = name; 157 this.packaging = packaging; 158 this.configuration = conf; 159 } 160 161 /** 162 * A project is considered as new if it's the first analysis ever done. 163 * 164 * @since 1.12 165 */ 166 public boolean isNew() { 167 return isNew; 168 } 169 170 public Project setIsNew(boolean b) { 171 this.isNew =b; 172 return this; 173 } 174 175 176 private static String getMavenKey(MavenProject pom, String branch) { 177 StringBuilder sb = new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()); 178 if (StringUtils.isNotBlank(branch)) { 179 sb.append(":").append(branch); 180 } 181 return sb.toString(); 182 } 183 184 private static String getMavenName(MavenProject pom, String branch) { 185 StringBuilder sb = new StringBuilder().append(pom.getName()); 186 if (StringUtils.isNotBlank(branch)) { 187 sb.append(" ").append(branch); 188 } 189 return sb.toString(); 190 } 191 192 private static String getBranch(Configuration configuration) { 193 if (configuration != null) { 194 return configuration.getString(CoreProperties.PROJECT_BRANCH_PROPERTY, configuration.getString(PARAM_DEPRECATED_BRANCH)); 195 } 196 return null; 197 } 198 199 /** 200 * Internal use 201 */ 202 public Snapshot getSnapshot() { 203 return snapshot; 204 } 205 206 /** 207 * Internal use 208 */ 209 public Integer getId() { 210 return id; 211 } 212 213 /** 214 * Internal use 215 */ 216 public Project setDatabaseSettings(Integer projectId, Snapshot snapshot) { 217 this.snapshot = snapshot; 218 this.id = projectId; 219 return this; 220 } 221 222 /** 223 * Sets the project languaage 224 * 225 * @return the current object 226 */ 227 public Project setLanguages(Languages languages) { 228 this.languages = languages; 229 return this; 230 } 231 232 /** 233 * @return the project's root project 234 */ 235 public Project getRoot() { 236 return root; 237 } 238 239 /** 240 * @return the project's packaging 241 */ 242 public String getPackaging() { 243 return packaging; 244 } 245 246 /** 247 * @return whether the current project is root project 248 */ 249 public boolean isRoot() { 250 return mavenProject.isExecutionRoot(); 251 } 252 253 /** 254 * @return whether the current project is a module 255 */ 256 public boolean isModule() { 257 return !isRoot(); 258 } 259 260 /** 261 * @return the type of analysis of the project 262 */ 263 public AnalysisType getAnalysisType() { 264 String value = getConfiguration().getString(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY); 265 if (value == null) { 266 return (isSonarLightMode() ? AnalysisType.STATIC : AnalysisType.DYNAMIC); 267 } 268 if ("true".equals(value)) { 269 return AnalysisType.DYNAMIC; 270 } 271 if ("reuseReports".equals(value)) { 272 return AnalysisType.REUSE_REPORTS; 273 } 274 return AnalysisType.STATIC; 275 } 276 277 278 /** 279 * @deprecated since 1.12. Avoid coupling with Maven concepts. 280 */ 281 @Deprecated 282 public String getGroupId() { 283 return mavenProject.getGroupId(); 284 } 285 286 /** 287 * @deprecated since 1.12. Avoid coupling with Maven concepts. 288 */ 289 @Deprecated 290 public String getArtifactId() { 291 return mavenProject.getArtifactId(); 292 } 293 294 /** 295 * @return project's name 296 */ 297 public String getName() { 298 return name; 299 } 300 301 /** 302 * @return project's long name 303 */ 304 public String getLongName() { 305 return null; 306 } 307 308 /** 309 * @return project's description 310 */ 311 public String getDescription() { 312 return description; 313 } 314 315 /** 316 * @return the project language 317 */ 318 public Language getLanguage() { 319 String key = getLanguageKey(); 320 if (languages != null) { 321 return languages.get(key); 322 } 323 if (Java.KEY.equals(key)) { 324 return Java.INSTANCE; 325 } 326 return null; 327 } 328 329 /** 330 * @return the language key 331 */ 332 public String getLanguageKey() { 333 String key = configuration.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY); 334 return StringUtils.isBlank(key) ? Java.KEY : key; 335 } 336 337 /** 338 * @return the scope of the current object 339 */ 340 public String getScope() { 341 return SCOPE_SET; 342 } 343 344 /** 345 * @return the qualifier of the current object 346 */ 347 public String getQualifier() { 348 return isRoot() ? QUALIFIER_PROJECT : QUALIFIER_MODULE; 349 } 350 351 public boolean matchFilePattern(String antPattern) { 352 return false; 353 } 354 355 /** 356 * @return the current object's parent 357 */ 358 public Project getParent() { 359 return parent; 360 } 361 362 /** 363 * Sets a parent to the current object 364 */ 365 public void setParent(Project parent) { 366 this.parent = parent; 367 if (parent != null) { 368 parent.modules.add(this); 369 if (parent.isRoot()) { 370 this.root = parent; 371 } else { 372 this.root = parent.getRoot(); 373 } 374 } 375 } 376 377 /** 378 * @return the list of modules 379 */ 380 public List<Project> getModules() { 381 return modules; 382 } 383 384 /** 385 * @return whether to use external source for rules configuration 386 */ 387 public boolean getReuseExistingRulesConfig() { 388 return configuration.getBoolean(CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY, false); 389 } 390 391 /** 392 * @return the current version of the project 393 */ 394 public String getAnalysisVersion() { 395 String version = configuration.getString(CoreProperties.PROJECT_VERSION_PROPERTY); 396 if (version == null) { 397 version = mavenProject.getVersion(); 398 } 399 return version; 400 } 401 402 /** 403 * @return the analysis date, i.e. the date that will be used to store the snapshot 404 */ 405 public Date getAnalysisDate() { 406 String formattedDate = configuration.getString(CoreProperties.PROJECT_DATE_PROPERTY); 407 if (formattedDate == null) { 408 return new Date(); 409 } 410 411 DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 412 try { 413 // see SONAR-908 make sure that a time is defined for the date. 414 Date date = DateUtils.setHours(format.parse(formattedDate), 0); 415 return DateUtils.setMinutes(date, 1); 416 417 } catch (ParseException e) { 418 throw new SonarException("The property " + PARAM_DATE + " does not respect the format yyyy-MM-dd (for example 2008-05-23) : " + formattedDate, e); 419 } 420 } 421 422 /** 423 * Project key is "groupId:artifactId[:branch]". Examples : org.struts:struts-core and org.codehaus.sonar:sonar:1.10 424 */ 425 public String getKey() { 426 return key; 427 } 428 429 /** 430 * Patterns of resource exclusion as defined in project settings page. 431 */ 432 public String[] getExclusionPatterns() { 433 String[] exclusions = getConfiguration().getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY); 434 if (exclusions == null) { 435 return new String[0]; 436 } 437 return exclusions; 438 } 439 440 /** 441 * Set exclusion patterns. Configuration is not saved, so this method must be used ONLY IN UNIT TESTS. 442 */ 443 public void setExclusionPatterns(String[] patterns) { 444 getConfiguration().setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, patterns); 445 } 446 447 public ProjectFileSystem getFileSystem() { 448 return fileSystem; 449 } 450 451 /** 452 * @return the underlying maven project 453 */ 454 public MavenProject getPom() { 455 return mavenProject; 456 } 457 458 @Deprecated 459 public boolean isSonarLightMode() { 460 return configuration.getBoolean("sonar.light", false); 461 } 462 463 /** 464 * @return the project configuration 465 */ 466 public Configuration getConfiguration() { 467 return configuration; 468 } 469 470 /** 471 * Sets the configuration 472 473 * @return the current object 474 */ 475 public Project setConfiguration(Configuration configuration) { 476 this.configuration = configuration; 477 return this; 478 } 479 480 public Object getProperty(String key) { 481 return configuration.getProperty(key); 482 } 483 484 @Override 485 public boolean equals(Object o) { 486 if (this == o) { 487 return true; 488 } 489 if (o == null || getClass() != o.getClass()) { 490 return false; 491 } 492 return ((Project) o).getKey().equals(getKey()); 493 } 494 495 @Override 496 public int hashCode() { 497 return getKey().hashCode(); 498 } 499 500 @Override 501 public String toString() { 502 return getKey(); 503 } 504 }