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.util.Enumeration;
020    
021    import org.apache.commons.discovery.ResourceClass;
022    import org.apache.commons.discovery.ResourceClassIterator;
023    import org.apache.commons.discovery.ResourceNameIterator;
024    import org.apache.commons.discovery.resource.ClassLoaders;
025    import org.apache.commons.discovery.resource.classes.DiscoverClasses;
026    import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
027    
028    
029    /**
030     * [this was ServiceDiscovery12... the 1.1 versus 1.2 issue
031     * has been abstracted to org.apache.commons.discover.jdk.JDKHooks]
032     * 
033     * <p>Implement the JDK1.3 'Service Provider' specification.
034     * ( http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html )
035     * </p>
036     *
037     * This class supports any VM, including JDK1.1, via
038     * org.apache.commons.discover.jdk.JDKHooks.
039     *
040     * The caller will first configure the discoverer by adding ( in the desired
041     * order ) all the places to look for the META-INF/services. Currently
042     * we support loaders.
043     *
044     * The findResources() method will check every loader.
045     *
046     * @author Richard A. Sitze
047     * @author Craig R. McClanahan
048     * @author Costin Manolache
049     * @author James Strachan
050     */
051    public class Service
052    {
053        /** Construct a new service discoverer
054         */
055        protected Service() {
056        }
057        
058        /**
059         * as described in
060         * sun/jdk1.3.1/docs/guide/jar/jar.html#Service Provider,
061         * Except this uses <code>Enumeration</code>
062         * instead of <code>Interator</code>.
063         * 
064         * @return Enumeration of class instances (<code>Object</code>)
065         */
066        public static Enumeration providers(Class spiClass) {
067            return providers(new SPInterface(spiClass), null);
068        }
069        
070        /**
071         * This version lets you specify constructor arguments..
072         * 
073         * @param spi SPI to look for and load.
074         * @param loaders loaders to use in search.
075         *        If <code>null</code> then use ClassLoaders.getAppLoaders().
076         */
077        public static Enumeration providers(final SPInterface spi,
078                                            ClassLoaders loaders)
079        {
080            if (loaders == null) {
081                loaders = ClassLoaders.getAppLoaders(spi.getSPClass(),
082                                                     Service.class,
083                                                     true);
084            }
085            
086            ResourceNameIterator servicesIter =
087                (new DiscoverServiceNames(loaders)).findResourceNames(spi.getSPName());
088    
089            final ResourceClassIterator services =
090                (new DiscoverClasses(loaders)).findResourceClasses(servicesIter);
091            
092            return new Enumeration() {
093                private Object object = null;
094                
095                public boolean hasMoreElements() {
096                    if (object == null) {
097                        object = getNextClassInstance();
098                    }
099                    return object != null;
100                }
101                
102                public Object nextElement() {
103                    Object obj = object;
104                    object = null;
105                    return obj;
106                }
107    
108                private Object getNextClassInstance() {
109                    while (services.hasNext()) {
110                        ResourceClass info = services.nextResourceClass();
111                        try {
112                            return spi.newInstance(info.loadClass());
113                        } catch (Exception e) {
114                            // ignore
115                        }
116                    }
117                    return null;
118                }
119            };
120        }
121    }