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 extends Resource<JavaPackage> {
035    
036      private String filename;
037      private String longName;
038      private String packageKey;
039      private boolean unitTest;
040      private JavaPackage parent = null;
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 && className.indexOf('$') >= 0) {
056          throw new IllegalArgumentException("Java inner classes are not supported : " + className);
057        }
058        this.filename = className.trim();
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 && key.indexOf('$') >= 0) {
087          throw new IllegalArgumentException("Java inner classes are not supported : " + key);
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      public JavaPackage getParent() {
110        if (parent == null) {
111          parent = new JavaPackage(packageKey);
112        }
113        return parent;
114      }
115    
116      /**
117       * @return null
118       */
119      public String getDescription() {
120        return null;
121      }
122    
123      /**
124       * @return Java
125       */
126      public Language getLanguage() {
127        return Java.INSTANCE;
128      }
129    
130      /**
131       * {@inheritDoc}
132       */
133      public String getName() {
134        return filename;
135      }
136    
137      /**
138       * {@inheritDoc}
139       */
140      public String getLongName() {
141        return longName;
142      }
143    
144      /**
145       * @return SCOPE_ENTITY
146       */
147      public String getScope() {
148        return Resource.SCOPE_ENTITY;
149      }
150    
151      /**
152       * @return QUALIFIER_UNIT_TEST_CLASS or QUALIFIER_CLASS depending whether it is a unit test class
153       */
154      public String getQualifier() {
155        return unitTest ? Resource.QUALIFIER_UNIT_TEST_CLASS : Resource.QUALIFIER_CLASS;
156      }
157    
158      /**
159       * @return whether the JavaFile is a unit test class or not
160       */
161      public boolean isUnitTest() {
162        return unitTest;
163      }
164    
165      /**
166       * {@inheritDoc}
167       */
168      public boolean matchFilePattern(String antPattern) {
169        if (unitTest) {
170          return false;
171        }
172        String patternWithoutFileSuffix = StringUtils.substringBeforeLast(antPattern, ".");
173        WildcardPattern matcher = WildcardPattern.create(patternWithoutFileSuffix, ".");
174        return matcher.match(getKey());
175      }
176    
177      /**
178       * Creates a JavaFile from a file in the source directories
179       *
180       * @return the JavaFile created if exists, null otherwise
181       */
182      public static JavaFile fromIOFile(File file, List<File> sourceDirs, boolean unitTest) {
183        if (file == null || !StringUtils.endsWithIgnoreCase(file.getName(), ".java")) {
184          return null;
185        }
186        String relativePath = DefaultProjectFileSystem.getRelativePath(file, sourceDirs);
187        if (relativePath != null) {
188          String pacname = null;
189          String classname = relativePath;
190    
191          if (relativePath.indexOf('/') >= 0) {
192            pacname = StringUtils.substringBeforeLast(relativePath, "/");
193            pacname = StringUtils.replace(pacname, "/", ".");
194            classname = StringUtils.substringAfterLast(relativePath, "/");
195          }
196          classname = StringUtils.substringBeforeLast(classname, ".");
197          return new JavaFile(pacname, classname, unitTest);
198        }
199        return null;
200      }
201    
202      /**
203       * Shortcut to fromIOFile with an abolute path
204       */
205      public static JavaFile fromAbsolutePath(String path, List<File> sourceDirs, boolean unitTest) {
206        if (path == null) {
207          return null;
208        }
209        return fromIOFile(new File(path), sourceDirs, unitTest);
210      }
211    
212      @Override
213      public String toString() {
214        return new ToStringBuilder(this)
215            .append("key", getKey())
216            .append("package", packageKey)
217            .append("longName", longName)
218            .append("unitTest", unitTest)
219            .toString();
220      }
221    }