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.transforms;
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 */
39// NOTE! This is a duplicate of utils.ClassLoaderUtils with public
40// modifiers changed to package-private. Make sure to integrate any future
41// changes to utils.ClassLoaderUtils to this file.
42final class ClassLoaderUtils {
43
44    /** {@link org.apache.commons.logging} logging facility */
45    private static final java.util.logging.Logger log =
46        java.util.logging.Logger.getLogger(ClassLoaderUtils.class.getName());
47
48    private ClassLoaderUtils() {
49    }
50
51    /**
52     * Load a given resource. <p/> This method will try to load the resource
53     * using the following methods (in order):
54     * <ul>
55     * <li>From Thread.currentThread().getContextClassLoader()
56     * <li>From ClassLoaderUtil.class.getClassLoader()
57     * <li>callingClass.getClassLoader()
58     * </ul>
59     *
60     * @param resourceName The name of the resource to load
61     * @param callingClass The Class object of the calling object
62     */
63    static URL getResource(String resourceName, Class<?> callingClass) {
64        URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
65        if (url == null && resourceName.startsWith("/")) {
66            //certain classloaders need it without the leading /
67            url =
68                Thread.currentThread().getContextClassLoader().getResource(
69                    resourceName.substring(1)
70                );
71        }
72
73        ClassLoader cluClassloader = ClassLoaderUtils.class.getClassLoader();
74        if (cluClassloader == null) {
75            cluClassloader = ClassLoader.getSystemClassLoader();
76        }
77        if (url == null) {
78            url = cluClassloader.getResource(resourceName);
79        }
80        if (url == null && resourceName.startsWith("/")) {
81            //certain classloaders need it without the leading /
82            url = cluClassloader.getResource(resourceName.substring(1));
83        }
84
85        if (url == null) {
86            ClassLoader cl = callingClass.getClassLoader();
87
88            if (cl != null) {
89                url = cl.getResource(resourceName);
90            }
91        }
92
93        if (url == null) {
94            url = callingClass.getResource(resourceName);
95        }
96
97        if ((url == null) && (resourceName != null) && (resourceName.charAt(0) != '/')) {
98            return getResource('/' + resourceName, callingClass);
99        }
100
101        return url;
102    }
103
104    /**
105     * Load a given resources. <p/> This method will try to load the resources
106     * using the following methods (in order):
107     * <ul>
108     * <li>From Thread.currentThread().getContextClassLoader()
109     * <li>From ClassLoaderUtil.class.getClassLoader()
110     * <li>callingClass.getClassLoader()
111     * </ul>
112     *
113     * @param resourceName The name of the resource to load
114     * @param callingClass The Class object of the calling object
115     */
116    static List<URL> getResources(String resourceName, Class<?> callingClass) {
117        List<URL> ret = new ArrayList<URL>();
118        Enumeration<URL> urls = new Enumeration<URL>() {
119            public boolean hasMoreElements() {
120                return false;
121            }
122            public URL nextElement() {
123                return null;
124            }
125
126        };
127        try {
128            urls = Thread.currentThread().getContextClassLoader().getResources(resourceName);
129        } catch (IOException e) {
130            if (log.isLoggable(java.util.logging.Level.FINE)) {
131                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
132            }
133            //ignore
134        }
135        if (!urls.hasMoreElements() && resourceName.startsWith("/")) {
136            //certain classloaders need it without the leading /
137            try {
138                urls =
139                    Thread.currentThread().getContextClassLoader().getResources(
140                        resourceName.substring(1)
141                    );
142            } catch (IOException e) {
143                if (log.isLoggable(java.util.logging.Level.FINE)) {
144                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
145                }
146                // ignore
147            }
148        }
149
150        ClassLoader cluClassloader = ClassLoaderUtils.class.getClassLoader();
151        if (cluClassloader == null) {
152            cluClassloader = ClassLoader.getSystemClassLoader();
153        }
154        if (!urls.hasMoreElements()) {
155            try {
156                urls = cluClassloader.getResources(resourceName);
157            } catch (IOException e) {
158                if (log.isLoggable(java.util.logging.Level.FINE)) {
159                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
160                }
161                // ignore
162            }
163        }
164        if (!urls.hasMoreElements() && resourceName.startsWith("/")) {
165            //certain classloaders need it without the leading /
166            try {
167                urls = cluClassloader.getResources(resourceName.substring(1));
168            } catch (IOException e) {
169                if (log.isLoggable(java.util.logging.Level.FINE)) {
170                    log.log(java.util.logging.Level.FINE, e.getMessage(), e);
171                }
172                // ignore
173            }
174        }
175
176        if (!urls.hasMoreElements()) {
177            ClassLoader cl = callingClass.getClassLoader();
178
179            if (cl != null) {
180                try {
181                    urls = cl.getResources(resourceName);
182                } catch (IOException e) {
183                    if (log.isLoggable(java.util.logging.Level.FINE)) {
184                        log.log(java.util.logging.Level.FINE, e.getMessage(), e);
185                    }
186                    // ignore
187                }
188            }
189        }
190
191        if (!urls.hasMoreElements()) {
192            URL url = callingClass.getResource(resourceName);
193            if (url != null) {
194                ret.add(url);
195            }
196        }
197        while (urls.hasMoreElements()) {
198            ret.add(urls.nextElement());
199        }
200
201
202        if (ret.isEmpty() && (resourceName != null) && (resourceName.charAt(0) != '/')) {
203            return getResources('/' + resourceName, callingClass);
204        }
205        return ret;
206    }
207
208
209    /**
210     * This is a convenience method to load a resource as a stream. <p/> The
211     * algorithm used to find the resource is given in getResource()
212     *
213     * @param resourceName The name of the resource to load
214     * @param callingClass The Class object of the calling object
215     */
216    static InputStream getResourceAsStream(String resourceName, Class<?> callingClass) {
217        URL url = getResource(resourceName, callingClass);
218
219        try {
220            return (url != null) ? url.openStream() : null;
221        } catch (IOException e) {
222            if (log.isLoggable(java.util.logging.Level.FINE)) {
223                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
224            }
225            return null;
226        }
227    }
228
229    /**
230     * Load a class with a given name. <p/> It will try to load the class in the
231     * following order:
232     * <ul>
233     * <li>From Thread.currentThread().getContextClassLoader()
234     * <li>Using the basic Class.forName()
235     * <li>From ClassLoaderUtil.class.getClassLoader()
236     * <li>From the callingClass.getClassLoader()
237     * </ul>
238     *
239     * @param className The name of the class to load
240     * @param callingClass The Class object of the calling object
241     * @throws ClassNotFoundException If the class cannot be found anywhere.
242     */
243    static Class<?> loadClass(String className, Class<?> callingClass)
244        throws ClassNotFoundException {
245        try {
246            ClassLoader cl = Thread.currentThread().getContextClassLoader();
247
248            if (cl != null) {
249                return cl.loadClass(className);
250            }
251        } catch (ClassNotFoundException e) {
252            if (log.isLoggable(java.util.logging.Level.FINE)) {
253                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
254            }
255            //ignore
256        }
257        return loadClass2(className, callingClass);
258    }
259
260    private static Class<?> loadClass2(String className, Class<?> callingClass)
261        throws ClassNotFoundException {
262        try {
263            return Class.forName(className);
264        } catch (ClassNotFoundException ex) {
265            try {
266                if (ClassLoaderUtils.class.getClassLoader() != null) {
267                    return ClassLoaderUtils.class.getClassLoader().loadClass(className);
268                }
269            } catch (ClassNotFoundException exc) {
270                if (callingClass != null && callingClass.getClassLoader() != null) {
271                    return callingClass.getClassLoader().loadClass(className);
272                }
273            }
274            if (log.isLoggable(java.util.logging.Level.FINE)) {
275                log.log(java.util.logging.Level.FINE, ex.getMessage(), ex);
276            }
277            throw ex;
278        }
279    }
280}
281