Mantid
Loading...
Searching...
No Matches
FileLoaderRegistry.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
10
11#include <Poco/File.h>
12
13namespace Mantid::API {
14namespace {
15//----------------------------------------------------------------------------------------------
16// Anonymous namespace helpers
17//----------------------------------------------------------------------------------------------
19template <typename T> struct DescriptorCallback {
20 void apply(std::shared_ptr<T> & /*unused*/) {} // general one does nothing
21};
22template <> struct DescriptorCallback<Kernel::FileDescriptor> {
23 void apply(std::shared_ptr<Kernel::FileDescriptor> &descriptor) { descriptor->resetStreamToStart(); }
24};
26
28template <typename T> struct DescriptorSetter {
29 // general one does nothing
30 void apply(std::shared_ptr<NexusFileLoader> & /*unused*/, std::shared_ptr<T> & /*unused*/) {}
31};
32template <> struct DescriptorSetter<Kernel::NexusHDF5Descriptor> {
33 void apply(std::shared_ptr<NexusFileLoader> &loader, const std::shared_ptr<Kernel::NexusHDF5Descriptor> &descriptor) {
34 loader->setFileInfo(descriptor);
35 }
36};
38
47template <typename DescriptorType, typename FileLoaderType>
48const IAlgorithm_sptr searchForLoader(const std::string &filename, const std::multimap<std::string, int> &names,
49 Kernel::Logger &logger) {
50 const auto &factory = AlgorithmFactory::Instance();
51 IAlgorithm_sptr bestLoader;
52 int maxConfidence(0);
53 auto descriptor = std::make_shared<DescriptorType>(filename);
54 DescriptorCallback<DescriptorType> callback;
55 DescriptorSetter<DescriptorType> setdescriptor;
56
57 auto iend = names.end();
58 for (auto it = names.begin(); it != iend; ++it) {
59 const std::string &name = it->first;
60 const int version = it->second;
61 logger.debug() << "Checking " << name << " version " << version << '\n';
62
63 // Use static cast for speed. Checks have been done at registration to check
64 // the types
65 auto alg = std::static_pointer_cast<FileLoaderType>(factory.create(name, version)); // highest version
66 try {
67 const int confidence = alg->confidence(*(descriptor.get()));
68 logger.debug() << name << " returned with confidence=" << confidence << '\n';
69 if (confidence > maxConfidence) // strictly greater
70 {
71 bestLoader = alg;
72 maxConfidence = confidence;
73 }
74 } catch (std::exception &exc) {
75 logger.warning() << "Checking loader '" << name << "' raised an error: '" << exc.what() << "'. Loader skipped.\n";
76 }
77 callback.apply(descriptor);
78 }
79
80 auto nxsLoader = std::dynamic_pointer_cast<NexusFileLoader>(bestLoader);
81 if (nxsLoader)
82 setdescriptor.apply(nxsLoader, descriptor);
83
84 return bestLoader;
85}
86} // namespace
87
88//----------------------------------------------------------------------------------------------
89// Public members
90//----------------------------------------------------------------------------------------------
91
98void FileLoaderRegistryImpl::unsubscribe(const std::string &name, const int version) {
99 auto iend = m_names.end();
100 for (auto it = m_names.begin(); it != iend; ++it) {
101 removeAlgorithm(name, version, *it);
102 }
103}
104
113const std::shared_ptr<IAlgorithm> FileLoaderRegistryImpl::chooseLoader(const std::string &filename) const {
117 m_log.debug() << "Trying to find loader for '" << filename << "'\n";
118
119 IAlgorithm_sptr bestLoader;
120 if (NexusDescriptor::isReadable(filename)) {
121 m_log.debug() << filename << " looks like a Nexus file. Checking registered Nexus loaders\n";
122
123 // a large subset of NeXus files are actually HDF5 based
124 if (NexusHDF5Descriptor::isReadable(filename)) {
125 try {
126 bestLoader =
127 searchForLoader<NexusHDF5Descriptor, IFileLoader<NexusHDF5Descriptor>>(filename, m_names[NexusHDF5], m_log);
128 } catch (const std::invalid_argument &e) {
129 m_log.debug() << "Error in looking for HDF5 based NeXus files: " << e.what() << '\n';
130 }
131 }
132
133 // try generic nexus loaders
134 if (!bestLoader) {
135 bestLoader = searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, m_names[Nexus], m_log);
136 }
137 } else {
138 m_log.debug() << "Checking registered non-HDF loaders\n";
139 bestLoader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, m_names[Generic], m_log);
140 }
141
142 if (!bestLoader) {
143 throw Kernel::Exception::NotFoundError(filename, "Unable to find loader");
144 }
145 m_log.debug() << "Found loader " << bestLoader->name() << " for file '" << filename << "'\n";
146 return bestLoader;
147}
148
156bool FileLoaderRegistryImpl::canLoad(const std::string &algorithmName, const std::string &filename) const {
160
161 // Check if it is in one of our lists
162 const bool nexus = (m_names[Nexus].find(algorithmName) != m_names[Nexus].end());
163 const bool nexusHDF5 = (m_names[NexusHDF5].find(algorithmName) != m_names[NexusHDF5].end());
164 const bool nonHDF = (m_names[Generic].find(algorithmName) != m_names[Generic].end());
165
166 if (!(nexus || nexusHDF5 || nonHDF))
167 throw std::invalid_argument("FileLoaderRegistryImpl::canLoad - Algorithm '" + algorithmName +
168 "' is not registered as a loader.");
169
170 std::multimap<std::string, int> names{{algorithmName, -1}};
171 IAlgorithm_sptr loader;
172 if (nexus) {
173 if (NexusDescriptor::isReadable(filename)) {
174 loader = searchForLoader<NexusDescriptor, IFileLoader<NexusDescriptor>>(filename, names, m_log);
175 }
176 } else if (nexusHDF5) {
177 if (NexusHDF5Descriptor::isReadable(filename)) {
178 try {
179 loader = searchForLoader<NexusHDF5Descriptor, IFileLoader<NexusHDF5Descriptor>>(filename, names, m_log);
180 } catch (const std::invalid_argument &e) {
181 m_log.debug() << "Error in looking for HDF5 based NeXus files: " << e.what() << '\n';
182 }
183 }
184 } else if (nonHDF) {
185 loader = searchForLoader<FileDescriptor, IFileLoader<FileDescriptor>>(filename, names, m_log);
186 }
187 return static_cast<bool>(loader);
188}
189
190//----------------------------------------------------------------------------------------------
191// Private members
192//----------------------------------------------------------------------------------------------
198FileLoaderRegistryImpl::FileLoaderRegistryImpl() : m_totalSize(0), m_log("FileLoaderRegistry") {}
199
201
207void FileLoaderRegistryImpl::removeAlgorithm(const std::string &name, const int version,
208 std::multimap<std::string, int> &typedLoaders) {
209 if (version == -1) // remove all
210 {
211 typedLoaders.erase(name);
212 } else // find the right version
213 {
214 auto range = typedLoaders.equal_range(name);
215 for (auto ritr = range.first; ritr != range.second; ++ritr) {
216 if (ritr->second == version) {
217 typedLoaders.erase(ritr);
218 break;
219 }
220 }
221 }
222}
223
224} // namespace Mantid::API
std::array< std::multimap< std::string, int >, 3 > m_names
The list of names.
const std::shared_ptr< IAlgorithm > chooseLoader(const std::string &filename) const
Returns the name of an Algorithm that can load the given filename.
FileLoaderRegistryImpl()
Default constructor (for singleton)
void unsubscribe(const std::string &name, const int version=-1)
Unsubscribe a named algorithm and version from the loader registration.
bool canLoad(const std::string &algorithmName, const std::string &filename) const
Checks whether the given algorithm can load the file.
void removeAlgorithm(const std::string &name, const int version, std::multimap< std::string, int > &typedLoaders)
Remove a named algorithm & version from the given map.
Kernel::Logger m_log
Reference to a logger.
Exception for when an item is not found in a collection.
Definition: Exception.h:145
Defines a wrapper around an open file.
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
static bool isReadable(const std::string &filename, const Version version=AnyVersion)
Returns true if the file is considered to store data in a hierarchy.
static bool isReadable(const std::string &filename)
Returns true if the file is considered to store data in a hierarchy.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm