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     */
020    package org.sonar.api.resources;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.sonar.api.scan.filesystem.PathResolver;
024    import org.sonar.api.utils.WildcardPattern;
025    
026    import java.io.File;
027    import java.util.List;
028    
029    /**
030     * A class that represents a Java class. This class can either be a Test class or source class
031     *
032     * @since 1.10
033     */
034    public class JavaFile extends Resource {
035    
036      private String filename;
037      private String longName;
038      private String packageKey;
039      private boolean unitTest;
040      private JavaPackage parent;
041    
042      /**
043       * Creates a JavaFile that is not a class of test based on package and file names
044       */
045      public JavaFile(String packageName, String className) {
046        this(packageName, className, false);
047      }
048    
049      /**
050       * Creates a JavaFile that can be of any type based on package and file names
051       *
052       * @param unitTest whether it is a unit test file or a source file
053       */
054      public JavaFile(String packageKey, String className, boolean unitTest) {
055        if (className == null) {
056          throw new IllegalArgumentException("Java filename can not be null");
057        }
058        this.filename = StringUtils.trim(className);
059        String key;
060        if (StringUtils.isBlank(packageKey)) {
061          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
062          this.longName = this.filename;
063          key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
064        } else {
065          this.packageKey = packageKey.trim();
066          key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
067          this.longName = key;
068        }
069        setKey(key);
070        this.unitTest = unitTest;
071      }
072    
073      /**
074       * Creates a source file from its key
075       */
076      public JavaFile(String key) {
077        this(key, false);
078      }
079    
080      /**
081       * Creates any JavaFile from its key
082       *
083       * @param unitTest whether it is a unit test file or a source file
084       */
085      public JavaFile(String key, boolean unitTest) {
086        if (key == null) {
087          throw new IllegalArgumentException("Java filename can not be null");
088        }
089        String realKey = StringUtils.trim(key);
090        this.unitTest = unitTest;
091    
092        if (realKey.contains(".")) {
093          this.filename = StringUtils.substringAfterLast(realKey, ".");
094          this.packageKey = StringUtils.substringBeforeLast(realKey, ".");
095          this.longName = realKey;
096    
097        } else {
098          this.filename = realKey;
099          this.longName = realKey;
100          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
101          realKey = new StringBuilder().append(JavaPackage.DEFAULT_PACKAGE_NAME).append(".").append(realKey).toString();
102        }
103        setKey(realKey);
104      }
105    
106      /**
107       * {@inheritDoc}
108       */
109      @Override
110      public JavaPackage getParent() {
111        if (parent == null) {
112          parent = new JavaPackage(packageKey);
113        }
114        return parent;
115    
116      }
117    
118      /**
119       * @return null
120       */
121      @Override
122      public String getDescription() {
123        return null;
124      }
125    
126      /**
127       * @return Java
128       */
129      @Override
130      public Language getLanguage() {
131        return Java.INSTANCE;
132      }
133    
134      /**
135       * {@inheritDoc}
136       */
137      @Override
138      public String getName() {
139        return filename;
140      }
141    
142      /**
143       * {@inheritDoc}
144       */
145      @Override
146      public String getLongName() {
147        return longName;
148      }
149    
150      /**
151       * @return SCOPE_ENTITY
152       */
153      @Override
154      public String getScope() {
155        return Scopes.FILE;
156      }
157    
158      /**
159       * @return QUALIFIER_UNIT_TEST_CLASS or QUALIFIER_CLASS depending whether it is a unit test class
160       */
161      @Override
162      public String getQualifier() {
163        return unitTest ? Qualifiers.UNIT_TEST_FILE : Qualifiers.CLASS;
164      }
165    
166      /**
167       * @return whether the JavaFile is a unit test class or not
168       */
169      public boolean isUnitTest() {
170        return unitTest;
171      }
172    
173      /**
174       * {@inheritDoc}
175       */
176      @Override
177      public boolean matchFilePattern(String antPattern) {
178        String fileKey = getKey();
179        if (!fileKey.endsWith(".java")) {
180          fileKey += ".java";
181        }
182        // Add wildcard extension if not provided
183        if ((antPattern.contains("/") && StringUtils.substringAfterLast(antPattern, "/").indexOf('.') < 0) || antPattern.indexOf('.') < 0) {
184          antPattern += ".*";
185        }
186        String noPackagePrefix = JavaPackage.DEFAULT_PACKAGE_NAME + ".";
187        if (fileKey.startsWith(noPackagePrefix)) {
188          fileKey = fileKey.substring(noPackagePrefix.length());
189        }
190        WildcardPattern matcher = WildcardPattern.create(antPattern, ".");
191        return matcher.match(fileKey);
192      }
193    
194      public static JavaFile fromRelativePath(String relativePath, boolean unitTest) {
195        if (relativePath != null) {
196          String pacname = null;
197          String classname = relativePath;
198    
199          if (relativePath.indexOf('/') >= 0) {
200            pacname = StringUtils.substringBeforeLast(relativePath, "/");
201            pacname = StringUtils.replace(pacname, "/", ".");
202            classname = StringUtils.substringAfterLast(relativePath, "/");
203          }
204          classname = StringUtils.substringBeforeLast(classname, ".");
205          return new JavaFile(pacname, classname, unitTest);
206        }
207        return null;
208      }
209    
210      /**
211       * Creates a JavaFile from a file in the source directories
212       *
213       * @return the JavaFile created if exists, null otherwise
214       */
215      public static JavaFile fromIOFile(File file, List<File> sourceDirs, boolean unitTest) {
216        if (file == null || !StringUtils.endsWithIgnoreCase(file.getName(), ".java")) {
217          return null;
218        }
219        PathResolver.RelativePath relativePath = new PathResolver().relativePath(sourceDirs, file);
220        if (relativePath != null) {
221          return fromRelativePath(relativePath.path(), unitTest);
222        }
223        return null;
224      }
225    
226      /**
227       * Shortcut to fromIOFile with an abolute path
228       */
229      public static JavaFile fromAbsolutePath(String path, List<File> sourceDirs, boolean unitTest) {
230        if (path == null) {
231          return null;
232        }
233        return fromIOFile(new File(path), sourceDirs, unitTest);
234      }
235    
236      @Override
237      public String toString() {
238        return getKey();
239      }
240    
241    }