001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
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.batch.bootstrap;
021    
022    import com.google.common.collect.Lists;
023    import org.apache.commons.lang.StringUtils;
024    import org.sonar.api.BatchComponent;
025    import org.sonar.api.CoreProperties;
026    
027    import java.io.File;
028    import java.util.Arrays;
029    import java.util.List;
030    import java.util.Properties;
031    
032    /**
033     * Defines project metadata (key, name, source directories, ...). It's generally used by the
034     * {@link org.sonar.api.batch.bootstrap.ProjectBuilder extension point} and must not be used
035     * by other standard extensions.
036     *
037     * @since 2.9
038     */
039    public final class ProjectDefinition implements BatchComponent {
040    
041      public static final String SOURCE_DIRS_PROPERTY = "sonar.sources";
042      public static final String SOURCE_FILES_PROPERTY = "sonar.sourceFiles";
043      public static final String TEST_DIRS_PROPERTY = "sonar.tests";
044      public static final String TEST_FILES_PROPERTY = "sonar.testFiles";
045      public static final String BINARIES_PROPERTY = "sonar.binaries";
046      public static final String LIBRARIES_PROPERTY = "sonar.libraries";
047    
048      private static final char SEPARATOR = ',';
049    
050      private File baseDir;
051      private File workDir;
052      private Properties properties = new Properties();
053      private ProjectDefinition parent = null;
054      private List<ProjectDefinition> subProjects = Lists.newArrayList();
055      private List<Object> containerExtensions = Lists.newArrayList();
056    
057      private ProjectDefinition(Properties p) {
058        this.properties = p;
059      }
060    
061      public static ProjectDefinition create(Properties properties) {
062        return new ProjectDefinition(properties);
063      }
064    
065      public static ProjectDefinition create() {
066        return new ProjectDefinition(new Properties());
067      }
068    
069      public ProjectDefinition setBaseDir(File baseDir) {
070        this.baseDir = baseDir;
071        return this;
072      }
073    
074      public File getBaseDir() {
075        return baseDir;
076      }
077      public ProjectDefinition setWorkDir(File workDir) {
078        this.workDir = workDir;
079        return this;
080      }
081    
082      public File getWorkDir() {
083        return workDir;
084      }
085    
086      public Properties getProperties() {
087        return properties;
088      }
089    
090      public ProjectDefinition setProperty(String key, String value) {
091        properties.setProperty(key, value);
092        return this;
093      }
094    
095      public ProjectDefinition setKey(String key) {
096        properties.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, key);
097        return this;
098      }
099    
100      public ProjectDefinition setVersion(String s) {
101        properties.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s));
102        return this;
103      }
104    
105      public ProjectDefinition setName(String s) {
106        properties.setProperty(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s));
107        return this;
108      }
109    
110      public ProjectDefinition setDescription(String s) {
111        properties.setProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s));
112        return this;
113      }
114    
115      public String getKey() {
116        return properties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY);
117      }
118    
119      public String getVersion() {
120        return properties.getProperty(CoreProperties.PROJECT_VERSION_PROPERTY);
121      }
122    
123      public String getName() {
124        String name = properties.getProperty(CoreProperties.PROJECT_NAME_PROPERTY);
125        if (StringUtils.isBlank(name)) {
126          name = "Unnamed - " + getKey();
127        }
128        return name;
129      }
130    
131      public String getDescription() {
132        return properties.getProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY);
133      }
134    
135      private void appendProperty(String key, String value) {
136        String newValue = properties.getProperty(key, "") + SEPARATOR + value;
137        properties.put(key, newValue);
138      }
139    
140      public List<String> getSourceDirs() {
141        String sources = properties.getProperty(SOURCE_DIRS_PROPERTY, "");
142        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
143      }
144    
145      /**
146       * @param paths paths to directory with main sources.
147       *              They can be absolute or relative to project base directory.
148       */
149      public ProjectDefinition addSourceDirs(String... paths) {
150        for (String path : paths) {
151          appendProperty(SOURCE_DIRS_PROPERTY, path);
152        }
153        return this;
154      }
155    
156      public ProjectDefinition addSourceDirs(File... dirs) {
157        for (File dir : dirs) {
158          addSourceDirs(dir.getAbsolutePath());
159        }
160        return this;
161      }
162    
163      public ProjectDefinition resetSourceDirs() {
164        properties.remove(SOURCE_DIRS_PROPERTY);
165        return this;
166      }
167    
168      public ProjectDefinition setSourceDirs(String... paths) {
169        resetSourceDirs();
170        return addSourceDirs(paths);
171      }
172    
173      public ProjectDefinition setSourceDirs(File... dirs) {
174        resetSourceDirs();
175        for (File dir : dirs) {
176          addSourceDirs(dir.getAbsolutePath());
177        }
178        return this;
179      }
180    
181      /**
182       * Adding source files is possible only if no source directories have been set.
183       * Absolute path or relative path from project base dir.
184       */
185      public ProjectDefinition addSourceFiles(String... paths) {
186        for (String path : paths) {
187          appendProperty(SOURCE_FILES_PROPERTY, path);
188        }
189        return this;
190      }
191    
192      /**
193       * Adding source files is possible only if no source directories have been set.
194       */
195      public ProjectDefinition addSourceFiles(File... files) {
196        for (File file : files) {
197          addSourceFiles(file.getAbsolutePath());
198        }
199        return this;
200      }
201    
202      public List<String> getSourceFiles() {
203        String sources = properties.getProperty(SOURCE_FILES_PROPERTY, "");
204        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
205      }
206    
207    
208      public List<String> getTestDirs() {
209        String sources = properties.getProperty(TEST_DIRS_PROPERTY, "");
210        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
211      }
212    
213      /**
214       * @param paths path to directory with test sources.
215       *              It can be absolute or relative to project directory.
216       */
217      public ProjectDefinition addTestDirs(String... paths) {
218        for (String path : paths) {
219          appendProperty(TEST_DIRS_PROPERTY, path);
220        }
221        return this;
222      }
223    
224      public ProjectDefinition addTestDirs(File... dirs) {
225        for (File dir : dirs) {
226          addTestDirs(dir.getAbsolutePath());
227        }
228        return this;
229      }
230    
231      public ProjectDefinition setTestDirs(String... paths) {
232        resetTestDirs();
233        return addTestDirs(paths);
234      }
235    
236      public ProjectDefinition setTestDirs(File... dirs) {
237        resetTestDirs();
238        for (File dir : dirs) {
239          addTestDirs(dir.getAbsolutePath());
240        }
241        return this;
242      }
243    
244      public ProjectDefinition resetTestDirs() {
245        properties.remove(TEST_DIRS_PROPERTY);
246        return this;
247      }
248    
249    
250      /**
251       * Adding source files is possible only if no source directories have been set.
252       * Absolute path or relative path from project base dir.
253       */
254      public ProjectDefinition addTestFiles(String... paths) {
255        for (String path : paths) {
256          appendProperty(TEST_FILES_PROPERTY, path);
257        }
258        return this;
259      }
260    
261      /**
262       * Adding source files is possible only if no source directories have been set.
263       */
264      public ProjectDefinition addTestFiles(File... files) {
265        for (File file : files) {
266          addTestFiles(file.getAbsolutePath());
267        }
268        return this;
269      }
270    
271      public List<String> getTestFiles() {
272        String sources = properties.getProperty(TEST_FILES_PROPERTY, "");
273        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
274      }
275    
276    
277      public List<String> getBinaries() {
278        String sources = properties.getProperty(BINARIES_PROPERTY, "");
279        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
280      }
281    
282      /**
283       * @param path path to directory with compiled source. In case of Java this is directory with class files.
284       *             It can be absolute or relative to project directory.
285       * @TODO currently Sonar supports only one such directory due to dependency on MavenProject
286       */
287      public ProjectDefinition addBinaryDir(String path) {
288        appendProperty(BINARIES_PROPERTY, path);
289        return this;
290      }
291    
292      public ProjectDefinition addBinaryDir(File f) {
293        return addBinaryDir(f.getAbsolutePath());
294      }
295    
296    
297      public List<String> getLibraries() {
298        String sources = properties.getProperty(LIBRARIES_PROPERTY, "");
299        return Arrays.asList(StringUtils.split(sources, SEPARATOR));
300      }
301    
302      /**
303       * @param path path to file with third-party library. In case of Java this is path to jar file.
304       *             It can be absolute or relative to project directory.
305       */
306      public void addLibrary(String path) {
307        appendProperty(LIBRARIES_PROPERTY, path);
308      }
309    
310      /**
311       * Adds an extension, which would be available in PicoContainer during analysis of this project.
312       *
313       * @since 2.8
314       */
315      public ProjectDefinition addContainerExtension(Object extension) {
316        containerExtensions.add(extension);
317        return this;
318      }
319    
320      /**
321       * @since 2.8
322       */
323      public List<Object> getContainerExtensions() {
324        return containerExtensions;
325      }
326    
327      /**
328       * @since 2.8
329       */
330      public ProjectDefinition addSubProject(ProjectDefinition child) {
331        subProjects.add(child);
332        child.setParent(this);
333        return this;
334      }
335    
336      public ProjectDefinition getParent() {
337        return parent;
338      }
339    
340      private void setParent(ProjectDefinition parent) {
341        this.parent = parent;
342      }
343    
344      /**
345       * @since 2.8
346       */
347      public List<ProjectDefinition> getSubProjects() {
348        return subProjects;
349      }
350    }