001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 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.apache.commons.lang.builder.ToStringBuilder; 024 import org.sonar.api.batch.SensorContext; 025 import org.sonar.api.batch.fs.FileSystem; 026 import org.sonar.api.scan.filesystem.PathResolver; 027 import org.sonar.api.utils.WildcardPattern; 028 029 import javax.annotation.CheckForNull; 030 031 import java.util.List; 032 033 /** 034 * This class is an implementation of a resource of type FILE 035 * 036 * @since 1.10 037 */ 038 public class File extends Resource { 039 040 public static final String SCOPE = Scopes.FILE; 041 042 private String directoryDeprecatedKey; 043 private String filename; 044 private Language language; 045 private Directory parent; 046 private String qualifier = Qualifiers.FILE; 047 048 private File() { 049 // Used by factory method 050 } 051 052 /** 053 * File in project. Key is the path relative to project source directories. It is not the absolute path and it does not include the path 054 * to source directories. Example : <code>new File("org/sonar/foo.sql")</code>. The absolute path may be 055 * c:/myproject/src/main/sql/org/sonar/foo.sql. Project root is c:/myproject and source dir is src/main/sql. 056 * @deprecated since 4.2 use {@link #fromIOFile(java.io.File, Project)} 057 */ 058 @Deprecated 059 public File(String relativePathFromSourceDir) { 060 if (relativePathFromSourceDir == null) { 061 throw new IllegalArgumentException("File key is null"); 062 } 063 String realKey = parseKey(relativePathFromSourceDir); 064 if (realKey.indexOf(Directory.SEPARATOR) >= 0) { 065 this.directoryDeprecatedKey = Directory.parseKey(StringUtils.substringBeforeLast(relativePathFromSourceDir, Directory.SEPARATOR)); 066 this.filename = StringUtils.substringAfterLast(realKey, Directory.SEPARATOR); 067 realKey = new StringBuilder().append(this.directoryDeprecatedKey).append(Directory.SEPARATOR).append(filename).toString(); 068 069 } else { 070 this.filename = relativePathFromSourceDir; 071 } 072 setDeprecatedKey(realKey); 073 } 074 075 /** 076 * Creates a file from its containing directory and name 077 * @deprecated since 4.2 use {@link #fromIOFile(java.io.File, Project)} 078 */ 079 @Deprecated 080 public File(String relativeDirectoryPathFromSourceDir, String filename) { 081 this.filename = StringUtils.trim(filename); 082 if (StringUtils.isBlank(relativeDirectoryPathFromSourceDir)) { 083 setDeprecatedKey(filename); 084 085 } else { 086 this.directoryDeprecatedKey = Directory.parseKey(relativeDirectoryPathFromSourceDir); 087 setDeprecatedKey(new StringBuilder().append(directoryDeprecatedKey).append(Directory.SEPARATOR).append(this.filename).toString()); 088 } 089 } 090 091 /** 092 * Creates a File from its language and its key 093 * @deprecated since 4.2 use {@link #fromIOFile(java.io.File, Project)} 094 */ 095 @Deprecated 096 public File(Language language, String relativePathFromSourceDir) { 097 this(relativePathFromSourceDir); 098 this.language = language; 099 } 100 101 /** 102 * Creates a File from language, directory and filename 103 * @deprecated since 4.2 use {@link #fromIOFile(java.io.File, Project)} 104 */ 105 @Deprecated 106 public File(Language language, String relativeDirectoryPathFromSourceDir, String filename) { 107 this(relativeDirectoryPathFromSourceDir, filename); 108 this.language = language; 109 } 110 111 /** 112 * {@inheritDoc} 113 * 114 * @see Resource#getParent() 115 */ 116 @Override 117 public Directory getParent() { 118 if (parent == null) { 119 parent = new Directory(directoryDeprecatedKey); 120 } 121 return parent; 122 } 123 124 private static String parseKey(String key) { 125 if (StringUtils.isBlank(key)) { 126 return null; 127 } 128 String normalizedKey = key; 129 normalizedKey = normalizedKey.replace('\\', '/'); 130 normalizedKey = StringUtils.trim(normalizedKey); 131 return normalizedKey; 132 } 133 134 /** 135 * {@inheritDoc} 136 * 137 * @see Resource#matchFilePattern(String) 138 */ 139 @Override 140 public boolean matchFilePattern(String antPattern) { 141 WildcardPattern matcher = WildcardPattern.create(antPattern, Directory.SEPARATOR); 142 return matcher.match(getKey()); 143 } 144 145 /** 146 * Creates a File from an io.file and a list of sources directories 147 * @deprecated since 4.2 use {@link #fromIOFile(java.io.File, Project)} 148 */ 149 @Deprecated 150 @CheckForNull 151 public static File fromIOFile(java.io.File file, List<java.io.File> sourceDirs) { 152 PathResolver.RelativePath relativePath = new PathResolver().relativePath(sourceDirs, file); 153 if (relativePath != null) { 154 return new File(relativePath.path()); 155 } 156 return null; 157 } 158 159 /** 160 * Creates a {@link File} from an absolute {@link java.io.File} and a module. 161 * The returned {@link File} can be then passed for example to 162 * {@link SensorContext#saveMeasure(Resource, org.sonar.api.measures.Measure)}. 163 * @param file absolute path to a file 164 * @param module 165 * @return null if the file is not under module basedir. 166 * @deprecated since 4.5 use {@link FileSystem#inputFile(org.sonar.api.batch.fs.FilePredicate)} 167 */ 168 @Deprecated 169 @CheckForNull 170 public static File fromIOFile(java.io.File file, Project module) { 171 String relativePathFromBasedir = new PathResolver().relativePath(module.getFileSystem().getBasedir(), file); 172 if (relativePathFromBasedir != null) { 173 return File.create(relativePathFromBasedir); 174 } 175 return null; 176 } 177 178 /** 179 * {@inheritDoc} 180 * 181 * @see Resource#getName() 182 */ 183 @Override 184 public String getName() { 185 return filename; 186 } 187 188 /** 189 * {@inheritDoc} 190 * 191 * @see Resource#getLongName() 192 */ 193 @Override 194 public String getLongName() { 195 return StringUtils.defaultIfBlank(getPath(), getKey()); 196 } 197 198 /** 199 * {@inheritDoc} 200 * 201 * @see Resource#getDescription() 202 */ 203 @Override 204 public String getDescription() { 205 return null; 206 } 207 208 /** 209 * {@inheritDoc} 210 * 211 * @see Resource#getLanguage() 212 */ 213 @Override 214 public Language getLanguage() { 215 return language; 216 } 217 218 /** 219 * Sets the language of the file 220 */ 221 public void setLanguage(Language language) { 222 this.language = language; 223 } 224 225 /** 226 * @return SCOPE_ENTITY 227 */ 228 @Override 229 public final String getScope() { 230 return SCOPE; 231 } 232 233 /** 234 * Returns the qualifier associated to this File. Should be QUALIFIER_FILE or QUALIFIER_UNIT_TEST_CLASS 235 */ 236 @Override 237 public String getQualifier() { 238 return qualifier; 239 } 240 241 public void setQualifier(String qualifier) { 242 this.qualifier = qualifier; 243 } 244 245 /** 246 * Create a File that is partially initialized. But that's enough to call for example 247 * {@link SensorContext#saveMeasure(Resource, org.sonar.api.measures.Measure)} when resources are already indexed. 248 * Internal use only. 249 * @since 4.2 250 */ 251 public static File create(String relativePathFromBasedir) { 252 File file = new File(); 253 String normalizedPath = normalize(relativePathFromBasedir); 254 file.setKey(normalizedPath); 255 file.setPath(normalizedPath); 256 String directoryPath; 257 if (normalizedPath != null && normalizedPath.contains(Directory.SEPARATOR)) { 258 directoryPath = StringUtils.substringBeforeLast(normalizedPath, Directory.SEPARATOR); 259 } else { 260 directoryPath = Directory.SEPARATOR; 261 } 262 file.parent = Directory.create(directoryPath); 263 return file; 264 } 265 266 /** 267 * Create a file that is fully initialized. Use for indexing resources. 268 * Internal use only. 269 * @since 4.2 270 */ 271 public static File create(String relativePathFromBasedir, String relativePathFromSourceDir, Language language, boolean unitTest) { 272 File file = create(relativePathFromBasedir); 273 file.setLanguage(language); 274 if (relativePathFromSourceDir.contains(Directory.SEPARATOR)) { 275 file.filename = StringUtils.substringAfterLast(relativePathFromSourceDir, Directory.SEPARATOR); 276 file.directoryDeprecatedKey = Directory.parseKey(StringUtils.substringBeforeLast(relativePathFromSourceDir, Directory.SEPARATOR)); 277 file.setDeprecatedKey(file.directoryDeprecatedKey + Directory.SEPARATOR + file.filename); 278 } else { 279 file.filename = relativePathFromSourceDir; 280 file.directoryDeprecatedKey = Directory.ROOT; 281 file.setDeprecatedKey(file.filename); 282 } 283 if (unitTest) { 284 file.setQualifier(Qualifiers.UNIT_TEST_FILE); 285 } 286 file.parent.setDeprecatedKey(file.directoryDeprecatedKey); 287 return file; 288 } 289 290 @Override 291 public String toString() { 292 return new ToStringBuilder(this) 293 .append("key", getKey()) 294 .append("deprecatedKey", getDeprecatedKey()) 295 .append("path", getPath()) 296 .append("dir", directoryDeprecatedKey) 297 .append("filename", filename) 298 .append("language", language) 299 .toString(); 300 } 301 }