fw4spl
DefaultPatcher.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2016.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 
8 #include "fwAtomsPatch/helper/functions.hpp"
9 #include "fwAtomsPatch/infos/log.hpp"
10 #include "fwAtomsPatch/IPatch.hpp"
11 #include "fwAtomsPatch/ISemanticPatch.hpp"
12 #include "fwAtomsPatch/IStructuralPatch.hpp"
13 #include "fwAtomsPatch/patcher/DefaultPatcher.hpp"
14 #include "fwAtomsPatch/patcher/registry/macros.hpp"
15 #include "fwAtomsPatch/SemanticPatchDB.hpp"
16 #include "fwAtomsPatch/StructuralPatchDB.hpp"
17 #include "fwAtomsPatch/types.hpp"
18 #include "fwAtomsPatch/VersionDescriptor.hpp"
19 #include "fwAtomsPatch/VersionsManager.hpp"
20 
21 #include <fwAtoms/Numeric.hpp>
22 #include <fwAtoms/Numeric.hxx>
23 
24 
25 namespace fwAtomsPatch
26 {
27 
28 namespace patcher
29 {
30 
31 patcherRegisterMacro(::fwAtomsPatch::patcher::DefaultPatcher, "DefaultPatcher");
32 
34 {
35 }
36 
37 //----------------------------------------------------------------------------
38 
40 {
41 }
42 
43 //----------------------------------------------------------------------------
44 
45 ::fwAtoms::Object::sptr DefaultPatcher::transformObject(::fwAtoms::Object::sptr object,
46  const std::string &context,
47  const std::string &currentVersion,
48  const std::string &targetVersion)
49 {
50  m_object = object;
51  m_context = context;
53  m_currentVersion = m_versionsGraph->getNode(currentVersion);
54  m_targetVersion = m_versionsGraph->getNode(targetVersion);
55 
56  fwAtomsPatchInfoLogMacro("Transform from version '"
57  + m_versionsGraph->getNode(m_currentVersion).getVersionName() + "' to '"
58  + m_versionsGraph->getNode(m_targetVersion).getVersionName() + "' in context '"
59  + m_context + "'");
60  fwAtomsPatchInfoLogMacro("Begin structural pass");
61 
62  // Structural
63  m_newVersions.clear();
64  m_cache.clear();
65  m_pass = Structural;
67  fwAtomsPatchInfoLogMacro("End structural pass");
68 
69  // Contextual
70  fwAtomsPatchInfoLogMacro("Begin contextual pass");
71  m_cache.clear();
72  m_pass = Contextual;
73  ::fwAtoms::Object::sptr obj = this->processContextualObject(m_object);
74  fwAtomsPatchInfoLogMacro("End contextual pass");
75 
76  return obj;
77 }
78 
79 
80 //----------------------------------------------------------------------------
81 
82 ::fwAtoms::Object::sptr DefaultPatcher::processStructuralObject(::fwAtoms::Object::sptr current)
83 {
84  CacheType::const_iterator cIt = m_cache.find(current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID ));
85 
86  // If the object has not been processed yet.
87  if(cIt == m_cache.end())
88  {
89  ::fwAtoms::Object::sptr newAtomObject = ::fwAtoms::Object::New();
90 
91  // Cache update
92  m_cache[current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID )] = newAtomObject;
93  m_newVersions[current] = newAtomObject;
94 
95  // Set id
96  newAtomObject->setMetaInfo( ::fwAtomsPatch::s_OBJ_ID,
97  current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID ));
98 
99  // Set meta Info
100  newAtomObject->setMetaInfos(current->getMetaInfos());
101 
102  // Fetch all attributes and affect them in the new object.
103  for( ::fwAtoms::Object::AttributesType::value_type elem : current->getAttributes() )
104  {
105  ::fwAtoms::Base::sptr obj = this->processBase(elem.second);
106  if(this->isKnown(obj))
107  {
108  newAtomObject->setAttribute(elem.first, obj);
109  }
110  }
111 
112  return this->applyStructuralPatch(current, newAtomObject);
113  }
114  // If the object has already been processed.
115  else
116  {
117  return cIt->second;
118  }
119 }
120 
121 //----------------------------------------------------------------------------
122 
123 ::fwAtoms::Object::sptr DefaultPatcher::processContextualObject(::fwAtoms::Object::sptr current)
124 {
125  CacheType::const_iterator cIt = m_cache.find(current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID ));
126 
127  // If the object has not been processed yet.
128  if(cIt == m_cache.end())
129  {
130  // Cache update
131  m_cache[current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID )] = m_newVersions[current];
132 
133  // Fetch all attributes and affect them in the new object.
134  for( ::fwAtoms::Object::AttributesType::value_type elem : current->getAttributes() )
135  {
136  if ( elem.second )
137  {
138  if(elem.second->isObject())
139  {
140  ::fwAtoms::Object::sptr obj = ::fwAtoms::Object::dynamicCast(elem.second);
141  m_newVersions[obj] = this->processContextualObject(obj);
142  }
143  else
144  {
145  this->processBase(elem.second);
146  }
147  }
148  }
149 
150  return this->applyContextualPatch(current, m_newVersions[current]);
151  }
152  // If the object has already been processed.
153  else
154  {
155  return m_cache[current->getMetaInfo( ::fwAtomsPatch::s_OBJ_ID )];
156  }
157 }
158 
159 // ----------------------------------------------------------------------------
160 
161 ::fwAtoms::Base::sptr DefaultPatcher::processBase(::fwAtoms::Base::sptr base)
162 {
163  ::fwAtoms::Base::sptr newBase;
164 
165  if ( !base )
166  {
167  return newBase;
168  }
169 
170  if(base->isObject())
171  {
172  ::fwAtoms::Object::sptr obj = ::fwAtoms::Object::dynamicCast(base);
173  if(m_pass == Structural)
174  {
175  newBase = this->processStructuralObject(obj);
176  }
177  else
178  {
179  newBase = this->processContextualObject(obj);
180  }
181  }
182  else if(base->isSequence())
183  {
184  ::fwAtoms::Sequence::sptr seq = ::fwAtoms::Sequence::dynamicCast(base);
185  newBase = this->processSequence(seq);
186  }
187  else if(base->isMapping())
188  {
189  ::fwAtoms::Map::sptr map = ::fwAtoms::Map::dynamicCast(base);
190  newBase = this->processMapping(map);
191  }
192  else if(base->isString())
193  {
194  newBase = ::fwAtoms::String::New(base->getString());
195  }
196  else if(base->isNumeric())
197  {
198  newBase = ::fwAtoms::Numeric::New(base->getString());
199  }
200  else if(base->isBoolean())
201  {
202  newBase = ::fwAtoms::Boolean::New(base->getString());
203  }
204  else if(base->isBlob())
205  {
206  ::fwAtoms::Blob::sptr blob = ::fwAtoms::Blob::dynamicCast(base);
207  newBase = ::fwAtoms::Blob::New(blob->getBufferObject());
208  }
209 
210 
211  return newBase;
212 }
213 
214 // ----------------------------------------------------------------------------
215 
216 ::fwAtoms::Map::sptr DefaultPatcher::processMapping(::fwAtoms::Map::sptr map)
217 {
218  ::fwAtoms::Map::sptr newMap = ::fwAtoms::Map::New();
219 
220  // Fetch all attributes and affect them in the new object
221  std::string key;
222  ::fwAtoms::Base::sptr value;
223 
224  for( ::fwAtoms::Map::MapType::value_type elem : map->getValue() )
225  {
226  key = elem.first;
227  value = elem.second;
228 
229  ::fwAtoms::Base::sptr obj = this->processBase(value);
230  if (this->isKnown(obj))
231  {
232  newMap->insert( key, obj);
233  }
234  }
235 
236  return newMap;
237 }
238 
239 //----------------------------------------------------------------------------
240 
241 ::fwAtoms::Sequence::sptr DefaultPatcher::processSequence(::fwAtoms::Sequence::sptr seq)
242 {
243  ::fwAtoms::Sequence::sptr newSeq = ::fwAtoms::Sequence::New();
244 
245  // Fetch all attributes and affect them in the new object
246  for( ::fwAtoms::Base::sptr elem : seq->getValue() )
247  {
248  ::fwAtoms::Base::sptr obj = this->processBase(elem);
249  if (this->isKnown(obj))
250  {
251  newSeq->push_back(obj);
252  }
253  }
254 
255  return newSeq;
256 }
257 
258 //----------------------------------------------------------------------------
259 
260 ::fwAtoms::Object::sptr DefaultPatcher::applyStructuralPatch(
261  ::fwAtoms::Object::sptr previous, ::fwAtoms::Object::sptr current)
262 {
263  if(previous)
264  {
265  // Get new version of the object.
267  bool success;
268  const std::string& classname = ::fwAtomsPatch::helper::getClassname(current);
269  const std::string& version = ::fwAtomsPatch::helper::getVersion(current);
270 
271  ::boost::tie(currentInfos,success) = m_versionsGraph->getLinkedVersion(
273  std::make_pair(classname, version) );
274 
275  if(success)
276  {
277  // Get patch
278  ::fwAtomsPatch::IStructuralPatch::sptr patch = ::fwAtomsPatch::StructuralPatchDB::getDefault()->getPatch(
279  classname, version, currentInfos.first, currentInfos.second);
280 
281  if(patch)
282  {
283  OSLM_TRACE("[SP] " << classname);
284  fwAtomsPatchInfoLogMacro("Apply structural patch to transform '" + classname
285  + "|" + version + "' to '"
286  + currentInfos.first + "|" + currentInfos.second + "'");
287  // Applying a patch on current (the current object is modified)
288  patch->apply(previous, current, m_newVersions);
289  fwAtomsPatchInfoLogMacro("End structural patch");
290  }
291  else
292  {
293  fwAtomsPatchInfoLogMacro("Move object '" + classname + "|" + version + "' to '"
294  + currentInfos.first + "|" + currentInfos.second + "'");
295  ::fwAtomsPatch::helper::setClassname(current, currentInfos.first);
296  ::fwAtomsPatch::helper::setVersion(current, currentInfos.second);
297  }
298  }
299  else
300  {
301  fwAtomsPatchErrorLogMacro("No linked version found for object '" + classname
302  + "' with version '" + version + "'");
303  }
304  }
305 
306  return current;
307 }
308 
309 //----------------------------------------------------------------------------
310 
311 ::fwAtoms::Object::sptr DefaultPatcher::applyContextualPatch(
312  ::fwAtoms::Object::sptr previous, ::fwAtoms::Object::sptr current)
313 {
314  if(previous)
315  {
316  const std::string currentName = m_versionsGraph->getNode(m_currentVersion).getVersionName();
317  const std::string targetName = m_versionsGraph->getNode(m_targetVersion).getVersionName();
318 
319  // Get patch
320  ::fwAtomsPatch::SemanticPatchDB::sptr contextDB = ::fwAtomsPatch::SemanticPatchDB::getDefault();
321  ::fwAtomsPatch::ISemanticPatch::sptr patch =
322  contextDB->getPatch(m_context, currentName, targetName,
325 
326  if(patch)
327  {
328  OSLM_TRACE("[CP] " << ::fwAtomsPatch::helper::getClassname(current));
329  fwAtomsPatchInfoLogMacro("Apply contextual patch to transform '"
331  + "|" + ::fwAtomsPatch::helper::getVersion(previous) + "' to '"
333  + "|" + ::fwAtomsPatch::helper::getVersion(current) + "'");
334 
335  // Applying a patch on current (the current object is modified)
336  patch->apply(previous, current, m_newVersions);
337  fwAtomsPatchInfoLogMacro("End contextual patch");
338  }
339  }
340 
341  return current;
342 }
343 
344 // ----------------------------------------------------------------------------
345 
346 bool DefaultPatcher::isKnown(const ::fwAtoms::Base::sptr& base)
347 {
348  bool isKnown = false;
350  VersionDescriptor::VersionsType versions = target.getVersions();
351  ::fwAtoms::Object::sptr obj = ::fwAtoms::Object::dynamicCast(base);
352 
353  if (!obj)
354  {
355  isKnown = true;
356  }
357  else
358  {
359  std::string classname = obj->getMetaInfo(::fwAtomsPatch::s_OBJ_CLASSNAME);
360 
361  if (classname.empty() || versions.find(classname) != versions.end())
362  {
363  isKnown = true;
364  }
365  }
366  return isKnown;
367 }
368 
369 // ----------------------------------------------------------------------------
370 
371 } // namespace patcher
372 
373 } // namespace fwAtomsPatch
374 
FWATOMSPATCH_API DefaultPatcher(::fwAtomsPatch::patcher::IPatcher::Key key)
Constructor.
virtual FWATOMSPATCH_API::fwAtoms::Base::sptr processBase(::fwAtoms::Base::sptr base)
Process atom base.
::fwAtomsPatch::VersionsGraph::sptr m_versionsGraph
Versions graph.
FWATOMSPATCH_API std::string getClassname(const ::fwAtoms::Object::sptr &obj)
Get classname of an object.
virtual FWATOMSPATCH_API::fwAtoms::Object::sptr applyContextualPatch(::fwAtoms::Object::sptr previous,::fwAtoms::Object::sptr current)
Apply contextual patch.
virtual FWATOMSPATCH_API::fwAtoms::Object::sptr processContextualObject(::fwAtoms::Object::sptr current)
Process contextual atom object.
const VersionsType & getVersions() const
Returns versions.
static FWATOMS_API String::sptr New(std::string value)
Construct a new Object represented a string.
NewVersionsType m_newVersions
Map used to store the correspondence between an old object and a new one.
Version descriptor used to identify a version.
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
Contains base functionalities used to transform objects from a version to another.
Definition: Abstract.hpp:16
::fwAtomsPatch::VersionsGraph::NodeIDType m_currentVersion
Current object version.
virtual FWATOMSPATCH_API::fwAtoms::Map::sptr processMapping(::fwAtoms::Map::sptr map)
Process atom mapping.
std::string m_context
Context where the object is patched.
::fwAtomsPatch::VersionsGraph::NodeIDType m_targetVersion
Target version for current object.
FWATOMSPATCH_API bool isKnown(const ::fwAtoms::Base::sptr &base)
Return true if the object is known in the target version.
::fwAtomsPatch::StructuralPatchDB::sptr getDefault()
Returns default instance.
PassType m_pass
Current type of pass during patching.
virtual FWATOMSPATCH_API ~DefaultPatcher()
Destructor.
std::map< std::string, std::string > VersionsType
VersionIDs used to link type and version.
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
static Numeric::sptr New(T value)
Build a new numeric type.
Definition: Numeric.hxx:77
virtual FWATOMSPATCH_API::fwAtoms::Object::sptr processStructuralObject(::fwAtoms::Object::sptr current)
Process structural atom object.
static const std::string & classname()
return object&#39;s classname without its namespace, i.e. BaseObject
static std::shared_ptr< VersionsManager > getDefault()
Returns the default instance of VersionsManager.
virtual FWATOMSPATCH_API::fwAtoms::Object::sptr applyStructuralPatch(::fwAtoms::Object::sptr previous,::fwAtoms::Object::sptr current)
Apply structural patch.
virtual FWATOMSPATCH_API::fwAtoms::Object::sptr transformObject(::fwAtoms::Object::sptr object, const std::string &context, const std::string &currentVersion, const std::string &targetVersion) override
Apply the patch to the specified object.
std::pair< std::string, std::string > VersionIDType
VersionID used to link type and version.
CacheType m_cache
Cache used to store objects which have already been patched (in order to avoid patching the same obje...
virtual FWATOMSPATCH_API::fwAtoms::Sequence::sptr processSequence(::fwAtoms::Sequence::sptr seq)
Process atom sequence.
FWATOMSPATCH_API std::string getVersion(const ::fwAtoms::Object::sptr &obj)
Get version of an object.
::fwAtoms::Object::sptr m_object
Current object being patched.
static FWATOMS_API Boolean::sptr New(std::string value)
Construct an object storing a bool value.
static FWATOMSPATCH_API SemanticPatchDB::sptr getDefault()
Return default instance of SemanticPatchDB.
static FWATOMS_API Blob::sptr New(::fwMemory::BufferObject::sptr buffer)
create a new Blob shared ptr.
Definition: Blob.cpp:17