/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.service.resource.loader; import static com.alibaba.citrus.service.resource.ResourceLoadingOption.*; import static com.alibaba.citrus.util.ArrayUtil.*; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.FileUtil.*; import static com.alibaba.citrus.util.StringUtil.*; import java.io.File; import java.net.URL; import java.util.Set; import com.alibaba.citrus.service.resource.Resource; import com.alibaba.citrus.service.resource.ResourceLister; import com.alibaba.citrus.service.resource.ResourceListerContext; import com.alibaba.citrus.service.resource.ResourceLoaderContext; import com.alibaba.citrus.service.resource.ResourceLoadingOption; import com.alibaba.citrus.service.resource.ResourceLoadingService; import com.alibaba.citrus.service.resource.ResourceMatchResult; import com.alibaba.citrus.service.resource.support.FileResource; import com.alibaba.citrus.util.ToStringBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 用来装载文件系统中的资源。 * * @author Michael Zhou */ public class FileResourceLoader implements ResourceLister { private final static Logger log = LoggerFactory.getLogger(FileResourceLoader.class); private String basedir; private String configFileBasedir; private SearchPath[] paths; /** * 取得basedir。 * <p> * 假如没有指定,则返回当前配置文件所在的目录(即file-loader配置所在的目录)。 * </p> */ public String getBasedir() { return basedir; } /** 设置basedir。 */ public void setBasedir(String basedir) { this.basedir = trimToNull(basedir); } /** * 取得用来配置当前file-loader的配置文件所在的目录。 * <p> * 这个目录将被用作默认的相对路径根目录。 * </p> * <p> * 假如配置文件并非直接从文件系统中取得,则返回<code>null</code>。 * </p> */ public String getConfigFileBasedir() { return configFileBasedir; } /** 设置file-loader所在的配置文件的URL。 */ public void setConfigFileURL(URL configFileURL) { if (configFileURL != null) { File configFile = null; try { configFile = new File(configFileURL.toURI()); } catch (Exception e) { // not a file: URL } if (configFile != null) { this.configFileBasedir = configFile.getParentFile().getAbsolutePath(); } } } public SearchPath[] getPaths() { return paths; } public void setPaths(SearchPath[] paths) { this.paths = paths; } /** 初始化loader,并设定loader所在的<code>ResourceLoadingService</code>的实例。 */ public void init(ResourceLoadingService resourceLoadingService) { // 设置basedir: // 1. 如果没有指定basedir,则将当前配置文件所在目录看做basedir // 2. 如果指定了相对路径的basedir,则相对于当前配置文件所在目录 // 3. 如果指定了绝对路径的basedir,则以此作为basedir // 最后,规格化basedir。 if (basedir == null) { basedir = configFileBasedir; } else { if (configFileBasedir != null) { basedir = getSystemDependentAbsolutePathBasedOn(configFileBasedir, basedir); } } basedir = trimToNull(normalizePath(basedir)); // 如果未指定path,则加入默认的path:/ if (isEmptyArray(paths)) { paths = new SearchPath[] { new SearchPath("/", true) }; } // 设置relative path的basedir for (SearchPath searchPath : paths) { searchPath.init(basedir); } } /** 查找文件资源。 */ public Resource getResource(ResourceLoaderContext context, Set<ResourceLoadingOption> options) { File file = find(context, options); if (file != null) { return new FileResource(file); } else { return null; } } /** 查找目录列表。 */ public String[] list(ResourceListerContext context, Set<ResourceLoadingOption> options) { File file = find(context, options); File[] files = file == null ? null : file.listFiles(); if (files != null) { String[] names = new String[files.length]; for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { names[i] = files[i].getName() + "/"; } else { names[i] = files[i].getName(); } } return names; } else { return null; } } /** 查找文件。 */ private File find(ResourceMatchResult context, Set<ResourceLoadingOption> options) { File file = null; log.trace("Searching for file {} in {} search-paths", context.getResourceName(), paths.length); for (SearchPath searchPath : paths) { File resourceFile = searchPath.getPath(context); if (log.isTraceEnabled()) { StringBuilder buf = new StringBuilder(); buf.append("Search in ").append(searchPath).append("\n"); buf.append(" Testing file: ").append(resourceFile.getAbsolutePath()); if (resourceFile.exists()) { buf.append(", file exists"); } else { buf.append(", file does not exist"); } log.trace(buf.toString()); } if (resourceFile.exists()) { file = resourceFile; break; } else { // 如果文件不存在,但指定了for_create参数,则返回第一个不存在的文件对象。 if (options != null && options.contains(FOR_CREATE)) { if (file == null) { file = resourceFile; } } } } return file; } @Override public String toString() { return new ToStringBuilder().append(getClass().getSimpleName()).append(paths).toString(); } /** * 代表一个搜索路径。 * <p> * 假如指定了basedir,则表示path为相对于basedir的路径;否则表示path为绝对路径。 * </p> */ public static class SearchPath { private final String path; private final boolean relative; private String basedir; public SearchPath(String path, boolean relative) { this.path = assertNotNull(trimToNull(normalizePath(path)), "path"); this.relative = relative; } public void init(String basedir) { if (relative) { this.basedir = assertNotNull(basedir, "Could not get basedir for search path: %s. " + "Please set basedir explictly at file-loader or use absolute path instead", this); } } /** 取得匹配的路径。 */ public File getPath(ResourceMatchResult context) { String realPath = context.substitute(path); if (basedir != null) { realPath = new File(basedir, realPath).getAbsolutePath(); } return new File(normalizePath(realPath)); } @Override public String toString() { StringBuilder buf = new StringBuilder(); if (relative) { buf.append("relpath=").append(path); buf.append(", basedir=").append(basedir); } else { buf.append("abspath=").append(path); } return buf.toString(); } } }