Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,443 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* InfrastructureBuilder
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-11-29
|
||||
*/
|
||||
|
||||
#include "asset_assignment_manager.h"
|
||||
#include "exercise.h"
|
||||
#include "asset.h"
|
||||
#include "mounting_point.h"
|
||||
#include <InfrastructureManagement/ism.hpp>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <QtGlobal>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isAssigned(const InfrastructureManagement::InstrumentationAsset &asset)
|
||||
{
|
||||
return asset.availableInExercise().size() > 0;
|
||||
}
|
||||
|
||||
int assignedExercise(const InfrastructureManagement::InstrumentationAsset &asset)
|
||||
{
|
||||
Q_ASSERT(asset.availableInExercise().size() == 1);
|
||||
return asset.availableInExercise()[0];
|
||||
}
|
||||
|
||||
bool isMountingPoint(const InfrastructureManagement::StructureElement &structureElement)
|
||||
{
|
||||
return structureElement.structureElementTypeId() == InfrastructureManagement::StructureElementType::MountingPoint;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
AssetAssignmentManager *AssetAssignmentManager::create(InfrastructureManagement::Interface::Dtc *ismDtc)
|
||||
{
|
||||
Q_ASSERT(ismDtc);
|
||||
|
||||
AssetAssignmentManager *newAssetAssignmentManager = new AssetAssignmentManager;
|
||||
|
||||
connect(ismDtc, &InfrastructureManagement::Interface::Dtc::instrumentationAssetChanged, newAssetAssignmentManager, &AssetAssignmentManager::onAssetChanged);
|
||||
connect(ismDtc, &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged, newAssetAssignmentManager, &AssetAssignmentManager::onMainStructureElementChanged);
|
||||
connect(ismDtc, &InfrastructureManagement::Interface::Dtc::mountingPointAssetChanged, newAssetAssignmentManager, &AssetAssignmentManager::onMountingChanged);
|
||||
|
||||
// No need to query the DTC here as it is not yet activated.
|
||||
// But explicitly check that the DTC (i.e. the contained DataReader) is not enabled yet.
|
||||
Q_ASSERT(!ismDtc->isInstrumentationAssetEnabled());
|
||||
Q_ASSERT(!ismDtc->isMainStructureElementEnabled());
|
||||
Q_ASSERT(!ismDtc->isMountingPointAssetEnabled());
|
||||
|
||||
return newAssetAssignmentManager;
|
||||
}
|
||||
|
||||
AssetAssignmentManager::AssetAssignmentManager()
|
||||
: m_logger(getLogger("AssetAssignmentManager"))
|
||||
{
|
||||
// Create a "pool" exercise to hold all elements that are not assigned to any exercise.
|
||||
std::unique_ptr<Exercise> poolExercise(new Exercise(ExerciseContext::defaultContext()));
|
||||
m_exercises[ExerciseContext::defaultContext()] = std::move(poolExercise);
|
||||
}
|
||||
|
||||
AssetAssignmentManager::~AssetAssignmentManager() = default;
|
||||
|
||||
|
||||
void AssetAssignmentManager::onAssetChanged(const InfrastructureManagement::InstrumentationAsset &asset, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
return addAsset(asset);
|
||||
case DataModification::eModified:
|
||||
return modifyAsset(asset);
|
||||
case DataModification::eRemoved:
|
||||
return removeAsset(asset);
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType)
|
||||
{
|
||||
// Is the removal of MainStructureElements a valid UseCase or does that only happen when stopping the services?
|
||||
// For now, we simply ignore the removal.
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
if (modType == DataModification::eAdded)
|
||||
{
|
||||
for (const auto &structureElement: data.elements())
|
||||
{
|
||||
if (!isMountingPoint(structureElement))
|
||||
continue;
|
||||
std::unique_ptr<MountingPoint> newMountingPoint(new MountingPoint(structureElement));
|
||||
pool()->add(std::move(newMountingPoint));
|
||||
}
|
||||
|
||||
processPendingMounts();
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(modType == DataModification::eModified);
|
||||
|
||||
// What to do on modification?
|
||||
// What does a modification mean?
|
||||
// Are the contained StructureElements still the same as before?
|
||||
// For now we simply assume that the MountingPoints are still the same
|
||||
// and we just update them.
|
||||
for (const auto &structureElement: data.elements())
|
||||
{
|
||||
if (!isMountingPoint(structureElement))
|
||||
continue;
|
||||
MountingPoint *mountingPoint = findMountingPoint(structureElement.id()).second;
|
||||
Q_ASSERT(mountingPoint);
|
||||
if (mountingPoint)
|
||||
mountingPoint->update(structureElement);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::onMountingChanged(const InfrastructureManagement::MountingPointAsset &mount, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
return addMount(mount);
|
||||
case DataModification::eRemoved:
|
||||
return removeMount(mount);
|
||||
case DataModification::eModified:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::addAsset(const InfrastructureManagement::InstrumentationAsset &asset)
|
||||
{
|
||||
// Put the new Asset into the pool exercise.
|
||||
std::unique_ptr<Asset> newAsset(new Asset(asset));
|
||||
Asset *newAsset_ = newAsset.get();
|
||||
pool()->add(std::move(newAsset));
|
||||
|
||||
processPendingMounts();
|
||||
|
||||
if (isAssigned(asset))
|
||||
{
|
||||
Exercise *targetExercise = exercise(assignedExercise(asset));
|
||||
tryAssignAsset(newAsset_, pool(), targetExercise, boost::none);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The modification of an Asset possibly only affects the assignment.
|
||||
*/
|
||||
void AssetAssignmentManager::modifyAsset(const InfrastructureManagement::InstrumentationAsset &asset)
|
||||
{
|
||||
if (hasPendingModifications(asset.id()))
|
||||
return m_pendingModifications.push_back(asset);
|
||||
|
||||
auto found = findAsset(asset.id());
|
||||
Asset *foundAsset = found.second;
|
||||
Q_ASSERT(foundAsset);
|
||||
|
||||
Exercise *currentExercise = found.first;
|
||||
Exercise *targetExercise = isAssigned(asset) ? exercise(assignedExercise(asset)) : pool();
|
||||
|
||||
if (targetExercise == currentExercise)
|
||||
{
|
||||
foundAsset->update(asset);
|
||||
return; // no change in assignment
|
||||
}
|
||||
|
||||
if (targetExercise == pool())
|
||||
{
|
||||
// unassign
|
||||
unassignAsset(foundAsset, currentExercise, asset);
|
||||
processPendingUnmounts();
|
||||
return;
|
||||
}
|
||||
|
||||
// assign or reassign
|
||||
tryAssignAsset(foundAsset, currentExercise, targetExercise, asset);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Asset is assigned, it will be unassigned.
|
||||
* If it is not unmounted yet, defer the removal.
|
||||
* The pending removals will be processed after the Unmount.
|
||||
*/
|
||||
void AssetAssignmentManager::removeAsset(const InfrastructureManagement::InstrumentationAsset &asset)
|
||||
{
|
||||
auto assetAndExercise = findAsset(asset.id());
|
||||
Asset *foundAsset = assetAndExercise.second;
|
||||
Exercise *exercise = assetAndExercise.first;
|
||||
Q_ASSERT(foundAsset);
|
||||
|
||||
if (exercise != pool())
|
||||
{
|
||||
unassignAsset(foundAsset, exercise, boost::none);
|
||||
processPendingUnmounts();
|
||||
}
|
||||
|
||||
if (foundAsset->isMounted())
|
||||
{
|
||||
m_pendingRemoves.push_back(asset);
|
||||
return;
|
||||
}
|
||||
|
||||
pool()->take(foundAsset); // implicit delete
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to assign the Asset to an Exercise.
|
||||
* Assets can only be assigned if they are mounted.
|
||||
* If the Asset is not mounted yet (because the info was not yet published),
|
||||
* the assignment will be deferred. It will be processed after the mount.
|
||||
* The Asset and MountingPoint must still be in the pool Exercise.
|
||||
* @param modifiedData only set when called as a result of a modification
|
||||
*/
|
||||
void AssetAssignmentManager::tryAssignAsset(Asset *asset, Exercise *currentExercise, Exercise *targetExercise, const boost::optional<InfrastructureManagement::InstrumentationAsset> &modifiedData)
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
Q_ASSERT(currentExercise);
|
||||
Q_ASSERT(targetExercise);
|
||||
Q_ASSERT(isAssigned(modifiedData.get_value_or(asset->data())));
|
||||
|
||||
if (!asset->isMounted())
|
||||
{
|
||||
m_pendingModifications.push_back(modifiedData.get_value_or(asset->data()));
|
||||
return;
|
||||
}
|
||||
|
||||
currentExercise->moveMountedTo(asset, targetExercise, modifiedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param modifiedData only set when called as a result of a modification
|
||||
*/
|
||||
void AssetAssignmentManager::unassignAsset(Asset *asset, Exercise *exercise, const boost::optional<InfrastructureManagement::InstrumentationAsset> &modifiedData)
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
Q_ASSERT(exercise != pool());
|
||||
// Q_ASSERT(!isAssigned(asset->data())); // Assertion does not hold in case the unassignment is a result of a removal.
|
||||
exercise->moveMountedTo(asset, pool(), modifiedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to mount the Asset. If the mounting was published before the referenced
|
||||
* Asset or MountingPoint, the mounting will be deferred.
|
||||
*/
|
||||
void AssetAssignmentManager::addMount(const InfrastructureManagement::MountingPointAsset &mount)
|
||||
{
|
||||
Asset *asset = pool()->findAsset(mount.assetId());
|
||||
if (!asset)
|
||||
{
|
||||
m_pendingMounts.push_back(mount);
|
||||
return;
|
||||
}
|
||||
|
||||
MountingPoint *mountingPoint = pool()->findMountingPoint(mount.structureElementId());
|
||||
if (!mountingPoint)
|
||||
{
|
||||
m_pendingMounts.push_back(mount);
|
||||
return;
|
||||
}
|
||||
|
||||
asset->mount(mountingPoint);
|
||||
|
||||
processPendingModifications();
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::removeMount(const InfrastructureManagement::MountingPointAsset &mount)
|
||||
{
|
||||
auto exerciseAndAsset = findAsset(mount.assetId());
|
||||
Asset *asset = exerciseAndAsset.second;
|
||||
Exercise *exercise = exerciseAndAsset.first;
|
||||
Q_ASSERT(asset);
|
||||
if (!asset)
|
||||
return;
|
||||
tryUnmount(asset, exercise);
|
||||
processPendingRemoves();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to unmount the Asset.
|
||||
* Unmonting can only happen in the pool Exercise.
|
||||
* If the Asset is not yet in the pool Exercise (because the updated Asset
|
||||
* was not yet published), the unmount will be deferred.
|
||||
* It will be processed after the Asset was unassigned.
|
||||
*/
|
||||
void AssetAssignmentManager::tryUnmount(Asset *asset, Exercise *exercise)
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
|
||||
bool inPoolExercise = false;
|
||||
if (exercise)
|
||||
inPoolExercise = exercise == pool();
|
||||
else
|
||||
inPoolExercise = pool()->findAsset(asset->data().id());
|
||||
|
||||
if (!inPoolExercise)
|
||||
{
|
||||
m_pendingUnmounts.push_back(asset);
|
||||
return;
|
||||
}
|
||||
|
||||
asset->unmount();
|
||||
}
|
||||
|
||||
template<class Container, class Function>
|
||||
void AssetAssignmentManager::processPending(Container &pendingSource, Function f)
|
||||
{
|
||||
if (pendingSource.empty())
|
||||
return;
|
||||
|
||||
logPending();
|
||||
|
||||
Container pending;
|
||||
std::swap(pending, pendingSource);
|
||||
for (const auto &element: pending)
|
||||
f(element);
|
||||
|
||||
logPending();
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to make sure that assignments are always processed after the corresponding mount.
|
||||
* On DDS these are not always published in that order.
|
||||
* Thus we need to internally defer assignments that are published before the mount.
|
||||
*/
|
||||
void AssetAssignmentManager::processPendingModifications()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
processPending(m_pendingModifications, std::bind(&AssetAssignmentManager::modifyAsset, this, _1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as for processPendingAssigns() but this time we internally defer
|
||||
* unmounts that are published before the unassign.
|
||||
*/
|
||||
void AssetAssignmentManager::processPendingUnmounts()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
processPending(m_pendingUnmounts, std::bind(&AssetAssignmentManager::tryUnmount, this, _1, nullptr));
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::processPendingMounts()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
processPending(m_pendingMounts, std::bind(&AssetAssignmentManager::addMount, this, _1));
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::processPendingRemoves()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
processPending(m_pendingRemoves, std::bind(&AssetAssignmentManager::removeAsset, this, _1));
|
||||
}
|
||||
|
||||
bool AssetAssignmentManager::hasPendingModifications(int assetId)
|
||||
{
|
||||
auto idMatches = [assetId] (const InfrastructureManagement::InstrumentationAsset &asset) { return asset.id() == assetId; };
|
||||
auto found = std::find_if(m_pendingModifications.begin(), m_pendingModifications.end(), idMatches);
|
||||
return found != m_pendingModifications.end();
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::logPending()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "pending Mounts, Modifications (Asset), Unmounts, Removes: "
|
||||
<< m_pendingMounts.size() << ", "
|
||||
<< m_pendingModifications.size() << ", "
|
||||
<< m_pendingUnmounts.size() << ", "
|
||||
<< m_pendingRemoves.size();
|
||||
}
|
||||
|
||||
bool AssetAssignmentManager::hasPending() const
|
||||
{
|
||||
return !(m_pendingMounts.empty() && m_pendingModifications.empty() && m_pendingUnmounts.empty() && m_pendingRemoves.empty());
|
||||
}
|
||||
|
||||
Exercise *AssetAssignmentManager::pool() const
|
||||
{
|
||||
auto it = m_exercises.find(ExerciseContext::defaultContext());
|
||||
return (it == m_exercises.end() ? nullptr : it->second.get());
|
||||
}
|
||||
|
||||
Exercise *AssetAssignmentManager::exercise(int id)
|
||||
{
|
||||
ExerciseContext context(id);
|
||||
|
||||
auto found = m_exercises.find(context);
|
||||
if (found != m_exercises.end())
|
||||
return found->second.get();
|
||||
|
||||
std::unique_ptr<Exercise> newExercise(new Exercise(context));
|
||||
Exercise *newExercise_ = newExercise.get();
|
||||
m_exercises[context] = std::move(newExercise);
|
||||
return newExercise_;
|
||||
}
|
||||
|
||||
void AssetAssignmentManager::removeExercise(int id)
|
||||
{
|
||||
ExerciseContext context(id);
|
||||
|
||||
auto found = m_exercises.find(context);
|
||||
Q_ASSERT(found != m_exercises.end());
|
||||
if (found != m_exercises.end())
|
||||
m_exercises.erase(found); // implicit delete
|
||||
}
|
||||
|
||||
std::pair<Exercise *, Asset *> AssetAssignmentManager::findAsset(int id)
|
||||
{
|
||||
for (const auto &exercise: m_exercises)
|
||||
{
|
||||
Asset *asset = exercise.second->findAsset(id);
|
||||
if (asset)
|
||||
return {exercise.second.get(), asset};
|
||||
}
|
||||
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
std::pair<Exercise *, MountingPoint *> AssetAssignmentManager::findMountingPoint(int id)
|
||||
{
|
||||
for (const auto &exercise: m_exercises)
|
||||
{
|
||||
MountingPoint *mountingPoint = exercise.second->findMountingPoint(id);
|
||||
if (mountingPoint)
|
||||
return {exercise.second.get(), mountingPoint};
|
||||
}
|
||||
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
|
||||
Reference in new issue
Block a user