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 }