001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.discovery.jdk; 018 019 import java.io.IOException; 020 import java.net.URL; 021 import java.security.AccessController; 022 import java.security.PrivilegedAction; 023 import java.util.Collections; 024 import java.util.Enumeration; 025 import java.util.List; 026 027 import org.apache.commons.logging.Log; 028 import org.apache.commons.logging.LogFactory; 029 030 /** 031 * JDK 1.2 Style Hooks implementation. 032 */ 033 public class JDK12Hooks extends JDKHooks { 034 035 /** 036 * Logger 037 */ 038 private static Log log = LogFactory.getLog(JDK12Hooks.class); 039 040 private static final ClassLoader systemClassLoader = findSystemClassLoader(); 041 042 /** 043 * Sets the {@code Log} for this class. 044 * 045 * @param _log This class {@code Log} 046 * @deprecated This method is not thread-safe 047 */ 048 @Deprecated 049 public static void setLog(Log _log) { 050 log = _log; 051 } 052 053 /** 054 * {@inheritDoc} 055 */ 056 @Override 057 public String getSystemProperty(final String propName) { 058 return AccessController.doPrivileged(new PrivilegedAction<String>() { 059 public String run() { 060 try { 061 return System.getProperty(propName); 062 } catch (SecurityException se){ 063 return null; 064 } 065 } 066 }); 067 } 068 069 /** 070 * {@inheritDoc} 071 */ 072 @Override 073 public ClassLoader getThreadContextClassLoader() { 074 ClassLoader classLoader; 075 076 try { 077 classLoader = Thread.currentThread().getContextClassLoader(); 078 } catch (SecurityException e) { 079 /* 080 * SecurityException is thrown when 081 * a) the context class loader isn't an ancestor of the 082 * calling class's class loader, or 083 * b) if security permissions are restricted. 084 * 085 * For (a), ignore and keep going. We cannot help but also 086 * ignore (b) with the logic below, but other calls elsewhere 087 * (to obtain a class loader) will re-trigger this exception 088 * where we can make a distinction. 089 */ 090 classLoader = null; // ignore 091 } 092 093 // Return the selected class loader 094 return classLoader; 095 } 096 097 /** 098 * {@inheritDoc} 099 */ 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 }