Medical Imaging Interaction Toolkit  2018.4.99-b585543d
Medical Imaging Interaction Toolkit
mitkStandaloneDataStorage.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include "itkMutexLockHolder.h"
16 #include "itkSimpleFastMutexLock.h"
17 #include "mitkDataNode.h"
18 #include "mitkGroupTagProperty.h"
19 #include "mitkNodePredicateBase.h"
21 #include "mitkProperties.h"
22 
24 {
25 }
26 
28 {
29  for (auto it = m_SourceNodes.begin(); it != m_SourceNodes.end(); ++it)
30  {
31  this->RemoveListeners(it->first);
32  }
33 }
34 
36 {
37  return true;
38 }
39 
41 {
42  {
44  if (!IsInitialized())
45  throw std::logic_error("DataStorage not initialized");
46  /* check if node is in its own list of sources */
47  if ((parents != nullptr) && (std::find(parents->begin(), parents->end(), node) != parents->end()))
48  throw std::invalid_argument("Node is it's own parent");
49  /* check if node already exists in StandaloneDataStorage */
50  if (m_SourceNodes.find(node) != m_SourceNodes.end())
51  throw std::invalid_argument("Node is already in DataStorage");
52 
53  /* create parent list if it does not exist */
54  mitk::DataStorage::SetOfObjects::ConstPointer sp;
55  if (parents != nullptr)
56  sp = parents;
57  else
58  sp = mitk::DataStorage::SetOfObjects::New();
59  /* Store node and parent list in sources adjacency list */
60  m_SourceNodes.insert(std::make_pair(node, sp));
61 
62  /* Store node and an empty children list in derivations adjacency list */
63  mitk::DataStorage::SetOfObjects::Pointer childrenPointer = mitk::DataStorage::SetOfObjects::New();
64  mitk::DataStorage::SetOfObjects::ConstPointer children = childrenPointer.GetPointer();
65  m_DerivedNodes.insert(std::make_pair(node, children));
66 
67  /* create entry in derivations adjacency list for each parent of the new node */
68  for (SetOfObjects::ConstIterator it = sp->Begin(); it != sp->End(); it++)
69  {
70  mitk::DataNode::ConstPointer parent = it.Value().GetPointer();
71  mitk::DataStorage::SetOfObjects::ConstPointer derivedObjects =
72  m_DerivedNodes[parent]; // get or create pointer to list of derived objects for that parent node
73  if (derivedObjects.IsNull())
74  m_DerivedNodes[parent] =
75  mitk::DataStorage::SetOfObjects::New(); // Create a set of Objects, if it does not already exist
76  auto *deob = const_cast<mitk::DataStorage::SetOfObjects *>(
77  m_DerivedNodes[parent].GetPointer()); // temporarily get rid of const pointer to insert new element
78  deob->InsertElement(deob->Size(),
79  node); // node is derived from parent. Insert it into the parents list of derived objects
80  }
81 
82  // register for ITK changed events
83  this->AddListeners(node);
84  }
85 
86  /* Notify observers */
87  EmitAddNodeEvent(node);
88 }
89 
91 {
92  if (!IsInitialized())
93  throw std::logic_error("DataStorage not initialized");
94  if (node == nullptr)
95  return;
96 
97  // remove ITK modified event listener
98  this->RemoveListeners(node);
99 
100  // muellerm, 22.9.10: add additional reference count to ensure
101  // that the node is not deleted when removed from the relation map
102  // while m_Mutex is locked. This would cause the an itk::DeleteEvent
103  // is thrown and a deadlock will occur when event receivers
104  // access the DataStorage again in their event processing function
105  //
106  mitk::DataNode::ConstPointer nodeGuard(node);
107 
108  /* Notify observers of imminent node removal */
109  EmitRemoveNodeEvent(node);
110  {
112  /* remove node from both relation adjacency lists */
113  this->RemoveFromRelation(node, m_SourceNodes);
114  this->RemoveFromRelation(node, m_DerivedNodes);
115  }
116 }
117 
119 {
121  return (m_SourceNodes.find(node) != m_SourceNodes.end());
122 }
123 
125 {
126  for (auto mapIter = relation.cbegin(); mapIter != relation.cend();
127  ++mapIter) // for each node in the relation
128  if (mapIter->second.IsNotNull()) // if node has a relation list
129  {
130  SetOfObjects::Pointer s =
131  const_cast<SetOfObjects *>(mapIter->second.GetPointer()); // search for node to be deleted in the relation list
132  auto relationListIter = std::find(
133  s->begin(),
134  s->end(),
135  node); // this assumes, that the relation list does not contain duplicates (which should be safe to assume)
136  if (relationListIter != s->end()) // if node to be deleted is in relation list
137  s->erase(relationListIter); // remove it from parentlist
138  }
139  /* now remove node from the relation */
140  AdjacencyList::iterator adIt;
141  adIt = relation.find(node);
142  if (adIt != relation.end())
143  relation.erase(adIt);
144 }
145 
146 mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetAll() const
147 {
149  if (!IsInitialized())
150  throw std::logic_error("DataStorage not initialized");
151 
152  mitk::DataStorage::SetOfObjects::Pointer resultset = mitk::DataStorage::SetOfObjects::New();
153  /* Fill resultset with all objects that are managed by the StandaloneDataStorage object */
154  unsigned int index = 0;
155  for (auto it = m_SourceNodes.cbegin(); it != m_SourceNodes.cend(); ++it)
156  if (it->first.IsNull())
157  continue;
158  else
159  resultset->InsertElement(index++, const_cast<mitk::DataNode *>(it->first.GetPointer()));
160 
161  return SetOfObjects::ConstPointer(resultset);
162 }
163 
164 mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetRelations(
165  const mitk::DataNode *node,
166  const AdjacencyList &relation,
167  const NodePredicateBase *condition,
168  bool onlyDirectlyRelated) const
169 {
170  if (node == nullptr)
171  throw std::invalid_argument("invalid node");
172 
173  /* Either read direct relations directly from adjacency list */
174  if (onlyDirectlyRelated)
175  {
176  auto it = relation.find(node); // get parents of current node
177  if ((it == relation.cend()) || (it->second.IsNull())) // node not found in list or no set of parents
178  return SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New()); // return an empty set
179  else
180  return this->FilterSetOfObjects(it->second, condition);
181  }
182 
183  /* Or traverse adjacency list to collect all related nodes */
184  std::vector<mitk::DataNode::ConstPointer> resultset;
185  std::vector<mitk::DataNode::ConstPointer> openlist;
186 
187  /* Initialize openlist with node. this will add node to resultset,
188  but that is necessary to detect circular relations that would lead to endless recursion */
189  openlist.push_back(node);
190 
191  while (openlist.size() > 0)
192  {
193  mitk::DataNode::ConstPointer current = openlist.back(); // get element that needs to be processed
194  openlist.pop_back(); // remove last element, because it gets processed now
195  resultset.push_back(current); // add current element to resultset
196  auto it = relation.find(current); // get parents of current node
197  if ((it == relation.cend()) // if node not found in list
198  ||
199  (it->second.IsNull()) // or no set of parents available
200  ||
201  (it->second->Size() == 0)) // or empty set of parents
202  continue; // then continue with next node in open list
203  else
204  for (SetOfObjects::ConstIterator parentIt = it->second->Begin(); parentIt != it->second->End();
205  ++parentIt) // for each parent of current node
206  {
207  mitk::DataNode::ConstPointer p = parentIt.Value().GetPointer();
208  if (!(std::find(resultset.cbegin(), resultset.cend(), p) !=
209  resultset.end()) // if it is not already in resultset
210  &&
211  !(std::find(openlist.cbegin(), openlist.cend(), p) != openlist.cend())) // and not already in openlist
212  openlist.push_back(p); // then add it to openlist, so that it can be processed
213  }
214  }
215 
216  /* now finally copy the results to a proper SetOfObjects variable exluding the initial node and checking the condition
217  * if any is given */
218  mitk::DataStorage::SetOfObjects::Pointer realResultset = mitk::DataStorage::SetOfObjects::New();
219  if (condition != nullptr)
220  {
221  for (auto resultIt = resultset.cbegin();
222  resultIt != resultset.cend();
223  ++resultIt)
224  if ((*resultIt != node) && (condition->CheckNode(*resultIt) == true))
225  realResultset->InsertElement(realResultset->Size(),
226  mitk::DataNode::Pointer(const_cast<mitk::DataNode *>((*resultIt).GetPointer())));
227  }
228  else
229  {
230  for (auto resultIt = resultset.cbegin();
231  resultIt != resultset.cend();
232  ++resultIt)
233  if (*resultIt != node)
234  realResultset->InsertElement(realResultset->Size(),
235  mitk::DataNode::Pointer(const_cast<mitk::DataNode *>((*resultIt).GetPointer())));
236  }
237  return SetOfObjects::ConstPointer(realResultset);
238 }
239 
240 mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetSources(
241  const mitk::DataNode *node, const NodePredicateBase *condition, bool onlyDirectSources) const
242 {
244  return this->GetRelations(node, m_SourceNodes, condition, onlyDirectSources);
245 }
246 
247 mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetDerivations(
248  const mitk::DataNode *node, const NodePredicateBase *condition, bool onlyDirectDerivations) const
249 {
251  return this->GetRelations(node, m_DerivedNodes, condition, onlyDirectDerivations);
252 }
253 
254 void mitk::StandaloneDataStorage::PrintSelf(std::ostream &os, itk::Indent indent) const
255 {
256  os << indent << "StandaloneDataStorage:\n";
257  Superclass::PrintSelf(os, indent);
258 }
void RemoveListeners(const DataNode *_Node)
Removes a Modified-Listener from the given Node.
Data management class that handles &#39;was created by&#39; relations.
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Prints the contents of the StandaloneDataStorage to os. Do not call directly, call ->Print() instead...
SetOfObjects::ConstPointer GetSources(const mitk::DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectSources=true) const override
returns a set of source objects for a given node that meet the given condition(s).
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Prints the contents of the DataStorage to os. Do not call directly, call ->Print() instead...
DataCollection - Class to facilitate loading/accessing structured data.
SetOfObjects::ConstPointer FilterSetOfObjects(const SetOfObjects *set, const NodePredicateBase *condition) const
Filters a SetOfObjects by the condition. If no condition is provided, the original set is returned...
bool Exists(const mitk::DataNode *node) const override
Checks if a node exists in the StandaloneDataStorage.
void EmitAddNodeEvent(const DataNode *node)
EmitAddNodeEvent emits the AddNodeEvent.
AdjacencyList m_SourceNodes
Nodes and their relation are stored in m_SourceNodes.
bool IsInitialized() const
convenience method to check if the object has been initialized (i.e. a data tree has been set) ...
~StandaloneDataStorage() override
Standard Destructor.
virtual bool CheckNode(const mitk::DataNode *node) const =0
This method will be used to evaluate the node. Has to be overwritten in subclasses.
itk::SmartPointer< Self > Pointer
Definition: mitkDataNode.h:71
void EmitRemoveNodeEvent(const DataNode *node)
EmitRemoveNodeEvent emits the RemoveNodeEvent.
void AddListeners(const DataNode *_Node)
Adds a Modified-Listener to the given Node.
SetOfObjects::ConstPointer GetDerivations(const mitk::DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectDerivations=true) const override
returns a set of derived objects for a given node.
itk::SimpleFastMutexLock m_Mutex
void Add(mitk::DataNode *node, const mitk::DataStorage::SetOfObjects *parents=nullptr) override
Adds a DataNode containing a data object to its internal storage.
void Remove(const mitk::DataNode *node) override
Removes node from the StandaloneDataStorage.
itk::VectorContainer< unsigned int, DataNode::Pointer > SetOfObjects
A Container of objects that is used as a result set of GetSubset() query operations (Set of...
AdjacencyList m_DerivedNodes
Nodes are stored in reverse relation for easier traversal in the opposite direction of the relation...
SetOfObjects::ConstPointer GetAll() const override
returns a set of all data objects that are stored in the data storage
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
StandaloneDataStorage()
Standard Constructor for ::New() instantiation.
void RemoveFromRelation(const mitk::DataNode *node, AdjacencyList &relation)
deletes all references to a node in a given relation (used in Remove() and TreeListener) ...
SetOfObjects::ConstPointer GetRelations(const mitk::DataNode *node, const AdjacencyList &relation, const NodePredicateBase *condition=nullptr, bool onlyDirectlyRelated=true) const
Traverses the Relation graph and extracts a list of related elements (e.g. Sources or Derivations) ...
std::map< mitk::DataNode::ConstPointer, SetOfObjects::ConstPointer > AdjacencyList
noncyclical directed graph data structure to store the nodes with their relation
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57