1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/**
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance
12 * with the License. You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
21 * under the License.
22 */
23
24package com.sun.org.apache.xml.internal.security.utils;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.net.URL;
29import java.util.ArrayList;
30import java.util.Enumeration;
31import java.util.List;
32
33/**
34 * This class is extremely useful for loading resources and classes in a fault
35 * tolerant manner that works across different applications servers. Do not
36 * touch this unless you're a grizzled classloading guru veteran who is going to
37 * verify any change on 6 different application servers.
38 */
39final class ClassLoaderUtils {
40
41    /** {@link org.apache.commons.logging} logging facility */
42    private static final java.util.logging.Logger log =
43        java.util.logging.Logger.getLogger(ClassLoaderUtils.class.getName());
44
45    private ClassLoaderUtils() {
46    }
47
48    /**
49     * Load a given resource. <p/> This method will try to load the resource
50     * using the following methods (in order):
51     * <ul>
52     * <li>From Thread.currentThread().getContextClassLoader()
53     * <li>From ClassLoaderUtil.class.getClassLoader()
54     * <li>callingClass.getClassLoader()
55     * </ul>
56     *
57     * @param resourceName The name of the resource to load
58     * @param callingClass The Class object of the calling object
59     */
60    static URL getResource(String resourceName, Class<?> callingClass) {
61        URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
62        if (url == null && resourceName.startsWith("/")) {
63            //certain classloaders need it without the leading /
64            url =
65                Thread.currentThread().getContextClassLoader().getResource(
66                    resourceName.substring(1)
67                );
68        }
69
70        ClassLoader cluClassloader = ClassLoaderUtils.class.getClassLoader();
71        if (cluClassloader == null) {
72            cluClassloader = ClassLoader.getSystemClassLoader();
73        }
74        if (url == null) {
75            url = cluClassloader.getResource(resourceName);
76        }
77        if (url == null && resourceName.startsWith("/")) {
78            //certain classloaders need it without the leading /
79            url = cluClassloader.getResource(resourceName.substring(1));
80        }
81
82        if (url == null) {
83            ClassLoader cl = callingClass.getClassLoader();
84
85            if (cl != null) {
86                url = cl.getResource(resourceName);
87            }
88        }
89
90        if (url == null) {
91            url = callingClass.getResource(resourceName);
92        }
93
94        if ((url == null) && (resourceName != null) && (resourceName.charAt(0) != '/')) {
95            return getResource('/' + resourceName, callingClass);
96        }
97
98        return url;
99    }
100
101    /**
102     * Load a given resources. <p/> This method will try to load the resources
103     * using the following methods (in order):
104     * <ul>
105     * <li>From Thread.currentThread().getContextClassLoader()
106     * <li>From ClassLoaderUtil.class.getClassLoader()
107     * <li>callingClass.getClassLoader()
108     * </ul>
109     *
110     * @param resourceName The name of the resource to load
111     * @param callingClass The Class object of the calling object
112     */
113    static List<URL> getResources(String resourceName, Class<?> callingClass) {
114        List<URL> ret = new ArrayList<URL>();
115        Enumeration<URL> urls = new Enumeration<URL>() {
116            public boolean hasMoreElements() {
117                return false;
118            }
119            public URL nextElement() {
120                return null;
121            }
122
123        };
124        try {
125            urls = Thread.currentThread().getContextClassLoader().getResources(resourceName);
126        } catch (IOException e) {
127            if (log.isLoggable(java.util.logging.Level.FINE)) {
128                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
129            }
130            //ignore
131        }
132        if (!urls.hasMoreElements() && resourceName.startsWith("/")) {
133            //certain classloaders need it without the leading /
134            try {
135                urls =
136                    Thread.currentThread().getContextClassLoader().getResources(
137                        resourceName.substring(1)
138                    );
139            } catch (IOException e) {
140                if (log.isLoggable(java.util.logging.Level.FINE)) {
141                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
142                }
143                // ignore
144            }
145        }
146
147        ClassLoader cluClassloader = ClassLoaderUtils.class.getClassLoader();
148        if (cluClassloader == null) {
149            cluClassloader = ClassLoader.getSystemClassLoader();
150        }
151        if (!urls.hasMoreElements()) {
152            try {
153                urls = cluClassloader.getResources(resourceName);
154            } catch (IOException e) {
155                if (log.isLoggable(java.util.logging.Level.FINE)) {
156                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
157                }
158                // ignore
159            }
160        }
161        if (!urls.hasMoreElements() && resourceName.startsWith("/")) {
162            //certain classloaders need it without the leading /
163            try {
164                urls = cluClassloader.getResources(resourceName.substring(1));
165            } catch (IOException e) {
166                if (log.isLoggable(java.util.logging.Level.FINE)) {
167                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
168                }
169                // ignore
170            }
171        }
172
173        if (!urls.hasMoreElements()) {
174            ClassLoader cl = callingClass.getClassLoader();
175
176            if (cl != null) {
177                try {
178                    urls = cl.getResources(resourceName);
179                } catch (IOException e) {
180                    if (log.isLoggable(java.util.logging.Level.FINE)) {
181                        log.log(java.util.logging.Level.FINE, e.getMessage(), e);
182                    }
183                    // ignore
184                }
185            }
186        }
187
188        if (!urls.hasMoreElements()) {
189            URL url = callingClass.getResource(resourceName);
190            if (url != null) {
191                ret.add(url);
192            }
193        }
194        while (urls.hasMoreElements()) {
195            ret.add(urls.nextElement());
196        }
197
198
199        if (ret.isEmpty() && (resourceName != null) && (resourceName.charAt(0) != '/')) {
200            return getResources('/' + resourceName, callingClass);
201        }
202        return ret;
203    }
204
205
206    /**
207     * This is a convenience method to load a resource as a stream. <p/> The
208     * algorithm used to find the resource is given in getResource()
209     *
210     * @param resourceName The name of the resource to load
211     * @param callingClass The Class object of the calling object
212     */
213    static InputStream getResourceAsStream(String resourceName, Class<?> callingClass) {
214        URL url = getResource(resourceName, callingClass);
215
216        try {
217            return (url != null) ? url.openStream() : null;
218        } catch (IOException e) {
219            if (log.isLoggable(java.util.logging.Level.FINE)) {
220                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
221            }
222            return null;
223        }
224    }
225
226    /**
227     * Load a class with a given name. <p/> It will try to load the class in the
228     * following order:
229     * <ul>
230     * <li>From Thread.currentThread().getContextClassLoader()
231     * <li>Using the basic Class.forName()
232     * <li>From ClassLoaderUtil.class.getClassLoader()
233     * <li>From the callingClass.getClassLoader()
234     * </ul>
235     *
236     * @param className The name of the class to load
237     * @param callingClass The Class object of the calling object
238     * @throws ClassNotFoundException If the class cannot be found anywhere.
239     */
240    static Class<?> loadClass(String className, Class<?> callingClass)
241        throws ClassNotFoundException {
242        try {
243            ClassLoader cl = Thread.currentThread().getContextClassLoader();
244
245            if (cl != null) {
246                return cl.loadClass(className);
247            }
248        } catch (ClassNotFoundException e) {
249            if (log.isLoggable(java.util.logging.Level.FINE)) {
250                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
251            }
252            //ignore
253        }
254        return loadClass2(className, callingClass);
255    }
256
257    private static Class<?> loadClass2(String className, Class<?> callingClass)
258        throws ClassNotFoundException {
259        try {
260            return Class.forName(className);
261        } catch (ClassNotFoundException ex) {
262            try {
263                if (ClassLoaderUtils.class.getClassLoader() != null) {
264                    return ClassLoaderUtils.class.getClassLoader().loadClass(className);
265                }
266            } catch (ClassNotFoundException exc) {
267                if (callingClass != null && callingClass.getClassLoader() != null) {
268                    return callingClass.getClassLoader().loadClass(className);
269                }
270            }
271            if (log.isLoggable(java.util.logging.Level.FINE)) {
272                log.log(java.util.logging.Level.FINE, ex.getMessage(), ex);
273            }
274            throw ex;
275        }
276    }
277}
278