From 8522c7a620ee8d6b1949c1197470089153a8314f Mon Sep 17 00:00:00 2001 From: Stuart Campbell <campbellsi@ornl.gov> Date: Wed, 11 Aug 2010 13:47:54 +0000 Subject: [PATCH] Added getInstrumentFilename() method to return the filename of the instrument geometry defintion file. refs #1463 --- .../Kernel/inc/MantidKernel/ConfigService.h | 2 + Code/Mantid/Kernel/src/ConfigService.cpp | 1579 +++++++++-------- 2 files changed, 812 insertions(+), 769 deletions(-) diff --git a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h index da21a3f7b9c..0d8b847a985 100644 --- a/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h +++ b/Code/Mantid/Kernel/inc/MantidKernel/ConfigService.h @@ -96,6 +96,8 @@ namespace Mantid const std::vector<std::string>& getDataSearchDirs() const; /// Get the list of known instrument prefixes for the given facility const std::vector<std::string>& getInstrumentPrefixes(const std::string& facility) const; + /// Gets the instrument geometry filename + const std::string getInstrumentFilename(const std::string& instrument) const; /// Load facility information from instrumentDir/Facilities.xml file void updateFacilities(const std::string& fName = ""); diff --git a/Code/Mantid/Kernel/src/ConfigService.cpp b/Code/Mantid/Kernel/src/ConfigService.cpp index 1443370183e..9d53b2c7c94 100644 --- a/Code/Mantid/Kernel/src/ConfigService.cpp +++ b/Code/Mantid/Kernel/src/ConfigService.cpp @@ -31,922 +31,963 @@ namespace Mantid namespace Kernel { - /** Inner templated class to wrap the poco library objects that have protected - * destructors and expose them as public. +/** 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 + * @param F The object to wrap */ - 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); - } + template<typename Field> + WrappedObject(Field& F) : + T(F) + { + m_pPtr = static_cast<T*> (this); + } - /** Constructor with a class to wrap - * @param F The object to wrap - */ - template<typename Field> - WrappedObject(Field& F) : T(F) - { - m_pPtr = static_cast<T*>(this); - } + /// Copy constructor + WrappedObject(const WrappedObject<T>& A) : + T(A) + { + m_pPtr = static_cast<T*> (this); + } - /// Copy constructor - WrappedObject(const WrappedObject<T>& A) : T(A) - { - m_pPtr = static_cast<T*>(this); - } + /// Virtual destructor + virtual ~WrappedObject() + { + } - /// Virtual destructor - virtual ~WrappedObject() - {} - - /// 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; } - - private: - /// Private pointer to the wrapped class - T* m_pPtr; - }; - - //Back to the ConfigService class itself... - - //------------------------------- - // Private member functions - //------------------------------- - - /// 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"), - m_user_properties_file_name("Mantid.user.properties"), - m_DataSearchDirs(), - m_instr_prefixes() - { - //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>); - - // Define a directory that serves as the 'application directory'. This is where we expect to find the Mantid.properties file - // It cannot simply be the current directory since the application may be called from a different place, .i.e. - // on Linux where the bin directory is in the path and the app is run from a different location. - // We have two scenarios: - // 1) The framework is compiled into an executable and its directory is then considered as the base or, - // 2) The framework is in a stand-alone library and is created from within another executing application - // e.g. Python or Matlab (only two at the moment). We can only use the current directory here as there - // is no programmatic way of determing where the library that contains this class is. - - // A MANTID environmental variable might solve all of this?? - - std::string callingApplication = Poco::Path(getPathToExecutable()).getFileName(); - // the cases used in the names varies on different systems so we do this case insensitive - std::transform(callingApplication.begin(), callingApplication.end(), - callingApplication.begin(), tolower); - if ( callingApplication.find("python") != std::string::npos || callingApplication.find("matlab") != std::string::npos) - { - m_strBaseDir = Poco::Path::current(); - } - else - { - m_strBaseDir = Mantid::Kernel::getDirectoryOfExecutable(); - } + /// 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; + } - //Fill the list of possible relative path keys that may require conversion to absolute paths - m_ConfigPaths.insert(std::make_pair("plugins.directory", true)); - m_ConfigPaths.insert(std::make_pair("instrumentDefinition.directory", true)); - 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)); +private: + /// Private pointer to the wrapped class + T* m_pPtr; +}; - //attempt to load the default properties file that resides in the directory of the executable - updateConfig(getBaseDir() + m_properties_file_name,false,false); - //and then append the user properties - updateConfig(getUserFilename(), true, true); +//Back to the ConfigService class itself... - updateFacilities(); +//------------------------------- +// Private member functions +//------------------------------- - g_log.debug() << "ConfigService created." << std::endl; - g_log.debug() << "Configured base directory of application as " << getBaseDir() << std::endl; - g_log.information() << "This is Mantid Version " << MANTID_VERSION << std::endl; +/// 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"), + m_user_properties_file_name("Mantid.user.properties"), m_DataSearchDirs(), m_instr_prefixes() +{ + //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>); + + // Define a directory that serves as the 'application directory'. This is where we expect to find the Mantid.properties file + // It cannot simply be the current directory since the application may be called from a different place, .i.e. + // on Linux where the bin directory is in the path and the app is run from a different location. + // We have two scenarios: + // 1) The framework is compiled into an executable and its directory is then considered as the base or, + // 2) The framework is in a stand-alone library and is created from within another executing application + // e.g. Python or Matlab (only two at the moment). We can only use the current directory here as there + // is no programmatic way of determing where the library that contains this class is. + + // A MANTID environmental variable might solve all of this?? + + std::string callingApplication = Poco::Path(getPathToExecutable()).getFileName(); + // the cases used in the names varies on different systems so we do this case insensitive + std::transform(callingApplication.begin(), callingApplication.end(), callingApplication.begin(), + tolower); + if (callingApplication.find("python") != std::string::npos || callingApplication.find("matlab") + != std::string::npos) + { + m_strBaseDir = Poco::Path::current(); } - - /// Private copy constructor for singleton class - ConfigServiceImpl::ConfigServiceImpl(const ConfigServiceImpl&) : g_log(Logger::get("ConfigService")) + else { + m_strBaseDir = Mantid::Kernel::getDirectoryOfExecutable(); } - /** Private Destructor - * Prevents client from calling 'delete' on the pointer handed out by Instance - */ - ConfigServiceImpl::~ConfigServiceImpl() + //Fill the list of possible relative path keys that may require conversion to absolute paths + m_ConfigPaths.insert(std::make_pair("plugins.directory", true)); + m_ConfigPaths.insert(std::make_pair("instrumentDefinition.directory", true)); + 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)); + + //attempt to load the default properties file that resides in the directory of the executable + updateConfig(getBaseDir() + m_properties_file_name, false, false); + //and then append the user properties + updateConfig(getUserFilename(), true, true); + + updateFacilities(); + + g_log.debug() << "ConfigService created." << std::endl; + g_log.debug() << "Configured base directory of application as " << getBaseDir() << std::endl; + g_log.information() << "This is Mantid Version " << MANTID_VERSION << std::endl; +} + +/// Private copy constructor for singleton class +ConfigServiceImpl::ConfigServiceImpl(const ConfigServiceImpl&) : + g_log(Logger::get("ConfigService")) +{ +} + +/** 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) { - //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) - { - delete *it; - } - m_facilities.clear(); + 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. + * + * @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. + */ +void ConfigServiceImpl::loadConfig(const std::string& filename, const bool append) +{ + delete m_pConf; + if (!append) + { + //remove the previous property string + m_PropertyString = ""; } - /** Loads the config file provided. - * If the file contains logging setup instructions then these will be used to setup the logging framework. - * - * @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. - */ - void ConfigServiceImpl::loadConfig(const std::string& filename, const bool append) + try { - delete m_pConf; - if (!append) - { - //remove the previous property string - m_PropertyString = ""; - } + //slurp in entire file + std::string temp; + bool good = readFile(filename, temp); - try + // check if we have failed to open the file + if ((!good) || (temp == "")) { - //slurp in entire file - std::string temp; - bool good = readFile(filename, temp); - - // check if we have failed to open the file - if ((!good) || (temp=="")) - { - if (filename == getOutputDir() + m_user_properties_file_name) - { - //write out a fresh file - createUserPropertiesFile(); - } - else - { - throw Exception::FileError("Cannot open file",filename); - } - } - - //store the property string - if((append) && (m_PropertyString!="")) + if (filename == getOutputDir() + m_user_properties_file_name) { - m_PropertyString = m_PropertyString + "\n" + temp; + //write out a fresh file + createUserPropertiesFile(); } else { - m_PropertyString = temp; + throw Exception::FileError("Cannot open file", filename); } + } + //store the property string + if ((append) && (m_PropertyString != "")) + { + m_PropertyString = m_PropertyString + "\n" + temp; } - catch (std::exception& e) + else { - //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) - { - // if we have no property values then take the default - m_PropertyString = defaultConfig(); - } + m_PropertyString = temp; } - //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 - * @param filename The filename of the file to read - * @param contents The file contents will be placed here - * @returns A boolean indicating whether opening the file was successful - */ - bool ConfigServiceImpl::readFile(const std::string& filename, std::string & contents) const + } catch (std::exception& e) { - std::ifstream propFile(filename.c_str(),std::ios::in); - bool good = propFile.good(); - if( !good ) + //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) { - contents = ""; - propFile.close(); - return good; + // if we have no property values then take the default + m_PropertyString = defaultConfig(); } + } - //slurp in entire file - extremely unlikely delimter used as an alternate to \n - contents.clear(); - getline(propFile,contents,'¬'); + //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 + * @param filename The filename of the file to read + * @param contents The file contents will be placed here + * @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; } - - /// Configures the Poco logging and starts it up - void ConfigServiceImpl::configureLogging() + + //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 +void ConfigServiceImpl::configureLogging() +{ + try { - try + //Ensure that the logging directory exists + Poco::Path logpath(getString("logging.channels.fileChannel.path")); + if (logpath.toString().empty() || getOutputDir() != getBaseDir()) { - //Ensure that the logging directory exists - Poco::Path logpath(getString("logging.channels.fileChannel.path")); - if( logpath.toString().empty() || getOutputDir() != getBaseDir() ) - { - std::string logfile = getOutputDir() + "mantid.log"; - logpath.assign(logfile); - m_pConf->setString("logging.channels.fileChannel.path", logfile); - } - //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).createDirectory(); - } - //configure the logging framework - Poco::Util::LoggingConfigurator configurator; - configurator.configure(m_pConf); + std::string logfile = getOutputDir() + "mantid.log"; + logpath.assign(logfile); + m_pConf->setString("logging.channels.fileChannel.path", logfile); } - catch (std::exception& e) + //make this path point to the parent directory and create it if it does not exist + logpath.makeParent(); + if (!logpath.toString().empty()) { - std::cerr << "Trouble configuring the logging framework " << e.what()<<std::endl; + Poco::File(logpath).createDirectory(); } - + //configure the logging framework + Poco::Util::LoggingConfigurator configurator; + configurator.configure(m_pConf); + } catch (std::exception& e) + { + std::cerr << "Trouble configuring the logging framework " << e.what() << std::endl; } - /** - * 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; +} - std::string execdir(getBaseDir()); - m_AbsolutePaths.clear(); +/** + * 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; - 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; + std::string execdir(getBaseDir()); + m_AbsolutePaths.clear(); - std::string value(m_pConf->getString(key)); - value = makeAbsolute(value, key); - m_AbsolutePaths.insert(std::make_pair(key, value)); - } - } + 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; - /** - * Make a relative path or a list of relative paths into an absolute one. - * @param dir The directory to convert - * @param key The key variable this relates to - * @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 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. + * @param dir The directory to convert + * @param key The key variable this relates to + * @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; + const std::string execdir(getBaseDir()); + // If we have a list, chop it up and convert each one + if (dir.find_first_of(";,") != std::string::npos) { - std::string converted; - const std::string execdir(getBaseDir()); - // If we have a list, chop it up and convert each one - if( dir.find_first_of(";,") != std::string::npos ) + 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;) { - 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; ) + std::string absolute = makeAbsolute(*itr, key); + if (absolute.empty()) { - std::string absolute = makeAbsolute(*itr, key); - if( absolute.empty() ) - { - ++itr; - } - else + ++itr; + } + else + { + converted += absolute; + if (++itr != iend) { - converted += absolute; - if( ++itr != iend ) - { - converted += ";"; - } + converted += ";"; } } - return converted; - } - - // 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 - { - is_relative = Poco::Path(dir).isRelative(); - } - catch(Poco::PathSyntaxException &) - { - g_log.warning() << "Malformed path detected in the \"" << key << "\" variable, skipping \"" << dir << "\"\n"; - return ""; - } - if( is_relative ) - { - converted = Poco::Path(execdir).resolve(dir).toString(); - } - else - { - converted = dir; - } - converted = Poco::Path(converted).makeDirectory().toString(); - - // 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() ) - { - required = it->second; - } - if( required && !Poco::File(converted).exists() ) - { - g_log.warning() << "Required properties path \"" << converted << "\" in the \"" << key << "\" variable does not exist.\n"; - converted = ""; } 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() + // 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 { - 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); - } + is_relative = Poco::Path(dir).isRelative(); + } catch (Poco::PathSyntaxException &) + { + g_log.warning() << "Malformed path detected in the \"" << key << "\" variable, skipping \"" << dir + << "\"\n"; + return ""; + } + if (is_relative) + { + converted = Poco::Path(execdir).resolve(dir).toString(); + } + else + { + converted = dir; } + converted = Poco::Path(converted).makeDirectory().toString(); - /** - * Create the map of facility to known instrument prefixes from the property file. The prefix list is specified using - * instrument.prefixes.[facility] key where [facility] is replaced with a facility from the "supported.facilities" list - */ - void ConfigServiceImpl::cacheInstrumentPrefixes() + // 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()) { - m_instr_prefixes.clear(); + required = it->second; + } + if (required && !Poco::File(converted).exists()) + { + g_log.warning() << "Required properties path \"" << converted << "\" in the \"" << key + << "\" variable does not exist.\n"; + converted = ""; + } + 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); + } +} - std::string facilities = getString("supported.facilities"); - if( facilities.empty() ) - { - g_log.error() << "No supported facilties defined within the \"supported.facilities\" key.\n"; - return; - } - int options = Poco::StringTokenizer::TOK_TRIM + Poco::StringTokenizer::TOK_IGNORE_EMPTY; - Poco::StringTokenizer fac_tokens(facilities, ";", options); - Poco::StringTokenizer::Iterator iend = fac_tokens.end(); - for( Poco::StringTokenizer::Iterator itr = fac_tokens.begin(); itr != iend; ++itr ) - { - // For each facility find the corresponding instrument list - std::string prefix_key = "instrument.prefixes." + *itr; - std::string prefixes = getString(prefix_key); - Poco::StringTokenizer instr_tokens(prefixes, ";", options); - std::vector<std::string> prefs; - if( instr_tokens.count() > 0 ) +/** + * Create the map of facility to known instrument prefixes from the property file. The prefix list is specified using + * instrument.prefixes.[facility] key where [facility] is replaced with a facility from the "supported.facilities" list + */ +void ConfigServiceImpl::cacheInstrumentPrefixes() +{ + m_instr_prefixes.clear(); + + std::string facilities = getString("supported.facilities"); + if (facilities.empty()) + { + g_log.error() << "No supported facilties defined within the \"supported.facilities\" key.\n"; + return; + } + int options = Poco::StringTokenizer::TOK_TRIM + Poco::StringTokenizer::TOK_IGNORE_EMPTY; + Poco::StringTokenizer fac_tokens(facilities, ";", options); + Poco::StringTokenizer::Iterator iend = fac_tokens.end(); + for (Poco::StringTokenizer::Iterator itr = fac_tokens.begin(); itr != iend; ++itr) + { + // For each facility find the corresponding instrument list + std::string prefix_key = "instrument.prefixes." + *itr; + std::string prefixes = getString(prefix_key); + Poco::StringTokenizer instr_tokens(prefixes, ";", options); + std::vector<std::string> prefs; + if (instr_tokens.count() > 0) + { + prefs.reserve(instr_tokens.count()); + Poco::StringTokenizer::Iterator pref_end = instr_tokens.end(); + for (Poco::StringTokenizer::Iterator pref_itr = instr_tokens.begin(); pref_itr != pref_end; ++pref_itr) { - prefs.reserve(instr_tokens.count()); - Poco::StringTokenizer::Iterator pref_end = instr_tokens.end(); - for( Poco::StringTokenizer::Iterator pref_itr = instr_tokens.begin(); pref_itr != pref_end; ++pref_itr ) - { - prefs.push_back(*pref_itr); - } + prefs.push_back(*pref_itr); } - m_instr_prefixes[*itr] = prefs; } + m_instr_prefixes[*itr] = prefs; + } - - +} +/** + * writes a basic placeholder user.properties file to disk + * any errors are caught and logged, but not propagated + */ +void ConfigServiceImpl::createUserPropertiesFile() const +{ + try + { + std::fstream filestr((getOutputDir() + m_user_properties_file_name).c_str(), std::fstream::out); + + 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) + { + g_log.warning() << "Unable to write out user.properties file to " << getOutputDir() + << m_user_properties_file_name << " error: " << ex.what() << std::endl; } - /** - * writes a basic placeholder user.properties file to disk - * any errors are caught and logged, but not propagated - */ - void ConfigServiceImpl::createUserPropertiesFile() const - { - try - { - std::fstream filestr ((getOutputDir() + m_user_properties_file_name).c_str(), std::fstream::out); - - 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) - { - g_log.warning()<<"Unable to write out user.properties file to " << getOutputDir() << m_user_properties_file_name - << " error: " << ex.what() << std::endl; - } +} +/** + * 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 + * @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. + * @param update_caches If true(default) then the various property caches are updated + */ +void ConfigServiceImpl::updateConfig(const std::string& filename, const bool append, + const bool update_caches) +{ + loadConfig(filename, append); + configureLogging(); + if (update_caches) + { + //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(); + cacheInstrumentPrefixes(); } +} + +/** + * Save the configuration to the user file + * @param filename The filename for the saved configuration + * @throws std::runtime_error if the file cannot be opened + */ +void ConfigServiceImpl::saveConfig(const std::string & filename) const +{ + if (m_changed_keys.empty()) + return; - /** - * 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 - * @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. - * @param update_caches If true(default) then the various property caches are updated - */ - void ConfigServiceImpl::updateConfig(const std::string& filename, const bool append, const bool update_caches) + // Open and read the user properties file + std::string updated_file(""); + + std::ifstream reader(filename.c_str(), std::ios::in); + if (reader.bad()) { - loadConfig(filename, append); - configureLogging(); - if( update_caches ) - { - //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(); - cacheInstrumentPrefixes(); - } + 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."); } - /** - * Save the configuration to the user file - * @param filename The filename for the saved configuration - * @throws std::runtime_error if the file cannot be opened - */ - void ConfigServiceImpl::saveConfig(const std::string & filename) const + std::string file_line(""), output(""); + bool line_continuing(false); + while (std::getline(reader, file_line)) { - if( m_changed_keys.empty() ) return; - - // Open and read the user properties file - std::string updated_file(""); - - std::ifstream reader(filename.c_str(), std::ios::in); - if( reader.bad() ) - { - 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."); - } - - std::string file_line(""), output(""); - bool line_continuing(false); - while( std::getline(reader, file_line) ) + if (!file_line.empty()) { - if( !file_line.empty() ) + char last = *(file_line.end() - 1); + if (last == '\\') { - char last = *(file_line.end() - 1); - if( last == '\\' ) - { - line_continuing = true; - output += file_line + "\n"; - continue; - } - else if( line_continuing ) - { - output += file_line; - line_continuing = false; - } - else - { - output = file_line; - } - } - else - { - output = ""; - updated_file += "\n"; + line_continuing = true; + output += file_line + "\n"; continue; } - std::set<std::string>::iterator iend = m_changed_keys.end(); - std::set<std::string>::iterator itr = m_changed_keys.begin(); - for( ; itr != iend; ++itr ) + else if (line_continuing) { - if( output.find(*itr) != std::string::npos ) - { - break; - } - } - - if( itr == iend ) - { - updated_file += output; + output += file_line; + line_continuing = false; } 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); + output = file_line; } - updated_file += "\n"; - } - - // Any remaining keys within the changed key store weren't present in the current user properties so append them - if( !m_changed_keys.empty() ) + else { + output = ""; 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;) + continue; + } + std::set<std::string>::iterator iend = m_changed_keys.end(); + std::set<std::string>::iterator itr = m_changed_keys.begin(); + for (; itr != iend; ++itr) + { + if (output.find(*itr) != std::string::npos) { - updated_file += *key_itr + "="; - updated_file += getString(*key_itr, false); - if( ++key_itr != key_end ) - { - updated_file += "\n"; - } + break; } - m_changed_keys.clear(); } - // Write out the new file - std::ofstream writer(filename.c_str(), std::ios_base::trunc); - if( writer.bad() ) + if (itr == iend) + { + updated_file += output; + } + else { - 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."); + 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"; - writer.write(updated_file.c_str(), updated_file.size()); - writer.close(); } - - /** 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. - * - * @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. - * @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 + // Any remaining keys within the changed key store weren't present in the current user properties so append them + if (!m_changed_keys.empty()) { - if( use_cache ) + 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;) { - std::map<std::string, std::string>::const_iterator mitr = m_AbsolutePaths.find(keyName); - if( mitr != m_AbsolutePaths.end() ) + updated_file += *key_itr + "="; + updated_file += getString(*key_itr, false); + if (++key_itr != key_end) { - return (*mitr).second; + updated_file += "\n"; } } - std::string retVal; - try - { - retVal = m_pConf->getString(keyName); - } - catch(Poco::NotFoundException&) - { - g_log.debug()<<"Unable to find " << keyName << " in the properties file" << std::endl; - retVal = ""; - } - return retVal; + m_changed_keys.clear(); } - /** - * Set a configuration property. An existing key will have its value updated. - * @param key The key to refer to this property - * @param value The value of the property - */ - void ConfigServiceImpl::setString(const std::string & key, const std::string & value) + // Write out the new file + std::ofstream writer(filename.c_str(), std::ios_base::trunc); + if (writer.bad()) { - //Ensure we keep a correct full path - std::map<std::string, bool>::const_iterator itr = m_ConfigPaths.find(key); - if( itr != m_ConfigPaths.end() ) - { - m_AbsolutePaths[key] = makeAbsolute(value, key); - } - - if( key == "datasearch.directories" ) - { - cacheDataSearchPaths(); - } + 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."); + } - // If this key exists within the loaded configuration then mark that its value will have - // changed from the default - if( m_pConf->hasProperty(key) ) + writer.write(updated_file.c_str(), updated_file.size()); + writer.close(); +} + +/** 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. + * + * @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. + * @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()) { - m_changed_keys.insert(key); + return (*mitr).second; } - - m_pConf->setString(key, value); } - - /** Searches for a string within the currently loaded configuaration values and - * attempts to convert the values to the template type supplied. - * - * @param keyName The case sensitive name of the property that you need the value of. - * @param out The value if found - * @returns A success flag - 0 on failure, 1 on success - */ - template<typename T> - int ConfigServiceImpl::getValue(const std::string& keyName, T& out) + std::string retVal; + try { - std::string strValue = getString(keyName); - int result = StrFunc::convert(strValue,out); - return result; - } - - /** - * Return the full filename of the user properties file - * @returns A string containg the full path to the user file - */ - std::string ConfigServiceImpl::getUserFilename() const + retVal = m_pConf->getString(keyName); + } catch (Poco::NotFoundException&) { - return getOutputDir() + m_user_properties_file_name; + g_log.debug() << "Unable to find " << keyName << " in the properties file" << std::endl; + retVal = ""; } - - /** Searches for the string within the environment variables and returns the - * value as a string. - * - * @param keyName The name of the environment variable that you need the value of. - * @returns The string value of the property - */ - std::string ConfigServiceImpl::getEnvironment(const std::string& keyName) + return retVal; +} + +/** + * Set a configuration property. An existing key will have its value updated. + * @param key The key to refer to this property + * @param value The value of the property + */ +void ConfigServiceImpl::setString(const std::string & key, const std::string & value) +{ + //Ensure we keep a correct full path + std::map<std::string, bool>::const_iterator itr = m_ConfigPaths.find(key); + if (itr != m_ConfigPaths.end()) { - return m_pSysConfig->getString("system.env." + keyName); + m_AbsolutePaths[key] = makeAbsolute(value, key); } - /** Gets the name of the host operating system - * - * @returns The name pf the OS version - */ - std::string ConfigServiceImpl::getOSName() + if (key == "datasearch.directories") { - return m_pSysConfig->getString("system.osName"); + cacheDataSearchPaths(); } - /** Gets the name of the computer running Mantid - * - * @returns The name of the computer - */ - std::string ConfigServiceImpl::getOSArchitecture() + // If this key exists within the loaded configuration then mark that its value will have + // changed from the default + if (m_pConf->hasProperty(key)) { - return m_pSysConfig->getString("system.osArchitecture"); + m_changed_keys.insert(key); } - /** Gets the name of the operating system Architecture - * - * @returns The operating system architecture - */ - std::string ConfigServiceImpl::getComputerName() - { - return m_pSysConfig->getString("system.nodeName"); - } + m_pConf->setString(key, value); +} + +/** Searches for a string within the currently loaded configuaration values and + * attempts to convert the values to the template type supplied. + * + * @param keyName The case sensitive name of the property that you need the value of. + * @param out The value if found + * @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); + int result = StrFunc::convert(strValue, out); + return result; +} + +/** + * Return the full filename of the user properties file + * @returns A string containg the full path to the user file + */ +std::string ConfigServiceImpl::getUserFilename() const +{ + return getOutputDir() + m_user_properties_file_name; +} + +/** Searches for the string within the environment variables and returns the + * value as a string. + * + * @param keyName The name of the environment variable that you need the value of. + * @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"); +} + +/** + * Gets the directory that we consider to be the bse directory. Basically, this is the + * executable directory when running normally or the current directory on startup when + * running through Python on the command line + * @returns The directory to consider as the base directory, including a trailing slash + */ +std::string ConfigServiceImpl::getBaseDir() const +{ + return m_strBaseDir; +} + +/** + * Return the directory that Mantid should use for writing files. A trailing slash is appended + * so that filenames can more easily be concatenated with this + * @return the directory that Mantid should use for writing files + */ +std::string ConfigServiceImpl::getOutputDir() const +{ +#ifdef _WIN32 + 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 +} - /** Gets the name of the operating system version - * - * @returns The operating system version - */ - std::string ConfigServiceImpl::getOSVersion() +/** + * 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; +} + +/** + * Return the list of instrument prefixes for the given facility. If the facility if unknown then a NotFoundError is thrown. + * @param facility A string giving a facility name + * @returns A vector of strings containing the instrument prefixes + */ +const std::vector<std::string>& ConfigServiceImpl::getInstrumentPrefixes(const std::string& facility) const +{ + std::map<std::string, std::vector<std::string> >::const_iterator itr = m_instr_prefixes.find(facility); + if (itr != m_instr_prefixes.end()) { - return m_pSysConfig->getString("system.osVersion"); + if (itr->second.empty()) + { + g_log.warning() << "Facility \"" << facility + << "\" has no instruments defined. Check instrument.prefixes." << facility + << " key in properties file.\n"; + } + return itr->second; } - - /** 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() + else { - return m_pSysConfig->getString("system.currentDir"); + g_log.error() << "Unknown facility \"" << facility << "\". No instrument prefixes defined.\n"; + throw Exception::NotFoundError("Unknown facility name. No instrument prefixes defined.", facility); } - - /** Gets the absolute path of the temp directory - * - * @returns The absolute path of the temp directory - */ - std::string ConfigServiceImpl::getTempDir() +} + +/** + * Return the filename of the instrument geometry definition file. + * @param instrument A string giving the instrument name + * @returns A string containing the full qualified filename of the instrument file. + */ +const std::string ConfigServiceImpl::getInstrumentFilename(const std::string& instrumentName) const +{ + // Determine the search directory for XML instrument definition files (IDFs) + std::string directoryName = getString("instrumentDefinition.directory"); + if (directoryName.empty()) { - return m_pSysConfig->getString("system.tempDir"); + // 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(getBaseDir()).resolve("../Instrument").toString(); } - /** - * Gets the directory that we consider to be the bse directory. Basically, this is the - * executable directory when running normally or the current directory on startup when - * running through Python on the command line - * @returns The directory to consider as the base directory, including a trailing slash - */ - std::string ConfigServiceImpl::getBaseDir() const - { - return m_strBaseDir; - } + // force ID to upper case + std::string instrument; + instrument = instrumentName; + std::transform(instrument.begin(), instrument.end(), instrument.begin(), toupper); + std::string fullPathIDF = directoryName + "/" + instrument + "_Definition.xml"; + + return fullPathIDF; +} + +/** + * Load facility information from instrumentDir/Facilities.xml file if fName parameter + * is not set + * @param fName An alternative file name for loading facilities information. + */ +void ConfigServiceImpl::updateFacilities(const std::string& fName) +{ + m_facilities.clear(); - /** - * Return the directory that Mantid should use for writing files. A trailing slash is appended - * so that filenames can more easily be concatenated with this - * @return the directory that Mantid should use for writing files - */ - std::string ConfigServiceImpl::getOutputDir() const + 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; + try { -#ifdef _WIN32 - 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 + pDoc = pParser.parse(fileName); + } catch (...) + { + g_log.error("Unable to parse file " + fileName); + throw Kernel::Exception::FileError("Unable to parse file:", fileName); } - - /** - * Return the list of search paths - * @returns A vector of strings containing the defined search directories - */ - const std::vector<std::string>& ConfigServiceImpl::getDataSearchDirs() const + // Get pointer to root element + Poco::XML::Element* pRootElem = pDoc->documentElement(); + if (!pRootElem->hasChildNodes()) { - return m_DataSearchDirs; + g_log.error("XML file: " + fileName + "contains no root element."); + throw std::runtime_error("No root element in Facilities.xml file"); } - /** - * Return the list of instrument prefixes for the given facility. If the facility if unknown then a NotFoundError is thrown. - * @param facility A string giving a facility name - * @returns A vector of strings containing the instrument prefixes - */ - const std::vector<std::string>& ConfigServiceImpl::getInstrumentPrefixes(const std::string& facility) const + Poco::XML::NodeList* pNL_facility = pRootElem->getElementsByTagName("facility"); + unsigned int n = pNL_facility->length(); + + for (unsigned int i = 0; i < n; ++i) { - std::map<std::string, std::vector<std::string> >::const_iterator itr = m_instr_prefixes.find(facility); - if( itr != m_instr_prefixes.end() ) + Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*> (pNL_facility->item(i)); + if (elem) { - if( itr->second.empty() ) - { - g_log.warning() << "Facility \"" << facility << "\" has no instruments defined. Check instrument.prefixes." - << facility << " key in properties file.\n"; - } - return itr->second; - } - else - { - g_log.error() << "Unknown facility \"" << facility << "\". No instrument prefixes defined.\n"; - throw Exception::NotFoundError("Unknown facility name. No instrument prefixes defined.", facility); + m_facilities.push_back(new FacilityInfo(elem)); } } - /** - * Load facility information from instrumentDir/Facilities.xml file if fName parameter - * is not set - * @param fName An alternative file name for loading facilities information. - */ - void ConfigServiceImpl::updateFacilities(const std::string& fName) + if (m_facilities.empty()) { - m_facilities.clear(); - - 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; - try - { - pDoc = pParser.parse(fileName); - } - catch(...) - { - g_log.error("Unable to parse file " + fileName); - throw Kernel::Exception::FileError("Unable to parse file:" , fileName); - } - // Get pointer to root element - Poco::XML::Element* pRootElem = pDoc->documentElement(); - if ( !pRootElem->hasChildNodes() ) - { - g_log.error("XML file: " + fileName + "contains no root element."); - throw std::runtime_error("No root element in Facilities.xml file"); - } - - Poco::XML::NodeList* pNL_facility = pRootElem->getElementsByTagName("facility"); - unsigned int n = pNL_facility->length(); - - for (unsigned int i = 0; i < n; ++i) - { - 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()) - { - throw std::runtime_error("The facility definition file "+fileName+" defines no facilities"); - } - + throw std::runtime_error("The facility definition file " + fileName + " defines no facilities"); } - /** Get the default facility - */ - const FacilityInfo& ConfigServiceImpl::Facility()const +} + +/** Get the default facility + */ +const FacilityInfo& ConfigServiceImpl::Facility() const +{ + std::string defFacility = getString("default.facility"); + if (defFacility.empty()) { - std::string defFacility = getString("default.facility"); - if (defFacility.empty()) - { - defFacility = "ISIS"; - } - return Facility(defFacility); + defFacility = "ISIS"; } - - /** - * Get a facility - * @param fName Facility name - * @throws NotFoundException if the facility is not found - */ - const FacilityInfo& ConfigServiceImpl::Facility(const std::string& fName)const + return Facility(defFacility); +} + +/** + * Get a facility + * @param fName Facility name + * @throws NotFoundException if the facility is not found + */ +const FacilityInfo& ConfigServiceImpl::Facility(const std::string& fName) const +{ + std::vector<FacilityInfo*>::const_iterator it = m_facilities.begin(); + for (; it != m_facilities.end(); ++it) { - std::vector<FacilityInfo*>::const_iterator it = m_facilities.begin(); - for(;it != m_facilities.end(); ++it) + if ((**it).name() == fName) { - if ((**it).name() == fName) - { - return **it; - } + return **it; } - g_log.error("Facility "+fName+" not found"); - throw Exception::NotFoundError("Facilities",fName); } - - - - /// \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&); - /// \endcond TEMPLATE + g_log.error("Facility " + fName + " not found"); + throw Exception::NotFoundError("Facilities", fName); +} + +/// \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&); +/// \endcond TEMPLATE } // namespace Kernel } // namespace Mantid -- GitLab