Newer
Older
Roman Tolchenov
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/FacilityInfo.h"
Janik Zikovsky
committed
#include "MantidKernel/Strings.h"
Roman Tolchenov
committed
#include "MantidKernel/Exception.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/RemoteJobManagerFactory.h"
Roman Tolchenov
committed
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
Roman Tolchenov
committed
#include <Poco/StringTokenizer.h>
#include <boost/algorithm/string.hpp>
Roman Tolchenov
committed
#include <algorithm>
#include <iostream>
using Poco::XML::Element;
Roman Tolchenov
committed
namespace Mantid
{
namespace Kernel
{
Logger& FacilityInfo::g_log(Logger::get("FacilityInfo"));
/** Constructor.
Janik Zikovsky
committed
* @param elem :: The Poco::XML::Element to read the data from
* @throw std::runtime_error if name or file extensions are not defined
Roman Tolchenov
committed
*/
Gigg, Martyn Anthony
committed
FacilityInfo::FacilityInfo(const Poco::XML::Element* elem) :
m_name(elem->getAttribute("name")), m_zeroPadding(0), m_delimiter(), m_extensions(),
m_soapEndPoint(), m_archiveSearch(), m_instruments(), m_catalogName(), m_liveListener(),
m_computeResources()
Roman Tolchenov
committed
{
if (m_name.empty())
{
g_log.error("Facility name is not defined");
throw std::runtime_error("Facility name is not defined");
Roman Tolchenov
committed
}
// Fill the various fields from the XML
fillZeroPadding(elem);
fillDelimiter(elem);
fillExtensions(elem);
fillSoapEndPoint(elem);
fillArchiveNames(elem);
fillCatalogName(elem);
fillLiveListener(elem);
fillInstruments(elem); // Make sure this is last as it picks up some defaults that are set above
}
/// Called from constructor to fill zero padding field
void FacilityInfo::fillZeroPadding(const Poco::XML::Element* elem)
{
Roman Tolchenov
committed
std::string paddingStr = elem->getAttribute("zeropadding");
Janik Zikovsky
committed
if ( paddingStr.empty() || !Mantid::Kernel::Strings::convert(paddingStr,m_zeroPadding) )
Roman Tolchenov
committed
{
m_zeroPadding = 0;
}
Roman Tolchenov
committed
/// Called from constructor to fill default delimiter
void FacilityInfo::fillDelimiter(const Poco::XML::Element* elem)
{
Campbell, Stuart
committed
// The string to separate the instrument name and the run number.
m_delimiter = elem->getAttribute("delimiter");
Campbell, Stuart
committed
/// Called from constructor to fill file extensions
void FacilityInfo::fillExtensions(const Poco::XML::Element* elem)
{
Roman Tolchenov
committed
std::string extsStr = elem->getAttribute("FileExtensions");
if (extsStr.empty())
{
g_log.error("No file extensions defined");
throw std::runtime_error("No file extensions defined");
}
typedef Poco::StringTokenizer tokenizer;
tokenizer exts(extsStr, ",", tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
for (tokenizer::Iterator it = exts.begin(); it != exts.end(); ++it)
{
addExtension(*it);
}
Roman Tolchenov
committed
/**
* Add new extension. Adds both a lowercase and uppercase version
* @param ext :: File extension, including the dot, e.g. ".nxs" or ".raw"
*/
void FacilityInfo::addExtension(const std::string& ext)
{
auto it = std::find(m_extensions.begin(),m_extensions.end(),ext);
if (it == m_extensions.end()) m_extensions.push_back(ext);
}
/// Called from constructor to fill ICAT soap end point
void FacilityInfo::fillSoapEndPoint(const Poco::XML::Element* elem)
{
Poco::XML::NodeList* pNL_soapEndPoint = elem->getElementsByTagName("soapEndPoint");
if (pNL_soapEndPoint->length() > 1)
{
pNL_soapEndPoint->release();
g_log.error("Facility must have only one soapEndPoint tag");
throw std::runtime_error("Facility must have only one csoapEndPoint tag");
}
else if (pNL_soapEndPoint->length() == 1)
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*>(pNL_soapEndPoint->item(0));
if(!elem->getAttribute("url").empty())
{
m_soapEndPoint= elem->getAttribute("url");
}
}
pNL_soapEndPoint->release();
/// Called from constructor to fill archive interface names
void FacilityInfo::fillArchiveNames(const Poco::XML::Element* elem)
{
Roman Tolchenov
committed
Poco::XML::NodeList* pNL_archives = elem->getElementsByTagName("archive");
if (pNL_archives->length() > 1)
{
g_log.error("Facility must have only one archive tag");
throw std::runtime_error("Facility must have only one archive tag");
}
else if (pNL_archives->length() == 1)
{
Poco::XML::NodeList* pNL_interfaces = elem->getElementsByTagName("archiveSearch");
for (unsigned int i = 0; i < pNL_interfaces->length(); ++i)
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*>(pNL_interfaces->item(i));
std::string plugin = elem->getAttribute("plugin");
if (!plugin.empty())
{
m_archiveSearch.push_back(plugin);
Roman Tolchenov
committed
}
}
pNL_interfaces->release();
}
pNL_archives->release();
Roman Tolchenov
committed
/// Called from constructor to fill catalog name
void FacilityInfo::fillCatalogName(const Poco::XML::Element* elem)
{
Poco::XML::NodeList* pNL_catalogs = elem->getElementsByTagName("catalog");
if (pNL_catalogs->length() > 1)
{
g_log.error("Facility must have only one catalog tag");
throw std::runtime_error("Facility must have only one catalog tag");
}
else if (pNL_catalogs->length() == 1)
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*>(pNL_catalogs->item(0));
if(!elem->getAttribute("name").empty())
{
m_catalogName= elem->getAttribute("name");
}
Roman Tolchenov
committed
}
pNL_catalogs->release();
Roman Tolchenov
committed
/// Called from constructor to fill instrument list
void FacilityInfo::fillInstruments(const Poco::XML::Element* elem)
{
Roman Tolchenov
committed
Poco::XML::NodeList* pNL_instrument = elem->getElementsByTagName("instrument");
unsigned long n = pNL_instrument->length();
m_instruments.reserve(n);
Roman Tolchenov
committed
for (unsigned long i = 0; i < n; ++i)
Roman Tolchenov
committed
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*>(pNL_instrument->item(i));
if (elem)
{
try
{
InstrumentInfo instr(this,elem);
m_instruments.push_back(instr);
}
catch(...)
{/*skip this instrument*/}
}
}
pNL_instrument->release();
Campbell, Stuart
committed
throw std::runtime_error("Facility "+m_name+" does not have any instruments;");
Roman Tolchenov
committed
}
/// Called from constructor to fill live listener name
void FacilityInfo::fillLiveListener(const Poco::XML::Element* elem)
{
// Get the first livedata element (will be NULL if there's none)
Element * live = elem->getChildElement("livedata");
if ( live )
{
// Get the name of the listener - empty string will be returned if missing
m_liveListener = live->getAttribute("listener");
}
}
/// Called from constructor to fill compute resources map
void FacilityInfo::fillComputeResources(const Poco::XML::Element* elem)
{
Poco::XML::NodeList* pNL_compute = elem->getElementsByTagName("computeResource");
unsigned long n = pNL_compute->length();
for (unsigned long i = 0; i < n; i++)
{
Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*>(pNL_compute->item(i));
std::string type = elem->getAttribute("type");
std::string name = elem->getAttribute("name");
if (RemoteJobManagerFactory::Instance().exists(type))
{
m_computeResources.insert( make_pair(name, RemoteJobManagerFactory::Instance().create(elem)));
}
else
{
// Log a warning about not having an instantiator for the requested type...
g_log.warning( "No instantiator registered for compute resource \"" + name + "\" of type \"" + type + "\"");
}
}
pNL_compute->release();
}
Roman Tolchenov
committed
/**
* Returns instrument with given name
Roman Tolchenov
committed
* @param iName Instrument name
* @return the instrument information object
Janik Zikovsky
committed
* @throw NotFoundError if iName was not found
Roman Tolchenov
committed
*/
const InstrumentInfo & FacilityInfo::instrument(std::string iName)const
Roman Tolchenov
committed
{
iName = ConfigService::Instance().getString("default.instrument");
g_log.debug() << "Blank instrument specified, using default instrument of " << iName << "." << std::endl;
if (iName.empty())
Roman Tolchenov
committed
std::vector<InstrumentInfo>::const_iterator it = m_instruments.begin();
for(;it != m_instruments.end(); ++it)
{
if ( boost::iequals( it->name(), iName) ) // Case-insensitive search
g_log.debug() << "Instrument '" << iName << "' found as " << it->name() << " at " << name() << "." << std::endl;
return *it;
}
}
// if unsuccessful try shortname
for(it = m_instruments.begin(); it != m_instruments.end(); ++it)
{
if ( boost::iequals( it->shortName(), iName) ) // Case-insensitive search
Roman Tolchenov
committed
{
g_log.debug() << "Instrument '" << iName << "' found as " << it->name() << " at " << name() << "." << std::endl;
Roman Tolchenov
committed
return *it;
}
}
Gigg, Martyn Anthony
committed
g_log.debug("Instrument "+iName+" not found in facility "+name());
throw Exception::NotFoundError("FacilityInfo",iName);
Roman Tolchenov
committed
}
/**
* Returns a list of instruments of given technique
Janik Zikovsky
committed
* @param tech :: Technique name
* @return a list of instrument information objects
Roman Tolchenov
committed
*/
std::vector<InstrumentInfo> FacilityInfo::instruments(const std::string& tech)const
Roman Tolchenov
committed
{
std::vector<InstrumentInfo> out;
std::vector<InstrumentInfo>::const_iterator it = m_instruments.begin();
for(;it != m_instruments.end(); ++it)
{
if (it->techniques().count(tech))
{
out.push_back(*it);
}
}
return out;
}
/**
* Returns a vector of the available compute resources
* @return vector of strings of the compute resource names
*/
std::vector<std::string> FacilityInfo::computeResources() const
{
std::vector<std::string> names;
std::map< std::string, boost::shared_ptr<RemoteJobManager> >::const_iterator it = m_computeResources.begin();
while (it != m_computeResources.end())
{
names.push_back( (*it).first);
it++;
}
return names;
}
/**
* Returns a reference to the requested remote job manager
* @param name :: Name of the cluster we want to submit jobs to
* @return a shared pointer to the RemoteJobManager instance (or
* Null if the name wasn't recognized)
*/
boost::shared_ptr <RemoteJobManager> FacilityInfo::getRemoteJobManager( const std::string &name) const
{
auto it = m_computeResources.find( name);
if (it == m_computeResources.end())
{
return boost::shared_ptr<RemoteJobManager>(); // return Null
}
return (*it).second;
}
Roman Tolchenov
committed
} // namespace Kernel
} // namespace Mantid