Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkPropertyListSerializer.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
19 
20 #include <tinyxml.h>
21 
23 #include <itksys/SystemTools.hxx>
24 
25 mitk::PropertyListSerializer::PropertyListSerializer() : m_FilenameHint("unnamed"), m_WorkingDirectory("")
26 {
27 }
28 
30 {
31 }
32 
34 {
35  m_FailedProperties = PropertyList::New();
36 
37  if (m_PropertyList.IsNull() || m_PropertyList->IsEmpty())
38  {
39  MITK_ERROR << "Not serializing NULL or empty PropertyList";
40  return "";
41  }
42 
43  // tmpname
44  static unsigned long count = 1;
45  unsigned long n = count++;
46  std::ostringstream name;
47  for (int i = 0; i < 6; ++i)
48  {
49  name << char('a' + (n % 26));
50  n /= 26;
51  }
52  std::string filename;
53  filename.append(name.str());
54 
55  std::string fullname(m_WorkingDirectory);
56  fullname += "/";
57  fullname += filename;
58  fullname = itksys::SystemTools::ConvertToOutputPath(fullname.c_str());
59 
60  // Trim quotes
61  std::string::size_type length = fullname.length();
62 
63  if (length >= 2 && fullname[0] == '"' && fullname[length - 1] == '"')
64  fullname = fullname.substr(1, length - 2);
65 
66  TiXmlDocument document;
67  auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
68  document.LinkEndChild(decl);
69 
70  auto version = new TiXmlElement("Version");
71  version->SetAttribute("Writer", __FILE__);
72  version->SetAttribute("Revision", "$Revision: 17055 $");
73  version->SetAttribute("FileVersion", 1);
74  document.LinkEndChild(version);
75 
76  // add XML contents
77  const PropertyList::PropertyMap *propmap = m_PropertyList->GetMap();
78  for (auto iter = propmap->begin(); iter != propmap->end(); ++iter)
79  {
80  std::string key = iter->first;
81  const BaseProperty *property = iter->second;
82  TiXmlElement *element = SerializeOneProperty(key, property);
83  if (element)
84  {
85  document.LinkEndChild(element);
86  // TODO test serializer for error
87  }
88  else
89  {
90  m_FailedProperties->ReplaceProperty(key, const_cast<BaseProperty *>(property));
91  }
92  }
93 
94  // save XML file
95  if (!document.SaveFile(fullname))
96  {
97  MITK_ERROR << "Could not write PropertyList to " << fullname << "\nTinyXML reports '" << document.ErrorDesc()
98  << "'";
99  return "";
100  }
101 
102  return filename;
103 }
104 
105 TiXmlElement *mitk::PropertyListSerializer::SerializeOneProperty(const std::string &key, const BaseProperty *property)
106 {
107  auto keyelement = new TiXmlElement("property");
108  keyelement->SetAttribute("key", key);
109  keyelement->SetAttribute("type", property->GetNameOfClass());
110 
111  // construct name of serializer class
112  std::string serializername(property->GetNameOfClass());
113  serializername += "Serializer";
114 
115  std::list<itk::LightObject::Pointer> allSerializers =
116  itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str());
117  if (allSerializers.size() < 1)
118  {
119  MITK_ERROR << "No serializer found for " << property->GetNameOfClass() << ". Skipping object";
120  }
121  if (allSerializers.size() > 1)
122  {
123  MITK_WARN << "Multiple serializers found for " << property->GetNameOfClass() << "Using arbitrarily the first one.";
124  }
125 
126  for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter)
127  {
128  if (BasePropertySerializer *serializer = dynamic_cast<BasePropertySerializer *>(iter->GetPointer()))
129  {
130  serializer->SetProperty(property);
131  try
132  {
133  TiXmlElement *valueelement = serializer->Serialize();
134  if (valueelement)
135  {
136  keyelement->LinkEndChild(valueelement);
137  }
138  }
139  catch (std::exception &e)
140  {
141  MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
142  // \TODO: log only if all potential serializers fail?
143  }
144  break;
145  }
146  else
147  {
148  MITK_ERROR << "Found a serializer called '" << (*iter)->GetNameOfClass()
149  << "' that does not implement the BasePropertySerializer interface.";
150  continue;
151  }
152  }
153 
154  if (keyelement->NoChildren())
155  {
156  m_FailedProperties->ReplaceProperty(key, const_cast<BaseProperty *>(property));
157  return nullptr;
158  }
159  else
160  {
161  return keyelement;
162  }
163 }
164 
166 {
167  if (m_FailedProperties.IsNotNull() && !m_FailedProperties->IsEmpty())
168  {
169  return m_FailedProperties;
170  }
171  else
172  {
173  return nullptr;
174  }
175 }
static Pointer New()
virtual std::string Serialize()
Serializes given PropertyList object.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
Key-value list holding instances of BaseProperty.
Abstract base class for properties.
#define MITK_WARN
Definition: mitkLogMacros.h:23
std::map< std::string, BaseProperty::Pointer > PropertyMap
static const std::string filename
TiXmlElement * SerializeOneProperty(const std::string &key, const BaseProperty *property)
Base class for objects that serialize BaseProperty types.