All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.bspi.ServiceLoader Maven / Gradle / Ivy

Go to download

The backport-spi library is backport of Service Provider Interface to Java5 with extra features.

There is a newer version: 1.0.1
Show newest version
/*
 *    Copyright 2010 The backport-spi Team
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.googlecode.bspi;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;

/**
 * A simple service-provider loading facility.
 *
 * @param  The type of the service to be loaded by this loader.
 * @version $Id: ServiceLoader.java 4 2010-07-24 18:45:26Z simone.tripodi $
 */
public final class ServiceLoader implements Iterable {

    private static final String SERVICE_PREFIX = "META-INF/services/";

    /**
     * Creates a new service loader for the given service type, using the
     * current thread's {@linkplain java.lang.Thread#getContextClassLoader
     * context class loader}.
     * 
     * @param  The type of the service to be loaded by this loader.
     * @param service The class or interface representing the service being
     *        loaded.
     * @return A new service loader.
     */
    public static  ServiceLoader load(Class service) {
        return load(service, Thread.currentThread().getContextClassLoader());
    }

    /**
     * Creates a new service loader for the given service type and class
     * loader.
     *
     * @param  The type of the service to be loaded by this loader.
     * @param service The class or interface representing the service being
     *        loaded.
     * @param classLoader The class loader used to locate, load, and instantiate
     *        providers.
     * @return A new service loader.
     */
    public static  ServiceLoader load(Class service,
            ClassLoader classLoader) {
        if (classLoader == null) {
            throw new IllegalArgumentException("Parameter 'classLoader' must not be null");
        }
        return new ServiceLoader(service, classLoader);
    }

    /**
     * Creates a new service loader for the given service type, using the
     * extension class loader.
     *
     * @param  The type of the service to be loaded by this loader.
     * @param service The class or interface representing the service being
     *        loaded.
     * @return A new service loader.
     */
    public static  ServiceLoader loadInstalled(Class service) {
        ClassLoader parent = ClassLoader.getSystemClassLoader();
        ClassLoader current = null;
        while (parent != null) {
            current = parent;
            parent = parent.getParent();
        }
        return load(service, current);
    }

    /**
     * Cached providers, in instantiation order.
     */
    private final LinkedHashMap providers = new LinkedHashMap();

    /**
     * The class or interface representing the service being loaded.
     */
    private final Class service;

    /**
     * The class loader used to locate, load, and instantiate providers.
     */
    private final ClassLoader classLoader;

    /**
     * The current lazy-lookup iterator.
     */
    private ServiceIterator serviceIterator;

    /**
     * This class can't be instantiate directly, use static methods instead.
     *
     * @param service the class or interface representing the service being
     *        loaded.
     * @param classLoader the class loader used to locate, load, and instantiate
     *        providers.
     */
    private ServiceLoader(Class service,
            ClassLoader classLoader) {
        this.service = service;
        this.classLoader = classLoader;
        this.reload();
    }

    /**
     * Clear this loader's provider cache so that all providers will be
     * reloaded.
     */
    public void reload() {
        this.providers.clear();

        String fullName = SERVICE_PREFIX + this.service.getName();
        try {
            Enumeration serviceResources = this.classLoader.getResources(fullName);
            this.serviceIterator = new ServiceIterator(this.service,
                    this.classLoader,
                    serviceResources,
                    this.providers);
        } catch (IOException e) {
            throw new ServiceConfigurationError("An error occurred while loading '"
                    + fullName
                    + "' Service resource(s) from clabackport-spiath", e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Iterator iterator() {
        return new ProviderIterator(this.providers.entrySet().iterator(),
                this.serviceIterator);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return this.getClass().getName()
                + "["
                + this.service.getName()
                + "]";
    }

}