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 117 // modules tree 118 private Project root; 119 private Project parent; 120 private List<Project> modules = new ArrayList<Project>(); 121 122 // internal use 123 private Snapshot snapshot; 124 private Integer id; 125 private Languages languages; 126 127 128 /** 129 * Creates a Project from a MavenProject (pom) 130 */ 131 public Project(MavenProject mavenProject) { 132 this(mavenProject, new MapConfiguration(mavenProject.getProperties())); 133 } 134 135 /** 136 * Creates a project from MavenProject and a configuration 137 */ 138 public Project(MavenProject pom, Configuration configuration) { 139 this.mavenProject = pom; 140 this.fileSystem = new DefaultProjectFileSystem(this); 141 this.configuration = configuration; 142 143 String branch = getBranch(configuration); 144 this.key = getMavenKey(pom, branch); 145 this.name = getMavenName(pom, branch); 146 this.packaging = pom.getPackaging(); 147 this.description = pom.getDescription(); 148 } 149 150 /** 151 * Creates a Project from key, name, packaging and configuration 152 */ 153 public Project(String key, String name, String packaging, Configuration conf) { 154 this.key = key; 155 this.name = name; 156 this.packaging = packaging; 157 this.configuration = conf; 158 } 159 160 private static String getMavenKey(MavenProject pom, String branch) { 161 StringBuilder sb = new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()); 162 if (StringUtils.isNotBlank(branch)) { 163 sb.append(":").append(branch); 164 } 165 return sb.toString(); 166 } 167 168 private static String getMavenName(MavenProject pom, String branch) { 169 StringBuilder sb = new StringBuilder().append(pom.getName()); 170 if (StringUtils.isNotBlank(branch)) { 171 sb.append(" ").append(branch); 172 } 173 return sb.toString(); 174 } 175 176 private static String getBranch(Configuration configuration) { 177 if (configuration != null) { 178 return configuration.getString(CoreProperties.PROJECT_BRANCH_PROPERTY, configuration.getString(PARAM_DEPRECATED_BRANCH)); 179 } 180 return null; 181 } 182 183 /** 184 * Internal use 185 */ 186 public Snapshot getSnapshot() { 187 return snapshot; 188 } 189 190 /** 191 * Internal use 192 */ 193 public Integer getId() { 194 return id; 195 } 196 197 /** 198 * Internal use 199 */ 200 public Project setDatabaseSettings(Integer projectId, Snapshot snapshot) { 201 this.snapshot = snapshot; 202 this.id = projectId; 203 return this; 204 } 205 206 /** 207 * Sets the project languaage 208 * 209 * @return the current object 210 */ 211 public Project setLanguages(Languages languages) { 212 this.languages = languages; 213 return this; 214 } 215 216 /** 217 * @return the project's root project 218 */ 219 public Project getRoot() { 220 return root; 221 } 222 223 /** 224 * @return the project's packaging 225 */ 226 public String getPackaging() { 227 return packaging; 228 } 229 230 /** 231 * @return whether the current project is root project 232 */ 233 public boolean isRoot() { 234 return mavenProject.isExecutionRoot(); 235 } 236 237 /** 238 * @return whether the current project is a module 239 */ 240 public boolean isModule() { 241 return !isRoot(); 242 } 243 244 /** 245 * @return the type of analysis of the project 246 */ 247 public AnalysisType getAnalysisType() { 248 String value = getConfiguration().getString(CoreProperties.DYNAMIC_ANALYSIS_PROPERTY); 249 if (value == null) { 250 return (isSonarLightMode() ? AnalysisType.STATIC : AnalysisType.DYNAMIC); 251 } 252 if ("true".equals(value)) { 253 return AnalysisType.DYNAMIC; 254 } 255 if ("reuseReports".equals(value)) { 256 return AnalysisType.REUSE_REPORTS; 257 } 258 return AnalysisType.STATIC; 259 } 260 261 262 /** 263 * @deprecated since 1.12. Avoid coupling with Maven concepts. 264 */ 265 @Deprecated 266 public String getGroupId() { 267 return mavenProject.getGroupId(); 268 } 269 270 /** 271 * @deprecated since 1.12. Avoid coupling with Maven concepts. 272 */ 273 @Deprecated 274 public String getArtifactId() { 275 return mavenProject.getArtifactId(); 276 } 277 278 /** 279 * @return project's name 280 */ 281 public String getName() { 282 return name; 283 } 284 285 /** 286 * @return project's long name 287 */ 288 public String getLongName() { 289 return null; 290 } 291 292 /** 293 * @return project's description 294 */ 295 public String getDescription() { 296 return description; 297 } 298 299 /** 300 * @return the project language 301 */ 302 public Language getLanguage() { 303 String key = getLanguageKey(); 304 if (languages != null) { 305 return languages.get(key); 306 } 307 if (Java.KEY.equals(key)) { 308 return Java.INSTANCE; 309 } 310 return null; 311 } 312 313 /** 314 * @return the language key 315 */ 316 public String getLanguageKey() { 317 String key = configuration.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY); 318 return StringUtils.isBlank(key) ? Java.KEY : key; 319 } 320 321 /** 322 * @return the scope of the current object 323 */ 324 public String getScope() { 325 return SCOPE_SET; 326 } 327 328 /** 329 * @return the qualifier of the current object 330 */ 331 public String getQualifier() { 332 return isRoot() ? QUALIFIER_PROJECT : QUALIFIER_MODULE; 333 } 334 335 public boolean matchFilePattern(String antPattern) { 336 return false; 337 } 338 339 /** 340 * @return the current object's parent 341 */ 342 public Project getParent() { 343 return parent; 344 } 345 346 /** 347 * Sets a parent to the current object 348 */ 349 public void setParent(Project parent) { 350 this.parent = parent; 351 if (parent != null) { 352 parent.modules.add(this); 353 if (parent.isRoot()) { 354 this.root = parent; 355 } else { 356 this.root = parent.getRoot(); 357 } 358 } 359 } 360 361 /** 362 * @return the list of modules 363 */ 364 public List<Project> getModules() { 365 return modules; 366 } 367 368 /** 369 * @return whether to use external source for rules configuration 370 */ 371 public boolean getReuseExistingRulesConfig() { 372 return configuration.getBoolean(CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY, false); 373 } 374 375 /** 376 * @return the current version of the project 377 */ 378 public String getAnalysisVersion() { 379 String version = configuration.getString(CoreProperties.PROJECT_VERSION_PROPERTY); 380 if (version == null) { 381 version = mavenProject.getVersion(); 382 } 383 return version; 384 } 385 386 /** 387 * @return the analysis date, i.e. the date that will be used to store the snapshot 388 */ 389 public Date getAnalysisDate() { 390 String formattedDate = configuration.getString(CoreProperties.PROJECT_DATE_PROPERTY); 391 if (formattedDate == null) { 392 return new Date(); 393 } 394 395 DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 396 try { 397 // see SONAR-908 make sure that a time is defined for the date. 398 Date date = DateUtils.setHours(format.parse(formattedDate), 0); 399 return DateUtils.setMinutes(date, 1); 400 401 } catch (ParseException e) { 402 throw new SonarException("The property " + PARAM_DATE + " does not respect the format yyyy-MM-dd (for example 2008-05-23) : " + formattedDate, e); 403 } 404 } 405 406 /** 407 * Project key is "groupId:artifactId[:branch]". Examples : org.struts:struts-core and org.codehaus.sonar:sonar:1.10 408 */ 409 public String getKey() { 410 return key; 411 } 412 413 /** 414 * Patterns of resource exclusion as defined in project settings page. 415 */ 416 public String[] getExclusionPatterns() { 417 String[] exclusions = getConfiguration().getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY); 418 if (exclusions == null) { 419 return new String[0]; 420 } 421 return exclusions; 422 } 423 424 /** 425 * Set exclusion patterns. Configuration is not saved, so this method must be used ONLY IN UNIT TESTS. 426 */ 427 public void setExclusionPatterns(String[] patterns) { 428 getConfiguration().setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, patterns); 429 } 430 431 public ProjectFileSystem getFileSystem() { 432 return fileSystem; 433 } 434 435 /** 436 * @return the underlying maven project 437 */ 438 public MavenProject getPom() { 439 return mavenProject; 440 } 441 442 @Deprecated 443 public boolean isSonarLightMode() { 444 return configuration.getBoolean("sonar.light", false); 445 } 446 447 /** 448 * @return the project configuration 449 */ 450 public Configuration getConfiguration() { 451 return configuration; 452 } 453 454 /** 455 * Sets the configuration 456 457 * @return the current object 458 */ 459 public Project setConfiguration(Configuration configuration) { 460 this.configuration = configuration; 461 return this; 462 } 463 464 public Object getProperty(String key) { 465 return configuration.getProperty(key); 466 } 467 468 @Override 469 public boolean equals(Object o) { 470 if (this == o) { 471 return true; 472 } 473 if (o == null || getClass() != o.getClass()) { 474 return false; 475 } 476 return ((Project) o).getKey().equals(getKey()); 477 } 478 479 @Override 480 public int hashCode() { 481 return getKey().hashCode(); 482 } 483 484 @Override 485 public String toString() { 486 return getKey(); 487 } 488 }