/*
* Copyright 2016 Function1. All Rights Reserved.
*
* 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 tools.gsf.config;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
/**
* Convenience class for working with reflection. Intended for internal GSF use only.
*
* @author Tony Field
* @since 2016-08-06
*/
final class ReflectionUtils {
private static final Logger LOG = LoggerFactory.getLogger(ReflectionUtils.class);
private ReflectionUtils() {
}
/**
* Locate a single resource in the classpath of the classloader specified. If more than one matching
* resource is found, an IllegalStateException is thrown
*
* @param classLoader the classloader to search
* @param resourceName the name of the resource to find
* @return a URL to the resource
*/
static URL getSingleResource(ClassLoader classLoader, String resourceName) {
try {
Enumeration<URL> resources = classLoader.getResources(resourceName);
URL result = null;
boolean bFound = false;
while (resources.hasMoreElements()) {
if (bFound) {
throw new IllegalStateException("Too many resources found matching name: " + resourceName);
}
result = resources.nextElement();
bFound = true;
}
return result;
} catch (IOException e) {
throw new IllegalStateException("Failed to locate resource: " + resourceName, e);
}
}
/**
* Locate a resource or resources in the classpath of the specified classloader, and read them.
* <p>
* More than one resource of the name specified is allowed.
* <p>
* The configuration resource file format ignores blank lines and lines starting with a #.
* <p>
* Each line of the configuration file will have its spaces normalized using
* org.apache.commons.lang3.StringUtils.normalizeSpace(String)
* <p>
* The configuration file names will be added to a set. If two matching configuration lines are
* found (after normalization), and IllegalStateException will be thrown.
*
* @param classLoader the classloader to search
* @param resourceName the name of the resource to find
* @return a set of the strings from the configuration resources. If no matching resources are
* found, or if the configuration resources are empty, an empty set will be returned.
* @throws IllegalStateException if more than one matching configuration line is found
* @throws RuntimeException if an error occurs reading the resources
*/
static Set<String> readConfigurationResource(ClassLoader classLoader, String resourceName) {
Set<String> lines = new HashSet<>();
try {
Enumeration<URL> resources = classLoader.getResources(resourceName);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try (InputStream in = url.openStream(); BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"))) {
String line;
while ((line = r.readLine()) != null) {
line = StringUtils.normalizeSpace(line);
if (StringUtils.isNotBlank(line) && !StringUtils.startsWith(line, "#")) {
if (lines.contains(line)) {
throw new IllegalStateException("Duplicate configuration information found in resource named " + resourceName + ". The following information was found more than once: " + line);
}
lines.add(line);
}
}
} catch (IOException e) {
throw new RuntimeException("Error reading configuration resource: " + resourceName, e);
}
}
} catch (IOException e) {
throw new RuntimeException("Error reading configuration resource: " + resourceName, e);
}
return lines;
}
/**
* @param <T> created method type
* @param name name of the object
* @param typeTocreate the type of the object to create
* @param factoryMethod the method to use to create the object
* @param factory The factory on which the factory method will be invoked
* @return created object
* @throws InvocationTargetException exception from invoking specified method from class name
*/
@SuppressWarnings("unchecked")
static <T> T createFromMethod(String name, Class<T> typeTocreate, Object factory, Method factoryMethod, Object... params) throws InvocationTargetException {
Object o = null;
LOG.trace("Trying to create a {} object with name {} from method {} from factory {}", typeTocreate.getName(), name, factoryMethod.toGenericString(), factory.getClass().getName());
if (typeTocreate.isAssignableFrom(factoryMethod.getReturnType())) {
try {
o = factoryMethod.invoke(factory, params);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Access exception creating object " + typeTocreate.getName() + ": " + e, e);
}
}
return (T) o;
}
}