/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* 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.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.framework.util;
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.mifos.core.MifosResourceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
/**
* Encapsulates logic for determining which directory to look in for
* configuration files.
* <p>
* Does not use MifosLogger since this requires prior initialization, but this
* particular class is used to find the file used to configure the logger.
*/
public class ConfigurationLocator {
public static final String LOCATOR_ENVIRONMENT_PROPERTY_NAME = "MIFOS_CONF";
private static final String LOCATOR_SYSTEM_PROPERTY_NAME = "mifos.conf";
private static final String HOME_PROPERTY_NAME = "user.home";
private static final String MIFOS_USER_CONFIG_DIRECTORY_NAME = ".mifos";
private static final String DEFAULT_CONFIGURATION_PATH = "org/mifos/config/resources/";
private static final String LOGO_DIR = "logo";
private static final String LOGO_NAME = "logo.png";
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationLocator.class.getName());
@SuppressWarnings("PMD.ImmutableField")
private ConfigurationLocatorHelper configurationLocatorHelper;
private String defaultConfigPath;
private static final Pattern PROPERTY_PATTERN = Pattern.compile("\\$\\{([^\\$\\s/\\{\\}]+)\\}");
private static final Pattern ENV_VAR_PATTERN = Pattern.compile("\\$([^\\$\\W\\{\\}/]+)");
public ConfigurationLocator() {
super();
configurationLocatorHelper = new ConfigurationLocatorHelper();
}
/**
* Will not throw an exception if the file is not found. This method may be
* used to find files in cases where we don't care if the file cannot be
* found.
* @throws IOException
*/
@SuppressWarnings("PMD")
// TODO It may be clearer if this returned an URI or URL instead of a String?
public String getCustomFilePath(String filename) throws IOException {
String returnValue = filename;
LOGGER.info("Checking existance of : " + filename);
Resource configFile = getResource(filename);
if(configFile != null && configFile.exists()) {
returnValue = configFile.getURL().toExternalForm();
LOGGER.info("Custom configuration file exists : " + returnValue);
}
return returnValue;
}
// TODO It would be clearer if this returned a File or even better a Resource instead of a String
public String getFilePath(String filename) throws IOException {
File file = getFile(filename);
if(file != null && file.exists()){
return file.getAbsolutePath(); // NOPMD by ugupta on 8/2/11 9:27 AM
}
return null;
}
private String[] getDirectoriesToSearch() {
String systemPropertyDirectory = System.getProperty(LOCATOR_SYSTEM_PROPERTY_NAME);
String envPropertyDirectory = configurationLocatorHelper.getEnvironmentProperty(LOCATOR_ENVIRONMENT_PROPERTY_NAME);
String homeDirectory = getHomeProperty();
String userConfigDirectory = homeDirectory + '/' + MIFOS_USER_CONFIG_DIRECTORY_NAME;
return new String[] { systemPropertyDirectory, envPropertyDirectory, userConfigDirectory };
}
@SuppressWarnings({"PMD.OnlyOneReturn"})
public String getConfigurationDirectory() {
for (String directoryPath : getDirectoriesToSearch()) {
if (directoryExists(directoryPath)) {
LOGGER.info("ConfigurationLocator found configuration directory: " + directoryPath);
return directoryPath;
}
}
return forceConfDirectoryCreation();
}
private String forceConfDirectoryCreation() {
String homeDirectory = getHomeProperty();
String userConfigDirectory = homeDirectory + '/' + MIFOS_USER_CONFIG_DIRECTORY_NAME;
File mifosConf = new File(userConfigDirectory);
if(!mifosConf.mkdir()) {
throw new SecurityException("unable to create .mifos under user.home");
}
return userConfigDirectory;
}
@SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops", "PMD.OnlyOneReturn"})
private Resource getConfigurationResource(String name) throws IOException {
for (String directoryPath : getDirectoriesToSearch()) {
if (StringUtils.isNotBlank(directoryPath)) {
File file = MifosResourceUtil.getFile(directoryPath +"/"+ name);
if (file.exists()) {
return new FileSystemResource(file);
}
}
}
return new ClassPathResource(getDefaultConfigPath() + name);
}
private String getHomeProperty() {
return configurationLocatorHelper.getHomeProperty(HOME_PROPERTY_NAME);
}
private boolean directoryExists(String directory) {
return StringUtils.isNotBlank(directory) && (getFileObject(directory)).exists();
}
private File getFileObject(String directory) {
return configurationLocatorHelper.getFile(directory);
}
private File getFile(String filename) throws IOException {
File fileToReturn = getConfigurationResource(filename).getFile();
LOGGER.info("ConfigurationLocator found configuration file: " + fileToReturn);
return fileToReturn;
}
/**
* Get a Configuration Resource, either from the classpath or from a configuration directory.
*
* @param configurationName name of a configuration resource on the classpatch (e.g. "package/something.properties")
* @return always a Resource, never null (use {@link Resource#exists()} to check)
* @throws IOException if something unexpected went wrong
*/
public Resource getResource(String configurationName) throws IOException {
Resource res = getConfigurationResource(configurationName);
LOGGER.info("ConfigurationLocator found configuration in resource: " + res.getDescription());
return res;
}
public Resource getUploadedMifosLogo() throws IOException {
return getConfigurationResource(getLogoDirectory() + File.separator + getLogoName());
}
public void setConfigurationLocatorHelper(ConfigurationLocatorHelper fileFactory) {
this.configurationLocatorHelper = fileFactory;
}
public void setDefaultConfigPath(String path) {
this.defaultConfigPath = path;
}
private String getDefaultConfigPath() {
return StringUtils.isBlank(this.defaultConfigPath) ? DEFAULT_CONFIGURATION_PATH : this.defaultConfigPath;
}
public String resolvePath(String fileName) {
StringBuilder fileBuffer = new StringBuilder(fileName);
resolveHomeProperties(fileName, fileBuffer);
resolveEnvironmentProperties(fileName, fileBuffer);
return fileBuffer.toString();
}
private void resolveEnvironmentProperties(String fileName, StringBuilder fileBuffer) {
Matcher envVarMatcher = ENV_VAR_PATTERN.matcher(fileName);
while (envVarMatcher.find()) {
String envVar = envVarMatcher.group();
String environmentProperty = configurationLocatorHelper.getEnvironmentProperty(envVar.substring(1));
if (environmentProperty != null) {
fileBuffer.replace(envVarMatcher.start(), envVarMatcher.end(), environmentProperty);
}
}
}
private void resolveHomeProperties(String fileName, StringBuilder fileBuffer) {
Matcher matcher = PROPERTY_PATTERN.matcher(fileName);
while (matcher.find()) {
String property = matcher.group();
String homeProperty = configurationLocatorHelper.getHomeProperty(property.substring(2, property.length() - 1));
if (homeProperty != null) {
fileBuffer.replace(matcher.start(), matcher.end(), homeProperty);
}
}
}
public String getLogoDirectory() {
return LOGO_DIR;
}
public String getLogoName() {
return LOGO_NAME;
}
}