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) {
056          throw new IllegalArgumentException("Java filename can not be null");
057        }
058        if (className.indexOf('$') >= 0) {
059          throw new IllegalArgumentException("Java inner classes are not supported : " + className);
060        }
061        this.filename = StringUtils.trim(className);
062        String key;
063        if (StringUtils.isBlank(packageKey)) {
064          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
065          this.longName = this.filename;
066          key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
067        } else {
068          this.packageKey = packageKey.trim();
069          key = new StringBuilder().append(this.packageKey).append(".").append(this.filename).toString();
070          this.longName = key;
071        }
072        setKey(key);
073        this.unitTest = unitTest;
074      }
075    
076      /**
077       * Creates a source file from its key
078       */
079      public JavaFile(String key) {
080        this(key, false);
081      }
082    
083      /**
084       * Creates any JavaFile from its key
085       *
086       * @param unitTest whether it is a unit test file or a source file
087       */
088      public JavaFile(String key, boolean unitTest) {
089        if (key==null) {
090          throw new IllegalArgumentException("Java filename can not be null");
091        }
092        if (key != null && key.indexOf('$') >= 0) {
093          throw new IllegalArgumentException("Java inner classes are not supported : " + key);
094        }
095        String realKey = StringUtils.trim(key);
096        this.unitTest = unitTest;
097    
098        if (realKey.contains(".")) {
099          this.filename = StringUtils.substringAfterLast(realKey, ".");
100          this.packageKey = StringUtils.substringBeforeLast(realKey, ".");
101          this.longName = realKey;
102    
103        } else {
104          this.filename = realKey;
105          this.longName = realKey;
106          this.packageKey = JavaPackage.DEFAULT_PACKAGE_NAME;
107          realKey = new StringBuilder().append(JavaPackage.DEFAULT_PACKAGE_NAME).append(".").append(realKey).toString();
108        }
109        setKey(realKey);
110      }
111    
112      /**
113       * {@inheritDoc}
114       */
115      public JavaPackage getParent() {
116        if (parent == null) {
117          parent = new JavaPackage(packageKey);
118        }
119        return parent;
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        if (unitTest) {
176          return false;
177        }
178        String fileKey = getKey();
179        if (!fileKey.endsWith(".java")) {
180          fileKey += ".java";
181        }
182        if (StringUtils.substringAfterLast(antPattern, "/").indexOf(".")<0) {
183          antPattern += ".*";
184        }
185        WildcardPattern matcher = WildcardPattern.create(antPattern, ".");
186        return matcher.match(fileKey);
187      }
188    
189      /**
190       * Creates a JavaFile from a file in the source directories
191       *
192       * @return the JavaFile created if exists, null otherwise
193       */
194      public static JavaFile fromIOFile(File file, List<File> sourceDirs, boolean unitTest) {
195        if (file == null || !StringUtils.endsWithIgnoreCase(file.getName(), ".java")) {
196          return null;
197        }
198        String relativePath = DefaultProjectFileSystem.getRelativePath(file, sourceDirs);
199        if (relativePath != null) {
200          String pacname = null;
201          String classname = relativePath;
202    
203          if (relativePath.indexOf('/') >= 0) {
204            pacname = StringUtils.substringBeforeLast(relativePath, "/");
205            pacname = StringUtils.replace(pacname, "/", ".");
206            classname = StringUtils.substringAfterLast(relativePath, "/");
207          }
208          classname = StringUtils.substringBeforeLast(classname, ".");
209          return new JavaFile(pacname, classname, unitTest);
210        }
211        return null;
212      }
213    
214      /**
215       * Shortcut to fromIOFile with an abolute path
216       */
217      public static JavaFile fromAbsolutePath(String path, List<File> sourceDirs, boolean unitTest) {
218        if (path == null) {
219          return null;
220        }
221        return fromIOFile(new File(path), sourceDirs, unitTest);
222      }
223    
224      @Override
225      public String toString() {
226        return new ToStringBuilder(this)
227            .append("key", getKey())
228            .append("package", packageKey)
229            .append("longName", longName)
230            .append("unitTest", unitTest)
231            .toString();
232      }
233    }