1 /*
2 * Copyright 2011-2020 Amazon Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
11 * OR CONDITIONS OF ANY KIND, either express or implied. See the
12 * License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package com.amazonaws.util;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.URL;
20
21 public enum ClassLoaderHelper {
22 ;
23 /**
24 * Retrieves the resource via the context class loader of the current
25 * thread, and if not found, via the class loaders of the optionally
26 * specified classes in the order of their specification, and if not
27 * found, from the class loader of {@link ClassLoaderHelper} as the last
28 * resort.
29 *
30 * @param resource
31 * resource to be loaded
32 * @param classes class loader providers
33 * @return the resource loaded as an URL or null if not found.
34 */
35 public static URL getResource(String resource, Class<?> ... classes) {
36 return getResource(resource, false, classes);
37 }
38
39 /**
40 * If classesFirst is false, retrieves the resource via the context class
41 * loader of the current thread, and if not found, via the class loaders of
42 * the optionally specified classes in the order of their specification, and
43 * if not found, from the class loader of {@link ClassLoaderHelper} as the
44 * last resort.
45 * <p>
46 * If classesFirst is true, retrieves the resource via the optionally
47 * specified classes in the order of their specification, and if not found,
48 * via the context class loader of the current thread, and if not found,
49 * from the class loader of {@link ClassLoaderHelper} as the last resort.
50 *
51 * @param resource
52 * resource to be loaded
53 * @param classesFirst
54 * true if the class loaders of the optionally specified classes
55 * take precedence over the context class loader of the current
56 * thread; false if the opposite is true.
57 * @param classes
58 * class loader providers
59 * @return the resource loaded as an URL or null if not found.
60 */
61 public static URL getResource(String resource, boolean classesFirst,
62 Class<?>... classes) {
63 URL url;
64 if (classesFirst) {
65 url = getResourceViaClasses(resource, classes);
66 if (url == null) {
67 url = getResourceViaContext(resource);
68 }
69 } else {
70 url = getResourceViaContext(resource);
71 if (url == null) {
72 url = getResourceViaClasses(resource, classes);
73 }
74 }
75 return url == null ? ClassLoaderHelper.class.getResource(resource) : url;
76 }
77
78 private static URL getResourceViaClasses(String resource, Class<?>[] classes) {
79 if (classes != null) {
80 for (Class<?> c: classes) {
81 URL url = c.getResource(resource);
82 if (url != null)
83 return url;
84 }
85 }
86 return null;
87 }
88
89 private static URL getResourceViaContext(String resource) {
90 ClassLoader loader = Thread.currentThread().getContextClassLoader();
91 return loader == null ? null : loader.getResource(resource);
92 }
93
94 private static Class<?> loadClassViaClasses(String fqcn, Class<?>[] classes) {
95 if (classes != null) {
96 for (Class<?> c: classes) {
97 ClassLoader loader = c.getClassLoader();
98 if (loader != null) {
99 try {
100 return loader.loadClass(fqcn);
101 } catch (ClassNotFoundException e) {
102 // move on to try the next class loader
103 }
104 }
105 }
106 }
107 return null;
108 }
109
110 private static Class<?> loadClassViaContext(String fqcn) {
111 ClassLoader loader = Thread.currentThread().getContextClassLoader();
112 try {
113 return loader == null ? null : loader.loadClass(fqcn);
114 } catch (ClassNotFoundException e) {
115 }
116 return null;
117 }
118
119 /**
120 * Loads the class via the optionally specified classes in the order of
121 * their specification, and if not found, via the context class loader of
122 * the current thread, and if not found, from the caller class loader as the
123 * last resort.
124 *
125 * @param fqcn
126 * fully qualified class name of the target class to be loaded
127 * @param classes
128 * class loader providers
129 * @return the class loaded; never null
130 *
131 * @throws ClassNotFoundException
132 * if failed to load the class
133 */
134 public static Class<?> loadClass(String fqcn, Class<?>... classes)
135 throws ClassNotFoundException {
136 return loadClass(fqcn, true, classes);
137 }
138
139 /**
140 * If classesFirst is false, loads the class via the context class
141 * loader of the current thread, and if not found, via the class loaders of
142 * the optionally specified classes in the order of their specification, and
143 * if not found, from the caller class loader as the
144 * last resort.
145 * <p>
146 * If classesFirst is true, loads the class via the optionally
147 * specified classes in the order of their specification, and if not found,
148 * via the context class loader of the current thread, and if not found,
149 * from the caller class loader as the last resort.
150 *
151 * @param fqcn
152 * fully qualified class name of the target class to be loaded
153 * @param classesFirst
154 * true if the class loaders of the optionally specified classes
155 * take precedence over the context class loader of the current
156 * thread; false if the opposite is true.
157 * @param classes
158 * class loader providers
159 * @return the class loaded; never null
160 *
161 * @throws ClassNotFoundException if failed to load the class
162 */
163 public static Class<?> loadClass(String fqcn, boolean classesFirst,
164 Class<?>... classes) throws ClassNotFoundException {
165 Class<?> target = null;
166 if (classesFirst) {
167 target = loadClassViaClasses(fqcn, classes);
168 if (target == null) {
169 target = loadClassViaContext(fqcn);
170 }
171 } else {
172 target = loadClassViaContext(fqcn);
173 if (target == null) {
174 target = loadClassViaClasses(fqcn, classes);
175 }
176 }
177 return target == null ? Class.forName(fqcn) : target;
178 }
179
180 /**
181 * Retrieves the resource as an input stream via
182 * the context class loader of the current thread, and if not found, via the
183 * class loaders of the optionally specified classes in the order of their
184 * specification, and if not found, from the class loader of
185 * {@link ClassLoaderHelper} as the last resort.
186 *
187 * @param resource
188 * resource to be loaded
189 * @param classes
190 * class loader providers
191 * @return the resource loaded as an input stream or null if not found.
192 */
193 public static InputStream getResourceAsStream(String resource,
194 Class<?>... classes) {
195 return getResourceAsStream(resource, false, classes);
196 }
197
198 /**
199 * If classesFirst is false, retrieves the resource as an input stream via
200 * the context class loader of the current thread, and if not found, via the
201 * class loaders of the optionally specified classes in the order of their
202 * specification, and if not found, from the class loader of
203 * {@link ClassLoaderHelper} as the last resort.
204 * <p>
205 * If classesFirst is true, retrieves the resource as an input stream via
206 * the optionally specified classes in the order of their specification, and
207 * if not found, via the context class loader of the current thread, and if
208 * not found, from the class loader of {@link ClassLoaderHelper} as the last
209 * resort.
210 *
211 * @param resource
212 * resource to be loaded
213 * @param classesFirst
214 * true if the class loaders of the optionally specified classes
215 * take precedence over the context class loader of the current
216 * thread; false if the opposite is true.
217 * @param classes
218 * class loader providers
219 * @return the resource loaded as an input stream or null if not found.
220 */
221 public static InputStream getResourceAsStream(String resource,
222 boolean classesFirst, Class<?>... classes) {
223 URL url = getResource(resource, classesFirst, classes);
224 try {
225 return url != null ? url.openStream() : null;
226 } catch (IOException e) {
227 return null;
228 }
229 }
230 }
231