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.tools; 18 19 import java.lang.reflect.InvocationTargetException; 20 21 import org.apache.commons.discovery.DiscoveryException; 22 23 /** 24 * Represents a Service Programming Interface (spi). 25 * - SPI's name 26 * - SPI's (provider) class 27 * - SPI's (alternate) override property name 28 * 29 * In addition, while there are many cases where this is NOT 30 * usefull, for those in which it is: 31 * 32 * - expected constructor argument types and parameters values. 33 * 34 * @param <T> The SPI type 35 */ 36 public class SPInterface<T> { 37 38 /** 39 * Construct object representing Class {@code provider}. 40 * 41 * @param <T> The SPI type 42 * @param provider The SPI class 43 * @return A new object representing Class {@code provider} 44 * @since 0.5 45 */ 46 public static <T> SPInterface<T> newSPInterface(Class<T> provider) { 47 return newSPInterface(provider, provider.getName()); 48 } 49 50 /** 51 * Construct object representing Class {@code provider}. 52 * 53 * @param <T> The SPI type 54 * @param provider The SPI class 55 * @param propertyName when looking for the name of a class implementing 56 * the provider class, a discovery strategy may involve looking for 57 * (system or other) properties having either the name of the class 58 * (provider) or the <code>propertyName</code>. 59 * @return A new object representing Class {@code provider} 60 * @since 0.5 61 */ 62 public static <T> SPInterface<T> newSPInterface(Class<T> provider, String propertyName) { 63 return new SPInterface<T>(provider, propertyName); 64 } 65 66 /** 67 * Construct object representing Class {@code provider}. 68 * 69 * @param <T> The SPI type 70 * @param provider The SPI class 71 * @param constructorParamClasses classes representing the 72 * constructor argument types 73 * @param constructorParams objects representing the 74 * constructor arguments 75 * @return A new object representing Class {@code provider} 76 * @since 0.5 77 */ 78 public static <T> SPInterface<T> newSPInterface(Class<T> provider, 79 Class<?> constructorParamClasses[], 80 Object constructorParams[]) { 81 return newSPInterface(provider, provider.getName(), constructorParamClasses, constructorParams); 82 } 83 84 /** 85 * Construct object representing Class {@code provider}. 86 * 87 * @param <T> The SPI type 88 * @param provider The SPI class 89 * @param propertyName when looking for the name of a class implementing 90 * the provider class, a discovery strategy may involve looking for 91 * (system or other) properties having either the name of the class 92 * (provider) or the <code>propertyName</code>. 93 * @param constructorParamClasses classes representing the 94 * constructor argument types 95 * @param constructorParams objects representing the 96 * constructor arguments 97 * @return A new object representing Class {@code provider} 98 * @since 0.5 99 */ 100 public static <T> SPInterface<T> newSPInterface(Class<T> provider, 101 String propertyName, 102 Class<?> constructorParamClasses[], 103 Object constructorParams[]) { 104 return new SPInterface<T>(provider, propertyName, constructorParamClasses, constructorParams); 105 } 106 107 /** 108 * The service programming interface: intended to be 109 * an interface or abstract class, but not limited 110 * to those two. 111 */ 112 private final Class<T> spi; 113 114 /** 115 * The property name to be used for finding the name of 116 * the SPI implementation class. 117 */ 118 private final String propertyName; 119 120 private final Class<?> paramClasses[]; 121 122 private final Object params[]; 123 124 /** 125 * Construct object representing Class <code>provider</code>. 126 * 127 * @param provider The SPI class 128 */ 129 public SPInterface(Class<T> provider) { 130 this(provider, provider.getName()); 131 } 132 133 /** 134 * Construct object representing Class <code>provider</code>. 135 * 136 * @param spi The SPI class 137 * 138 * @param propertyName when looking for the name of a class implementing 139 * the provider class, a discovery strategy may involve looking for 140 * (system or other) properties having either the name of the class 141 * (provider) or the <code>propertyName</code>. 142 */ 143 public SPInterface(Class<T> spi, String propertyName) { 144 this.spi = spi; 145 this.propertyName = propertyName; 146 this.paramClasses = null; 147 this.params = null; 148 } 149 150 /** 151 * Construct object representing Class <code>provider</code>. 152 * 153 * @param provider The SPI class 154 * 155 * @param constructorParamClasses classes representing the 156 * constructor argument types. 157 * 158 * @param constructorParams objects representing the 159 * constructor arguments. 160 */ 161 public SPInterface(Class<T> provider, 162 Class<?> constructorParamClasses[], 163 Object constructorParams[]) { 164 this(provider, 165 provider.getName(), 166 constructorParamClasses, 167 constructorParams); 168 } 169 170 /** 171 * Construct object representing Class <code>provider</code>. 172 * 173 * @param spi The SPI class 174 * 175 * @param propertyName when looking for the name of a class implementing 176 * the provider class, a discovery strategy may involve looking for 177 * (system or other) properties having either the name of the class 178 * (provider) or the <code>propertyName</code>. 179 * 180 * @param constructorParamClasses classes representing the 181 * constructor argument types. 182 * 183 * @param constructorParams objects representing the 184 * constructor arguments. 185 */ 186 public SPInterface(Class<T> spi, 187 String propertyName, 188 Class<?> constructorParamClasses[], 189 Object constructorParams[]) { 190 this.spi = spi; 191 this.propertyName = propertyName; 192 this.paramClasses = constructorParamClasses; 193 this.params = constructorParams; 194 } 195 196 /** 197 * Returns the SPI class name. 198 * 199 * @return The SPI class name 200 */ 201 public String getSPName() { 202 return spi.getName(); 203 } 204 205 /** 206 * Returns the SPI class. 207 * 208 * @return The SPI class 209 */ 210 public Class<T> getSPClass() { 211 return spi; 212 } 213 214 /** 215 * Returns the property name to be used for finding 216 * the name of the SPI implementation class. 217 * 218 * @return The property name to be used for finding 219 * the name of the SPI implementation class 220 */ 221 public String getPropertyName() { 222 return propertyName; 223 } 224 225 /** 226 * Creates a new instance of the given SPI class. 227 * 228 * @param <S> Any type extends T 229 * @param impl The SPI class has to be instantiated 230 * @return A new instance of the given SPI class 231 * @throws DiscoveryException if the class implementing 232 * the SPI cannot be found, cannot be loaded and 233 * instantiated, or if the resulting class does not implement 234 * (or extend) the SPI 235 * @throws InstantiationException see {@link Class#newInstance()} 236 * @throws IllegalAccessException see {@link Class#newInstance()} 237 * @throws NoSuchMethodException see {@link Class#newInstance()} 238 * @throws InvocationTargetException see {@link Class#newInstance()} 239 */ 240 public <S extends T> S newInstance(Class<S> impl) 241 throws DiscoveryException, 242 InstantiationException, 243 IllegalAccessException, 244 NoSuchMethodException, 245 InvocationTargetException { 246 verifyAncestory(impl); 247 248 return ClassUtils.newInstance(impl, paramClasses, params); 249 } 250 251 /** 252 * Verifies the given SPI implementation is a SPI specialization. 253 * 254 * @param <S> Any type extends T 255 * @param impl The SPI instantance 256 */ 257 public <S extends T> void verifyAncestory(Class<S> impl) { 258 ClassUtils.verifyAncestory(spi, impl); 259 } 260 261 }