001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.io; 018 019import java.net.MalformedURLException; 020import java.net.URL; 021import java.util.Collection; 022import java.util.LinkedHashSet; 023import java.util.Set; 024 025import org.springframework.util.Assert; 026import org.springframework.util.ClassUtils; 027import org.springframework.util.StringUtils; 028 029/** 030 * Default implementation of the {@link ResourceLoader} interface. 031 * Used by {@link ResourceEditor}, and serves as base class for 032 * {@link org.springframework.context.support.AbstractApplicationContext}. 033 * Can also be used standalone. 034 * 035 * <p>Will return a {@link UrlResource} if the location value is a URL, 036 * and a {@link ClassPathResource} if it is a non-URL path or a 037 * "classpath:" pseudo-URL. 038 * 039 * @author Juergen Hoeller 040 * @since 10.03.2004 041 * @see FileSystemResourceLoader 042 * @see org.springframework.context.support.ClassPathXmlApplicationContext 043 */ 044public class DefaultResourceLoader implements ResourceLoader { 045 046 private ClassLoader classLoader; 047 048 private final Set<ProtocolResolver> protocolResolvers = new LinkedHashSet<ProtocolResolver>(4); 049 050 051 /** 052 * Create a new DefaultResourceLoader. 053 * <p>ClassLoader access will happen using the thread context class loader 054 * at the time of this ResourceLoader's initialization. 055 * @see java.lang.Thread#getContextClassLoader() 056 */ 057 public DefaultResourceLoader() { 058 this.classLoader = ClassUtils.getDefaultClassLoader(); 059 } 060 061 /** 062 * Create a new DefaultResourceLoader. 063 * @param classLoader the ClassLoader to load class path resources with, or {@code null} 064 * for using the thread context class loader at the time of actual resource access 065 */ 066 public DefaultResourceLoader(ClassLoader classLoader) { 067 this.classLoader = classLoader; 068 } 069 070 071 /** 072 * Specify the ClassLoader to load class path resources with, or {@code null} 073 * for using the thread context class loader at the time of actual resource access. 074 * <p>The default is that ClassLoader access will happen using the thread context 075 * class loader at the time of this ResourceLoader's initialization. 076 */ 077 public void setClassLoader(ClassLoader classLoader) { 078 this.classLoader = classLoader; 079 } 080 081 /** 082 * Return the ClassLoader to load class path resources with. 083 * <p>Will get passed to ClassPathResource's constructor for all 084 * ClassPathResource objects created by this resource loader. 085 * @see ClassPathResource 086 */ 087 @Override 088 public ClassLoader getClassLoader() { 089 return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader()); 090 } 091 092 /** 093 * Register the given resolver with this resource loader, allowing for 094 * additional protocols to be handled. 095 * <p>Any such resolver will be invoked ahead of this loader's standard 096 * resolution rules. It may therefore also override any default rules. 097 * @since 4.3 098 * @see #getProtocolResolvers() 099 */ 100 public void addProtocolResolver(ProtocolResolver resolver) { 101 Assert.notNull(resolver, "ProtocolResolver must not be null"); 102 this.protocolResolvers.add(resolver); 103 } 104 105 /** 106 * Return the collection of currently registered protocol resolvers, 107 * allowing for introspection as well as modification. 108 * @since 4.3 109 */ 110 public Collection<ProtocolResolver> getProtocolResolvers() { 111 return this.protocolResolvers; 112 } 113 114 115 @Override 116 public Resource getResource(String location) { 117 Assert.notNull(location, "Location must not be null"); 118 119 for (ProtocolResolver protocolResolver : this.protocolResolvers) { 120 Resource resource = protocolResolver.resolve(location, this); 121 if (resource != null) { 122 return resource; 123 } 124 } 125 126 if (location.startsWith("/")) { 127 return getResourceByPath(location); 128 } 129 else if (location.startsWith(CLASSPATH_URL_PREFIX)) { 130 return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); 131 } 132 else { 133 try { 134 // Try to parse the location as a URL... 135 URL url = new URL(location); 136 return new UrlResource(url); 137 } 138 catch (MalformedURLException ex) { 139 // No URL -> resolve as resource path. 140 return getResourceByPath(location); 141 } 142 } 143 } 144 145 /** 146 * Return a Resource handle for the resource at the given path. 147 * <p>The default implementation supports class path locations. This should 148 * be appropriate for standalone implementations but can be overridden, 149 * e.g. for implementations targeted at a Servlet container. 150 * @param path the path to the resource 151 * @return the corresponding Resource handle 152 * @see ClassPathResource 153 * @see org.springframework.context.support.FileSystemXmlApplicationContext#getResourceByPath 154 * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath 155 */ 156 protected Resource getResourceByPath(String path) { 157 return new ClassPathContextResource(path, getClassLoader()); 158 } 159 160 161 /** 162 * ClassPathResource that explicitly expresses a context-relative path 163 * through implementing the ContextResource interface. 164 */ 165 protected static class ClassPathContextResource extends ClassPathResource implements ContextResource { 166 167 public ClassPathContextResource(String path, ClassLoader classLoader) { 168 super(path, classLoader); 169 } 170 171 @Override 172 public String getPathWithinContext() { 173 return getPath(); 174 } 175 176 @Override 177 public Resource createRelative(String relativePath) { 178 String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath); 179 return new ClassPathContextResource(pathToUse, getClassLoader()); 180 } 181 } 182 183}