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 }