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 }