Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
Gigg, Martyn Anthony
committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <iostream>
#include <sstream>
#include "MantidAPI/AlgorithmFactory.h"
#include "MantidKernel/LibraryManager.h"
#include "MantidAPI/CloneableAlgorithm.h"
namespace Mantid
{
namespace API
{
AlgorithmFactoryImpl::AlgorithmFactoryImpl() :
Kernel::DynamicFactory<Algorithm>(), g_log(Kernel::Logger::get("AlgorithmFactory")),
m_vmap(), m_cloneable_algs()
{
// we need to make sure the library manager has been loaded before we
// are constructed so that it is destroyed after us and thus does
// not close any loaded DLLs with loaded algorithms in them
Mantid::Kernel::LibraryManager::Instance();
g_log.debug() << "Algorithm Factory created." << std::endl;
}
AlgorithmFactoryImpl::~AlgorithmFactoryImpl()
{
}
/** Creates a mangled name for interal storage
* @param name the name of the Algrorithm
* @param version the version of the algroithm
* @returns a mangled name string
*/
std::string AlgorithmFactoryImpl::createName(const std::string& name, const int& version)const
{
std::ostringstream oss;
oss << name << "|" << version;
return(oss.str());
}
/** Creates an instance of an algorithm
* @param name the name of the Algrorithm to create
* @param version the version of the algroithm to create
* @returns a shared pointer to the created algorithm
*/
boost::shared_ptr<IAlgorithm> AlgorithmFactoryImpl::create(const std::string& name,const int& version) const
{
int local_version=version;
if( version < 0)
{
if(version == -1)//get latest version since not supplied
{
versionMap::const_iterator it = m_vmap.find(name);
if (!name.empty())
{
if(it == m_vmap.end() )
throw std::runtime_error("algorithm not registered "+ name );
else
local_version = it->second;
}
else
throw;
}
}
try
{
return this->createAlgorithm(name, local_version);
}
catch(Kernel::Exception::NotFoundError&)
{
versionMap::const_iterator it = m_vmap.find(name);
if(it == m_vmap.end() )
throw std::runtime_error("algorithm not registered "+ name );
else
{
g_log.error()<< "algorithm "<< name<< " version " << version << " is not registered "<<std::endl;
g_log.error()<< "the latest registered version is " << it->second<<std::endl;
throw std::runtime_error("algorithm not registered "+ createName(name,local_version) );
}
}
}
/**
* Return the keys used for identifying algorithms. This includes those within the Factory itself and
* any cleanly constructed algorithms stored here.
* @returns The strings used to identify individual algorithms
*/
const std::vector<std::string> AlgorithmFactoryImpl::getKeys() const
{
//Start with those subscribed with the factory and add the cleanly constructed algorithm keys
std::vector<std::string> names = Kernel::DynamicFactory<Algorithm>::getKeys();
names.reserve(names.size() + m_cloneable_algs.size());
std::map<std::string, API::CloneableAlgorithm*>::const_iterator itr_end = m_cloneable_algs.end();
for(std::map<std::string, API::CloneableAlgorithm*>::const_iterator itr = m_cloneable_algs.begin();
itr!= itr_end; ++itr )
{
names.push_back(itr->first);
}
return names;
}
/**
* Get a list of descriptor objects used to order the algorithms in the stored map
* @returns A vector of descriptor objects
*/
std::vector<Algorithm_descriptor> AlgorithmFactoryImpl::getDescriptors() const
{
std::vector<std::string> sv;
sv = getKeys();
std::vector<Algorithm_descriptor> res;
for(std::vector<std::string>::const_iterator s=sv.begin();s!=sv.end();s++)
{
if (s->empty()) continue;
Algorithm_descriptor desc;
size_t i = s->find('|');
if (i == std::string::npos)
{
desc.name = *s;
desc.version = 1;
}
else if (i > 0)
{
desc.name = s->substr(0,i);
std::string vers = s->substr(i+1);
desc.version = vers.empty()? 1 : atoi(vers.c_str());
}
else
continue;
boost::shared_ptr<IAlgorithm> alg = create(desc.name,desc.version);
desc.category = alg->category();
res.push_back(desc);
}
return res;
}
/**
* Store a pointer to an Algorithm object that is cloneable, e.g. a Python algorithm
* @param algorithm A pointer to a clonable algorithm object
*/
bool AlgorithmFactoryImpl::storeCloneableAlgorithm(CloneableAlgorithm* algorithm)
Gigg, Martyn Anthony
committed
{
const std::string alg_name = algorithm->name();
if( alg_name.empty() )
{
throw std::runtime_error("Cannot register algorithm with empty name.");
}
const int alg_version(algorithm->version());
//Check if we already have an algorithm of this name and version within the factory
std::map<std::string, int>::const_iterator itr = m_vmap.find(alg_name);
if( itr != m_vmap.end() )
{
int registered_version = itr->second;
if( alg_version > registered_version )
{
m_vmap[alg_name] = alg_version;
}
}
else
{
m_vmap[alg_name] = alg_version;
}
// Finally check that the algorithm can be initialized without throwing
try
{
algorithm->clone()->initialize();
}
catch( std::runtime_error & e )
{
g_log.error(e.what());
return false;
}
catch( ... )
{
return false;
}
Gigg, Martyn Anthony
committed
//Insert into map, overwriting if necessary
m_cloneable_algs[createName(alg_name, alg_version)] = algorithm;
//Notify whomever is interested that the factory has been updated
notificationCenter.postNotification(new AlgorithmFactoryUpdateNotification);
Gigg, Martyn Anthony
committed
}
/** Extract the name of an algorithm
* @param alg the Algrorithm to use
* @returns the name of the algroithm
*/
const std::string AlgorithmFactoryImpl::extractAlgName(const boost::shared_ptr<IAlgorithm> alg) const
return alg->name();
Gigg, Martyn Anthony
committed
/** Extract the version of an algorithm
* @param alg the Algrorithm to use
* @returns the version of the algroithm
*/
const int AlgorithmFactoryImpl::extractAlgVersion(const boost::shared_ptr<IAlgorithm> alg) const
{
return alg->version();
}
Gigg, Martyn Anthony
committed
/**
* Create a shared pointer to an algorithm object with the given name and version. If the algorithm is one registered with a clean pointer rather than
* an instantiator then a clone is returned.
* @param name Algorithm name
* @param version Algorithm version
* @returns A shared pointer to the algorithm object
*/
boost::shared_ptr<IAlgorithm> AlgorithmFactoryImpl::createAlgorithm(const std::string & name, const int version) const
{
try
{
return Kernel::DynamicFactory<Algorithm>::create(createName(name,version));
}
catch(Mantid::Kernel::Exception::NotFoundError &)
{
}
//See if we can make one from the clean cache
const std::string fqlname(createName(name, version));
std::map<std::string, CloneableAlgorithm*>::const_iterator itr = m_cloneable_algs.find(fqlname);
if( itr != m_cloneable_algs.end() )
{
API::CloneableAlgorithm *cloned = itr->second->clone();
if( !cloned )
{
throw std::runtime_error("Cloning algorithm failed, cannot create algorithm \"" + name + "\"");
}
return boost::shared_ptr<API::CloneableAlgorithm>(cloned, std::mem_fun(&CloneableAlgorithm::kill));