View Javadoc

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 }