jaitools.lookup.Lookup Maven / Gradle / Ivy
Show all versions of jt-all Show documentation
/*
* Copyright 2010 Michael Bedward
*
* This file is part of jai-tools.
*
* jai-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* jai-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with jai-tools. If not, see .
*
*/
package jaitools.lookup;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* This class offers minimal Service Provider Interface lookup functions.
* Within jai-tools it is used to find implementations of non-operator interfaces
* such as {@code jaitools.numeric.Processor}. Class names are read from registry
* files in the META-INF/services folder. Each registry file name corresponds to a
* fully qualified interface name. File format is one class name per line. Comment
* lines are prefixed with a hash (#) character. Blank lines are permitted.
*
* Each time a registry file is read its contents are cached (weakly) for subsequent
* lookups.
*
* Discovery of image operators is done using the standard JAI mechanisms.
*
* @author Michael Bedward
* @since 1.0
* @version $Id: Lookup.java 1383 2011-02-10 11:22:29Z michael.bedward $
*/
public class Lookup {
private static final String prefix = "META-INF/services/";
private static final Logger LOGGER = Logger.getLogger("jaitools.lookup");
private static HashMap>> cache = new HashMap>>();
/**
* Get classes that implement the given service provider interface.
*
* @param spiName the fully qualified name of the interface
*
* @return list of implementing classes
*/
public static List getProviders(String spiName) {
List providers = null;
WeakReference> ref = cache.get(spiName);
if (ref != null) {
providers = ref.get();
}
if (providers == null) {
providers = getProvidersFromSpiFile(spiName);
cache.put(spiName, new WeakReference>(providers));
}
return providers;
}
/**
* Clear any cached lookups. This forces subsequent lookups to read
* the registry files.
*/
public static void clearCache() {
cache.clear();
}
/**
* Returns a copy of the cached lookups as a {@code Map} with
* service provider interface names as keys and lists of implementing
* classes as values.
*
* This method was added for testing purposes.
*
* @return a copy of the cached lookups as a new {@code Map} (may be empty)
*/
public static Map> getCachedProviders() {
Map> copy = new HashMap>();
for (String key : cache.keySet()) {
WeakReference> ref = cache.get(key);
if (ref != null) {
List list = ref.get();
if (list != null) {
copy.put(key, list);
}
}
}
return copy;
}
/**
* Read class names from a registry file and return the list of
* implementing classes.
*
* @param spiName a fully qualified interface name
*
* @return list of implementing classes
*/
private static List getProvidersFromSpiFile(String spiName) {
List providers = new ArrayList();
ClassLoader cl = Lookup.class.getClassLoader();
if (cl != null) {
InputStream str = cl.getResourceAsStream(prefix + spiName);
if (str != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(str));
String line = null;
try {
while ((line = reader.readLine()) != null) {
String text = line.trim();
if (text.length() > 0 && !text.startsWith("#")) {
try {
providers.add(Class.forName(text));
} catch (ClassNotFoundException ex) {
LOGGER.warning("Class not found: " + text);
}
}
}
} catch (IOException ex) {
LOGGER.severe("Problem reading services file: " + spiName);
} finally {
try {
str.close();
} catch (Throwable e) {
// ignore
}
try {
if (reader != null) {
reader.close();
}
} catch (Throwable e) {
// ignore
}
}
} else {
LOGGER.severe("Could not find " + prefix + spiName);
}
}
return providers;
}
}