hyperion.ng
QJsonFactory.h
1 #pragma once
2 
3 #include <iostream>
4 #include <stdexcept>
5 
6 // JSON-Schema includes
7 #include <utils/jsonschema/QJsonSchemaChecker.h>
8 
9 #include <QFile>
10 #include <QString>
11 #include <QJsonObject>
12 #include <QJsonDocument>
13 #include <QRegularExpression>
14 
16 {
17 public:
18 
19  static int load(const QString& schema, const QString& config, QJsonObject& json)
20  {
21  // Load the schema and the config trees
22  QJsonObject schemaTree = readSchema(schema);
23  QJsonObject configTree = readConfig(config);
24 
25  // create the validator
26  QJsonSchemaChecker schemaChecker;
27  schemaChecker.setSchema(schemaTree);
28 
29  QStringList messages = schemaChecker.getMessages();
30 
31  if (!schemaChecker.validate(configTree).first)
32  {
33  for (int i = 0; i < messages.size(); ++i)
34  std::cout << messages[i].toStdString() << std::endl;
35 
36  std::cerr << "Validation failed for configuration file: " << config.toStdString() << std::endl;
37  return -3;
38  }
39 
40  json = configTree;
41  return 0;
42  }
43 
44  static QJsonObject readConfig(const QString& path)
45  {
46  QFile file(path);
47  QJsonParseError error;
48 
49  if (!file.open(QIODevice::ReadOnly))
50  {
51  throw std::runtime_error(QString("Configuration file not found: '" + path + "' (" + file.errorString() + ")").toStdString());
52  }
53 
54  //Allow Comments in Config
55  QString config = QString(file.readAll());
56  config.remove(QRegularExpression("([^:]?\\/\\/.*)"));
57 
58  QJsonDocument doc = QJsonDocument::fromJson(config.toUtf8(), &error);
59  file.close();
60 
61  if (error.error != QJsonParseError::NoError)
62  {
63  // report to the user the failure and their locations in the document.
64  int errorLine(0), errorColumn(0);
65 
66  for( int i=0, count=qMin( error.offset,config.size()); i<count; ++i )
67  {
68  ++errorColumn;
69  if(config.at(i) == '\n' )
70  {
71  errorColumn = 0;
72  ++errorLine;
73  }
74  }
75 
76  throw std::runtime_error (
77  QString("Failed to parse configuration: " + error.errorString() + " at Line: " + QString::number(errorLine) + ", Column: " + QString::number(errorColumn)).toStdString()
78  );
79  }
80 
81  return doc.object();
82  }
83 
84  static QJsonObject readSchema(const QString& path)
85  {
86  QFile schemaData(path);
87  QJsonParseError error;
88 
89  if (!schemaData.open(QIODevice::ReadOnly))
90  {
91  throw std::runtime_error(QString("Schema not found: '" + path + "' (" + schemaData.errorString() + ")").toStdString());
92  }
93 
94  QByteArray schema = schemaData.readAll();
95  QJsonDocument doc = QJsonDocument::fromJson(schema, &error);
96  schemaData.close();
97 
98  if (error.error != QJsonParseError::NoError)
99  {
100  // report to the user the failure and their locations in the document.
101  int errorLine(0), errorColumn(0);
102 
103  for( int i=0, count=qMin( error.offset,schema.size()); i<count; ++i )
104  {
105  ++errorColumn;
106  if(schema.at(i) == '\n' )
107  {
108  errorColumn = 0;
109  ++errorLine;
110  }
111  }
112 
113  throw std::runtime_error(QString("ERROR: Json schema wrong: " + error.errorString() +
114  " at Line: " + QString::number(errorLine) +
115  ", Column: " + QString::number(errorColumn)).toStdString());
116  }
117 
118  return resolveReferences(doc.object());
119  }
120 
121  static QJsonObject resolveReferences(const QJsonObject& schema)
122  {
123  QJsonObject result;
124 
125  for (QJsonObject::const_iterator i = schema.begin(); i != schema.end(); ++i)
126  {
127  QString attribute = i.key();
128  const QJsonValue & attributeValue = *i;
129 
130  if (attribute == "$ref" && attributeValue.isString())
131  {
132  try
133  {
134  result = readSchema(":/" + attributeValue.toString());
135  }
136  catch (std::runtime_error& error)
137  {
138  throw std::runtime_error(error.what());
139  }
140  }
141  else if (attributeValue.isObject())
142  result.insert(attribute, resolveReferences(attributeValue.toObject()));
143  else
144  result.insert(attribute, attributeValue);
145  }
146 
147  return result;
148  }
149 
150  static bool writeJson(const QString& filename, QJsonObject& jsonTree)
151  {
152  QJsonDocument doc;
153 
154  doc.setObject(jsonTree);
155  QByteArray configData = doc.toJson(QJsonDocument::Indented);
156 
157  QFile configFile(filename);
158  if (!configFile.open(QFile::WriteOnly | QFile::Truncate))
159  return false;
160 
161  configFile.write(configData);
162 
163  QFile::FileError error = configFile.error();
164  if (error != QFile::NoError)
165  return false;
166 
167  configFile.close();
168 
169  return true;
170  }
171 };
QPair< bool, bool > validate(const QJsonObject &value, bool ignoreRequired=false)
Validate a JSON structure.
Definition: QJsonSchemaChecker.cpp:29
const QStringList & getMessages() const
Definition: QJsonSchemaChecker.cpp:157
JsonSchemaChecker is a very basic implementation of json schema.
Definition: QJsonSchemaChecker.h:28
Definition: QJsonFactory.h:15
bool setSchema(const QJsonObject &schema)
Definition: QJsonSchemaChecker.cpp:20