Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/MantidVersion.h"
Janik Zikovsky
committed
#include "MantidKernel/Strings.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/FilterChannel.h"
#include "MantidKernel/SignalChannel.h"
#include "MantidKernel/Exception.h"
Roman Tolchenov
committed
#include "MantidKernel/FacilityInfo.h"
#include <Poco/Util/LoggingConfigurator.h>
#include <Poco/Util/SystemConfiguration.h>
#include <Poco/Util/PropertyFileConfiguration.h>
#include <Poco/LoggingFactory.h>
#include <Poco/Path.h>
#include <Poco/File.h>
#include <Poco/StringTokenizer.h>
#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/Notification.h>
#include <Poco/Environment.h>
Robert Whitley
committed
#include <Poco/Process.h>
Robert Whitley
committed
#include <Poco/String.h>
Gigg, Martyn Anthony
committed
#include <boost/algorithm/string/replace.hpp>
Gigg, Martyn Anthony
committed
#include <boost/algorithm/string/join.hpp>
Gigg, Martyn Anthony
committed
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
Janik Zikovsky
committed
/**
* Get the welcome message for Mantid.
* @returns A string containing the welcome message for Mantid.
*/
std::string welcomeMessage()
{
return "Welcome to Mantid - Manipulation and Analysis Toolkit for Instrument Data";
}
Campbell, Stuart
committed
/** Inner templated class to wrap the poco library objects that have protected
* destructors and expose them as public.
*/
template<typename T>
class ConfigServiceImpl::WrappedObject: public T
{
public:
/// The template type of class that is being wrapped
typedef T element_type;
/// Simple constructor
WrappedObject() :
T()
{
m_pPtr = static_cast<T*> (this);
}
/** Constructor with a class to wrap
Janik Zikovsky
committed
* @param F :: The object to wrap
Campbell, Stuart
committed
template<typename Field>
WrappedObject(Field& F) :
T(F)
{
m_pPtr = static_cast<T*> (this);
}
Campbell, Stuart
committed
/// Copy constructor
WrappedObject(const WrappedObject<T>& A) :
T(A)
{
m_pPtr = static_cast<T*> (this);
}
Campbell, Stuart
committed
/// Virtual destructor
virtual ~WrappedObject()
{
}
Campbell, Stuart
committed
/// Overloaded * operator returns the wrapped object pointer
const T& operator*() const
{
return *m_pPtr;
}
/// Overloaded * operator returns the wrapped object pointer
T& operator*()
{
return m_pPtr;
}
/// Overloaded -> operator returns the wrapped object pointer
const T* operator->() const
{
return m_pPtr;
}
/// Overloaded -> operator returns the wrapped object pointer
T* operator->()
{
return m_pPtr;
}
Campbell, Stuart
committed
private:
/// Private pointer to the wrapped class
T* m_pPtr;
};
Campbell, Stuart
committed
//Back to the ConfigService class itself...
Campbell, Stuart
committed
//-------------------------------
// Private member functions
//-------------------------------
Roman Tolchenov
committed
Campbell, Stuart
committed
/// Private constructor for singleton class
ConfigServiceImpl::ConfigServiceImpl() :
m_pConf(NULL), m_pSysConfig(NULL), g_log(Logger::get("ConfigService")), m_changed_keys(),
m_ConfigPaths(), m_AbsolutePaths(), m_strBaseDir(""), m_PropertyString(""),
m_properties_file_name("Mantid.properties"),
Janik Zikovsky
committed
m_user_properties_file_name("Mantid.user.properties"), m_DataSearchDirs(), m_UserSearchDirs(),
m_instr_prefixes()
Campbell, Stuart
committed
{
//getting at system details
m_pSysConfig = new WrappedObject<Poco::Util::SystemConfiguration> ;
m_pConf = 0;
//Register the FilterChannel with the Poco logging factory
Poco::LoggingFactory::defaultFactory().registerChannelClass("FilterChannel", new Poco::Instantiator<
Poco::FilterChannel, Poco::Channel>);
//Register the SignalChannel with the Poco logging factory
Poco::LoggingFactory::defaultFactory().registerChannelClass("SignalChannel", new Poco::Instantiator<
Poco::SignalChannel, Poco::Channel>);
Gigg, Martyn Anthony
committed
// Define the directory to search for the Mantid.properties file.
Janik Zikovsky
committed
Poco::File f;
// First directory: the current working
m_strBaseDir = Poco::Path::current();
f = Poco::File(m_strBaseDir + m_properties_file_name);
Janik Zikovsky
committed
// Check the executable directory to see if it includes a mantid.properties file
Gigg, Martyn Anthony
committed
m_strBaseDir = getDirectoryOfExecutable();
Janik Zikovsky
committed
f = Poco::File(m_strBaseDir + m_properties_file_name);
if (!f.exists())
Janik Zikovsky
committed
// Last, use the MANTIDPATH environment var
if (Poco::Environment::has("MANTIDPATH"))
{
// Here we have to follow the convention of the rest of this code and add a trailing slash.
// Note: adding it to the MANTIDPATH itself will make other parts of the code crash.
m_strBaseDir = Poco::Environment::get("MANTIDPATH") + "/";
}
Campbell, Stuart
committed
//Fill the list of possible relative path keys that may require conversion to absolute paths
m_ConfigPaths.insert(std::make_pair("plugins.directory", true));
Russell Taylor
committed
m_ConfigPaths.insert(std::make_pair("mantidqt.plugins.directory", true));
Campbell, Stuart
committed
m_ConfigPaths.insert(std::make_pair("instrumentDefinition.directory", true));
Russell Taylor
committed
m_ConfigPaths.insert(std::make_pair("parameterDefinition.directory", true));
Campbell, Stuart
committed
m_ConfigPaths.insert(std::make_pair("requiredpythonscript.directories", true));
m_ConfigPaths.insert(std::make_pair("pythonscripts.directory", true));
m_ConfigPaths.insert(std::make_pair("pythonscripts.directories", true));
m_ConfigPaths.insert(std::make_pair("ManagedWorkspace.FilePath", true));
m_ConfigPaths.insert(std::make_pair("defaultsave.directory", false));
m_ConfigPaths.insert(std::make_pair("datasearch.directories", true));
m_ConfigPaths.insert(std::make_pair("pythonalgorithms.directories", true));
m_ConfigPaths.insert(std::make_pair("icatDownload.directory", true));
Doucet, Mathieu
committed
m_ConfigPaths.insert(std::make_pair("mantidqt.python_interfaces_directory", true));
Campbell, Stuart
committed
//attempt to load the default properties file that resides in the directory of the executable
Janik Zikovsky
committed
std::string propertiesFilesList;
Gigg, Martyn Anthony
committed
updateConfig(getPropertiesDir() + m_properties_file_name, false, false);
Janik Zikovsky
committed
propertiesFilesList = getPropertiesDir() + m_properties_file_name;
// Load the local (machine) properties file, if it exists
Poco::File localFile(getLocalFilename());
if ( localFile.exists() )
{
updateConfig(getLocalFilename(), true, false);
propertiesFilesList += ", " + getLocalFilename();
}
Janik Zikovsky
committed
if (Poco::Environment::has("MANTIDPROPERTIES"))
{
//and then append the user properties
updateConfig(getUserFilename(), true, false);
Janik Zikovsky
committed
propertiesFilesList += ", " + getUserFilename();
//and the extra one from the environment
updateConfig(Poco::Environment::get("MANTIDPROPERTIES"), true, true);
propertiesFilesList += ", " + Poco::Environment::get("MANTIDPROPERTIES");
}
else
{
// Just do the user properties
updateConfig(getUserFilename(), true, true);
propertiesFilesList += ", " + getUserFilename();
}
Campbell, Stuart
committed
updateFacilities();
g_log.debug() << "ConfigService created." << std::endl;
Janik Zikovsky
committed
g_log.debug() << "Configured Mantid.properties directory of application as " << getPropertiesDir()
<< std::endl;
Russell Taylor
committed
g_log.information() << "This is Mantid Version " << MantidVersion::version() << std::endl;
Janik Zikovsky
committed
g_log.information() << "Properties file(s) loaded: " << propertiesFilesList << std::endl;
g_log.information() << "Logging to: " << m_logFilePath << std::endl;
// Make sure the log path is shown somewhere.
//std::cout << "Logging to: " << m_logFilePath << std::endl;
Campbell, Stuart
committed
}
/** Private Destructor
* Prevents client from calling 'delete' on the pointer handed out by Instance
*/
ConfigServiceImpl::~ConfigServiceImpl()
{
//std::cerr << "ConfigService destroyed." << std::endl;
Kernel::Logger::shutdown();
delete m_pSysConfig;
delete m_pConf; // potential double delete???
for (std::vector<FacilityInfo*>::iterator it = m_facilities.begin(); it != m_facilities.end(); ++it)
Campbell, Stuart
committed
delete *it;
}
m_facilities.clear();
}
/** Loads the config file provided.
* If the file contains logging setup instructions then these will be used to setup the logging framework.
*
Janik Zikovsky
committed
* @param filename :: The filename and optionally path of the file to load
* @param append :: If false (default) then any previous configuration is discarded, otherwise the new keys are added, and repeated keys will override existing ones.
Campbell, Stuart
committed
*/
void ConfigServiceImpl::loadConfig(const std::string& filename, const bool append)
{
delete m_pConf;
if (!append)
{
//remove the previous property string
m_PropertyString = "";
Campbell, Stuart
committed
try
Campbell, Stuart
committed
//slurp in entire file
std::string temp;
bool good = readFile(filename, temp);
Campbell, Stuart
committed
// check if we have failed to open the file
if ((!good) || (temp == ""))
Gigg, Martyn Anthony
committed
if (filename == getUserPropertiesDir() + m_user_properties_file_name)
Campbell, Stuart
committed
//write out a fresh file
createUserPropertiesFile();
Campbell, Stuart
committed
throw Exception::FileError("Cannot open file", filename);
Campbell, Stuart
committed
}
Campbell, Stuart
committed
//store the property string
if ((append) && (m_PropertyString != ""))
{
m_PropertyString = m_PropertyString + "\n" + temp;
Campbell, Stuart
committed
else
Campbell, Stuart
committed
m_PropertyString = temp;
Campbell, Stuart
committed
} catch (std::exception& e)
Campbell, Stuart
committed
//there was a problem loading the file - it probably is not there
std::cerr << "Problem loading the configuration file " << filename << " " << e.what() << std::endl;
if (!append)
Campbell, Stuart
committed
// if we have no property values then take the default
m_PropertyString = defaultConfig();
Campbell, Stuart
committed
}
Campbell, Stuart
committed
//use the cached property string to initialise the POCO property file
std::istringstream istr(m_PropertyString);
m_pConf = new WrappedObject<Poco::Util::PropertyFileConfiguration> (istr);
}
/**
* Read a file and place its contents into the given string
Janik Zikovsky
committed
* @param filename :: The filename of the file to read
* @param contents :: The file contents will be placed here
Campbell, Stuart
committed
* @returns A boolean indicating whether opening the file was successful
*/
bool ConfigServiceImpl::readFile(const std::string& filename, std::string & contents) const
{
std::ifstream propFile(filename.c_str(), std::ios::in);
bool good = propFile.good();
if (!good)
{
contents = "";
propFile.close();
return good;
}
Campbell, Stuart
committed
//slurp in entire file - extremely unlikely delimiter used as an alternate to \n
contents.clear();
getline(propFile, contents, '`');
propFile.close();
return good;
}
/** Configures the Poco logging and starts it up
*
*/
Campbell, Stuart
committed
void ConfigServiceImpl::configureLogging()
{
try
Campbell, Stuart
committed
//Ensure that the logging directory exists
m_logFilePath = getString("logging.channels.fileChannel.path");
Poco::Path logpath(m_logFilePath);
// Undocumented way to override the mantid.log path
if (Poco::Environment::has("MANTIDLOGPATH"))
Gigg, Martyn Anthony
committed
{
logpath = Poco::Path(Poco::Environment::get("MANTIDLOGPATH"));
Gigg, Martyn Anthony
committed
logpath = logpath.absolute();
m_logFilePath = logpath.toString();
}
// An absolute path makes things simpler
logpath = logpath.absolute();
Gigg, Martyn Anthony
committed
// First, try the logpath given
if (!m_logFilePath.empty())
{
try
{
// Save it for later
m_logFilePath = logpath.toString();
//make this path point to the parent directory and create it if it does not exist
Poco::Path parent = logpath;
parent.makeParent();
Poco::File(parent).createDirectories();
// Try to create or append to the file. If it fails, use the default
FILE *fp = fopen(m_logFilePath.c_str(), "a+");
if (fp == NULL)
{
Janik Zikovsky
committed
std::cerr << "Error writing to log file path given in properties file: \"" << m_logFilePath
<< "\". Will use a default path instead." << std::endl;
// Clear the path; this will make it use the default
m_logFilePath = "";
}
else
fclose(fp);
Janik Zikovsky
committed
} catch (std::exception &)
{
Janik Zikovsky
committed
std::cerr << "Error writing to log file path given in properties file: \"" << m_logFilePath
<< "\". Will use a default path instead." << std::endl;
// ERROR! Maybe the file is not writable!
// Clear the path; this will make it use the default
m_logFilePath = "";
}
}
// The path given was invalid somehow? Use a default
if (m_logFilePath.empty())
m_logFilePath = getUserPropertiesDir() + "mantid.log";
logpath.assign(m_logFilePath);
logpath = logpath.absolute();
m_logFilePath = logpath.toString();
// Set the line in the configuration properties.
// this'll be picked up by LoggingConfigurator (somehow)
m_pConf->setString("logging.channels.fileChannel.path", m_logFilePath);
Campbell, Stuart
committed
//make this path point to the parent directory and create it if it does not exist
logpath.makeParent();
if (!logpath.toString().empty())
Poco::File(logpath).createDirectories(); // Also creates all necessary directories
// Configure the logging framework
Campbell, Stuart
committed
Poco::Util::LoggingConfigurator configurator;
configurator.configure(m_pConf);
Janik Zikovsky
committed
} catch (std::exception& e)
Campbell, Stuart
committed
{
std::cerr << "Trouble configuring the logging framework " << e.what() << std::endl;
Campbell, Stuart
committed
}
Campbell, Stuart
committed
/**
* Searches the stored list for keys that have been loaded from the config file and may contain
* relative paths. Any it find are converted to absolute paths and stored separately
*/
void ConfigServiceImpl::convertRelativeToAbsolute()
{
if (m_ConfigPaths.empty())
return;
Campbell, Stuart
committed
m_AbsolutePaths.clear();
std::map<std::string, bool>::const_iterator send = m_ConfigPaths.end();
for (std::map<std::string, bool>::const_iterator sitr = m_ConfigPaths.begin(); sitr != send; ++sitr)
{
std::string key = sitr->first;
if (!m_pConf->hasProperty(key))
continue;
Campbell, Stuart
committed
std::string value(m_pConf->getString(key));
value = makeAbsolute(value, key);
m_AbsolutePaths.insert(std::make_pair(key, value));
}
}
/**
* Make a relative path or a list of relative paths into an absolute one.
Janik Zikovsky
committed
* @param dir :: The directory to convert
* @param key :: The key variable this relates to
Campbell, Stuart
committed
* @returns A string containing an aboluste path by resolving the relative directory with the executable directory
*/
std::string ConfigServiceImpl::makeAbsolute(const std::string & dir, const std::string & key) const
{
std::string converted;
// If we have a list, chop it up and convert each one
if (dir.find_first_of(";,") != std::string::npos)
Campbell, Stuart
committed
int options = Poco::StringTokenizer::TOK_TRIM + Poco::StringTokenizer::TOK_IGNORE_EMPTY;
Poco::StringTokenizer tokenizer(dir, ";,", options);
Poco::StringTokenizer::Iterator iend = tokenizer.end();
for (Poco::StringTokenizer::Iterator itr = tokenizer.begin(); itr != iend;)
Campbell, Stuart
committed
std::string absolute = makeAbsolute(*itr, key);
if (absolute.empty())
Campbell, Stuart
committed
++itr;
}
else
{
converted += absolute;
if (++itr != iend)
Campbell, Stuart
committed
converted += ";";
Campbell, Stuart
committed
}
Campbell, Stuart
committed
// MG 05/10/09: When the Poco::FilePropertyConfiguration object reads its key/value pairs it
// treats a backslash as the start of an escape sequence. If the next character does not
// form a valid sequence then the backslash is removed from the stream. This has the effect
// of giving malformed paths when using Windows-style directories. E.g C:\Mantid ->C:Mantid
// and Poco::Path::isRelative throws an exception on this
bool is_relative(false);
try
Campbell, Stuart
committed
is_relative = Poco::Path(dir).isRelative();
} catch (Poco::PathSyntaxException&)
Campbell, Stuart
committed
{
g_log.warning() << "Malformed path detected in the \"" << key << "\" variable, skipping \"" << dir
<< "\"\n";
return "";
}
if (is_relative)
{
Gigg, Martyn Anthony
committed
const std::string propFileDir(getPropertiesDir());
Gigg, Martyn Anthony
committed
converted = Poco::Path(propFileDir).resolve(dir).toString();
Campbell, Stuart
committed
}
else
{
converted = dir;
Campbell, Stuart
committed
converted = Poco::Path(converted).makeDirectory().toString();
Campbell, Stuart
committed
// C++ doesn't have a const version of operator[] for maps so I can't call that here
std::map<std::string, bool>::const_iterator it = m_ConfigPaths.find(key);
bool required = false;
if (it != m_ConfigPaths.end())
Campbell, Stuart
committed
required = it->second;
}
Michael Whitty
committed
try
{
if (required && !Poco::File(converted).exists())
{
g_log.warning() << "Required properties path \"" << converted << "\" in the \"" << key
<< "\" variable does not exist.\n";
converted = "";
}
} catch ( Poco::FileException & )
Campbell, Stuart
committed
{
g_log.warning() << "Required properties path \"" << converted << "\" in the \"" << key
<< "\" variable does not exist.\n";
converted = "";
}
Michael Whitty
committed
Gigg, Martyn Anthony
committed
// Backward slashes cannot be allowed to go into our properties file
// Note this is a temporary fix for ticket #2445.
// Ticket #2460 prompts a review of our path handling in the config service.
Janik Zikovsky
committed
boost::replace_all(converted, "\\", "/");
Campbell, Stuart
committed
return converted;
}
/**
* Create the store of data search paths from the 'datasearch.directories' key within the Mantid.properties file.
* The value of the key should be a semi-colon separated list of directories
*/
void ConfigServiceImpl::cacheDataSearchPaths()
{
m_DataSearchDirs.clear();
std::string paths = getString("datasearch.directories");
//Nothing to do
if (paths.empty())
return;
int options = Poco::StringTokenizer::TOK_TRIM + Poco::StringTokenizer::TOK_IGNORE_EMPTY;
Poco::StringTokenizer tokenizer(paths, ";,", options);
Poco::StringTokenizer::Iterator iend = tokenizer.end();
m_DataSearchDirs.reserve(tokenizer.count());
for (Poco::StringTokenizer::Iterator itr = tokenizer.begin(); itr != iend; ++itr)
{
m_DataSearchDirs.push_back(*itr);
}
}
/**
* Create the store of user search paths from the 'usersearch.directories' key within the Mantid.properties file.
* The value of the key should be a semi-colon separated list of directories
*/
void ConfigServiceImpl::cacheUserSearchPaths()
{
m_UserSearchDirs.clear();
std::string paths = getString("usersearch.directories");
//Nothing to do
if (paths.empty())
return;
int options = Poco::StringTokenizer::TOK_TRIM + Poco::StringTokenizer::TOK_IGNORE_EMPTY;
Poco::StringTokenizer tokenizer(paths, ";,", options);
Poco::StringTokenizer::Iterator iend = tokenizer.end();
m_UserSearchDirs.reserve(tokenizer.count());
for (Poco::StringTokenizer::Iterator itr = tokenizer.begin(); itr != iend; ++itr)
{
m_UserSearchDirs.push_back(*itr);
}
}
/**
* The path that is passed should be as returned by makeAbsolute() and
* this function will return true if that path is in the list
Janik Zikovsky
committed
* @param path :: the absolute path name to search for
* @return true if the path was found
*/
Gigg, Martyn Anthony
committed
bool ConfigServiceImpl::isInDataSearchList(const std::string & path) const
{
Janik Zikovsky
committed
std::vector<std::string>::const_iterator it = std::find_if(m_DataSearchDirs.begin(),
m_DataSearchDirs.end(), std::bind2nd(std::equal_to<std::string>(), path));
Gigg, Martyn Anthony
committed
return (it != m_DataSearchDirs.end());
}
Campbell, Stuart
committed
/**
* writes a basic placeholder user.properties file to disk
* any errors are caught and logged, but not propagated
*/
void ConfigServiceImpl::createUserPropertiesFile() const
{
try
{
Janik Zikovsky
committed
std::fstream filestr((getUserPropertiesDir() + m_user_properties_file_name).c_str(),
std::fstream::out);
Campbell, Stuart
committed
filestr << "# This file can be used to override any properties for this installation." << std::endl;
filestr
<< "# Any properties found in this file will override any that are found in the Mantid.Properties file"
<< std::endl;
filestr
<< "# As this file will not be replaced with futher installations of Mantid it is a safe place to put "
<< std::endl;
filestr << "# properties that suit your particular installation." << std::endl;
filestr << "" << std::endl;
filestr << "#for example" << std::endl;
filestr
<< "#uncommenting the line below will set the number of algorithms to retain interim results for to be 90"
<< std::endl;
filestr << "#overriding any value set in the Mantid.properties file" << std::endl;
filestr << "#algorithms.retained = 90" << std::endl;
filestr.close();
} catch (std::runtime_error& ex)
Campbell, Stuart
committed
{
Gigg, Martyn Anthony
committed
g_log.warning() << "Unable to write out user.properties file to " << getUserPropertiesDir()
Campbell, Stuart
committed
<< m_user_properties_file_name << " error: " << ex.what() << std::endl;
Campbell, Stuart
committed
}
Campbell, Stuart
committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
/**
* Provides a default Configuration string to use if the config file cannot be loaded.
* @returns The string value of default properties
*/
std::string ConfigServiceImpl::defaultConfig() const
{
std::string propFile = "# logging configuration"
"# root level message filter (drop to debug for more messages)"
"logging.loggers.root.level = debug"
"# splitting the messages to many logging channels"
"logging.loggers.root.channel.class = SplitterChannel"
"logging.loggers.root.channel.channel1 = consoleChannel"
"logging.loggers.root.channel.channel2 = fileFilterChannel"
"logging.loggers.root.channel.channel3 = signalChannel"
"# output to the console - primarily for console based apps"
"logging.channels.consoleChannel.class = ConsoleChannel"
"logging.channels.consoleChannel.formatter = f1"
"# specfic filter for the file channel raising the level to warning (drop to debug for debugging)"
"logging.channels.fileFilterChannel.class= FilterChannel"
"logging.channels.fileFilterChannel.channel= fileChannel"
"logging.channels.fileFilterChannel.level= warning"
"# output to a file (For error capturing and debugging)"
"logging.channels.fileChannel.class = debug"
"logging.channels.fileChannel.path = ../logs/mantid.log"
"logging.channels.fileChannel.formatter.class = PatternFormatter"
"logging.channels.fileChannel.formatter.pattern = %Y-%m-%d %H:%M:%S,%i [%I] %p %s - %t"
"logging.formatters.f1.class = PatternFormatter"
"logging.formatters.f1.pattern = %s-[%p] %t"
"logging.formatters.f1.times = UTC;"
"# SignalChannel - Passes messages to the MantidPlot User interface"
"logging.channels.signalChannel.class = SignalChannel";
return propFile;
}
//-------------------------------
// Public member functions
//-------------------------------
/** Updates and existing configuration and restarts the logging
Janik Zikovsky
committed
* @param filename :: The filename and optionally path of the file to load
* @param append :: If false (default) then any previous configuration is discarded,
Campbell, Stuart
committed
* otherwise the new keys are added, and repeated keys will override existing ones.
Janik Zikovsky
committed
* @param update_caches :: If true(default) then the various property caches are updated
Campbell, Stuart
committed
*/
void ConfigServiceImpl::updateConfig(const std::string& filename, const bool append,
const bool update_caches)
{
//std::cout << "Properties file loaded: " << filename << std::endl;
Campbell, Stuart
committed
loadConfig(filename, append);
if (update_caches)
{
// Only configure logging once
configureLogging();
Campbell, Stuart
committed
//Ensure that any relative paths given in the configuration file are relative to the correct directory
convertRelativeToAbsolute();
//Configure search paths into a specially saved store as they will be used frequently
cacheDataSearchPaths();
cacheUserSearchPaths();
Campbell, Stuart
committed
}
/**
* Save the configuration to the user file
Janik Zikovsky
committed
* @param filename :: The filename for the saved configuration
* @throw std::runtime_error if the file cannot be opened
Campbell, Stuart
committed
*/
void ConfigServiceImpl::saveConfig(const std::string & filename) const
{
if (m_changed_keys.empty())
return;
Campbell, Stuart
committed
// Open and read the user properties file
std::string updated_file("");
std::ifstream reader(filename.c_str(), std::ios::in);
if (reader.bad())
Campbell, Stuart
committed
g_log.error() << "Error reading current user properties file. Cannot save updated configuration.\n";
throw std::runtime_error("Error opening user properties file. Cannot save updated configuration.");
Campbell, Stuart
committed
std::string file_line(""), output("");
bool line_continuing(false);
while (std::getline(reader, file_line))
Campbell, Stuart
committed
if (!file_line.empty())
Campbell, Stuart
committed
char last = *(file_line.end() - 1);
if (last == '\\')
// If we are not in line continuation mode then need
// a fresh start line
Janik Zikovsky
committed
if (!line_continuing)
output = "";
Campbell, Stuart
committed
line_continuing = true;
output += file_line + "\n";
Gigg, Martyn Anthony
committed
continue;
Campbell, Stuart
committed
else if (line_continuing)
Campbell, Stuart
committed
output += file_line;
line_continuing = false;
Campbell, Stuart
committed
output = file_line;
Campbell, Stuart
committed
else
Campbell, Stuart
committed
output = "";
Gigg, Martyn Anthony
committed
updated_file += "\n";
Campbell, Stuart
committed
continue;
Robert Whitley
committed
} //end if-else
// Output is the current line in the file
// Extract the key from the current line
std::string key;
std::string::size_type pos = output.find('=');
if( pos == std::string::npos )
{
key = output; //If no equals then the entire thing is the key
Campbell, Stuart
committed
}
Robert Whitley
committed
else
Campbell, Stuart
committed
{
Robert Whitley
committed
key = output.substr(0,pos); //Strip the equals to get only the key
Robert Whitley
committed
//Now deal with trimming (removes spaces)
Poco::trimInPlace(key);
//Find the comments
std::string::size_type comment = key.find('#');
//Check if it exists in the service using hasProperty and make sure it isn't a comment
if( comment != 0 && !hasProperty(key) )
Campbell, Stuart
committed
{
Robert Whitley
committed
//Remove the key from the changed key list
m_changed_keys.erase(key);
continue;
Campbell, Stuart
committed
}
else
Robert Whitley
committed
//If it does exist perform the current actions below
std::set<std::string>::iterator iend = m_changed_keys.end();
std::set<std::string>::iterator itr = m_changed_keys.begin();
Gigg, Martyn Anthony
committed
Robert Whitley
committed
for (; itr != iend; ++itr)
{
if (output.find(*itr) != std::string::npos)
{
break;
}
}
if (itr == iend)
{
updated_file += output;
}
else
{
std::string key = *itr;
std::string value = getString(*itr, false);
updated_file += key + "=" + value;
//Remove the key from the changed key list
m_changed_keys.erase(itr);
}
updated_file += "\n";
}
} // End while-loop
Campbell, Stuart
committed
// Any remaining keys within the changed key store weren't present in the current user properties so append them
if (!m_changed_keys.empty())
Campbell, Stuart
committed
updated_file += "\n";
std::set<std::string>::iterator key_end = m_changed_keys.end();
for (std::set<std::string>::iterator key_itr = m_changed_keys.begin(); key_itr != key_end;)
Campbell, Stuart
committed
updated_file += *key_itr + "=";
updated_file += getString(*key_itr, false);
if (++key_itr != key_end)
Campbell, Stuart
committed
updated_file += "\n";
Campbell, Stuart
committed
m_changed_keys.clear();
Campbell, Stuart
committed
// Write out the new file
std::ofstream writer(filename.c_str(), std::ios_base::trunc);
if (writer.bad())
Campbell, Stuart
committed
writer.close();
g_log.error() << "Error writing new user properties file. Cannot save current configuration.\n";
throw std::runtime_error(
"Error writing new user properties file. Cannot save current configuration.");
}
Campbell, Stuart
committed
writer.write(updated_file.c_str(), updated_file.size());
writer.close();
}
Robert Whitley
committed
/** Removes the leading and trailing white spaces from a given string and returns the value
* as a string.
*
* @param toTrim :: The string value to be trimmed left and right.
* @returns The string value of toTrim without the white spaces at the beginning and end.
*/
std::string ConfigServiceImpl::trimLeadingAndTrailing(std::string& toTrim)
{
std::string tempValue;
std::string rtValue;
tempValue = Poco::trimRight(toTrim);
rtValue = Poco::trimLeft(tempValue);
Robert Whitley
committed
Robert Whitley
committed
return rtValue;
}
Robert Whitley
committed
Campbell, Stuart
committed
/** Searches for a string within the currently loaded configuaration values and
* returns the value as a string. If the key is one of those that was a possible relative path
* then the local store is searched first.
*
Janik Zikovsky
committed
* @param keyName :: The case sensitive name of the property that you need the value of.
* @param use_cache :: If true, the local cache of directory names is queried first.
Campbell, Stuart
committed
* @returns The string value of the property, or an empty string if the key cannot be found
*/
std::string ConfigServiceImpl::getString(const std::string& keyName, bool use_cache) const
{
if (use_cache)
{
std::map<std::string, std::string>::const_iterator mitr = m_AbsolutePaths.find(keyName);
if (mitr != m_AbsolutePaths.end())
Campbell, Stuart
committed
return (*mitr).second;
Campbell, Stuart
committed
std::string retVal;
try
Campbell, Stuart
committed
retVal = m_pConf->getString(keyName);
} catch (Poco::NotFoundException&)
Campbell, Stuart
committed
g_log.debug() << "Unable to find " << keyName << " in the properties file" << std::endl;
retVal = "";
Campbell, Stuart
committed
return retVal;
}
Robert Whitley
committed
/** Searches for keys within the currently loaded configuaration values and
* returns them as strings in a vector.
*
* @param keyName :: The case sensitive name of the property that you need the key for.
* @returns The string value of each key within a vector, or an empty vector if there isn't
* a key or it couldn't be found.
*/
std::vector<std::string> ConfigServiceImpl::getKeys(const std::string& keyName) const
{
std::vector<std::string> keyVector;
try
{
m_pConf->keys(keyName,keyVector);
}
catch (Poco::NotFoundException&)
{
g_log.debug() << "Unable to find " << keyName << " in the properties file" << std::endl;
keyVector.clear();
}
return keyVector;
}
Robert Whitley
committed
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
/** Removes a key from the memory stored properties file and inserts the key into the
* changed key list so that when the program calls saveConfig the properties file will
* be the same and not contain the key no more
*
* @param keyName :: The key that is to be deleted
*/
void ConfigServiceImpl::remove(const std::string& rootName) const
{
try
{
m_pConf->remove(rootName);
}
catch (Poco::NotFoundException&)
{
g_log.debug() << "Unable to find " << rootName << " in the properties file" << std::endl;
}
m_changed_keys.insert(rootName);
}
/** Checks to see whether the given key exists.
*
* @param keyName :: The case sensitive key that you are looking to see if exists.
* @returns Boolean value denoting whether the exists or not.
*/
bool ConfigServiceImpl::hasProperty(const std::string& rootName) const
{
return m_pConf->hasProperty(rootName);
}
/** Checks to see whether the given file target is an executable one and it exists
*
* @param keyName :: The path to the file you wish to see whether it's an executable.
* @returns Boolean value denoting whether the file is an executable or not.
*/
bool ConfigServiceImpl::isExecutable(const std::string& target) const
{
try
{
Poco::File tempFile = Poco::File(target);
if (tempFile.exists())
{
if(tempFile.canExecute())
return true;
else
return false;
}
else
return false;
}
catch(Poco::Exception&)
{
return false;
}
}
Robert Whitley
committed
/** Runs a command line string to open a program. The function can take program arguments.
* i.e it can load in a file to the program on startup.
*
* @param programFilePath :: The directory where the program is located.
* @param programArguments :: The arguments that the program can take on startup. For example,
* the file to load up.
*/
void ConfigServiceImpl::launchProcess(const std::string& programFilePath, const std::vector<std::string>& programArguments) const
{
try
{
Poco::Process::launch(programFilePath, programArguments);
}
catch(Poco::SystemException &e)
{
throw std::runtime_error(e.what());
}
}
Campbell, Stuart
committed
/**
* Set a configuration property. An existing key will have its value updated.
Janik Zikovsky
committed
* @param key :: The key to refer to this property
* @param value :: The value of the property
Campbell, Stuart
committed
*/
void ConfigServiceImpl::setString(const std::string & key, const std::string & value)
{
Michael Whitty
committed
std::string old;
try
{
old = m_pConf->getString(key);
Janik Zikovsky
committed
} catch (Poco::NotFoundException &)
Michael Whitty
committed
{
old = "";
}
Janik Zikovsky
committed
Campbell, Stuart
committed
//Ensure we keep a correct full path
std::map<std::string, bool>::const_iterator itr = m_ConfigPaths.find(key);
if (itr != m_ConfigPaths.end())
Campbell, Stuart
committed
m_AbsolutePaths[key] = makeAbsolute(value, key);
Campbell, Stuart
committed
if (key == "datasearch.directories")
Campbell, Stuart
committed
cacheDataSearchPaths();
else if (key == "usersearch.directories")
{
cacheUserSearchPaths();
}
else if (key == "defaultsave.directory")
{
//Some recursion here! As this call calls the current function
appendDataSearchDir(m_AbsolutePaths[key]);
}
Campbell, Stuart
committed
m_pConf->setString(key, value);
Janik Zikovsky
committed
if (value != old)
Michael Whitty
committed
m_notificationCenter.postNotification(new ValueChanged(key, value, old));
Campbell, Stuart
committed
}
/** Searches for a string within the currently loaded configuaration values and
* attempts to convert the values to the template type supplied.
*
Janik Zikovsky
committed
* @param keyName :: The case sensitive name of the property that you need the value of.
* @param out :: The value if found
Campbell, Stuart
committed
* @returns A success flag - 0 on failure, 1 on success
*/
template<typename T>
int ConfigServiceImpl::getValue(const std::string& keyName, T& out)
{
std::string strValue = getString(keyName);
Janik Zikovsky
committed
int result = Mantid::Kernel::Strings::convert(strValue, out);
Campbell, Stuart
committed
return result;
}
/**
* Return the full filename of the local properties file.
* @returns A string containing the full path to the local file.
*/
std::string ConfigServiceImpl::getLocalFilename() const
{
#ifdef _WIN32
return "Mantid.local.properties";
#else
return "/etc/mantid.local.properties";
#endif
}
Campbell, Stuart
committed
/**
* Return the full filename of the user properties file
* @returns A string containing the full path to the user file
Campbell, Stuart
committed
*/
std::string ConfigServiceImpl::getUserFilename() const
{
Gigg, Martyn Anthony
committed
return getUserPropertiesDir() + m_user_properties_file_name;
Campbell, Stuart
committed
}
/** Searches for the string within the environment variables and returns the
* value as a string.
*
Janik Zikovsky
committed
* @param keyName :: The name of the environment variable that you need the value of.
Campbell, Stuart
committed
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
* @returns The string value of the property
*/
std::string ConfigServiceImpl::getEnvironment(const std::string& keyName)
{
return m_pSysConfig->getString("system.env." + keyName);
}
/** Gets the name of the host operating system
*
* @returns The name pf the OS version
*/
std::string ConfigServiceImpl::getOSName()
{
return m_pSysConfig->getString("system.osName");
}
/** Gets the name of the computer running Mantid
*
* @returns The name of the computer
*/
std::string ConfigServiceImpl::getOSArchitecture()
{
return m_pSysConfig->getString("system.osArchitecture");
}
/** Gets the name of the operating system Architecture
*
* @returns The operating system architecture
*/
std::string ConfigServiceImpl::getComputerName()
{
return m_pSysConfig->getString("system.nodeName");
}
/** Gets the name of the operating system version
*
* @returns The operating system version
*/
std::string ConfigServiceImpl::getOSVersion()
{
return m_pSysConfig->getString("system.osVersion");
}
/** Gets the absolute path of the current directory containing the dll
*
* @returns The absolute path of the current directory containing the dll
*/
std::string ConfigServiceImpl::getCurrentDir()
{
return m_pSysConfig->getString("system.currentDir");
}
/** Gets the absolute path of the temp directory
*
* @returns The absolute path of the temp directory
*/
std::string ConfigServiceImpl::getTempDir()
{
return m_pSysConfig->getString("system.tempDir");
}
Gigg, Martyn Anthony
committed
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
/**
* Get the directory containing the program executable
* @returns A string containing the path of the directory
* containing the executable, including a trailing slash
*/
std::string ConfigServiceImpl::getDirectoryOfExecutable()
{
return Poco::Path(getPathToExecutable()).parent().toString();
}
/**
* Get the full path to the executing program (i.e. whatever Mantid is embedded in)
* @returns A string containing the full path the the executable
*/
std::string ConfigServiceImpl::getPathToExecutable()
{
std::string execpath("");
const size_t LEN(1024);
char pBuf[LEN];
#ifdef _WIN32
unsigned int bytes = GetModuleFileName(NULL, pBuf, LEN);
#elif defined __linux__
char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
ssize_t bytes = readlink(szTmp, pBuf, LEN);
#elif defined __APPLE__
// Two calls to _NSGetExecutablePath required - first to get size of buffer
uint32_t bytes(0);
_NSGetExecutablePath(pBuf,&bytes);
const int success = _NSGetExecutablePath(pBuf,&bytes);
if (success < 0) bytes = 1025;
#endif
if( bytes > 0 && bytes < 1024 )
{
pBuf[bytes] = '\0';
execpath = std::string(pBuf);
}
return execpath;
}
/**
* Check if the path is on a network drive
* @param path :: The path to be checked
* @return True if the path is on a network drive.
*/
bool ConfigServiceImpl::isNetworkDrive(const std::string & path)
{
#ifdef _WIN32
// if path is relative get the full one
char buff[MAX_PATH];
GetFullPathName(path.c_str(),MAX_PATH,buff,NULL);
std::string fullName(buff);
size_t i = fullName.find(':');
// if the full path doesn't contain a drive letter assume it's on the network
if (i == std::string::npos) return true;
fullName.erase(i+1);
fullName += '\\'; // make sure the name has the trailing backslash
UINT type = GetDriveType(fullName.c_str());
return DRIVE_REMOTE == type;
#elif defined __linux__
// This information is only present in the /proc/mounts file on linux. There are no drives on
// linux only mount locations therefore the test will have to check the path against
// entries in /proc/mounts to see if the filesystem type is NFS or SMB (any others ????)
// Each line corresponds to a particular mounted location
// 1st column - device name
// 2nd column - mounted location
// 3rd column - filesystem type commonly ext2, ext3 for hard drives and NFS or SMB for
// network locations
std::ifstream mntfile("/proc/mounts");
std::string txtread("");
while( getline(mntfile, txtread) )
{
std::istringstream strm(txtread);
std::string devname(""), mntpoint(""), fstype("");
strm >> devname >> mntpoint >> fstype;
if( !strm ) continue;
// I can't be sure that the file system type is always lower case
std::transform(fstype.begin(), fstype.end(), fstype.begin(), toupper);
// Skip the current line if the file system isn't a network one
if( fstype != "NFS" && fstype != "SMB" ) continue;
// Now we have a line containing a network filesystem and just need to check if the path
// supplied contains the mount location. There is a small complication in that the mount
// points within the file have certain characters transformed into their octal
// representations, for example spaces->040.
std::string::size_type idx = mntpoint.find("\\0");
if( idx != std::string::npos )
{
std::string oct = mntpoint.substr(idx + 1, 3);
strm.str(oct);
int printch(-1);
strm.setf( std::ios::oct, std::ios::basefield );
strm >> printch;
if( printch != -1 )
{
mntpoint = mntpoint.substr(0, idx) + static_cast<char>(printch) + mntpoint.substr(idx + 4);
}
// Search for this at the start of the path
if( path.find(mntpoint) == 0 ) return true;
}
}
return false;
#else
// Not yet implemented for the mac
return false;
#endif
}
Campbell, Stuart
committed
/**
Gigg, Martyn Anthony
committed
* Gets the directory that we consider to be the directory containing the Mantid.properties file.
* Basically, this is the either the directory pointed to by MANTIDPATH or the directory of the current
* executable if this is not set.
Campbell, Stuart
committed
* @returns The directory to consider as the base directory, including a trailing slash
*/
Gigg, Martyn Anthony
committed
std::string ConfigServiceImpl::getPropertiesDir() const
Campbell, Stuart
committed
{
return m_strBaseDir;
}
/**
Gigg, Martyn Anthony
committed
* Return the directory that Mantid should use for writing any files it needs so that
* this is kept separated to user saved files. A trailing slash is appended
Campbell, Stuart
committed
* so that filenames can more easily be concatenated with this
* @return the directory that Mantid should use for writing files
*/
Gigg, Martyn Anthony
committed
std::string ConfigServiceImpl::getUserPropertiesDir() const
Campbell, Stuart
committed
{
Gigg, Martyn Anthony
committed
#ifdef _WIN32
Campbell, Stuart
committed
return m_strBaseDir;
#else
Poco::Path datadir(m_pSysConfig->getString("system.homeDir"));
datadir.append(".mantid");
// Create the directory if it doesn't already exist
Poco::File(datadir).createDirectory();
return datadir.toString() + "/";
#endif
}
Campbell, Stuart
committed
/**
* Return the list of search paths
* @returns A vector of strings containing the defined search directories
*/
const std::vector<std::string>& ConfigServiceImpl::getDataSearchDirs() const
{
return m_DataSearchDirs;
}
Gigg, Martyn Anthony
committed
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
/**
* Set a list of search paths via a vector
* @param searchDirs :: A list of search directories
*/
void ConfigServiceImpl::setDataSearchDirs(const std::vector<std::string> &searchDirs)
{
std::string searchPaths = boost::join(searchDirs, ";");
setDataSearchDirs(searchPaths);
}
/**
* Set a list of search paths via a string
* @param searchDirs :: A string containing a list of search directories separated by a semi colon (;).
*/
void ConfigServiceImpl::setDataSearchDirs(const std::string &searchDirs)
{
setString("datasearch.directories", searchDirs);
}
/**
* Adds the passed path to the end of the list of data search paths
* the path name must be absolute
* @param path :: the absolute path to add
*/
void ConfigServiceImpl::appendDataSearchDir(const std::string & path)
{
Janik Zikovsky
committed
if (!isInDataSearchList(path))
Gigg, Martyn Anthony
committed
{
std::string newSearchString;
std::vector<std::string>::const_iterator it = m_DataSearchDirs.begin();
Janik Zikovsky
committed
for (; it != m_DataSearchDirs.end(); ++it)
Gigg, Martyn Anthony
committed
{
newSearchString.append(*it);
newSearchString.append(";");
}
newSearchString.append(path);
setString("datasearch.directories", newSearchString);
}
}
/**
* Return the list of user search paths
* @returns A vector of strings containing the defined search directories
*/
const std::vector<std::string>& ConfigServiceImpl::getUserSearchDirs() const
{
return m_UserSearchDirs;
}
/**
* Return the search directory for XML instrument definition files (IDFs)
* @returns Full path of instrument search directory
*/
const std::string ConfigServiceImpl::getInstrumentDirectory() const
Campbell, Stuart
committed
{
// Determine the search directory for XML instrument definition files (IDFs)
std::string directoryName = getString("instrumentDefinition.directory");
if (directoryName.empty())
Campbell, Stuart
committed
// This is the assumed deployment directory for IDFs, where we need to be relative to the
// directory of the executable, not the current working directory.
directoryName = Poco::Path(getPropertiesDir()).resolve("../instrument").toString();
Janik Zikovsky
committed
if (!Poco::File(directoryName).isDirectory())
g_log.error("Unable to locate instrument search directory at: " + directoryName);
return directoryName;
Campbell, Stuart
committed
}
/**
* Load facility information from instrumentDir/Facilities.xml file if fName parameter
* is not set
Janik Zikovsky
committed
* @param fName :: An alternative file name for loading facilities information.
Campbell, Stuart
committed
*/
void ConfigServiceImpl::updateFacilities(const std::string& fName)
{
m_facilities.clear();
Campbell, Stuart
committed
std::string instrDir = getString("instrumentDefinition.directory");
std::string fileName = fName.empty() ? instrDir + "Facilities.xml" : fName;
// Set up the DOM parser and parse xml file
Poco::XML::DOMParser pParser;
Poco::XML::Document* pDoc;
Roman Tolchenov
committed
Campbell, Stuart
committed
try
Roman Tolchenov
committed
try
{
pDoc = pParser.parse(fileName);
} catch (...)
{
throw Kernel::Exception::FileError("Unable to parse file:", fileName);
}
// Get pointer to root element
Poco::XML::Element* pRootElem = pDoc->documentElement();
if (!pRootElem->hasChildNodes())
{
pDoc->release();
throw std::runtime_error("No root element in Facilities.xml file");
}
Roman Tolchenov
committed
Poco::XML::NodeList* pNL_facility = pRootElem->getElementsByTagName("facility");
unsigned long n = pNL_facility->length();
Campbell, Stuart
committed
for (unsigned long i = 0; i < n; ++i)
Roman Tolchenov
committed
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*> (pNL_facility->item(i));
if (elem)
{
m_facilities.push_back(new FacilityInfo(elem));
}
}
if (m_facilities.empty())
Roman Tolchenov
committed
pNL_facility->release();
pDoc->release();
throw std::runtime_error("The facility definition file " + fileName + " defines no facilities");
Janik Zikovsky
committed
Roman Tolchenov
committed
pNL_facility->release();
pDoc->release();
Janik Zikovsky
committed
} catch (std::exception& e)
Roman Tolchenov
committed
{
Roman Tolchenov
committed
g_log.error(e.what());
Roman Tolchenov
committed
}
Campbell, Stuart
committed
}
/**
* Returns instruments with given name
* @param iName Instrument name
* @return the instrument information object
* @throw NotFoundError if iName was not found
*/
const InstrumentInfo & ConfigServiceImpl::getInstrument(const std::string& instrumentName) const
{
// Let's first search for the instrument in our default facility
std::string defaultFacility = ConfigService::Instance().getFacility().name();
if (!defaultFacility.empty())
{
try
{
g_log.debug() << "Looking for " << instrumentName << " at " << defaultFacility << "." << std::endl;
return getFacility(defaultFacility).Instrument(instrumentName);
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
}
catch (Exception::NotFoundError e)
{
// Well the instName doesn't exist for this facility
// Move along, there's nothing to see here...
}
}
// Now let's look through the other facilities
std::vector<FacilityInfo*>::const_iterator it = m_facilities.begin();
for (; it != m_facilities.end(); ++it)
{
try
{
g_log.debug() << "Looking for " << instrumentName << " at " << (**it).name() << "." << std::endl;
return (**it).Instrument(instrumentName);
}
catch (Exception::NotFoundError e)
{
// Well the instName doesn't exist for this facility...
// Move along, there's nothing to see here...
}
}
g_log.error("Instrument " + instrumentName + " not found");
throw Exception::NotFoundError("Instrument", instrumentName);
}
/** Get the default facility
* @return the facility information object
Campbell, Stuart
committed
*/
const FacilityInfo& ConfigServiceImpl::getFacility() const
Campbell, Stuart
committed
{
std::string defFacility = getString("default.facility");
if (defFacility.empty())
Roman Tolchenov
committed
{
Campbell, Stuart
committed
defFacility = "ISIS";
Roman Tolchenov
committed
}
return getFacility(defFacility);
Michael Whitty
committed
}
Campbell, Stuart
committed
/**
* Get a facility
Janik Zikovsky
committed
* @param fName :: Facility name
* @return the facility information object
Janik Zikovsky
committed
* @throw NotFoundException if the facility is not found
Campbell, Stuart
committed
*/
const FacilityInfo& ConfigServiceImpl::getFacility(const std::string& facilityName) const
Campbell, Stuart
committed
{
if (facilityName.empty())
return this->getFacility();
Campbell, Stuart
committed
std::vector<FacilityInfo*>::const_iterator it = m_facilities.begin();
for (; it != m_facilities.end(); ++it)
Roman Tolchenov
committed
{
if ((**it).name() == facilityName)
Roman Tolchenov
committed
{
Campbell, Stuart
committed
return **it;
Roman Tolchenov
committed
}
}
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
g_log.error("Facility " + facilityName + " not found");
throw Exception::NotFoundError("Facilities", facilityName);
}
/**
* Set the default facility
* @param facilityName the facility name
* @throw NotFoundException if the facility is not found
*/
void ConfigServiceImpl::setFacility(const std::string &facilityName)
{
bool found = false;
// Look through the facilities for a matching one.
std::vector<FacilityInfo*>::const_iterator it = m_facilities.begin();
for (; it != m_facilities.end(); ++it)
{
if ((**it).name() == facilityName)
{
// Found the facility
found = true;
// So it's safe to set it as our default
setString("default.facility", facilityName);
}
}
if (found == false)
{
g_log.error("Failed to set default facility to be " + facilityName + ". Facility not found");
throw Exception::NotFoundError("Facilities", facilityName);
}
}
/** Add an observer to a notification
@param observer :: Reference to the observer to add
*/
void ConfigServiceImpl::addObserver(const Poco::AbstractObserver& observer) const
{
m_notificationCenter.addObserver(observer);
}
/** Remove an observer
@param observer :: Reference to the observer to remove
*/
void ConfigServiceImpl::removeObserver(const Poco::AbstractObserver& observer) const
{
m_notificationCenter.removeObserver(observer);
Campbell, Stuart
committed
}
/// \cond TEMPLATE
template DLLExport int ConfigServiceImpl::getValue(const std::string&, double&);
template DLLExport int ConfigServiceImpl::getValue(const std::string&, std::string&);
template DLLExport int ConfigServiceImpl::getValue(const std::string&, int&);
template DLLExport int ConfigServiceImpl::getValue(const std::string&, std::size_t&);
Campbell, Stuart
committed
/// \endcond TEMPLATE
} // namespace Kernel
} // namespace Mantid