/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * 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 de.ks; import de.ks.reflection.ReflectionUtil; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.reflections.util.FilterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.function.Predicate; import java.util.stream.Collectors; public class SubclassInstantiator { private static final Logger log = LoggerFactory.getLogger(SubclassInstantiator.class); private final ExecutorService executorService; private final Package defaultPackage; private final String propertyFile; private final String packagePropertyName; private final String separator; private Predicate<URL> urlFilter; public SubclassInstantiator(ExecutorService executorService, Package defaultPackage, String propertyFile, String packagePropertyName, String separator) { this.executorService = executorService; this.defaultPackage = defaultPackage; this.propertyFile = propertyFile; this.packagePropertyName = packagePropertyName; this.separator = separator; } public boolean isExcludeTestResources() { return urlFilter != null; } public void setExcludeTestResources(boolean excludeTestResources) { if (excludeTestResources) { urlFilter = (url) -> { if (excludeTestResources) { return !url.toString().contains("classes/test"); } else { return true; } }; } else { urlFilter = null; } } private Reflections getReflections() { ConfigurationBuilder builder = new ConfigurationBuilder(); builder.setExecutorService(executorService); FilterBuilder filterBuilder = new FilterBuilder(); try (InputStream stream = getClass().getResourceAsStream(propertyFile)) { addPackagesFromPropertyFile(builder, filterBuilder, stream); } catch (IOException e) { log.warn(propertyFile + " file not found. Will only use package '{}'", defaultPackage, e); } catch (NullPointerException e) { log.warn(propertyFile + " file not found. Will only use package '{}'", defaultPackage); } addDefaultPackage(builder); builder.filterInputsBy(filterBuilder); builder.addScanners(new SubTypesScanner()); return new Reflections(builder); } private void addDefaultPackage(ConfigurationBuilder builder) { builder.addUrls(ClasspathHelper.forPackage(defaultPackage.getName()).stream().filter(urlFilter == null ? a -> true : urlFilter).collect(Collectors.toList())); } private void addPackagesFromPropertyFile(ConfigurationBuilder builder, FilterBuilder filterBuilder, InputStream stream) throws IOException { log.debug("Reading properties {}", getClass().getResource(propertyFile)); Properties properties = new Properties(); properties.load(stream); String property = properties.getProperty(packagePropertyName); Arrays.asList(property.split(separator))// .forEach((pkg) -> { log.info("Scanning package {} for version upgraders.", pkg); filterBuilder.includePackage(pkg); ClasspathHelper.forPackage(pkg).stream().filter(urlFilter == null ? a -> true : urlFilter).forEach((url) -> { log.debug("Adding url {}", url); builder.addUrls(url); }); }); } public <T> List<T> instantiateSubclasses(Class<T> rootClass) { Reflections reflections = getReflections(); ArrayList<T> retval = new ArrayList<>(); reflections.getSubTypesOf(rootClass).stream()// .filter((clazz) -> !Modifier.isAbstract(clazz.getModifiers())).// forEach((clazz) -> { T instance = ReflectionUtil.newInstance(clazz); retval.add(instance); }); return retval; } }