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 */
020package org.sonar.api.resources;
021
022import org.apache.commons.lang.StringUtils;
023import org.sonar.api.scan.filesystem.PathResolver;
024import org.sonar.api.utils.WildcardPattern;
025
026import java.io.File;
027import 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 */
034public 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}