package io.lumify.core.util; import io.lumify.core.config.Configuration; import io.lumify.core.exception.LumifyException; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.net.URL; import java.util.*; /** * This class exists to provide much deeper and extensive debugging and logging as * opposed to (@see java.util.ServiceLoader) */ public class ServiceLoaderUtil { private static final LumifyLogger LOGGER = LumifyLoggerFactory.getLogger(ServiceLoaderUtil.class); private static final String PREFIX = "META-INF/services/"; public static final String CONFIG_DISABLE_PREFIX = "disable."; public static <T> Iterable<T> load(Class<T> clazz, Configuration configuration) { List<T> services = new ArrayList<>(); String fullName = PREFIX + clazz.getName(); LOGGER.debug("loading services for class %s", fullName); try { Enumeration<URL> serviceFiles = Thread.currentThread().getContextClassLoader().getResources(fullName); if (!serviceFiles.hasMoreElements()) { LOGGER.debug("Could not find any services for %s", fullName); } else { Set<URL> serviceFilesSet = new HashSet<>(); while (serviceFiles.hasMoreElements()) { URL serviceFile = serviceFiles.nextElement(); serviceFilesSet.add(serviceFile); } for (URL serviceFile : serviceFilesSet) { services.addAll(ServiceLoaderUtil.<T>loadFile(serviceFile, configuration)); } } return services; } catch (IOException e) { throw new LumifyException("Could not load services for class: " + clazz.getName(), e); } } public static <T> Collection<T> loadFile(URL serviceFile, Configuration configuration) throws IOException { List<T> services = new ArrayList<>(); LOGGER.debug("loadFile(%s)", serviceFile); try (BufferedReader reader = new BufferedReader(new InputStreamReader(serviceFile.openStream()))) { String className; while ((className = reader.readLine()) != null) { className = className.trim(); if (className.length() == 0) { continue; } if (configuration.getBoolean(CONFIG_DISABLE_PREFIX + className, false)) { LOGGER.info("ignoring class %s because it is disabled in configuration", className); continue; } services.add(ServiceLoaderUtil.<T>loadClass(serviceFile, className)); } } return services; } public static <T> T loadClass(URL config, String className) { try { LOGGER.info("Loading %s from %s", className, config.toString()); Class<? extends T> serviceClass = ClassUtil.forName(className); Constructor<? extends T> constructor = serviceClass.getConstructor(); return constructor.newInstance(); } catch (Throwable t) { String errorMessage = String.format("Failed to load %s from %s", className, config.toString()); LOGGER.error("%s", errorMessage, t); throw new LumifyException(errorMessage, t); } } }