Commit bb4446dd authored by David Thompson's avatar David Thompson
Browse files

Add a class to simplify logging of operations.

This class watches a manager and records each Operator's
invocation and result. Subclasses override 2 methods on
it to log the result. The OperatorLog class may even be
subclassed by Python classes.
parent 5cfd0cda
......@@ -155,6 +155,7 @@ namespace smtk
{
class ExportJSON;
class ImportJSON;
class OperatorLog;
}
namespace common
......
......@@ -5,6 +5,7 @@ set(ioSrcs
ExportJSON.cxx
ImportJSON.cxx
Logger.cxx
OperatorLog.cxx
ResourceSetReader.cxx
ResourceSetWriter.cxx
XmlDocV1Parser.cxx
......@@ -18,6 +19,7 @@ set(ioHeaders
ExportJSON.h
ImportJSON.h
Logger.h
OperatorLog.h
ResourceSetReader.h
ResourceSetWriter.h
#XmlDocV1Parser.h
......
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "smtk/io/OperatorLog.h"
#include "smtk/model/Operator.h"
#include "smtk/attribute/IntItem.h"
using namespace smtk::model;
namespace smtk {
namespace io {
OperatorLog::OperatorLog(smtk::model::ManagerPtr mgr)
: m_hasFailures(false), m_manager(mgr)
{
mgr->observe(smtk::model::CREATED_OPERATOR, OperatorLog::operatorCreated, this);
}
OperatorLog::~OperatorLog()
{
smtk::model::ManagerPtr mgr = this->m_manager.lock();
if (mgr)
mgr->unobserve(smtk::model::CREATED_OPERATOR, OperatorLog::operatorCreated, this);
smtk::model::OperatorPtr watched;
WeakOpSet::iterator it;
for (it = this->m_watching.begin(); it != this->m_watching.end(); ++it)
{
if ((watched = it->lock()))
{
watched->unobserve(smtk::model::WILL_OPERATE, OperatorLog::operatorInvoked, this);
watched->unobserve(smtk::model::DID_OPERATE, OperatorLog::operatorReturned, this);
}
}
}
bool OperatorLog::hasFailures() const
{
return this->m_hasFailures;
}
void OperatorLog::resetFailures()
{
this->m_hasFailures = false;
}
int OperatorLog::operatorCreated(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
void* data)
{
OperatorLog* self = reinterpret_cast<OperatorLog*>(data);
if (!self)
return 0; // Don't stop an operation just because the recorder is unhappy.
OperatorPtr oper = smtk::const_pointer_cast<Operator>(op.shared_from_this());
self->m_watching.insert(oper);
oper->observe(smtk::model::WILL_OPERATE, OperatorLog::operatorInvoked, self);
oper->observe(smtk::model::DID_OPERATE, OperatorLog::operatorReturned, self);
return 0;
}
int OperatorLog::operatorInvoked(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
void* data)
{
OperatorLog* self = reinterpret_cast<OperatorLog*>(data);
if (!self)
return 0; // Don't stop an operation just because the recorder is unhappy.
return self->recordInvocation(event, op);
}
int OperatorLog::operatorReturned(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
smtk::model::OperatorResult r,
void* data)
{
OperatorLog* self = reinterpret_cast<OperatorLog*>(data);
if (!self)
return 0; // Don't stop an operation just because the recorder is unhappy.
self->m_hasFailures |=
(r->findInt("outcome")->value(0) == smtk::model::OPERATION_FAILED);
return self->recordResult(event, op, r);
}
} // namespace io
} // namespace smtk
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef __smtk_io_OperatorLog_h
#define __smtk_io_OperatorLog_h
/*! \file */
#include "smtk/CoreExports.h"
#include "smtk/SystemConfig.h"
#include "smtk/PublicPointerDefs.h"
#include "smtk/model/Events.h"
namespace smtk {
namespace io {
/**\brief Log operations run in a session for later adaptation or replay.
*
* This class captures all of the operator creation events
* for a given model manager and invokes pure virtual methods
* to log the events if they are deemed acceptable by a filter.
*/
class SMTKCORE_EXPORT OperatorLog
{
public:
OperatorLog(smtk::model::ManagerPtr mgr);
virtual ~OperatorLog();
bool hasFailures() const;
void resetFailures();
protected:
/**\brief Log the invocation of an operator.
*
* Subclasses must implement this method.
* Be aware that this method may not be called for
* all operators if a filter is in place.
*/
virtual int recordInvocation(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op) = 0;
/**\brief Log the result of an operator.
*
* Subclasses must implement this method.
* Be aware that this method may not be called for
* all operators if a filter is in place.
*/
virtual int recordResult(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
smtk::model::OperatorResult r) = 0;
static int operatorCreated(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
void* user);
static int operatorInvoked(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
void* user);
static int operatorReturned(
smtk::model::OperatorEventType event,
const smtk::model::Operator& op,
smtk::model::OperatorResult r,
void* user);
typedef std::set<smtk::model::WeakOperatorPtr, std::owner_less<smtk::model::WeakOperatorPtr> > WeakOpSet;
bool m_hasFailures;
smtk::model::WeakManagerPtr m_manager;
WeakOpSet m_watching;
};
} // namespace io
} // namespace smtk
#endif /* __smtk_io_OperatorLog_h */
......@@ -143,24 +143,33 @@ typedef std::pair<ManagerEventType,OneToManyObserver> OneToManyTrigger;
/**\brief Enumerate events that an operator may encounter.
*
* No event is provided for operator deletion because
* (1) operator deletion is not managed by the model Manager class and
* (2) "this" is not complete in class destructors (subclass data is
* already freed).
* So, there is no easy way to observe when an operator is about to be
* deleted but is still valid.
*/
enum OperatorEventType
{
CREATED_OPERATOR, //!< An instance of the Operator class has been created by a model Manager.
WILL_OPERATE, //!< The operation will commence if no observers cancel it.
DID_OPERATE //!< The operation has completed or been canceled.
};
/// Callbacks for WILL_OPERATE events provide access to the operator. Returning non-zero values cancel the operation.
typedef int (*WillOperateCallback)(
/// Callbacks for CREATED_OPERATOR and WILL_OPERATE events provide access to the operator. Returning non-zero values cancel the operation.
typedef int (*BareOperatorCallback)(
OperatorEventType event, const Operator& op, void* user);
/// An observer of WILL_OPERATE events binds a callback and opaque, user-provided data.
typedef std::pair<WillOperateCallback,void*> WillOperateObserver;
/// An observer of CREATED_OPERATOR or WILL_OPERATE events binds a callback and opaque, user-provided data.
typedef std::pair<BareOperatorCallback,void*> BareOperatorObserver;
/// A trigger for CREATED_OPERATOR or WILL_OPERATE events holds the event type and its observer.
typedef std::pair<OperatorEventType,BareOperatorObserver> BareOperatorTrigger;
/// Callbacks for DID_OPERATE events provide access to the operator and the results of the operation. Return values are ignored.
typedef int (*DidOperateCallback)(
typedef int (*OperatorWithResultCallback)(
OperatorEventType event, const Operator& op, OperatorResult r, void* user);
/// An observer of DID_OPERATE events binds a callback and opaque, user-provided data.
typedef std::pair<DidOperateCallback,void*> DidOperateObserver;
typedef std::pair<OperatorWithResultCallback,void*> OperatorWithResultObserver;
} // namespace model
} // namespace smtk
......
......@@ -3587,6 +3587,20 @@ void Manager::observe(ManagerEventType event, OneToManyCallback functionHandle,
OneToManyObserver(functionHandle, callData)));
}
/// Request notification from this manager instance when \a event occurs.
void Manager::observe(OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
if (event != CREATED_OPERATOR)
{
smtkWarningMacro(this->m_log,
"The model manager only allows observation of CREATED_OPERATOR, not " << event << ".");
return;
}
this->m_operatorTriggers.insert(
BareOperatorTrigger(event, BareOperatorObserver(functionHandle, callData)));
}
/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(ManagerEventType event, ConditionCallback functionHandle, void* callData)
{
......@@ -3650,6 +3664,14 @@ void Manager::unobserve(ManagerEventType event, OneToManyCallback functionHandle
OneToManyObserver(functionHandle, callData)));
}
/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
this->m_operatorTriggers.erase(
BareOperatorTrigger(event,
BareOperatorObserver(functionHandle, callData)));
}
/// Called by this Manager instance or EntityRef instances referencing it when \a event occurs.
void Manager::trigger(ManagerEventType event, const smtk::model::EntityRef& src)
{
......@@ -3694,6 +3716,17 @@ void Manager::trigger(ManagerEventType event, const smtk::model::EntityRef& src,
for (std::set<OneToManyTrigger>::const_iterator it = begin; it != end; ++it)
(*it->second.first)(it->first, src, related, it->second.second);
}
/// Called by this Manager instance or Session instances referencing it when \a event occurs.
void Manager::trigger(OperatorEventType event, const smtk::model::Operator& src)
{
std::set<BareOperatorTrigger>::const_iterator begin =
this->m_operatorTriggers.lower_bound(
BareOperatorTrigger(event,
BareOperatorObserver(BareOperatorCallback(), static_cast<void*>(NULL))));
for (std::set<BareOperatorTrigger>::const_iterator it = begin; it != this->m_operatorTriggers.end() && it->first == event; ++it)
(*it->second.first)(it->first, src, it->second.second);
}
//@}
} // namespace model
......
......@@ -371,12 +371,15 @@ public:
void observe(ManagerEventType event, ConditionCallback functionHandle, void* callData);
void observe(ManagerEventType event, OneToOneCallback functionHandle, void* callData);
void observe(ManagerEventType event, OneToManyCallback functionHandle, void* callData);
void observe(OperatorEventType event, BareOperatorCallback functionHandle, void* callData);
void unobserve(ManagerEventType event, ConditionCallback functionHandle, void* callData);
void unobserve(ManagerEventType event, OneToOneCallback functionHandle, void* callData);
void unobserve(ManagerEventType event, OneToManyCallback functionHandle, void* callData);
void unobserve(OperatorEventType event, BareOperatorCallback functionHandle, void* callData);
void trigger(ManagerEventType event, const smtk::model::EntityRef& src);
void trigger(ManagerEventType event, const smtk::model::EntityRef& src, const smtk::model::EntityRef& related);
void trigger(ManagerEventType event, const smtk::model::EntityRef& src, const smtk::model::EntityRefArray& related);
void trigger(OperatorEventType event, const smtk::model::Operator& src);
smtk::io::Logger& log() { return this->m_log; }
......@@ -415,6 +418,7 @@ protected:
std::set<ConditionTrigger> m_conditionTriggers;
std::set<OneToOneTrigger> m_oneToOneTriggers;
std::set<OneToManyTrigger> m_oneToManyTriggers;
std::set<BareOperatorTrigger> m_operatorTriggers;
smtk::io::Logger m_log;
};
......
......@@ -130,7 +130,7 @@ OperatorResult Operator::operate()
}
/// Add an observer of WILL_OPERATE events on this operator.
void Operator::observe(OperatorEventType event, WillOperateCallback functionHandle, void* callData)
void Operator::observe(OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
(void)event;
this->m_willOperateTriggers.insert(
......@@ -138,7 +138,7 @@ void Operator::observe(OperatorEventType event, WillOperateCallback functionHand
}
/// Add an observer of DID_OPERATE events on this operator.
void Operator::observe(OperatorEventType event, DidOperateCallback functionHandle, void* callData)
void Operator::observe(OperatorEventType event, OperatorWithResultCallback functionHandle, void* callData)
{
(void)event;
this->m_didOperateTriggers.insert(
......@@ -146,7 +146,7 @@ void Operator::observe(OperatorEventType event, DidOperateCallback functionHandl
}
/// Remove an existing WILL_OPERATE observer. The \a callData must match the value passed to Operator::observe().
void Operator::unobserve(OperatorEventType event, WillOperateCallback functionHandle, void* callData)
void Operator::unobserve(OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
(void)event;
this->m_willOperateTriggers.erase(
......@@ -154,7 +154,7 @@ void Operator::unobserve(OperatorEventType event, WillOperateCallback functionHa
}
/// Remove an existing DID_OPERATE observer. The \a callData must match the value passed to Operator::observe().
void Operator::unobserve(OperatorEventType event, DidOperateCallback functionHandle, void* callData)
void Operator::unobserve(OperatorEventType event, OperatorWithResultCallback functionHandle, void* callData)
{
(void)event;
this->m_didOperateTriggers.erase(
......@@ -172,7 +172,7 @@ void Operator::unobserve(OperatorEventType event, DidOperateCallback functionHan
int Operator::trigger(OperatorEventType event)
{
int status = 0;
std::set<WillOperateObserver>::const_iterator it;
std::set<BareOperatorObserver>::const_iterator it;
for (it = this->m_willOperateTriggers.begin(); it != this->m_willOperateTriggers.end(); ++it)
status |= (*it->first)(event, *this, it->second);
return status;
......@@ -181,7 +181,7 @@ int Operator::trigger(OperatorEventType event)
/// Invoke all DID_OPERATE observer callbacks. The return value is always 0 (this may change in future releases).
int Operator::trigger(OperatorEventType event, const OperatorResult& result)
{
std::set<DidOperateObserver>::const_iterator it;
std::set<OperatorWithResultObserver>::const_iterator it;
for (it = this->m_didOperateTriggers.begin(); it != this->m_didOperateTriggers.end(); ++it)
(*it->first)(event, *this, result, it->second);
return 0;
......
......@@ -151,11 +151,11 @@ public:
virtual OperatorResult operate();
#ifndef SHIBOKEN_SKIP
void observe(OperatorEventType event, WillOperateCallback functionHandle, void* callData);
void observe(OperatorEventType event, DidOperateCallback functionHandle, void* callData);
void observe(OperatorEventType event, BareOperatorCallback functionHandle, void* callData);
void observe(OperatorEventType event, OperatorWithResultCallback functionHandle, void* callData);
void unobserve(OperatorEventType event, WillOperateCallback functionHandle, void* callData);
void unobserve(OperatorEventType event, DidOperateCallback functionHandle, void* callData);
void unobserve(OperatorEventType event, BareOperatorCallback functionHandle, void* callData);
void unobserve(OperatorEventType event, OperatorWithResultCallback functionHandle, void* callData);
int trigger(OperatorEventType event);
int trigger(OperatorEventType event, const OperatorResult& result);
......@@ -244,8 +244,8 @@ protected:
ManagerPtr m_manager; // Model manager, not the attribute manager for the operator.
Session* m_session;
OperatorSpecification m_specification;
std::set<WillOperateObserver> m_willOperateTriggers;
std::set<DidOperateObserver> m_didOperateTriggers;
std::set<BareOperatorObserver> m_willOperateTriggers;
std::set<OperatorWithResultObserver> m_didOperateTriggers;
#endif // SHIBOKEN_SKIP
};
......
......@@ -171,6 +171,10 @@ OperatorPtr Session::op(const std::string& opName) const
if (remoteOp)
remoteOp->setName(opName);
// Notify observers that an operator was created.
if (this->m_manager)
this->m_manager->trigger(CREATED_OPERATOR, *oper.get());
return oper;
}
......
......@@ -137,6 +137,9 @@
<suppress-warning text="skipping field 'Manager::m_arrangements' with unmatched type 'smtk::shared_ptr&lt;UUIDsToArrangements&gt;'"/>
<suppress-warning text="skipping field 'UUIDGenerator::P' with unmatched type 'Internal'"/>
<suppress-warning text="skipping function 'smtk::model::Manager::assignDefaultNamesWithOwner', unmatched parameter type 'smtk::model::UUIDWithEntity const&amp;'"/>
<suppress-warning text="skipping field 'OperatorLog::m_watching' with unmatched type 'std::set&lt;smtk::model::WeakOperatorPtr,std::owner_less&lt;smtk::model::WeakOperatorPtr&gt;&gt;'"/>
<suppress-warning text="skipping field 'OperatorLog::m_manager' with unmatched type 'smtk::weak_ptr&lt;smtk::model::Manager&gt;'"/>
<!-- do not support input or output streams-->
<suppress-warning text="skipping function 'smtk::common::operator&lt;&lt;', unmatched return type 'std::ostream&amp;'"/>
......@@ -336,6 +339,7 @@
<suppress-warning text="skipping field 'Manager::m_conditionTriggers' with unmatched type 'std::set&lt;ConditionTrigger&gt;'"/>
<suppress-warning text="skipping field 'Manager::m_oneToOneTriggers' with unmatched type 'std::set&lt;OneToOneTrigger&gt;'"/>
<suppress-warning text="skipping field 'Manager::m_oneToManyTriggers' with unmatched type 'std::set&lt;OneToManyTrigger&gt;'"/>
<suppress-warning text="skipping field 'Manager::m_operatorTriggers' with unmatched type 'std::set&lt;BareOperatorTrigger&gt;'"/>
<suppress-warning text="skipping function 'smtk::model::Manager::unobserve', unmatched parameter type 'smtk::model::OneToOneCallback'"/>
<suppress-warning text="skipping field 'DescriptivePhrase::m_parent' with unmatched type 'smtk::weak_ptr&lt;smtk::model::DescriptivePhrase&gt;'"/>
<suppress-warning text="skipping function 'smtk::io::AttributeReader::readContents', unmatched parameter type 'pugi::xml_node&amp;'" />
......@@ -1961,6 +1965,10 @@
<enum-type name="Severity"/>
<object-type name="Record" />
</object-type>
<object-type name="OperatorLog">
<include file-name="smtk/io/OperatorLog.h" location="local"/>
</object-type>
</namespace-type>
<namespace-type name="simulation">
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment