001/* 002 * Copyright 2002-2012 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.instrument.classloading; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.net.URL; 022import java.util.Enumeration; 023import java.util.HashMap; 024import java.util.Map; 025 026import org.springframework.util.Assert; 027 028/** 029 * Subclass of ShadowingClassLoader that overrides attempts to 030 * locate certain files. 031 * 032 * @author Rod Johnson 033 * @author Adrian Colyer 034 * @since 2.0 035 */ 036public class ResourceOverridingShadowingClassLoader extends ShadowingClassLoader { 037 038 private static final Enumeration<URL> EMPTY_URL_ENUMERATION = new Enumeration<URL>() { 039 @Override 040 public boolean hasMoreElements() { 041 return false; 042 } 043 @Override 044 public URL nextElement() { 045 throw new UnsupportedOperationException("Should not be called. I am empty."); 046 } 047 }; 048 049 050 /** 051 * Key is asked for value: value is actual value 052 */ 053 private Map<String, String> overrides = new HashMap<String, String>(); 054 055 056 /** 057 * Create a new ResourceOverridingShadowingClassLoader, 058 * decorating the given ClassLoader. 059 * @param enclosingClassLoader the ClassLoader to decorate 060 */ 061 public ResourceOverridingShadowingClassLoader(ClassLoader enclosingClassLoader) { 062 super(enclosingClassLoader); 063 } 064 065 066 /** 067 * Return the resource (if any) at the new path 068 * on an attempt to locate a resource at the old path. 069 * @param oldPath the path requested 070 * @param newPath the actual path to be looked up 071 */ 072 public void override(String oldPath, String newPath) { 073 this.overrides.put(oldPath, newPath); 074 } 075 076 /** 077 * Ensure that a resource with the given path is not found. 078 * @param oldPath the path of the resource to hide even if 079 * it exists in the parent ClassLoader 080 */ 081 public void suppress(String oldPath) { 082 this.overrides.put(oldPath, null); 083 } 084 085 /** 086 * Copy all overrides from the given ClassLoader. 087 * @param other the other ClassLoader to copy from 088 */ 089 public void copyOverrides(ResourceOverridingShadowingClassLoader other) { 090 Assert.notNull(other, "Other ClassLoader must not be null"); 091 this.overrides.putAll(other.overrides); 092 } 093 094 095 @Override 096 public URL getResource(String requestedPath) { 097 if (this.overrides.containsKey(requestedPath)) { 098 String overriddenPath = this.overrides.get(requestedPath); 099 return (overriddenPath != null ? super.getResource(overriddenPath) : null); 100 } 101 else { 102 return super.getResource(requestedPath); 103 } 104 } 105 106 @Override 107 public InputStream getResourceAsStream(String requestedPath) { 108 if (this.overrides.containsKey(requestedPath)) { 109 String overriddenPath = this.overrides.get(requestedPath); 110 return (overriddenPath != null ? super.getResourceAsStream(overriddenPath) : null); 111 } 112 else { 113 return super.getResourceAsStream(requestedPath); 114 } 115 } 116 117 @Override 118 public Enumeration<URL> getResources(String requestedPath) throws IOException { 119 if (this.overrides.containsKey(requestedPath)) { 120 String overriddenLocation = this.overrides.get(requestedPath); 121 return (overriddenLocation != null ? 122 super.getResources(overriddenLocation) : EMPTY_URL_ENUMERATION); 123 } 124 else { 125 return super.getResources(requestedPath); 126 } 127 } 128 129}