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.lang.StringUtils;
023    import org.apache.commons.lang.builder.ToStringBuilder;
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 implements Resource<JavaPackage> {
035    
036      private String key;
037      private String filename;
038      private String longName;
039      private String packageKey;
040      private boolean unitTest;
041      private JavaPackage parent = null;
042    
043      /**
044       * Creates a JavaFile that is not a class of test based on package and file names
045       */
046      public JavaFile(String packageName, String className) {
047        this(packageName, className, false);
048      }
049    
050      /**
051       * Creates a JavaFile that can be of any type based on package and file names
052       *
053       * @param unitTest whether it is a unit test file or a source file
054       */
055      public JavaFile(String packageKey, String className, boolean unitTest) {
056        if (className != null && className.indexOf('$') >= 0) {
057          throw new IllegalArgumentException("Java inner classes are not supported : " + className);
058        }
059        this.filename = className.trim();
060        if (StringUtils.isBlank(packageKey)) {
061          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
062          this.longName = this.filename;
063          this.key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
064        } else {
065          this.packageKey = packageKey.trim();
066          this.key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
067          this.longName = this.key;
068        }
069    
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 && key.indexOf('$') >= 0) {
087          throw new IllegalArgumentException("Java inner classes are not supported : " + key);
088        }
089        this.key = key.trim();
090        this.unitTest = unitTest;
091    
092        if (this.key.contains(".")) {
093          this.filename = StringUtils.substringAfterLast(this.key, ".");
094          this.packageKey = StringUtils.substringBeforeLast(this.key, ".");
095          this.longName = this.key;
096    
097        } else {
098          this.filename = this.key;
099          this.longName = this.key;
100          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
101          this.key = new StringBuilder().append(JavaPackage.DEFAULT_PACKAGE_NAME).append(".").append(this.key).toString();
102        }
103      }
104    
105      /**
106       * {@inheritDoc}
107       */
108      public JavaPackage getParent() {
109        if (parent == null) {
110          parent = new JavaPackage(packageKey);
111        }
112        return parent;
113      }
114    
115      /**
116       * {@inheritDoc}
117       */
118      public String getKey() {
119        return key;
120      }
121    
122      /**
123       * @return null
124       */
125      public String getDescription() {
126        return null;
127      }
128    
129      /**
130       * @return Java
131       */
132      public Language getLanguage() {
133        return Java.INSTANCE;
134      }
135    
136      /**
137       * {@inheritDoc}
138       */
139      public String getName() {
140        return filename;
141      }
142    
143      /**
144       * {@inheritDoc}
145       */
146      public String getLongName() {
147        return longName;
148      }
149    
150      /**
151       * @return SCOPE_ENTITY
152       */
153      public String getScope() {
154        return Resource.SCOPE_ENTITY;
155      }
156    
157      /**
158       * @return QUALIFIER_UNIT_TEST_CLASS or QUALIFIER_CLASS depending whether it is a unit test class
159       */
160      public String getQualifier() {
161        return unitTest ? Resource.QUALIFIER_UNIT_TEST_CLASS : Resource.QUALIFIER_CLASS;
162      }
163    
164      /**
165       * @return whether the JavaFile is a unit test class or not
166       */
167      public boolean isUnitTest() {
168        return unitTest;
169      }
170    
171      /**
172       * {@inheritDoc}
173       */
174      public boolean matchFilePattern(String antPattern) {
175        String patternWithoutFileSuffix = StringUtils.substringBeforeLast(antPattern, ".");
176        WildcardPattern matcher = WildcardPattern.create(patternWithoutFileSuffix, ".");
177        return matcher.match(getKey());
178      }
179    
180      /**
181       * Creates a JavaFile from a file in the source directories
182       *
183       * @return the JavaFile created if exists, null otherwise
184       */
185      public static JavaFile fromIOFile(File file, List<File> sourceDirs, boolean unitTest) {
186        if (file == null || !StringUtils.endsWithIgnoreCase(file.getName(), ".java")) {
187          return null;
188        }
189        String relativePath = DefaultProjectFileSystem.getRelativePath(file, sourceDirs);
190        if (relativePath != null) {
191          String pacname = null;
192          String classname = relativePath;
193    
194          if (relativePath.indexOf('/') >= 0) {
195            pacname = StringUtils.substringBeforeLast(relativePath, "/");
196            pacname = StringUtils.replace(pacname, "/", ".");
197            classname = StringUtils.substringAfterLast(relativePath, "/");
198          }
199          classname = StringUtils.substringBeforeLast(classname, ".");
200          return new JavaFile(pacname, classname, unitTest);
201        }
202        return null;
203      }
204    
205      /**
206       * Shortcut to fromIOFile with an abolute path
207       */
208      public static JavaFile fromAbsolutePath(String path, List<File> sourceDirs, boolean unitTest) {
209        if (path == null) {
210          return null;
211        }
212        return fromIOFile(new File(path), sourceDirs, unitTest);
213      }
214    
215      @Override
216      public boolean equals(Object obj) {
217        if (!(obj instanceof JavaFile)) {
218          return false;
219        }
220        if (this == obj) {
221          return true;
222        }
223        JavaFile other = (JavaFile) obj;
224        return StringUtils.equals(key, other.getKey());
225      }
226    
227      @Override
228      public int hashCode() {
229        return key.hashCode();
230      }
231    
232      @Override
233      public String toString() {
234        return new ToStringBuilder(this)
235          .append("key", key)
236          .append("package", packageKey)
237          .append("longName", longName)
238          .append("unitTest", unitTest)
239          .toString();
240      }
241    }