在上面一篇文章 中我们提到了目录结构检查器,现在我们就做下一步动作了,用于检查放置在这些目录下的文件是否有合法的扩展名。
需求:
假定我们已经有了一个合法的目录结构,我们必须检查放置这些目录下文件的扩展名。
(1) js目录下的文件必须以.js扩展名结尾,css目录下的文件必须以.css扩展名结尾,p_w_picpath目录下的文件必须以jpg,png,gif等等结尾
(2)这些扩展名都是写在.properties文件中而且是可配置的
(3)这些扩展名都是忽略大小写的,比如a.PNG和a.png都是可以的。
(4)根目录固定,css/js/p_w_picpath,但是他们可以有任意层次结构的子目录,只要最终的文件扩展名合法就可以,比如css子目录下可以有 mycss子目录,然后mycss子目录下在有abc.css,这样是合法的。
实现:
- /**
- * This class will be responsible for checking the file/folder extension setting
- * based on the valid file extension list
- *
- * @author cwang58
- * @created date: Aug 3, 2012
- */
- public class FileExtensionChecker implements IFileExtensionChecker {
- private final Logger logger = LoggerFactory
- .getLogger(FileExtensionChecker.class);
- private static ConfigureUtility configureUtility;
- private List<String> validHtmlFileExtensionList = new ArrayList<String>();
- private List<String> validJsFileExtensionList = new ArrayList<String>();
- private List<String> validCssFileExtensionList = new ArrayList<String>();
- private List<String> validImageFileExtensionList = new ArrayList<String>();
- public FileExtensionChecker() throws Exception {
- configureUtility = ConfigureUtility.getInstance();
- try {
- setFileExtension(validHtmlFileExtensionList,
- configureUtility.getProperty(VALID_HTML_FILE_EXTENSION));
- setFileExtension(validJsFileExtensionList,
- configureUtility.getProperty(VALID_JS_FILE_EXTENSION));
- setFileExtension(validCssFileExtensionList,
- configureUtility.getProperty(VALID_CSS_FILE_EXTENSION));
- setFileExtension(validImageFileExtensionList,
- configureUtility.getProperty(VALID_IMAGE_FILE_EXTENSION));
- } catch (Exception ex) {
- if (logger.isErrorEnabled()) {
- logger.error("fail when parsing the file extension configuration file");
- }
- throw new ConfigureSystemException(CONFIGURATION_ERROR, ex);
- }
- }
- /**
- * to check whether the files has correct extensions ,the logic is as
- * follows:
- *
- * (1) check whether the target folderPath is a folder (2) Invoke the
- * FolderStructureCheck's checkFolderStructure method to see whether this
- * folder has the correct folder structure (3) check root directory to see
- * whether there are only html files (4) traverse all the top sub folder
- * {css/js/p_w_picpath} ,go to the leaf nodes ,to see whether the file extension
- * matches
- *
- * Actually, all the major task of this method is to pass parameter to
- * checkFileExtensionWithPath method
- *
- * @param pathString
- * the string of the folder path
- * @throws Exception
- */
- public void checkFileExtensions(String pathString) throws Exception {
- // TODO Auto-generated method stub
- File path = new File(pathString);
- // if path doesn't exist ,return false
- if (path == null || !path.exists()) {
- if (logger.isErrorEnabled()) {
- logger.error("the path doesn't exist");
- }
- throw new ParameterNullException(FILE_EXTN_ERROR);
- }
- // if path is a file ,that's not what we expected ,we just expect that
- // it is a folder
- if (path.isFile()) {
- if (logger.isErrorEnabled()) {
- logger.error("the path should not be a file");
- }
- throw new ParameterInvalidException(FILE_EXTN_ERROR);
- }
- // now the path is a directory, we check the folder structure
- FolderStructureChecker fsc = new FolderStructureChecker();
- try {
- fsc.checkFolderStructure(pathString);
- } catch (Exception ex) {
- if (logger.isErrorEnabled()) {
- logger.error("this path don't have valid folder structure ,skip the file extension check");
- }
- throw new InvalidFileExtensionException(FILE_EXTN_ERROR, ex);
- }
- // now the path has valid folder structure,we can check it one by one
- boolean checkResult = true;
- for (File file : path.listFiles()) {
- // if the file is a file ,since only html file is allowed here ,so
- // we use html rule to check it
- if (file.isFile())
- checkResult = checkResult
- && checkFileExtensionsWithPath(file,
- getValidHtmlFileExtensionList());
- // if the file is a directory, since only supports "css"
- // "js","p_w_picpath" ,so we check one by one
- else {
- if (file.getName().trim().equals(fsc.getCssFolderName().trim()))
- checkResult = checkResult
- && checkFileExtensionsWithPath(file,
- getValidCssFileExtensionList());
- else if (file.getName().trim()
- .equals(fsc.getJavascriptFolderName().trim()))
- checkResult = checkResult
- && checkFileExtensionsWithPath(file,
- getValidJsFileExtensionList());
- else if (file.getName().trim()
- .equals(fsc.getImageFolderName().trim()))
- checkResult = checkResult
- && checkFileExtensionsWithPath(file,
- getValidImageFileExtensionList());
- }
- }
- if (checkResult == false) {
- throw new InvalidFileExtensionException(FILE_EXTN_ERROR);
- }
- }
- /**
- * this method will recursively check the subfolders util it reaches the end
- * file the recursive rule is as follows:
- *
- * If the path is file ,then check the file's extension with the valid file
- * extension list If the path is a folder ,then recursively traverse all the
- * sub files inside this folder
- *
- * @param path
- * the path of the folder
- * @param fileExtensionList
- * the list of all valid file extensions
- * @return whether the check is correct or has invalid file extensions
- */
- public boolean checkFileExtensionsWithPath(File path,
- List<String> fileExtensionList) {
- // if the fileExtensionList is null ,which means no file extension can
- // be checked ,returns false
- if (fileExtensionList == null || fileExtensionList.size() == 0) {
- if (logger.isErrorEnabled()) {
- logger.error("the file extension check list can't be null");
- }
- return false;
- }
- // if path doesn't exist ,return false
- if (path == null || !path.exists()) {
- if (logger.isErrorEnabled()) {
- logger.error("the path doesn't exist");
- }
- return false;
- }
- // if the path is a file ,
- // then check whether this file's file name matches the
- // fileExtensionList provided by the second param
- if (path.isFile()) {
- if (logger.isDebugEnabled()) {
- logger.debug("this path is a file");
- }
- // retrieve the filename
- String fileName = path.getName();
- System.out.println("fileName: " + fileName);
- // retrieve the file extension
- // if fileName don't have dot(.), which means this file has no file
- // extension
- if (fileName.indexOf(DOT) == -1) {
- if (logger.isErrorEnabled()) {
- logger.error("This file has no extension");
- }
- return false;
- }
- // otherwise ,get the file extension from the file name
- String fileExtension = fileName.substring(
- fileName.indexOf(".") + 1, fileName.length());
- if (fileExtensionList.contains(fileExtension.toLowerCase())) {
- if (logger.isDebugEnabled()) {
- logger.debug("This file matches file extension list");
- }
- return true;
- } else {
- if (logger.isErrorEnabled()) {
- logger.error("This file doesn't match the file extension");
- }
- return false;
- }
- }
- // other wise, this file is a folder ,then traverse all the sub folders
- // and files in it,recursively
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("this path is a folder");
- }
- boolean result = true;
- for (File file : path.listFiles()) {
- result = result
- && checkFileExtensionsWithPath(file, fileExtensionList);
- }
- return result;
- }
- }
- /**
- * this method can convert the comma seperated file extension string to a
- * List object
- *
- * @param fileExtensionList
- * the list which stores all the file extensions
- * @param fileExtensionCommaSeparated
- * the comma separated string ,which put every file extension
- * into this string ,and separate by comma
- */
- public void setFileExtension(List<String> fileExtensionList,
- String fileExtensionCommaSeparated) {
- String[] fileExtensions = fileExtensionCommaSeparated.split(COMMA);
- for (String fileExtension : fileExtensions) {
- fileExtensionList.add(fileExtension.trim());
- }
- }
- public List<String> getValidHtmlFileExtensionList() {
- return validHtmlFileExtensionList;
- }
- public List<String> getValidJsFileExtensionList() {
- return validJsFileExtensionList;
- }
- public List<String> getValidCssFileExtensionList() {
- return validCssFileExtensionList;
- }
- public List<String> getValidImageFileExtensionList() {
- return validImageFileExtensionList;
- }
- }
这个类也很长很长,我们依次来分析:
(1)从477-509行定义了一个辅助方法叫setFileExtension,它有2个参数,第一个参数是扩展名数组,第二个参数是扩展名字符串,它的职责是吧第二个参数的以逗号","分开的扩展名字符串转为第一个参数的扩展名数组,比如说对于图像有好几种扩展名,所以第二个参数为 "jpg,png,gif,tiff",那么通过这个辅助方法,则最终存入第一个参数的扩展名字符串为 {"jpg","png","gif","tiff"}
(2)第39-89行的构造器解决了如何灵活的初始化扩展名检查器的问题。因为允许的扩展名列表都被配置在了属性文件中,所以我们用ConfigureUtility去读取这些属性文件,并且将读来的扩展名字符串用刚才提到的setFileExtension方法正确的转为扩展名数组,然后初始化。
(3)第281-第473行定义了一个递归方法checkFileExtensionsWithPath,它有2个参数,参数1为子目录,参数2为允许扩展名数组,所以它会去检查参数1的子目录下所有文件的扩展名都在参数2数组中。这是一个递归的检查。首先从319-349对入参进行了非空检查。然后第353-437行对于参数1是个文件的情况进行了检查。其中第383-399中排除了某些不含扩展名的文件,因为假定所有的文件都必须含有扩展名(当然了,UNIX系统中经常有没有扩展名的文件,但是这在我们的讨论范畴之外),第403-437行则是从参数1中提取扩展名字符串,然后去判断这个扩展名字符串是否被包含在参数2中声明的扩展名数组中。第441-473行则是对于参数1是个目录的情况进行了检查,因为是目录,所以它会列出这个目录下的所有的文件或目录,然后递归的调用checkFileExtensionsWithPath方法,直到得出结果。
(4)第93-277行的方法checkFileExtensions则是对(3)中的checkFileExtensionsWithPath进行了多次调用。因为我们知道了跟目录的直接子目录只有3个(css,js,p_w_picpath),而且我们在(2)中也从属性文件中获取并初始化了每种情况下的合法扩展名字符串数组,所以我们需要的就是构造多个检查条件,然后调用(3)的方法,最后把这些检查的结果做逻辑与运算,见235-260行,把最终元素结果最为最后的检查结果,很一目了然。