package org.vertexium.util; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.StrSubstitutor; import org.vertexium.Graph; import org.vertexium.GraphConfiguration; import org.vertexium.VertexiumException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import static org.vertexium.util.Preconditions.checkNotNull; public class ConfigurationUtils { private static final VertexiumLogger LOGGER = VertexiumLoggerFactory.getLogger(ConfigurationUtils.class); public static <T> T createProvider(Graph graph, GraphConfiguration config, String propPrefix, String defaultProvider) throws VertexiumException { String implClass = config.getString(propPrefix, defaultProvider); checkNotNull(implClass, "createProvider could not find " + propPrefix + " configuration item"); return createProvider(implClass, graph, config); } @SuppressWarnings("unchecked") public static <T> T createProvider(String className, Graph graph, GraphConfiguration config) throws VertexiumException { checkNotNull(className, "className is required"); className = className.trim(); LOGGER.debug("creating provider '%s'", className); Class<Graph> graphClass = Graph.class; Class<GraphConfiguration> graphConfigurationClass = GraphConfiguration.class; try { Class<?> clazz = Class.forName(className); try { Constructor constructor; try { constructor = clazz.getConstructor(graphClass); return (T) constructor.newInstance(graph); } catch (NoSuchMethodException ignore1) { try { constructor = clazz.getConstructor(graphClass, graphConfigurationClass); return (T) constructor.newInstance(graph, config); } catch (NoSuchMethodException ignore2) { try { constructor = clazz.getConstructor(graphConfigurationClass); return (T) constructor.newInstance(config); } catch (NoSuchMethodException ignore3) { try { constructor = clazz.getConstructor(Map.class); return (T) constructor.newInstance(config.getConfig()); } catch (NoSuchMethodException ignoreInner) { constructor = clazz.getConstructor(); return (T) constructor.newInstance(); } } } } } catch (IllegalArgumentException e) { StringBuilder possibleMatches = new StringBuilder(); for (Constructor<?> s : clazz.getConstructors()) { possibleMatches.append(s.toGenericString()); possibleMatches.append(", "); } throw new VertexiumException("Invalid constructor for " + className + ". Expected <init>(" + graphConfigurationClass.getName() + "). Found: " + possibleMatches, e); } } catch (NoSuchMethodException e) { throw new VertexiumException("Provider must have a single argument constructor taking a " + graphConfigurationClass.getName(), e); } catch (ClassNotFoundException e) { throw new VertexiumException("No provider found with class name " + className, e); } catch (Exception e) { throw new VertexiumException(e); } } public static Map<String, String> loadConfig(List<String> configFileNames, String configPropertyPrefix) throws IOException { Map<String, String> props = loadFiles(configFileNames); resolvePropertyReferences(props); return stripPrefix(props, configPropertyPrefix); } private static Map<String, String> loadFiles(List<String> configFileNames) throws IOException { Properties props = new Properties(); for (String configFileName : configFileNames) { File configFile = new File(configFileName); if (!configFile.exists()) { throw new RuntimeException("Could not load config file: " + configFile.getAbsolutePath()); } try (InputStream in = new FileInputStream(configFile)) { props.load(in); } } return propertiesToMap(props); } private static Map<String, String> stripPrefix(Map<String, String> propsMap, String configPropertyPrefix) { Map<String, String> result = new HashMap<>(); if (configPropertyPrefix == null) { result.putAll(propsMap); } else { for (Map.Entry<String, String> p : propsMap.entrySet()) { if (p.getKey().startsWith(configPropertyPrefix + ".")) { result.put(p.getKey().substring((configPropertyPrefix + ".").length()), p.getValue()); } else if (p.getKey().startsWith(configPropertyPrefix)) { result.put(p.getKey().substring(configPropertyPrefix.length()), p.getValue()); } } } return result; } private static Map<String, String> propertiesToMap(Properties props) { Map<String, String> results = new HashMap<>(); for (Map.Entry<Object, Object> entry : props.entrySet()) { results.put("" + entry.getKey(), "" + entry.getValue()); } return results; } private static void resolvePropertyReferences(Map<String, String> config) { for (Map.Entry<String, String> entry : config.entrySet()) { String entryValue = (String) ((Map.Entry) entry).getValue(); if (!StringUtils.isBlank(entryValue)) { entry.setValue(StrSubstitutor.replace(entryValue, config)); } } } }