Commit 49ab00a0 authored by Nick Draper's avatar Nick Draper
Browse files

Remove the AlgorithmProxy class

First checking, more to save state over the weekend
parent 5c3c9535
......@@ -8,7 +8,6 @@ set(SRC_FILES
src/AlgorithmManager.cpp
src/AlgorithmObserver.cpp
src/AlgorithmProperty.cpp
src/AlgorithmProxy.cpp
src/AnalysisDataService.cpp
src/AnalysisDataServiceObserver.cpp
src/ArchiveSearchFactory.cpp
......@@ -172,7 +171,6 @@ set(INC_FILES
inc/MantidAPI/AlgorithmManager.h
inc/MantidAPI/AlgorithmObserver.h
inc/MantidAPI/AlgorithmProperty.h
inc/MantidAPI/AlgorithmProxy.h
inc/MantidAPI/AnalysisDataService.h
inc/MantidAPI/AnalysisDataServiceObserver.h
inc/MantidAPI/ArchiveSearchFactory.h
......@@ -379,7 +377,6 @@ set(TEST_FILES
AlgorithmMPITest.h
AlgorithmManagerTest.h
AlgorithmPropertyTest.h
AlgorithmProxyTest.h
AlgorithmTest.h
AnalysisDataServiceTest.h
AnalysisDataServiceObserverTest.h
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/DllConfig.h"
#include "MantidAPI/IAlgorithm.h"
#include "MantidKernel/PropertyManagerOwner.h"
#ifdef _MSC_VER
#pragma warning(disable : 4250) // Disable warning regarding inheritance via
// dominance, we have no way around it with the
// design
#endif
//----------------------------------------------------------------------
// Forward Declaration
//----------------------------------------------------------------------
namespace Poco {
template <class R, class A, class O, class S> class ActiveMethod;
template <class O> class ActiveStarter;
class Void;
} // namespace Poco
namespace Mantid {
namespace API {
class Algorithm;
using Algorithm_sptr = boost::shared_ptr<Algorithm>;
/**
A proxy class that stands between the user and the actual algorithm.
AlgorithmDataService stores algoruithm proxies. Actual algorithms are
created by the proxy and destroyed after execution to free memory.
Algorithm and its proxy share all properties.
@author Russell Taylor, Tessella Support Services plc
@author Based on the Gaudi class of the same name (see
http://proj-gaudi.web.cern.ch/proj-gaudi/)
@date 12/09/2007
@author Roman Tolchenov, Tessella plc
@date 03/03/2009
*/
class MANTID_API_DLL AlgorithmProxy : public IAlgorithm,
public Kernel::PropertyManagerOwner {
public:
AlgorithmProxy(Algorithm_sptr alg);
AlgorithmProxy(const AlgorithmProxy &) = delete;
AlgorithmProxy &operator=(const AlgorithmProxy &) = delete;
~AlgorithmProxy() override;
/// The name of the algorithm
const std::string name() const override { return m_name; }
/// The version of the algorithm
int version() const override { return m_version; }
/// The category of the algorithm
const std::string category() const override { return m_category; }
/// Function to return all of the categories that contain this algorithm
const std::vector<std::string> categories() const override;
/// Function to return the seperator token for the category string. A default
/// implementation ',' is provided
const std::string categorySeparator() const override {
return m_categorySeparator;
}
/// Function to return all of the seeAlso algorithms related to this algorithm
const std::vector<std::string> seeAlso() const override { return m_seeAlso; };
/// Aliases to the algorithm
const std::string alias() const override { return m_alias; }
/// Optional documentation URL for the real algorithm
const std::string helpURL() const override { return m_helpURL; }
/// function returns a summary message that will be displayed in the default
/// GUI, and in the help.
const std::string summary() const override { return m_summary; }
/// The algorithmID
AlgorithmID getAlgorithmID() const override;
void initialize() override;
std::map<std::string, std::string> validateInputs() override;
bool execute() override;
void executeAsChildAlg() override {
throw std::runtime_error("Not implemented.");
}
Poco::ActiveResult<bool> executeAsync() override;
/// Gets the current execution state
ExecutionState executionState() const override;
/// Gets the current result State
ResultState resultState() const override;
bool isInitialized() const override;
bool isExecuted() const override;
/// To query whether algorithm is a child. A proxy is always at top level,
/// returns false
bool isChild() const override { return m_isChild; }
void setChild(const bool val) override {
m_isChild = val;
setAlwaysStoreInADS(!val);
}
void setAlwaysStoreInADS(const bool val) override {
m_setAlwaysStoreInADS = val;
}
bool getAlwaysStoreInADS() const override { return m_setAlwaysStoreInADS; }
/// Proxies only manage parent algorithms
void enableHistoryRecordingForChild(const bool) override{};
void setRethrows(const bool rethrow) override;
const std::string workspaceMethodName() const override;
const std::vector<std::string> workspaceMethodOn() const override;
const std::string workspaceMethodInputProperty() const override;
/** @name PropertyManager methods */
//@{
/// Set the property value
void setPropertyValue(const std::string &name,
const std::string &value) override;
/// Do something after a property was set
void afterPropertySet(const std::string &) override;
/// Make m_properties point to the same PropertyManager as po.
void copyPropertiesFrom(const PropertyManagerOwner &po) override;
//@}
void cancel() override;
bool isRunning() const override;
void addObserver(const Poco::AbstractObserver &observer) const override;
void removeObserver(const Poco::AbstractObserver &observer) const override;
/// Set logging on or off
///@param value :: true = logging enabled
void setLogging(const bool value) override { m_isLoggingEnabled = value; }
/// Is the algorithm have logging enabled
bool isLogging() const override { return m_isLoggingEnabled; }
/// returns the logging priority offset
void setLoggingOffset(const int value) override { m_loggingOffset = value; }
/// returns the logging priority offset
int getLoggingOffset() const override { return m_loggingOffset; }
/// disable Logging of start and end messages
void setAlgStartupLogging(const bool enabled) override;
/// get the state of Logging of start and end messages
bool getAlgStartupLogging() const override;
/// setting the child start progress
void setChildStartProgress(const double startProgress) const override;
/// setting the child end progress
void setChildEndProgress(const double endProgress) const override;
/** @name Serialization */
//@{
/// Serialize an object to a string
std::string toString() const override;
/// Serialize as a json value
Json::Value toJson() const override;
//@}
private:
void createConcreteAlg(bool initOnly = false);
void stopped();
void addObservers();
void dropWorkspaceReferences();
/// Poco::ActiveMethod used to implement asynchronous execution.
Poco::ActiveMethod<bool, Poco::Void, AlgorithmProxy,
Poco::ActiveStarter<AlgorithmProxy>> *m_executeAsync;
/// Execute asynchronous implementation
bool executeAsyncImpl(const Poco::Void &dummy);
const std::string m_name; ///< name of the real algorithm
const std::string m_category; ///< category of the real algorithm
const std::string
m_categorySeparator; ///< category seperator of the real algorithm
const std::vector<std::string> m_seeAlso; ///< seeAlso of the real algorithm
const std::string m_alias; ///< alias to the algorithm
const std::string m_helpURL; ///< Optional documentation URL
const std::string m_summary; ///< Message to display in GUI and help.
const int m_version; ///< version of the real algorithm
mutable boost::shared_ptr<Algorithm>
m_alg; ///< Shared pointer to a real algorithm. Created on demand
ExecutionState m_executionState; ///< the current execution state
ResultState m_resultState; ///< the current result State
bool m_isLoggingEnabled; ///< is the logging of the underlying algorithm
/// enabled
int m_loggingOffset; ///< the logging priority offset
bool m_isAlgStartupLoggingEnabled; /// Whether to log alg startup and
/// closedown messages from the base class
/// (default = true)
bool m_rethrow; ///< Whether or not to rethrow exceptions.
bool m_isChild; ///< Is this a child algo
bool m_setAlwaysStoreInADS; ///< If this will save in ADS
/// Temporary holder of external observers wishing to subscribe
mutable std::vector<const Poco::AbstractObserver *> m_externalObservers;
};
} // namespace API
} // namespace Mantid
......@@ -8,7 +8,6 @@
#include "MantidAPI/ADSValidator.h"
#include "MantidAPI/AlgorithmHistory.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/AlgorithmProxy.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/DeprecatedAlgorithm.h"
#include "MantidAPI/IWorkspaceProperty.h"
......@@ -995,21 +994,6 @@ IAlgorithm_sptr Algorithm::fromJson(const Json::Value &serialized) {
return alg;
}
//-------------------------------------------------------------------------
/** Initialize using proxy algorithm.
* Call the main initialize method and then copy in the property values.
* @param proxy :: Initialising proxy algorithm */
void Algorithm::initializeFromProxy(const AlgorithmProxy &proxy) {
initialize();
copyPropertiesFrom(proxy);
m_algorithmID = proxy.getAlgorithmID();
setLogging(proxy.isLogging());
setLoggingOffset(proxy.getLoggingOffset());
setAlgStartupLogging(proxy.getAlgStartupLogging());
setChild(proxy.isChild());
setAlwaysStoreInADS(proxy.getAlwaysStoreInADS());
}
/** Fills History, Algorithm History and Algorithm Parameters
*/
void Algorithm::fillHistory() {
......
......@@ -10,7 +10,6 @@
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/AlgorithmFactory.h"
#include "MantidAPI/AlgorithmProxy.h"
#include "MantidKernel/ConfigService.h"
namespace Mantid {
......@@ -75,12 +74,8 @@ IAlgorithm_sptr AlgorithmManagerImpl::create(const std::string &algName,
std::lock_guard<std::mutex> _lock(this->m_managedMutex);
IAlgorithm_sptr alg;
try {
Algorithm_sptr unmanagedAlg = AlgorithmFactory::Instance().create(
alg = AlgorithmFactory::Instance().create(
algName, version); // Throws on fail:
if (makeProxy)
alg = IAlgorithm_sptr(new AlgorithmProxy(unmanagedAlg));
else
alg = unmanagedAlg;
auto count = removeFinishedAlgorithms();
g_log.debug()
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAPI/AlgorithmProxy.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/AlgorithmObserver.h"
#include "MantidAPI/DeprecatedAlgorithm.h"
#include "MantidKernel/StringTokenizer.h"
#include <Poco/ActiveMethod.h>
#include <Poco/ActiveResult.h>
#include <Poco/Void.h>
#include <json/value.h>
using namespace Mantid::Kernel;
namespace Mantid {
namespace API {
/// Constructor
AlgorithmProxy::AlgorithmProxy(Algorithm_sptr alg)
: PropertyManagerOwner(),
m_executeAsync(new Poco::ActiveMethod<bool, Poco::Void, AlgorithmProxy>(
this, &AlgorithmProxy::executeAsyncImpl)),
m_name(alg->name()), m_category(alg->category()),
m_categorySeparator(alg->categorySeparator()), m_seeAlso(alg->seeAlso()),
m_alias(alg->alias()), m_summary(alg->summary()),
m_version(alg->version()), m_alg(alg),
m_executionState(ExecutionState::Initialized),
m_resultState(ResultState::NotFinished), m_isLoggingEnabled(true),
m_loggingOffset(0), m_isAlgStartupLoggingEnabled(true), m_rethrow(false),
m_isChild(false), m_setAlwaysStoreInADS(true) {
if (!alg) {
throw std::logic_error("Unable to create a proxy algorithm.");
}
alg->initialize();
copyPropertiesFrom(*alg);
}
/// Virtual destructor
AlgorithmProxy::~AlgorithmProxy() { delete m_executeAsync; }
/** Initialization method invoked by the framework.
* Does nothing for AlgorithmProxy as initialization is done in the
* constructor.
*/
void AlgorithmProxy::initialize() {}
AlgorithmID AlgorithmProxy::getAlgorithmID() const {
return AlgorithmID(const_cast<AlgorithmProxy *>(this));
}
/** Perform whole-input validation */
std::map<std::string, std::string> AlgorithmProxy::validateInputs() {
if (!m_alg)
createConcreteAlg(true);
return m_alg->validateInputs();
}
/** The actions to be performed by the AlgorithmProxy on a dataset. This method
*is
* invoked for top level AlgorithmProxys by the application manager.
* This method invokes exec() method.
* For Child AlgorithmProxys either the execute() method or exec() method
* must be EXPLICITLY invoked by the parent AlgorithmProxy.
*
* @throw runtime_error Thrown if AlgorithmProxy or Child AlgorithmProxy cannot
*be executed
*/
bool AlgorithmProxy::execute() {
createConcreteAlg(false);
try {
m_alg->execute();
} catch (...) {
stopped();
throw;
}
stopped();
return isExecuted();
}
/** Asynchronous execution of the algorithm.
* This will launch the AlgorithmProxy::executeAsyncImpl() method
* but in a separate thread.
*
* @return Poco::ActiveResult containing the result from the thread.
*/
Poco::ActiveResult<bool> AlgorithmProxy::executeAsync() {
return (*m_executeAsync)(Poco::Void());
}
/** executeAsync() implementation.
* Calls execute and, when it has finished, deletes the real algorithm.
* @param dummy :: An unused dummy variable
*/
bool AlgorithmProxy::executeAsyncImpl(const Poco::Void &dummy) {
createConcreteAlg(false);
// Call Algorithm::executeAsyncImpl rather than executeAsync() because the
// latter
// would spawn off another (3rd) thread which is unecessary.
try {
m_alg->executeAsyncImpl(
dummy); // Pass through dummy argument, though not used
} catch (...) {
stopped();
throw;
}
stopped();
return (resultState() == ResultState::Success);
}
/// Gets the current execution state
ExecutionState AlgorithmProxy::executionState() const {
return m_executionState;
}
/// Gets the current result State
ResultState AlgorithmProxy::resultState() const { return m_resultState; }
/// True if the algorithm is running.
bool AlgorithmProxy::isRunning() const {
return m_alg ? (m_alg->executionState() == ExecutionState::Running) : false;
}
/// Has the AlgorithmProxy already been initialized
bool AlgorithmProxy::isInitialized() const {
return true; // Algorithm Proxies will always initialize the algorithm
}
/// Has the AlgorithmProxy already been executed successfully
bool AlgorithmProxy::isExecuted() const {
return resultState() == ResultState::Success;
}
/// Cancel the execution of the algorithm
void AlgorithmProxy::cancel() {
if (m_alg)
m_alg->cancel();
}
/** Add an observer for a notification. If the real algorithm is running
* the observer is added directly. If the algorithm is not running yet
* the observer's address is added to a buffer to be used later when
* execute/executeAsync
* method is called.
* @param observer :: Observer
*/
void AlgorithmProxy::addObserver(const Poco::AbstractObserver &observer) const {
const Poco::AbstractObserver *obs = &observer;
if (m_alg) {
m_alg->addObserver(*obs);
}
// save the observer in any case because m_alg can be reset (eg in
// createConcreteAlg())
m_externalObservers.emplace_back(obs);
}
/** Remove an observer.
* @param observer :: Observer
*/
void AlgorithmProxy::removeObserver(
const Poco::AbstractObserver &observer) const {
auto o = std::find(m_externalObservers.begin(), m_externalObservers.end(),
&observer);
if (o != m_externalObservers.end())
m_externalObservers.erase(o);
if (m_alg)
m_alg->removeObserver(observer);
}
void AlgorithmProxy::setRethrows(const bool rethrow) {
this->m_rethrow = rethrow;
if (m_alg)
m_alg->setRethrows(rethrow);
}
/**
* @return A string giving the method name that should be attached to a
* workspace
*/
const std::string AlgorithmProxy::workspaceMethodName() const {
if (m_alg)
return m_alg->workspaceMethodName();
else
return "";
}
/**
* @return A set of workspace class names that should have the
* workspaceMethodName attached
*/
const std::vector<std::string> AlgorithmProxy::workspaceMethodOn() const {
if (m_alg)
return m_alg->workspaceMethodOn();
else
return std::vector<std::string>();
}
/**
* @return The name of the property that the calling object will be passed to
*/
const std::string AlgorithmProxy::workspaceMethodInputProperty() const {
if (m_alg)
return m_alg->workspaceMethodInputProperty();
else
return "";
}
/**
* Override setPropertyValue
* @param name The name of the property
* @param value The value of the property as a string
*/
void AlgorithmProxy::setPropertyValue(const std::string &name,
const std::string &value) {
createConcreteAlg(true);
m_alg->setPropertyValue(name, value);
copyPropertiesFrom(*m_alg);
}
/**
* Do something after a property was set
* @param name :: The name of the property
*/
void AlgorithmProxy::afterPropertySet(const std::string &name) {
createConcreteAlg(true);
m_alg->getPointerToProperty(name)->setValueFromProperty(
*this->getPointerToProperty(name));
m_alg->afterPropertySet(name);
copyPropertiesFrom(*m_alg);
}
/**
* Copy properties from another property manager
* Making sure that the concrete alg is kept in sync
* @param po :: The property manager to copy
*/
void AlgorithmProxy::copyPropertiesFrom(const PropertyManagerOwner &po) {
PropertyManagerOwner::copyPropertiesFrom(po);
createConcreteAlg(true);
m_alg->copyPropertiesFrom(*this);
}
//----------------------------------------------------------------------
// Private methods
//----------------------------------------------------------------------
/**
* Creates an unmanaged instance of the actual algorithm and sets its properties
* @param initOnly If true then the algorithm will only having its init step
* run, otherwise observers will also be added and rethrows will be true
*/
void AlgorithmProxy::createConcreteAlg(bool initOnly) {
if ((m_alg) && initOnly) {
// the cached algorithm exists and is not going to be executed,
// use that one
} else {
m_alg = boost::dynamic_pointer_cast<Algorithm>(
AlgorithmManager::Instance().createUnmanaged(name(), version()));
m_alg->initializeFromProxy(*this);
if (!initOnly) {
m_alg->setRethrows(this->m_rethrow);
addObservers();
}
}
}
/**
* Clean up when the real algorithm stops
*/
void AlgorithmProxy::stopped() {
if (m_setAlwaysStoreInADS)
dropWorkspaceReferences();
m_executionState = m_alg->executionState();
m_resultState = m_alg->resultState();
m_alg.reset();
}
/**
* Forces any workspace property to clear its internal workspace reference
*/
void AlgorithmProxy::dropWorkspaceReferences() {
const std::vector<Property *> &props = getProperties();
for (auto prop : props) {
if (auto *wsProp = dynamic_cast<IWorkspaceProperty *>(prop)) {
wsProp->clear();
}
}
}
/**
* Add observers stored previously in m_externalObservers
*/
void AlgorithmProxy::addObservers() {
if (!m_alg)
return;
for (auto o = m_externalObservers.rbegin(); o != m_externalObservers.rend();
++o)
m_alg->addObserver(**o);
m_externalObservers.clear();
}
/// setting the child start progress
void AlgorithmProxy::setChildStartProgress(const double startProgress) const {
m_alg->setChildStartProgress(startProgress);
}
/// setting the child end progress
void AlgorithmProxy::setChildEndProgress(const double endProgress) const {
m_alg->setChildEndProgress(endProgress);
}
/**
* Serialize this object to a string. Simple routes the call the algorithm
* @returns This object serialized as a string
*/
std::string AlgorithmProxy::toString() const {
const_cast<AlgorithmProxy *>(this)->createConcreteAlg(true);
return m_alg->toString();
}
/**
* Serialize this object to a Json::Value. Simple routes the call the algorithm
* @returns This object serialized as a Json::Value
*/
Json::Value AlgorithmProxy::toJson() const {