Mantid
Loading...
Searching...
No Matches
ISISJournal.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7// Includes
11
12#include "Poco/SAX/SAXException.h"
13#include <Poco/DOM/DOMParser.h>
14#include <Poco/DOM/Document.h>
15#include <Poco/DOM/NodeFilter.h>
16#include <Poco/DOM/TreeWalker.h>
17#include <Poco/Net/HTTPResponse.h>
18
19#include <boost/algorithm/string.hpp>
20#include <boost/regex.hpp>
21#include <sstream>
22
23namespace Mantid::DataHandling {
24
25using Kernel::InternetHelper;
26using Poco::XML::Document;
27using Poco::XML::DOMParser;
28using Poco::XML::Element;
29using Poco::XML::Node;
30using Poco::XML::NodeFilter;
31using Poco::XML::TreeWalker;
32
33namespace {
34static constexpr const char *INDEX_FILE_NAME = "main";
35static constexpr const char *JOURNAL_PREFIX = "/journal_";
36static constexpr const char *JOURNAL_EXT = ".xml";
37static constexpr const char *NXROOT_TAG = "NXroot";
38static constexpr const char *NXENTRY_TAG = "NXentry";
39static constexpr const char *JOURNAL_TAG = "journal";
40static constexpr const char *FILE_TAG = "file";
41
50std::string constructURL(std::string instrument, std::string const &name) {
51 boost::algorithm::to_lower(instrument);
52 std::ostringstream url;
53 url << Mantid::Kernel::ConfigService::Instance().getString("isisjournal.url_prefix") << instrument << JOURNAL_PREFIX
54 << name << JOURNAL_EXT;
55 return url.str();
56}
57
63Poco::AutoPtr<Document> parse(std::string const &xmlString) {
64 DOMParser domParser;
65 Poco::AutoPtr<Document> xmldoc;
66 try {
67 xmldoc = domParser.parseString(xmlString);
68 } catch (Poco::XML::SAXParseException const &ex) {
69 std::ostringstream msg;
70 msg << "ISISJournal: Error parsing file: " << ex.what();
71 throw std::runtime_error(msg.str());
72 }
73 return xmldoc;
74}
75
80void throwIfNotValid(Element *element, const char *expectedName) {
81 if (!element) {
82 std::ostringstream msg;
83 msg << "ISISJournal::throwIfNotValid() - invalid element for '" << expectedName << "'\n";
84 throw std::invalid_argument(msg.str());
85 }
86
87 if (element->nodeName() != expectedName) {
88 std::ostringstream msg;
89 msg << "ISISJournal::throwIfNotValid() - Element name does not match '" << expectedName << "'. Found "
90 << element->nodeName() << "\n";
91 throw std::invalid_argument(msg.str());
92 }
93}
94
100std::string getTextValue(Node *node) {
101 if (!node)
102 return std::string();
103
104 auto child = node->firstChild();
105 if (child && child->nodeName() == "#text") {
106 auto value = child->nodeValue();
107 boost::algorithm::trim(value);
108 return value;
109 }
110
111 return std::string();
112}
113
120bool matchesAllFilters(Element *element, ISISJournal::RunData const &filters) {
121 for (auto const &filterKvp : filters) {
122 auto const childElement = element->getChildElement(filterKvp.first);
123 if (getTextValue(childElement) != filterKvp.second)
124 return false;
125 }
126 return true;
127}
128
135ISISJournal::RunData createRunDataForElement(Element *element) {
136 return ISISJournal::RunData{{"name", element->getAttribute("name")}};
137}
138
146void addValuesForElement(Element *element, std::vector<std::string> const &valuesToLookup,
147 ISISJournal::RunData &result) {
148 for (auto &name : valuesToLookup)
149 result[name] = getTextValue(element->getChildElement(name));
150}
151
162std::vector<ISISJournal::RunData> getValuesForAllElements(Element *parentElement,
163 std::vector<std::string> const &valuesToLookup,
164 ISISJournal::RunData const &filters) {
165 auto results = std::vector<ISISJournal::RunData>{};
166
167 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
168 for (auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
169 auto element = dynamic_cast<Element *>(node);
170 throwIfNotValid(element, NXENTRY_TAG);
171
172 if (matchesAllFilters(element, filters)) {
173 auto result = createRunDataForElement(element);
174 addValuesForElement(element, valuesToLookup, result);
175 results.emplace_back(std::move(result));
176 }
177 }
178
179 return results;
180}
181
188std::vector<std::string> getAttributeForAllChildElements(Element *parentElement, const char *childElementName,
189 const char *attributeName) {
190 auto results = std::vector<std::string>{};
191
192 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
193 for (auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
194 auto element = dynamic_cast<Element *>(node);
195 throwIfNotValid(element, childElementName);
196 results.emplace_back(element->getAttribute(attributeName));
197 }
198
199 return results;
200}
201
207std::string convertFilenameToCycleName(std::string const &filename) {
208 boost::regex pattern("[0-9]+_[0-9]+");
209 boost::smatch matches;
210 boost::regex_search(filename, matches, pattern);
211
212 if (matches.size() == 1)
213 return matches[0];
214
215 return std::string();
216}
217
224std::vector<std::string> convertFilenamesToCycleNames(std::vector<std::string> const &filenames) {
225 auto cycles = std::vector<std::string>();
226 cycles.reserve(filenames.size());
227 for (const auto &filename : filenames) {
228 auto cycle = convertFilenameToCycleName(filename);
229 if (!cycle.empty())
230 cycles.emplace_back(std::move(cycle));
231 }
232 return cycles;
233}
234} // namespace
235
242ISISJournal::ISISJournal(std::string const &instrument, std::string const &cycle,
243 std::unique_ptr<InternetHelper> internetHelper)
244 : m_internetHelper(std::move(internetHelper)), m_runsFileURL(constructURL(instrument, cycle)),
245 m_indexFileURL(constructURL(instrument, INDEX_FILE_NAME)) {}
246
248
250
256std::vector<std::string> ISISJournal::getCycleNames() {
257 if (!m_indexDocument) {
258 auto xmlString = getURLContents(m_indexFileURL);
259 m_indexDocument = parse(xmlString);
260 }
261 auto rootElement = m_indexDocument->documentElement();
262 throwIfNotValid(rootElement, JOURNAL_TAG);
263 auto filenames = getAttributeForAllChildElements(rootElement, FILE_TAG, "name");
264 return convertFilenamesToCycleNames(filenames);
265}
266
275std::vector<ISISJournal::RunData> ISISJournal::getRuns(std::vector<std::string> const &valuesToLookup,
276 ISISJournal::RunData const &filters) {
277 if (!m_runsDocument) {
278 auto xmlString = getURLContents(m_runsFileURL);
279 m_runsDocument = parse(xmlString);
280 }
281 auto rootElement = m_runsDocument->documentElement();
282 throwIfNotValid(rootElement, NXROOT_TAG);
283 return getValuesForAllElements(rootElement, valuesToLookup, filters);
284}
285
291std::string ISISJournal::getURLContents(std::string const &url) {
292 std::ostringstream serverReply;
294 try {
295 statusCode = m_internetHelper->sendRequest(url, serverReply);
296 } catch (Kernel::Exception::InternetError const &) {
297 std::ostringstream msg;
298 msg << "Failed to access file " << url << "\nCheck that the cycle name is valid.";
299 throw Kernel::Exception::InternetError(msg.str());
300 }
301
302 if (statusCode != InternetHelper::HTTPStatus::OK) {
303 std::ostringstream msg;
304 msg << "Failed to access file " << url << "\nHTTP Code: " << static_cast<int>(statusCode)
305 << "\nCheck that the cycle name is valid.";
306 throw Kernel::Exception::InternetError(msg.str());
307 }
308 return serverReply.str();
309}
310} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
const std::vector< double > & rhs
double value
The value of the point.
Definition FitMW.cpp:51
std::map< std::string, std::string > RunData
Definition IJournal.h:21
ISISJournal: Helper class to aid in fetching ISIS specific run information from journal files.
Definition ISISJournal.h:32
std::string getURLContents(std::string const &url)
Get the contents of a file at a given URL.
std::vector< std::string > getCycleNames() override
Get the list of cycle names.
std::unique_ptr< Kernel::InternetHelper > m_internetHelper
Definition ISISJournal.h:48
Poco::AutoPtr< Poco::XML::Document > m_indexDocument
Definition ISISJournal.h:52
ISISJournal const & operator=(ISISJournal const &rhs)=delete
ISISJournal(std::string const &instrument, std::string const &cycle, std::unique_ptr< Kernel::InternetHelper > internetHelper=std::make_unique< Kernel::InternetHelper >())
Construct the journal class for a specific instrument and cycle.
Poco::AutoPtr< Poco::XML::Document > m_runsDocument
Definition ISISJournal.h:51
std::vector< RunData > getRuns(std::vector< std::string > const &valuesToLookup={}, RunData const &filters=RunData()) override
Get data for runs that match the given filters.
Exception thrown when error occurs accessing an internet resource.
Definition Exception.h:321
STL namespace.