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.tools;
018    
019    import java.lang.reflect.InvocationTargetException;
020    
021    import org.apache.commons.discovery.DiscoveryException;
022    
023    
024    /**
025     * Represents a Service Programming Interface (spi).
026     * - SPI's name
027     * - SPI's (provider) class
028     * - SPI's (alternate) override property name
029     * 
030     * In addition, while there are many cases where this is NOT
031     * usefull, for those in which it is:
032     * 
033     * - expected constructor argument types and parameters values.
034     * 
035     * @author Richard A. Sitze
036     */
037    public class SPInterface {
038        /**
039         * The service programming interface: intended to be
040         * an interface or abstract class, but not limited
041         * to those two.
042         */        
043        private final Class spi;
044        
045        /**
046         * The property name to be used for finding the name of
047         * the SPI implementation class.
048         */
049        private final String propertyName;
050        
051        
052        private Class  paramClasses[] = null;
053        private Object params[] = null;
054    
055    
056        /**
057         * Construct object representing Class <code>provider</code>.
058         * 
059         * @param provider The SPI class
060         */
061        public SPInterface(Class provider) {
062            this(provider, provider.getName());
063        }
064        
065        /**
066         * Construct object representing Class <code>provider</code>.
067         * 
068         * @param spi The SPI class
069         * 
070         * @param propertyName when looking for the name of a class implementing
071         *        the provider class, a discovery strategy may involve looking for
072         *        (system or other) properties having either the name of the class
073         *        (provider) or the <code>propertyName</code>.
074         */
075        public SPInterface(Class spi, String propertyName) {
076            this.spi = spi;
077            this.propertyName = propertyName;
078        }
079    
080        /**
081         * Construct object representing Class <code>provider</code>.
082         * 
083         * @param provider The SPI class
084         * 
085         * @param constructorParamClasses classes representing the
086         *        constructor argument types.
087         * 
088         * @param constructorParams objects representing the
089         *        constructor arguments.
090         */
091        public SPInterface(Class provider,
092                           Class constructorParamClasses[],
093                           Object constructorParams[])
094        {
095            this(provider,
096                 provider.getName(),
097                 constructorParamClasses,
098                 constructorParams);
099        }
100        
101        /**
102         * Construct object representing Class <code>provider</code>.
103         * 
104         * @param spi The SPI class
105         * 
106         * @param propertyName when looking for the name of a class implementing
107         *        the provider class, a discovery strategy may involve looking for
108         *        (system or other) properties having either the name of the class
109         *        (provider) or the <code>propertyName</code>.
110         * 
111         * @param constructorParamClasses classes representing the
112         *        constructor argument types.
113         * 
114         * @param constructorParams objects representing the
115         *        constructor arguments.
116         */
117        public SPInterface(Class spi,
118                           String propertyName,
119                           Class constructorParamClasses[],
120                           Object constructorParams[])
121        {
122            this.spi = spi;
123            this.propertyName = propertyName;
124            this.paramClasses = constructorParamClasses;
125            this.params = constructorParams;
126        }
127    
128        public String getSPName() {
129            return spi.getName();
130        }
131    
132        public Class getSPClass() {
133            return spi;
134        }
135        
136        public String getPropertyName() {
137            return propertyName;
138        }
139    
140        /**
141         * Instantiate a new 
142         */    
143        public Object newInstance(Class impl)
144            throws DiscoveryException,
145                   InstantiationException,
146                   IllegalAccessException,
147                   NoSuchMethodException,
148                   InvocationTargetException
149        {
150            verifyAncestory(impl);
151            
152            return ClassUtils.newInstance(impl, paramClasses, params);
153        }
154        
155        public void verifyAncestory(Class impl) {
156            ClassUtils.verifyAncestory(spi, impl);
157        }
158    }