/** * Copyright 2013 Benjamin Lerer * * 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 io.horizondb.db; import io.horizondb.db.Configuration.Builder; import io.horizondb.model.ErrorCodes; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.PropertyResourceBundle; /** * <code>ConfigurationLoader</code> that loads the configuration from a properties file. * * @author Benjamin * */ final class PropertiesFileConfigurationLoader implements ConfigurationLoader { /** * The methods of the <code>Configuration.Builder</code>. */ private final Map<String, Method> methods = new HashMap<>(); /** * Creates a new <code>PropertiesFileConfigurationLoader</code> */ public PropertiesFileConfigurationLoader() { Method[] declaredMethods = Builder.class.getDeclaredMethods(); for (Method method : declaredMethods) { this.methods.put(method.getName(), method); } } /** * {@inheritDoc} */ @Override public Configuration loadConfigurationFrom(InputStream input) throws IOException, HorizonDBException { PropertyResourceBundle resourceBundle = new PropertyResourceBundle(input); Builder builder = Configuration.newBuilder(); for (String key : resourceBundle.keySet()) { setProperty(builder, key, resourceBundle.getString(key)); } return builder.build(); } /** * {@inheritDoc} */ @Override public Configuration loadConfigurationFromClasspath(String filename) throws IOException, HorizonDBException { InputStream in = getClassLoader().getResourceAsStream(filename); if (in == null) { throw new IllegalStateException("The '" + filename + "' file cannot be found within the classpath."); } return loadConfigurationFrom(in); } /** * Returns the <code>ClassLoader</code> that has been used to load this class. * * @return the <code>ClassLoader</code> that has been used to load this class. */ private ClassLoader getClassLoader() { return this.getClass().getClassLoader(); } /** * Sets the specified property on the specified builder. * * @param builder the configuration builder * @param propertyName the property name * @param value the property value * @throws HorizonDBException if the property cannot be converted */ private void setProperty(Builder builder, String propertyName, String value) throws HorizonDBException { Method method = this.methods.get(propertyName); try { method.invoke(builder, toType(propertyName, value.trim(), method.getParameterTypes()[0])); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NullPointerException e) { throw new HorizonDBException(ErrorCodes.INVALID_CONFIGURATION, "The configuration property: " + propertyName + " does not exists."); } } /** * Converts the specified <code>String</code> value into the specified type. * * @param propertyName the property name * @param value the value to convert * @param type the type into which the value must be converted * @return the converted value * @throws HorizonDBException if the value cannot be converted */ @SuppressWarnings("boxing") private static Object toType(String propertyName, String value, Class<?> type) throws HorizonDBException { try { if (int.class.equals(type)) { return Integer.parseInt(value); } if (long.class.equals(type)) { return Long.parseLong(value); } if (Path.class.equals(type)) { return FileSystems.getDefault().getPath(value); } } catch (NumberFormatException e) { throw new HorizonDBException(ErrorCodes.INVALID_CONFIGURATION, "The value: '" + value + "' associated to the property: " + propertyName + " is not a valid " + type + "."); } throw new IllegalStateException("Convertion to the type: " + type + " is not supported."); } }