1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.discovery.jdk;
18
19 import java.io.IOException;
20 import java.net.URL;
21 import java.security.AccessController;
22 import java.security.PrivilegedAction;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 /**
31 * JDK 1.2 Style Hooks implementation.
32 */
33 public class JDK12Hooks extends JDKHooks {
34
35 /**
36 * Logger
37 */
38 private static Log log = LogFactory.getLog(JDK12Hooks.class);
39
40 private static final ClassLoader systemClassLoader = findSystemClassLoader();
41
42 /**
43 * Sets the {@code Log} for this class.
44 *
45 * @param _log This class {@code Log}
46 * @deprecated This method is not thread-safe
47 */
48 @Deprecated
49 public static void setLog(Log _log) {
50 log = _log;
51 }
52
53 /**
54 * {@inheritDoc}
55 */
56 @Override
57 public String getSystemProperty(final String propName) {
58 return AccessController.doPrivileged(new PrivilegedAction<String>() {
59 public String run() {
60 try {
61 return System.getProperty(propName);
62 } catch (SecurityException se){
63 return null;
64 }
65 }
66 });
67 }
68
69 /**
70 * {@inheritDoc}
71 */
72 @Override
73 public ClassLoader getThreadContextClassLoader() {
74 ClassLoader classLoader;
75
76 try {
77 classLoader = Thread.currentThread().getContextClassLoader();
78 } catch (SecurityException e) {
79 /*
80 * SecurityException is thrown when
81 * a) the context class loader isn't an ancestor of the
82 * calling class's class loader, or
83 * b) if security permissions are restricted.
84 *
85 * For (a), ignore and keep going. We cannot help but also
86 * ignore (b) with the logic below, but other calls elsewhere
87 * (to obtain a class loader) will re-trigger this exception
88 * where we can make a distinction.
89 */
90 classLoader = null; // ignore
91 }
92
93 // Return the selected class loader
94 return classLoader;
95 }
96
97 /**
98 * {@inheritDoc}
99 */
100 @Override
101 public ClassLoader getSystemClassLoader() {
102 return systemClassLoader;
103 }
104
105 /**
106 * {@inheritDoc}
107 */
108 @Override
109 public Enumeration<URL> getResources(ClassLoader loader, String resourceName) throws IOException {
110 /*
111 * The simple answer is/was:
112 * return loader.getResources(resourceName);
113 *
114 * However, some classloaders overload the behavior of getResource
115 * (loadClass, etc) such that the order of returned results changes
116 * from normally expected behavior.
117 *
118 * Example: locate classes/resources from child ClassLoaders first,
119 * parents last (in some J2EE environs).
120 *
121 * The resource returned by getResource() should be the same as the
122 * first resource returned by getResources(). Unfortunately, this
123 * is not, and cannot be: getResources() is 'final' in the current
124 * JDK's (1.2, 1.3, 1.4).
125 *
126 * To address this, the implementation of this method will
127 * return an Enumeration such that the first element is the
128 * results of getResource, and all trailing elements are
129 * from getResources. On each iteration, we check so see
130 * if the resource (from getResources) matches the first resource,
131 * and eliminate the redundent element.
132 */
133
134 final URL first = loader.getResource(resourceName);
135
136 // XXX: Trying to avoid JBoss UnifiedClassLoader problem
137
138 Enumeration<URL> resources;
139
140 if (first == null) {
141 if (log.isDebugEnabled()) {
142 log.debug("Could not find resource: " + resourceName);
143 }
144 List<URL> emptyURL = Collections.emptyList();
145 resources = Collections.enumeration(emptyURL);
146
147 } else {
148
149 try {
150
151 resources = loader.getResources(resourceName);
152
153 } catch (RuntimeException ex) {
154 log.error("Exception occured during attept to get " + resourceName
155 + " from " + first, ex);
156 List<URL> emptyURL = Collections.emptyList();
157 resources = Collections.enumeration(emptyURL);
158 }
159
160 resources = getResourcesFromUrl(first, resources);
161 }
162
163 return resources;
164 }
165
166 /**
167 * Enumerates resources URL.
168 *
169 * @param first The first URL in the enumeration sequence
170 * @param rest The URL enumeration
171 * @return A new resources URL enumeration
172 */
173 private static Enumeration<URL> getResourcesFromUrl(final URL first, final Enumeration<URL> rest) {
174 return new Enumeration<URL>() {
175
176 private boolean firstDone = (first == null);
177
178 private URL next = getNext();
179
180 public URL nextElement() {
181 URL o = next;
182 next = getNext();
183 return o;
184 }
185
186 public boolean hasMoreElements() {
187 return next != null;
188 }
189
190 private URL getNext() {
191 URL n;
192
193 if (!firstDone) {
194 /*
195 * First time through, use results of getReference()
196 * if they were non-null.
197 */
198 firstDone = true;
199 n = first;
200 } else {
201 /*
202 * Subsequent times through,
203 * use results of getReferences()
204 * but take out anything that matches 'first'.
205 *
206 * Iterate through list until we find one that
207 * doesn't match 'first'.
208 */
209 n = null;
210 while (rest.hasMoreElements() && n == null) {
211 n = rest.nextElement();
212 if (first != null &&
213 n != null &&
214 n.equals(first))
215 {
216 n = null;
217 }
218 }
219 }
220
221 return n;
222 }
223 };
224 }
225
226 /**
227 * Find the System {@code ClassLoader}.
228 *
229 * @return The System {@code ClassLoader}
230 */
231 static private ClassLoader findSystemClassLoader() {
232
233 ClassLoader classLoader;
234
235 try {
236 classLoader = ClassLoader.getSystemClassLoader();
237 } catch (SecurityException e) {
238 /*
239 * Ignore and keep going.
240 */
241 classLoader = null;
242 }
243
244 if (classLoader == null) {
245 SecurityManager security = System.getSecurityManager();
246 if (security != null) {
247 try {
248 security.checkCreateClassLoader();
249 classLoader = new PsuedoSystemClassLoader();
250 } catch (SecurityException se){
251 }
252 }
253 }
254
255 // Return the selected class loader
256 return classLoader;
257 }
258
259 }