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; 018 019 import java.net.URL; 020 import java.security.AccessController; 021 import java.security.PrivilegedAction; 022 023 import org.apache.commons.logging.Log; 024 import org.apache.commons.logging.LogFactory; 025 026 /** 027 * 'Resource' located by discovery. 028 * Naming of methods becomes a real pain ('getClass()') 029 * so I've patterned this after ClassLoader... 030 * 031 * I think it works well as it will give users a point-of-reference. 032 * 033 * @param <T> The SPI type 034 */ 035 public class ResourceClass<T> extends Resource { 036 037 private static Log log = LogFactory.getLog(ResourceClass.class); 038 039 /** 040 * Sets the {@code Log} for this class. 041 * 042 * @param _log This class {@code Log} 043 * @deprecated This method is not thread-safe 044 */ 045 @Deprecated 046 public static void setLog(Log _log) { 047 log = _log; 048 } 049 050 protected Class<? extends T> resourceClass; 051 052 /** 053 * Create a new {@code Resource} class located by discovery. 054 * 055 * @param <S> Any type extends T 056 * @param resourceClass The resource class has to be located 057 * @param resource The resource URL has to be located 058 */ 059 public <S extends T> ResourceClass(Class<S> resourceClass, URL resource) { 060 super(resourceClass.getName(), resource, resourceClass.getClassLoader()); 061 this.resourceClass = resourceClass; 062 } 063 064 /** 065 * Create a new {@code Resource} class located by discovery. 066 * 067 * @param resourceName The resource class name has to be located 068 * @param resource The resource URL has to be located 069 * @param loader The class loaders holder 070 */ 071 public ResourceClass(String resourceName, URL resource, ClassLoader loader) { 072 super(resourceName, resource, loader); 073 } 074 075 /** 076 * Get the value of resourceClass. 077 * Loading the class does NOT guarentee that the class can be 078 * instantiated. Go figure. 079 * The class can be instantiated when the class is linked/resolved, 080 * and all dependencies are resolved. 081 * Various JDKs do this at different times, so beware: 082 * java.lang.NoClassDefFoundError when 083 * calling Class.getDeclaredMethod() (JDK14), 084 * java.lang.reflect.InvocationTargetException 085 * (wrapping java.lang.NoClassDefFoundError) when calling 086 * java.lang.newInstance (JDK13), 087 * and who knows what else.. 088 * 089 * @param <S> Any type extends T 090 * 091 * @return value of resourceClass. 092 */ 093 public <S extends T> Class<S> loadClass() { 094 if (resourceClass == null && getClassLoader() != null) { 095 if (log.isDebugEnabled()) { 096 log.debug("loadClass: Loading class '" + getName() + "' with " + getClassLoader()); 097 } 098 099 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 }