Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.