Commit 886c46e5 authored by Aron Helser's avatar Aron Helser
Browse files

Let Operation handle removing resources at the right time.

Add a `resourcesToExpunge` item to the `Result` attribute of operations,
and have the `Operation` base class remove resources from the
resource manager after operation observers have run, and before releasing
resource locks, to avoid conflicts. Rework the `RemoveResource`
operation to use this mechanism, and have `File .. Close Resource` use
this operation instead of closing resources directly.

Because `Operation` now accesses the resource manager, there is no need
for the `ResourceManagerOperation` sub-class, so alias it to `XMLOperation`.
parent e9323642
Remove Resources via Operation
------------------------------
The `Result` attribute of `Operation` now includes a `resourcesToExpunge`
item that tells the `Operation` base class to remove resources from the
resource manager after operation observers have run, and before releasing
resource locks, to avoid conflicts. The `RemoveResource`
operation now uses this mechanism, and `File .. Close Resource` uses
this operation instead of closing resources directly.
The `ResourceManagerOperation` sub-class is now redundant, so it is now
and alias of `XMLOperation`.
......@@ -35,8 +35,10 @@
#include "smtk/extension/paraview/server/vtkSMTKSettings.h"
#include "smtk/extension/qt/qtOperationView.h"
#include "smtk/extension/qt/qtUIManager.h"
#include "smtk/io/Logger.h"
#include "smtk/operation/Manager.h"
#include "smtk/operation/groups/CreatorGroup.h"
#include "smtk/operation/operators/RemoveResource.h"
#include "smtk/project/Manager.h"
#include "smtk/project/Project.h"
#include "smtk/resource/Manager.h"
......@@ -135,22 +137,32 @@ void pqCloseResourceReaction::closeResource()
if (ret != QMessageBox::Cancel)
{
// Remove it from its manager
if (smtk::resource::Manager::Ptr manager = resource->manager())
// Remove it from its manager. Use an operation to avoid observer conflicts.
pqServer* server = pqActiveObjects::instance().activeServer();
pqSMTKWrapper* wrapper = pqSMTKBehavior::instance()->resourceManagerForServer(server);
if (server && wrapper)
{
manager->remove(resource);
}
smtk::operation::RemoveResource::Ptr removeOp =
wrapper->smtkOperationManager()->create<smtk::operation::RemoveResource>();
// Remove project instance from project manager
auto project = std::dynamic_pointer_cast<smtk::project::Project>(resource);
if (project)
{
pqServer* server = pqActiveObjects::instance().activeServer();
pqSMTKWrapper* wrapper = pqSMTKBehavior::instance()->resourceManagerForServer(server);
auto projectManager = wrapper->smtkProjectManager();
projectManager->remove(project);
}
removeOp->parameters()->associate(resource);
smtk::operation::Operation::Result removeOpResult = removeOp->operate();
if (
removeOpResult->findInt("outcome")->value() !=
static_cast<int>(smtk::operation::Operation::Outcome::SUCCEEDED))
{
smtkWarningMacro(
smtk::io::Logger::instance(), "RemoveResource operation failed while closing a resource");
}
// Remove project instance from project manager
auto project = std::dynamic_pointer_cast<smtk::project::Project>(resource);
if (project)
{
auto projectManager = wrapper->smtkProjectManager();
projectManager->remove(project);
}
}
// Remove it from the active selection
{
smtk::view::Selection::SelectionMap& selections =
......
......@@ -6,7 +6,6 @@ set(operationSrcs
Metadata.cxx
Operation.cxx
Registrar.cxx
ResourceManagerOperation.cxx
SpecificationOps.cxx
XMLOperation.cxx
......
......@@ -18,10 +18,11 @@
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/io/AttributeReader.h"
#include "smtk/io/Logger.h"
#include "smtk/resource/Manager.h"
#include "smtk/operation/Operation_xml.h"
......@@ -238,6 +239,9 @@ Operation::Result Operation::operate()
manager->observers()(*this, EventType::DID_OPERATE, result);
}
// Un-manage any resources marked for removal before releasing locks.
this->unmanageResources(result);
// Unlock the resources.
for (auto& resourceAndLockType : resourcesAndLockTypes)
{
......@@ -380,6 +384,42 @@ void Operation::markModifiedResources(Operation::Result& result)
}
}
void Operation::unmanageResources(Operation::Result& result)
{
auto item = result->findResource("resourcesToExpunge");
// Access the resource manager (provided by the operation manager that created
// this operation, if any)
auto resourceManager = this->resourceManager();
if (!item || !resourceManager)
{
return;
}
for (std::size_t i = 0; i < item->numberOfValues(); i++)
{
// no need to look at items that cannot be resolved
if (item->value(i) == nullptr)
{
continue;
}
// ...access the associated resource.
smtk::resource::ResourcePtr resource =
std::dynamic_pointer_cast<smtk::resource::Resource>(item->value(i));
if (resource)
{
bool removed = resourceManager->remove(resource);
if (removed)
{
resourceManager->visit([&resource](smtk::resource::Resource& rsrc) {
rsrc.links().removeAllLinksTo(resource);
return smtk::common::Processing::CONTINUE;
});
}
}
}
}
void Operation::generateSummary(Operation::Result& result)
{
std::stringstream s;
......@@ -422,6 +462,23 @@ Operation::Specification Operation::createBaseSpecification() const
return spec;
}
smtk::resource::ManagerPtr Operation::resourceManager()
{
if (auto mgr = manager())
{
if (auto mgrs = mgr->managers())
{
if (mgrs->contains<smtk::resource::Manager::Ptr>())
{
return mgrs->get<smtk::resource::Manager::Ptr>();
}
}
}
return smtk::resource::ManagerPtr();
}
bool Operation::restoreTrace(const std::string& trace)
{
auto specification = this->specification();
......
......@@ -154,6 +154,9 @@ public:
/// Is this type of operation safe to launch in a thread?
virtual bool threadSafe() const { return true; }
/// retrieve the resource manager, if available.
smtk::resource::ManagerPtr resourceManager();
protected:
Operation();
......@@ -170,6 +173,9 @@ protected:
// resources referenced in the result are marked dirty.
virtual void markModifiedResources(Result&);
// Remove resources from the resource manager.
virtual void unmanageResources(Result&);
// Append an output summary string to the output result. Derived classes can
// reimplement this method to send custom summary strings to the logger.
virtual void generateSummary(Result&);
......
//=========================================================================
// 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/operation/ResourceManagerOperation.h"
#include "smtk/operation/Manager.h"
#include "smtk/resource/Manager.h"
namespace smtk
{
namespace operation
{
smtk::resource::ManagerPtr ResourceManagerOperation::resourceManager()
{
if (auto mgr = manager())
{
if (auto mgrs = mgr->managers())
{
if (mgrs->contains<smtk::resource::Manager::Ptr>())
{
return mgrs->get<smtk::resource::Manager::Ptr>();
}
}
}
return smtk::resource::ManagerPtr();
}
} // namespace operation
} // namespace smtk
......@@ -24,15 +24,8 @@ namespace operation
/// manager that has a resource manager registered to it will have the resource
/// manager assigned to them upon creation. Otherwise, the resource manager must
/// be set manually.
class SMTKCORE_EXPORT ResourceManagerOperation : public smtk::operation::XMLOperation
{
public:
smtkTypeMacro(ResourceManagerOperation);
smtkSharedFromThisMacro(smtk::operation::Operation);
smtkSuperclassMacro(smtk::operation::XMLOperation);
smtk::resource::ManagerPtr resourceManager();
};
/// Functionality has been absorbed by smtk::operation::Operation
using ResourceManagerOperation = smtk::operation::XMLOperation;
} // namespace operation
} // namespace smtk
......
......@@ -7,5 +7,6 @@
<Component Name="created" NumberOfRequiredValues="0" Extensible="1" HoldReference="1"/>
<Component Name="modified" NumberOfRequiredValues="0" Extensible="1" HoldReference="1"/>
<Component Name="expunged" NumberOfRequiredValues="0" Extensible="1" HoldReference="1"/>
<Resource Name="resourcesToExpunge" NumberOfRequiredValues="0" Extensible="1"/>
</ItemDefinitions>
</AttDef>
......@@ -15,6 +15,7 @@
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/io/Logger.h"
......@@ -58,34 +59,22 @@ RemoveResource::Result RemoveResource::operateInternal()
// Access the associated resources.
auto params = this->parameters();
auto resourceItem = this->parameters()->associations();
auto assoc = this->parameters()->associations();
// Construct a result object and access its resource item.
Result result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);
auto resourceItem = result->findResource("resourcesToExpunge");
// For each resource...
for (std::size_t i = 0; i < resourceItem->numberOfValues(); i++)
for (std::size_t i = 0; i < assoc->numberOfValues(); i++)
{
// ...access the resource...
auto resource = std::dynamic_pointer_cast<smtk::resource::Resource>(resourceItem->value(i));
auto resource = std::dynamic_pointer_cast<smtk::resource::Resource>(assoc->value(i));
// ...remove it from the manager...
bool removed = resourceManager->remove(resource);
if (removed)
// append to the to-be-expunged list. smtk::operation::Operation takes care of removal.
if (resource)
{
// ...and add it to the result.
// TODO: the "expunged" item in the result should accept resources.
resourceManager->visit([&resource](smtk::resource::Resource& rsrc) {
rsrc.links().removeAllLinksTo(resource);
return smtk::common::Processing::CONTINUE;
});
}
else
{
// If the resource was not removed, change the result status to failure.
result->findInt("outcome")->setValue(
static_cast<int>(smtk::operation::Operation::Outcome::FAILED));
resourceItem->appendValue(resource);
}
}
......
......@@ -28,6 +28,10 @@ public:
smtkSharedPtrCreateMacro(smtk::operation::Operation);
smtkSuperclassMacro(smtk::operation::ResourceManagerOperation);
/// Interaction with resource manager observers means this should
/// run on the main thread.
bool threadSafe() const override { return false; }
protected:
RemoveResource();
......
......@@ -27,7 +27,6 @@ using PySharedPtrClass = py::class_<T, std::shared_ptr<T>, Args...>;
#include "PybindManager.h"
#include "PybindMarkGeometry.h"
#include "PybindObserver.h"
#include "PybindResourceManagerOperation.h"
#include "PybindXMLOperation.h"
#include "PybindReadResource.h"
......@@ -61,7 +60,5 @@ PYBIND11_MODULE(_smtkPybindOperation, operation)
PySharedPtrClass< smtk::operation::SetProperty, smtk::operation::XMLOperation > smtk_operation_SetProperty = pybind11_init_smtk_operation_SetProperty(operation);
PySharedPtrClass< smtk::operation::WriteResource, smtk::operation::XMLOperation > smtk_operation_WriteResource = pybind11_init_smtk_operation_WriteResource(operation);
PySharedPtrClass< smtk::operation::ResourceManagerOperation, smtk::operation::XMLOperation > smtk_operation_ResourceManagerOperation = pybind11_init_smtk_operation_ResourceManagerOperation(operation);
py::class_< smtk::operation::Registrar > smtk_operation_Registrar = pybind11_init_smtk_operation_Registrar(operation);
}
//=========================================================================
// 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 pybind_smtk_operation_ResourceManagerOperation_h
#define pybind_smtk_operation_ResourceManagerOperation_h
#include <pybind11/pybind11.h>
#include "smtk/operation/ResourceManagerOperation.h"
#include "smtk/operation/XMLOperation.h"
namespace py = pybind11;
inline PySharedPtrClass< smtk::operation::ResourceManagerOperation, smtk::operation::XMLOperation > pybind11_init_smtk_operation_ResourceManagerOperation(py::module &m)
{
PySharedPtrClass< smtk::operation::ResourceManagerOperation, smtk::operation::XMLOperation > instance(m, "ResourceManagerOperation");
instance
.def("deepcopy", (smtk::operation::XMLOperation & (smtk::operation::XMLOperation::*)(::smtk::operation::XMLOperation const &)) &smtk::operation::XMLOperation::operator=)
.def("shared_from_this", (std::shared_ptr<const smtk::operation::XMLOperation> (smtk::operation::XMLOperation::*)() const) &smtk::operation::XMLOperation::shared_from_this)
.def("shared_from_this", (std::shared_ptr<smtk::operation::XMLOperation> (smtk::operation::XMLOperation::*)()) &smtk::operation::XMLOperation::shared_from_this)
.def("resourceManager", &smtk::operation::ResourceManagerOperation::resourceManager)
;
return instance;
}
#endif
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