View Javadoc
1   /*
2    * Copyright 2016 Function1. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package tools.gsf.config;
17  
18  import org.apache.commons.lang3.StringUtils;
19  import org.slf4j.Logger;
20  import org.slf4j.LoggerFactory;
21  
22  import java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.net.URL;
29  import java.util.Enumeration;
30  import java.util.HashSet;
31  import java.util.Set;
32  
33  /**
34   * Convenience class for working with reflection. Intended for internal GSF use only.
35   *
36   * @author Tony Field
37   * @since 2016-08-06
38   */
39  final class ReflectionUtils {
40  
41      private static final Logger LOG = LoggerFactory.getLogger(ReflectionUtils.class);
42  
43      private ReflectionUtils() {
44      }
45  
46      /**
47       * Locate a single resource in the classpath of the classloader specified. If more than one matching
48       * resource is found, an IllegalStateException is thrown
49       *
50       * @param classLoader  the classloader to search
51       * @param resourceName the name of the resource to find
52       * @return a URL to the resource
53       */
54      static URL getSingleResource(ClassLoader classLoader, String resourceName) {
55          try {
56              Enumeration<URL> resources = classLoader.getResources(resourceName);
57              URL result = null;
58              boolean bFound = false;
59              while (resources.hasMoreElements()) {
60                  if (bFound) {
61                      throw new IllegalStateException("Too many resources found matching name: " + resourceName);
62                  }
63                  result = resources.nextElement();
64                  bFound = true;
65              }
66              return result;
67          } catch (IOException e) {
68              throw new IllegalStateException("Failed to locate resource: " + resourceName, e);
69          }
70      }
71  
72      /**
73       * Locate a resource or resources in the classpath of the specified classloader, and read them.
74       * <p>
75       * More than one resource of the name specified is allowed.
76       * <p>
77       * The configuration resource file format ignores blank lines and lines starting with a #.
78       * <p>
79       * Each line of the configuration file will have its spaces normalized using
80       * org.apache.commons.lang3.StringUtils.normalizeSpace(String)
81       * <p>
82       * The configuration file names will be added to a set. If two matching configuration lines are
83       * found (after normalization), and IllegalStateException will be thrown.
84       *
85       * @param classLoader  the classloader to search
86       * @param resourceName the name of the resource to find
87       * @return a set of the strings from the configuration resources. If no matching resources are
88       * found, or if the configuration resources are empty, an empty set will be returned.
89       * @throws IllegalStateException if more than one matching configuration line is found
90       * @throws RuntimeException      if an error occurs reading the resources
91       */
92      static Set<String> readConfigurationResource(ClassLoader classLoader, String resourceName) {
93          Set<String> lines = new HashSet<>();
94          try {
95              Enumeration<URL> resources = classLoader.getResources(resourceName);
96              while (resources.hasMoreElements()) {
97                  URL url = resources.nextElement();
98                  try (InputStream in = url.openStream(); BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"))) {
99                      String line;
100                     while ((line = r.readLine()) != null) {
101                         line = StringUtils.normalizeSpace(line);
102                         if (StringUtils.isNotBlank(line) && !StringUtils.startsWith(line, "#")) {
103                             if (lines.contains(line)) {
104                                 throw new IllegalStateException("Duplicate configuration information found in resource named " + resourceName + ". The following information was found more than once: " + line);
105                             }
106                             lines.add(line);
107                         }
108                     }
109                 } catch (IOException e) {
110                     throw new RuntimeException("Error reading configuration resource: " + resourceName, e);
111                 }
112             }
113         } catch (IOException e) {
114             throw new RuntimeException("Error reading configuration resource: " + resourceName, e);
115         }
116         return lines;
117     }
118 
119     /**
120      * @param <T>           created method type
121      * @param name          name of the object
122      * @param typeTocreate  the type of the object to create
123      * @param factoryMethod the method to use to create the object
124      * @param factory       The factory on which the factory method will be invoked
125      * @return created object
126      * @throws InvocationTargetException exception from invoking specified method from class name
127      */
128     @SuppressWarnings("unchecked")
129     static <T> T createFromMethod(String name, Class<T> typeTocreate, Object factory, Method factoryMethod, Object... params) throws InvocationTargetException {
130         Object o = null;
131         LOG.trace("Trying to create a {} object with name {} from method {} from factory {}", typeTocreate.getName(), name, factoryMethod.toGenericString(), factory.getClass().getName());
132 
133         if (typeTocreate.isAssignableFrom(factoryMethod.getReturnType())) {
134             try {
135                 o = factoryMethod.invoke(factory, params);
136             } catch (IllegalAccessException e) {
137                 throw new IllegalStateException("Access exception creating object " + typeTocreate.getName() + ": " + e, e);
138             }
139         }
140         return (T) o;
141     }
142 }