fw4spl
VersionsManager.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2015.
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 #include "fwAtomsPatch/VersionsManager.hpp"
8 #include "fwAtomsPatch/exceptions/MissingInformation.hpp"
9 #include "fwAtomsPatch/exceptions/BadExtension.hpp"
10 #include "fwAtomsPatch/types.hpp"
11 
12 #include <fwCore/spyLog.hpp>
13 
14 #include <boost/filesystem.hpp>
15 #include <boost/property_tree/ptree.hpp>
16 #include <boost/property_tree/json_parser.hpp>
17 #include <boost/property_tree/exceptions.hpp>
18 
19 #include <camp/class.hpp>
20 
21 #include <fstream>
22 
23 namespace fwAtomsPatch
24 {
25 
26 std::string getValue(const ::boost::property_tree::ptree& node, const std::string& name,
27  const ::boost::filesystem::path& filePath )
28 {
29  std::string value;
30  try
31  {
32  value = node.get< std::string >(name);
33  }
34  catch( ::boost::property_tree::ptree_bad_path & )
35  {
37  name + " information are missing in '"+ filePath.string() +"'."));
38  }
39 
40  return value;
41 }
42 
43 SPTR(VersionsManager) VersionsManager::s_default = std::make_shared<VersionsManager>();
44 
45 // ----------------------------------------------------------------------------
46 
47 VersionsManager::VersionsManager()
48 {
49 }
50 
51 // ----------------------------------------------------------------------------
52 
53 VersionsManager::~VersionsManager()
54 {
55 }
56 
57 // ----------------------------------------------------------------------------
58 
59 void VersionsManager::buildVersionTable(const std::string& dirPath)
60 {
61  ::fwCore::mt::WriteLock lock(m_versionMutex);
62  for (::boost::filesystem::recursive_directory_iterator end, dir(dirPath); dir != end; ++dir)
63  {
64  if( !::boost::filesystem::is_directory(*dir)
65  && ::boost::filesystem::extension(*dir) == ".versions")
66  {
67  m_versionTable.push_back((*dir).path());
68  }
69  }
70 }
71 
72 // ----------------------------------------------------------------------------
73 
74 void VersionsManager::buildLinkTable(const std::string& dirPath)
75 {
76  ::fwCore::mt::WriteLock lock(m_linkMutex);
77  for ( ::boost::filesystem::recursive_directory_iterator end, dir(dirPath);
78  dir != end; ++dir )
79  {
80  if( !::boost::filesystem::is_directory(*dir)
81  && ::boost::filesystem::extension(*dir) == ".graphlink")
82  {
83  m_linkTable.push_back((*dir).path());
84  }
85  }
86 }
87 
88 // ----------------------------------------------------------------------------
89 
90 void VersionsManager::generateNewFile(const ::boost::filesystem::path& filePath,
91  const std::string& context, const std::string& versionName)
92 {
93  FW_RAISE_EXCEPTION_IF( ::fwAtomsPatch::exceptions::BadExtension(".versions file required"),
94  filePath.extension() != ".versions");
95 
96  namespace pt = ::boost::property_tree;
97  std::size_t classCount = ::camp::classCount();
98  pt::ptree root;
99 
100  root.put("context", context);
101  root.put("version_name", versionName);
102 
103  pt::ptree versions;
104  for (int i = 0; i < classCount; ++i)
105  {
106  const ::camp::Class& metaclass = ::camp::classByIndex(i);
107  const std::string& className = metaclass.name();
108 
109  if (metaclass.hasTag(::fwAtomsPatch::s_OBJ_VERSION))
110  {
111  const ::camp::Value& value = metaclass.tag(::fwAtomsPatch::s_OBJ_VERSION);
112  versions.put(className, value.to<std::string>());
113  }
114  }
115 
116  root.push_back( pt::ptree::value_type("versions", pt::ptree(versions)));
117  pt::json_parser::write_json(filePath.string(), root);
118 }
119 
120 // ----------------------------------------------------------------------------
121 
122 ::fwAtomsPatch::VersionDescriptor VersionsManager::getVersion(const ::boost::filesystem::path& filePath)
123 {
124  FW_RAISE_EXCEPTION_IF( ::fwAtomsPatch::exceptions::BadExtension(".versions file required"),
125  filePath.extension() != ".versions");
126 
127  namespace pt = ::boost::property_tree;
128  pt::ptree root;
129 
131 
132  std::ifstream file(filePath.string().c_str());
133  std::istream input(file.rdbuf());
134  pt::json_parser::read_json(input, root);
135  const std::string& context = getValue(root, "context", filePath);
136  const std::string& versionName = getValue(root, "version_name", filePath);
137 
138  for(pt::ptree::value_type &node : root.get_child("versions"))
139  {
140  versionids[node.first] = std::string(node.second.data().c_str());
141  }
142 
143  file.close();
144 
145  return ::fwAtomsPatch::VersionDescriptor(context, versionName, versionids);
146 }
147 
148 // ----------------------------------------------------------------------------
149 
150 ::fwAtomsPatch::LinkDescriptor VersionsManager::getLink(const ::boost::filesystem::path& filePath)
151 {
152  FW_RAISE_EXCEPTION_IF( ::fwAtomsPatch::exceptions::BadExtension(".graphlink file required"),
153  filePath.extension() != ".graphlink");
154 
155  namespace pt = ::boost::property_tree;
156  typedef std::vector< std::pair< std::string, std::string > > LinkType;
157 
158  LinkType link;
160  pt::ptree root;
161 
162  std::ifstream file(filePath.string().c_str());
163  std::istream input(file.rdbuf());
164  pt::json_parser::read_json(input, root);
165 
166  const std::string& context = getValue(root, "context", filePath);
167  const std::string& originVersion = getValue(root, "origin_version", filePath);
168  const std::string& targetVersion = getValue(root, "target_version", filePath);
169 
170  const std::string& patcher = root.get("patcher", "DefaultPatcher");
171 
172  for(pt::ptree::value_type &child : root.get_child("links"))
173  {
174  for(pt::ptree::value_type &node : (child.second).get_child(""))
175  {
176  link.push_back(std::make_pair(node.first, node.second.data()));
177  }
178 
179  FW_RAISE_EXCEPTION_IF(::fwAtomsPatch::exceptions::MissingInformation(
180  "A link should contain an origin version and a target version."), link.size() != 2);
181 
182  links[link[0]] = link[1];
183 
184  // Clear the vector
185  LinkType().swap(link);
186  }
187 
188  file.close();
189 
190  return ::fwAtomsPatch::LinkDescriptor(context, originVersion, targetVersion, patcher, links);
191 }
192 
193 // ----------------------------------------------------------------------------
194 
195 void VersionsManager::generateVersionsGraph()
196 {
197  {
198  ::fwCore::mt::ReadLock versionLock(m_versionMutex);
199  //For every versions
200  for(VersionsManager::ListPathType::value_type elt : m_versionTable)
201  {
202  ::fwAtomsPatch::VersionDescriptor version = VersionsManager::getVersion(elt);
203 
204  if(m_versionsGraphMap.find(version.getContext()) == m_versionsGraphMap.end())
205  {
206  m_versionsGraphMap[version.getContext()] = VersionsGraph::New();
207  }
208 
209  m_versionsGraphMap[version.getContext()]->addNode(version);
210  }
211  }
212 
213  {
214  ::fwCore::mt::ReadLock linkLock(m_linkMutex);
215  //For every links
216  for(VersionsManager::ListPathType::value_type elt : m_linkTable)
217  {
218  ::fwAtomsPatch::LinkDescriptor link = VersionsManager::getLink(elt);
219 
220  OSLM_ASSERT("There is no graph created for the context \"" << link.getContext() << "\".",
221  m_versionsGraphMap.find(link.getContext()) != m_versionsGraphMap.end());
222 
223  m_versionsGraphMap[link.getContext()]->addEdge(link);
224  }
225  }
226 }
227 
228 // ----------------------------------------------------------------------------
229 
230 VersionsGraph::sptr VersionsManager::getGraph(const std::string& context)
231 {
232  VersionsGraph::sptr vg;
233 
234  ::fwCore::mt::ReadToWriteLock lock(m_graphMutex);
235  if (m_versionsGraphMap.empty())
236  {
237  ::fwCore::mt::UpgradeToWriteLock writeLock(lock);
238  VersionsManager::generateVersionsGraph();
239  }
240 
241  VersionsGraphMapType::iterator elem = m_versionsGraphMap.find(context);
242  if (elem != m_versionsGraphMap.end())
243  {
244  vg = elem->second;
245  }
246 
247  return vg;
248 }
249 
250 } // namespace fwAtomsPatch
251 
#define SPTR(_cls_)
::boost::upgrade_lock< ReadWriteMutex > ReadToWriteLock
Defines an upgradable lock type for read/write mutex.
::boost::upgrade_to_unique_lock< ReadWriteMutex > UpgradeToWriteLock
Defines a write lock upgraded from ReadToWriteLock.
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
Reports an missing information required for data object patching.
STL namespace.
const std::string & getContext() const
Returns context name.
Version descriptor used to identify a version.
Contains base functionalities used to transform objects from a version to another.
Definition: Abstract.hpp:16
::boost::unique_lock< ReadWriteMutex > WriteLock
Defines a lock of write type for read/write mutex.
FWATOMSPATCH_API void buildLinkTable(const std::string &dirPath)
Builds link table.
Exception defining a wrong extension in a filename.
FWATOMSPATCH_API void buildVersionTable(const std::string &dirPath)
Builds version table.
std::map< std::string, std::string > VersionsType
VersionIDs used to link type and version.
FWATOMSPATCH_API VersionsGraph::sptr getGraph(const std::string &context)
Returns graph corresponding to given context.
Link descriptor used to identify a link between two versions.
::boost::shared_lock< ReadWriteMutex > ReadLock
Defines a lock of read type for read/write mutex.
const std::string & getContext() const
Returns context name.
std::map< VersionIDType, VersionIDType > LinksType
Links used to link two versions.
This file defines SpyLog macros. These macros are used to log messages to a file or to the console du...
static FWATOMSPATCH_API void generateNewFile(const ::boost::filesystem::path &filePath, const std::string &context, const std::string &versionName)
Generates a .versions file with currently known data versions.