View Javadoc

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 }