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

org.ops4j.spi.SafeServiceLoader Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 Harald Wellmann.
 *
 * 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 org.ops4j.spi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * Loads service provider instances from {@code META-INF/services} using a given class loader,
 * avoiding the system class loader used by {@code java.util.ServiceLoader}.
 * 
 * @author Harald Wellmann
 */
public class SafeServiceLoader
{
    private ClassLoader classLoader;

    /**
     * Constructs a service loader using the given class loader.
     * 
     * @param classLoader
     */
    public SafeServiceLoader( ClassLoader classLoader )
    {
        this.classLoader = classLoader;
    }

    /**
     * Returns a list of service instances for the given a service type, finding all
     * META-INF/services resources for the given type and loading and instantiating all classes
     * listed in these resources.
     * 

* A class that cannot be loaded by the class loader passed to the constructor of this class is * silently ignored. * * @param serviceType fully qualified service class name * @return list of services matching the given service type * @throws NoServiceProviderException if a resource cannot be read or if a loaded class cannot * be instantiated */ public List load( String serviceType ) { List services = new ArrayList(); String resourceName = "/META-INF/services/" + serviceType; try { Enumeration resources = classLoader.getResources( resourceName ); while( resources.hasMoreElements() ) { URL url = resources.nextElement(); List classNames = parse( url ); for( String className : classNames ) { Class klass = loadClassIfVisible( className, classLoader ); if( klass != null ) { T service = klass.newInstance(); services.add( service ); } } } } catch ( IOException exc ) { throw new NoServiceProviderException( exc ); } catch ( InstantiationException exc ) { throw new NoServiceProviderException( exc ); } catch ( IllegalAccessException exc ) { throw new NoServiceProviderException( exc ); } return services; } /** * Loads a class with the given name from the given class loader. * * @param className fully qualified class name * @param classLoader class loader * @return class with given name, or null */ @SuppressWarnings( "unchecked" ) private Class loadClassIfVisible( String className, ClassLoader classLoader ) { try { Class klass = (Class) classLoader.loadClass( className ); return klass; } catch ( ClassNotFoundException e ) { return null; } } /** * Parses a META-INF/services resource and returns the list of service provider class names * defined in that resource. * * @param url a URL of a META-INF/services resource * @return list of service class names (not null, but possibly empty) */ private List parse( URL url ) { InputStream is = null; BufferedReader reader = null; List names = new ArrayList(); try { is = url.openStream(); reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) ); String line = null; while( ( line = reader.readLine() ) != null ) { parseLine( names, line ); } } catch ( IOException exc ) { throw new NoServiceProviderException( exc ); } finally { closeSilently( reader ); } return names; } /** * Closes the given reader, silently ignoring any exception. * * @param reader */ private void closeSilently( BufferedReader reader ) { try { if( reader != null ) { reader.close(); } } catch ( IOException exc ) { // ignore } } /** * Parses a single line of a META-INF/services resources. If the line contains a class name, the * name is added to the given list. * * @param names list of class names * @param line line to be parsed */ private void parseLine( List names, String line ) { int commentPos = line.indexOf( '#' ); if( commentPos >= 0 ) { line = line.substring( 0, commentPos ); } line = line.trim(); if( !line.isEmpty() && !names.contains( line ) ) { names.add( line ); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy