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; 18 19 import java.net.URL; 20 import java.security.AccessController; 21 import java.security.PrivilegedAction; 22 23 import org.apache.commons.logging.Log; 24 import org.apache.commons.logging.LogFactory; 25 26 /** 27 * 'Resource' located by discovery. 28 * Naming of methods becomes a real pain ('getClass()') 29 * so I've patterned this after ClassLoader... 30 * 31 * I think it works well as it will give users a point-of-reference. 32 * 33 * @param <T> The SPI type 34 */ 35 public class ResourceClass<T> extends Resource { 36 37 private static Log log = LogFactory.getLog(ResourceClass.class); 38 39 /** 40 * Sets the {@code Log} for this class. 41 * 42 * @param _log This class {@code Log} 43 * @deprecated This method is not thread-safe 44 */ 45 @Deprecated 46 public static void setLog(Log _log) { 47 log = _log; 48 } 49 50 protected Class<? extends T> resourceClass; 51 52 /** 53 * Create a new {@code Resource} class located by discovery. 54 * 55 * @param <S> Any type extends T 56 * @param resourceClass The resource class has to be located 57 * @param resource The resource URL has to be located 58 */ 59 public <S extends T> ResourceClass(Class<S> resourceClass, URL resource) { 60 super(resourceClass.getName(), resource, resourceClass.getClassLoader()); 61 this.resourceClass = resourceClass; 62 } 63 64 /** 65 * Create a new {@code Resource} class located by discovery. 66 * 67 * @param resourceName The resource class name has to be located 68 * @param resource The resource URL has to be located 69 * @param loader The class loaders holder 70 */ 71 public ResourceClass(String resourceName, URL resource, ClassLoader loader) { 72 super(resourceName, resource, loader); 73 } 74 75 /** 76 * Get the value of resourceClass. 77 * Loading the class does NOT guarentee that the class can be 78 * instantiated. Go figure. 79 * The class can be instantiated when the class is linked/resolved, 80 * and all dependencies are resolved. 81 * Various JDKs do this at different times, so beware: 82 * java.lang.NoClassDefFoundError when 83 * calling Class.getDeclaredMethod() (JDK14), 84 * java.lang.reflect.InvocationTargetException 85 * (wrapping java.lang.NoClassDefFoundError) when calling 86 * java.lang.newInstance (JDK13), 87 * and who knows what else.. 88 * 89 * @param <S> Any type extends T 90 * 91 * @return value of resourceClass. 92 */ 93 public <S extends T> Class<S> loadClass() { 94 if (resourceClass == null && getClassLoader() != null) { 95 if (log.isDebugEnabled()) { 96 log.debug("loadClass: Loading class '" + getName() + "' with " + getClassLoader()); 97 } 98 99 resourceClass = AccessController.doPrivileged( 100 new PrivilegedAction<Class<? extends T>>() { 101 public Class<? extends T> run() { 102 try { 103 @SuppressWarnings("unchecked") // this can raise a ClassCastException at runtime 104 Class<S> returned = (Class<S>) getClassLoader().loadClass(getName()); 105 return returned; 106 } catch (ClassNotFoundException e) { 107 return null; 108 } 109 } 110 }); 111 } 112 113 @SuppressWarnings("unchecked") // this is assumed by default, see the ctor 114 Class<S> returned = (Class<S>) resourceClass; 115 return returned; 116 } 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public String toString() { 123 return "ResourceClass[" + getName() + ", " + getResource() + ", " + getClassLoader() + "]"; 124 } 125 126 }