2016-07-20 17:16:06 +02:00
# pragma once
# include <iostream>
# include <stdexcept>
// JSON-Schema includes
# include <utils/jsonschema/QJsonSchemaChecker.h>
# include <QFile>
# include <QString>
# include <QJsonObject>
# include <QJsonDocument>
# include <QRegularExpression>
class QJsonFactory
{
public :
static int load ( const QString & schema , const QString & config , QJsonObject & json )
{
// Load the schema and the config trees
2017-01-23 23:25:12 +01:00
QJsonObject schemaTree = readSchema ( schema ) ;
QJsonObject configTree = readConfig ( config ) ;
2016-07-20 17:16:06 +02:00
// create the validator
QJsonSchemaChecker schemaChecker ;
schemaChecker . setSchema ( schemaTree ) ;
2017-10-12 11:55:03 +02:00
2017-03-04 22:17:42 +01:00
QStringList messages = schemaChecker . getMessages ( ) ;
2017-07-30 13:32:10 +02:00
if ( ! schemaChecker . validate ( configTree ) . first )
2016-07-20 17:16:06 +02:00
{
2017-07-30 13:32:10 +02:00
for ( int i = 0 ; i < messages . size ( ) ; + + i )
std : : cout < < messages [ i ] . toStdString ( ) < < std : : endl ;
2016-07-20 17:16:06 +02:00
std : : cerr < < " Validation failed for configuration file: " < < config . toStdString ( ) < < std : : endl ;
return - 3 ;
}
json = configTree ;
return 0 ;
}
2017-10-12 11:55:03 +02:00
2017-01-23 23:25:12 +01:00
static QJsonObject readConfig ( const QString & path )
2016-07-20 17:16:06 +02:00
{
QFile file ( path ) ;
QJsonParseError error ;
2017-01-23 23:25:12 +01:00
2016-07-20 17:16:06 +02:00
if ( ! file . open ( QIODevice : : ReadOnly ) )
{
2017-03-04 22:17:42 +01:00
throw std : : runtime_error ( QString ( " Configuration file not found: ' " + path + " ' ( " + file . errorString ( ) + " ) " ) . toStdString ( ) ) ;
2016-07-20 17:16:06 +02:00
}
2017-07-30 13:32:10 +02:00
//Allow Comments in Config
2016-07-20 17:16:06 +02:00
QString config = QString ( file . readAll ( ) ) ;
config . remove ( QRegularExpression ( " ([^:]? \\ / \\ /.*) " ) ) ;
2017-10-12 11:55:03 +02:00
2016-07-20 17:16:06 +02:00
QJsonDocument doc = QJsonDocument : : fromJson ( config . toUtf8 ( ) , & error ) ;
2017-01-23 23:25:12 +01:00
file . close ( ) ;
2016-07-20 17:16:06 +02:00
if ( error . error ! = QJsonParseError : : NoError )
{
// report to the user the failure and their locations in the document.
int errorLine ( 0 ) , errorColumn ( 0 ) ;
2017-01-23 23:25:12 +01:00
2016-07-20 17:16:06 +02:00
for ( int i = 0 , count = qMin ( error . offset , config . size ( ) ) ; i < count ; + + i )
{
+ + errorColumn ;
if ( config . at ( i ) = = ' \n ' )
{
errorColumn = 0 ;
+ + errorLine ;
}
}
2017-01-23 23:25:12 +01:00
2017-03-04 22:17:42 +01:00
throw std : : runtime_error (
QString ( " Failed to parse configuration: " + error . errorString ( ) + " at Line: " + QString : : number ( errorLine ) + " , Column: " + QString : : number ( errorColumn ) ) . toStdString ( )
) ;
2016-07-20 17:16:06 +02:00
}
2017-01-23 23:25:12 +01:00
return doc . object ( ) ;
}
static QJsonObject readSchema ( const QString & path )
{
QFile schemaData ( path ) ;
QJsonParseError error ;
if ( ! schemaData . open ( QIODevice : : ReadOnly ) )
{
2017-03-04 22:17:42 +01:00
throw std : : runtime_error ( QString ( " Schema not found: ' " + path + " ' ( " + schemaData . errorString ( ) + " ) " ) . toStdString ( ) ) ;
2017-01-23 23:25:12 +01:00
}
QByteArray schema = schemaData . readAll ( ) ;
QJsonDocument doc = QJsonDocument : : fromJson ( schema , & error ) ;
schemaData . close ( ) ;
2017-10-12 11:55:03 +02:00
2017-01-23 23:25:12 +01:00
if ( error . error ! = QJsonParseError : : NoError )
{
// report to the user the failure and their locations in the document.
int errorLine ( 0 ) , errorColumn ( 0 ) ;
for ( int i = 0 , count = qMin ( error . offset , schema . size ( ) ) ; i < count ; + + i )
{
+ + errorColumn ;
if ( schema . at ( i ) = = ' \n ' )
{
errorColumn = 0 ;
+ + errorLine ;
}
}
2017-07-30 13:32:10 +02:00
throw std : : runtime_error ( QString ( " ERROR: Json schema wrong: " + error . errorString ( ) +
" at Line: " + QString : : number ( errorLine ) +
" , Column: " + QString : : number ( errorColumn ) ) . toStdString ( ) ) ;
2017-01-23 23:25:12 +01:00
}
2017-07-30 13:32:10 +02:00
return resolveReferences ( doc . object ( ) ) ;
2016-07-20 17:16:06 +02:00
}
2016-10-09 22:22:17 +02:00
2017-07-30 13:32:10 +02:00
static QJsonObject resolveReferences ( const QJsonObject & schema )
{
QJsonObject result ;
for ( QJsonObject : : const_iterator i = schema . begin ( ) ; i ! = schema . end ( ) ; + + i )
{
QString attribute = i . key ( ) ;
const QJsonValue & attributeValue = * i ;
if ( attribute = = " $ref " & & attributeValue . isString ( ) )
{
try
{
result = readSchema ( " :/ " + attributeValue . toString ( ) ) ;
}
catch ( std : : runtime_error & error )
{
throw std : : runtime_error ( error . what ( ) ) ;
}
}
else if ( attributeValue . isObject ( ) )
result . insert ( attribute , resolveReferences ( attributeValue . toObject ( ) ) ) ;
else
result . insert ( attribute , attributeValue ) ;
}
return result ;
}
static bool writeJson ( const QString & filename , QJsonObject & jsonTree )
2016-10-09 22:22:17 +02:00
{
QJsonDocument doc ;
2017-07-30 13:32:10 +02:00
2016-10-09 22:22:17 +02:00
doc . setObject ( jsonTree ) ;
QByteArray configData = doc . toJson ( QJsonDocument : : Indented ) ;
2017-07-30 13:32:10 +02:00
2016-10-09 22:22:17 +02:00
QFile configFile ( filename ) ;
2017-07-30 13:32:10 +02:00
if ( ! configFile . open ( QFile : : WriteOnly | QFile : : Truncate ) )
return false ;
2016-10-09 22:22:17 +02:00
configFile . write ( configData ) ;
2017-07-30 13:32:10 +02:00
QFile : : FileError error = configFile . error ( ) ;
if ( error ! = QFile : : NoError )
return false ;
2016-10-09 22:22:17 +02:00
configFile . close ( ) ;
2017-07-30 13:32:10 +02:00
return true ;
2016-10-09 22:22:17 +02:00
}
2016-07-20 17:16:06 +02:00
} ;