blob: b45f36fa12947ab6524d4ea9403b35707bbee9ff [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
******************************************************************************/
package uk.org.taverna.configuration.app.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.log4j.Logger;
import uk.org.taverna.commons.profile.xml.jaxb.ApplicationProfile;
import uk.org.taverna.configuration.app.ApplicationConfiguration;
/**
* Represent the application config as it has been specified in {@value #PROPERTIES}. This
* configuration specifies the application's name and title, etc.
* <p>
* An application would typically provide the {@value #PROPERTIES} file on the classpath under a
* <code>conf</code> directory, or in a <code>conf</code> directory in the application's
* distribution directory.
*
* @author Stian Soiland-Reyes
* @author David Withers
*/
public class ApplicationConfigurationImpl implements ApplicationConfiguration {
private static final Logger logger = Logger.getLogger(ApplicationConfigurationImpl.class);
private static final String UNKNOWN_APPLICATION = "unknownApplication-"
+ UUID.randomUUID().toString();
public static final String APP_HOME = "taverna.app.home";
public static final String APP_STARTUP = "taverna.app.startup";
public static final String APPLICATION_PROFILE = "ApplicationProfile.xml";
private File startupDir;
private File homeDir;
private ApplicationProfile applicationProfile;
private ApplicationProfile defaultApplicationProfile;
public ApplicationConfigurationImpl() {
}
@Override
public String getName() {
String name = null;
ApplicationProfile profile = getDefaultApplicationProfile();
if (profile != null) {
name = profile.getName();
}
if (name == null) {
logger.error("ApplicationConfig could not determine application name, using "
+ UNKNOWN_APPLICATION);
return UNKNOWN_APPLICATION;
}
return name;
}
@Override
public String getTitle() {
return getName();
}
@Override
public File getStartupDir() {
if (startupDir == null) {
String startupDirName = System.getProperty(APP_STARTUP);
if (startupDirName != null) {
startupDir = new File(startupDirName).getAbsoluteFile();
}
}
return startupDir;
}
@Override
public synchronized File getApplicationHomeDir() {
if (homeDir == null) {
if (getName().equals(ApplicationConfigurationImpl.UNKNOWN_APPLICATION)) {
try {
// Make a temporary home directory as a backup
homeDir = File.createTempFile(getName(), "home");
homeDir.delete();
homeDir.mkdirs();
} catch (IOException e) {
throw new IllegalStateException("Can't create temporary application home", e);
}
logger.warn("Could not determine application's user home,"
+ " using temporary dir " + homeDir);
} else {
homeDir = new ApplicationUserHome(getName(), System.getProperty(APP_HOME)).getAppUserHome();
}
if (homeDir == null || !homeDir.isDirectory()) {
throw new IllegalStateException("Could not create application home directory "
+ homeDir);
}
}
return homeDir;
}
@Override
public File getUserPluginDir() {
File userPluginsDir = new File(getApplicationHomeDir(), PLUGINS_DIR);
try {
userPluginsDir.mkdirs();
} catch (SecurityException e) {
logger.warn("Error creating user plugin directory at " + userPluginsDir, e);
}
return userPluginsDir;
}
@Override
public File getSystemPluginDir() {
File systemPluginsDir = new File(getStartupDir(), PLUGINS_DIR);
try {
systemPluginsDir.mkdirs();
} catch (SecurityException e) {
logger.debug("Error creating system plugin directory at " + systemPluginsDir, e);
}
return systemPluginsDir;
}
@Override
public File getLogFile() {
return new File(getLogDir(), getName() + ".log");
}
@Override
public File getLogDir() {
File logDir = new File(getApplicationHomeDir(), "logs");
logDir.mkdirs();
if (!logDir.isDirectory()) {
throw new IllegalStateException("Could not create log directory " + logDir);
}
return logDir;
}
private void findInClassLoader(List<URI> configs, ClassLoader classLoader, String resourcePath) {
Enumeration<URL> resources;
try {
resources = classLoader.getResources(resourcePath);
} catch (IOException ex) {
System.err.println("Error looking for " + resourcePath + " in " + classLoader);
ex.printStackTrace();
return;
}
while (resources.hasMoreElements()) {
URL configURL = resources.nextElement();
try {
configs.add(configURL.toURI());
} catch (URISyntaxException ex) {
throw new RuntimeException("Invalid URL from getResource(): " + configURL, ex);
}
}
}
/**
* Attempt to load application properties from propertyFileName.
* <p>
* Will attempt to load a property file from the locations below. The first non-empty properties
* successfully loaded will be returned.
* <ol>
* <li>$startup/conf/$resourceName</li>
* <li>$startup/$resourceName</li>
* <li>$contextClassPath/conf/$resourceName</li>
* <li>$contextClassPath/$resourceName</li>
* <li>$classpath/conf/$resourceName</li>
* <li>$classpath/$resourceName</li>
* </ol>
* <p>
* Where <code>$startup</code> is this application's startup directory as determined by
* {@link #getStartupDir()}, and <code>$contextClassPath</code> means a search using
* {@link ClassLoader#getResources(String)} from the classloader returned by
* {@link Thread#getContextClassLoader()} and then again <code>$classpath</code> for the
* classloader of {@link #getClass()} of this instance.
* </p>
* <p>
* If none of these sources could find a non-empty property file, a warning is logged, and an
* empty {@link Properties} instance is returned.
*
* @param resourceName
* Relative filename of property file
*
* @return Loaded or empty {@link Properties} instance.
*/
protected Properties loadProperties(String resourceName) {
// Ordered list of config locations to attempt to load
// properties from
List<URI> configs = new ArrayList<URI>();
File startupDir = getStartupDir();
if (startupDir != null) {
configs.add(startupDir.toURI().resolve(CONF_DIR).resolve(resourceName));
configs.add(startupDir.toURI().resolve(resourceName));
}
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
findInClassLoader(configs, contextClassLoader, CONF_DIR + resourceName);
findInClassLoader(configs, contextClassLoader, resourceName);
findInClassLoader(configs, getClass().getClassLoader(), CONF_DIR + resourceName);
findInClassLoader(configs, getClass().getClassLoader(), resourceName);
Properties loadedProps = new Properties();
for (URI config : configs) {
try {
InputStream inputStream = config.toURL().openStream();
loadedProps.load(inputStream);
} catch (MalformedURLException ex) {
throw new RuntimeException("Invalid URL from URI: " + config, ex);
} catch (IOException ex) {
continue; // Probably not found/access denied
}
if (!loadedProps.isEmpty()) {
logger.debug("Loaded " + resourceName + " from " + config);
return loadedProps;
}
}
logger.debug("Could not find application properties file " + resourceName);
return loadedProps;
}
@Override
public ApplicationProfile getApplicationProfile() {
if (applicationProfile == null) {
File applicationProfileFile = new File(getApplicationHomeDir(), APPLICATION_PROFILE);
if (!applicationProfileFile.exists()) {
logger.debug("Application profile not found at " + applicationProfileFile);
return getDefaultApplicationProfile();
}
try {
JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationProfile.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
applicationProfile = (ApplicationProfile) unmarshaller.unmarshal(applicationProfileFile);
} catch (JAXBException e) {
logger.error("Could not read application profile from " + applicationProfileFile, e);
}
if (applicationProfile == null) {
logger.debug("Application profile not found at " + applicationProfileFile);
return getDefaultApplicationProfile();
}
}
return applicationProfile;
}
public ApplicationProfile getDefaultApplicationProfile() {
if (defaultApplicationProfile == null) {
File applicationProfileFile = new File(getStartupDir(), APPLICATION_PROFILE);
if (applicationProfileFile.exists()) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationProfile.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
defaultApplicationProfile = (ApplicationProfile) unmarshaller.unmarshal(applicationProfileFile);
} catch (JAXBException e) {
throw new IllegalStateException("Could not read application profile from " + applicationProfileFile);
}
}
}
return defaultApplicationProfile;
}
}