#pragma once #include <source_location> #include "AbstractElement.h" #include "Array.h" #include "JSON.h" #include "Trie.h" #include "XML.h" namespace Framework { namespace Validator { class ValidationResult : public Framework::ReferenceCounter { public: __declspec(dllexport) ValidationResult(); __declspec(dllexport) virtual ~ValidationResult(); virtual bool isValid() const = 0; __declspec(dllexport) void logInvalidInfo( std::source_location location = std::source_location::current()) const; virtual Text getInvalidInfo(int indent = 0) const = 0; virtual JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) = 0; virtual Text getPath() const = 0; virtual void addBasePath(Text basePath) = 0; virtual bool isDifferent(const ValidationResult* zResult) const = 0; }; class TypeMissmatch : public ValidationResult { private: Text path; AbstractElement* foundValue; XML::Element* expected; ValidationResult* reason; public: __declspec(dllexport) TypeMissmatch(Text path, AbstractElement* foundValue, XML::Element* expected, ValidationResult* reason); __declspec(dllexport) ~TypeMissmatch(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; protected: __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class UnknownValue : public ValidationResult { private: Text path; AbstractElement* foundValue; public: __declspec(dllexport) UnknownValue( Text path, AbstractElement* foundValue); __declspec(dllexport) ~UnknownValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class MissingValue : public ValidationResult { private: Text path; XML::Element* expected; public: __declspec(dllexport) MissingValue( Text path, XML::Element* expected); __declspec(dllexport) ~MissingValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class MissingOneOf : public ValidationResult { private: Text path; RCArray<XML::Element> expected; public: __declspec(dllexport) MissingOneOf(Text path, XML::Editor expected); __declspec(dllexport) ~MissingOneOf(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class NoTypeMatching : public ValidationResult { private: Text path; AbstractElement* foundValue; RCArray<XML::Element> expected; RCArray<ValidationResult> reasons; public: __declspec(dllexport) NoTypeMatching(Text path, AbstractElement* foundValue, RCArray<XML::Element>& expected, RCArray<ValidationResult>& reasons); __declspec(dllexport) ~NoTypeMatching(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class ValidationPathNotFound : public ValidationResult { private: Text path; AbstractElement* foundValue; Text validationPath; public: __declspec(dllexport) ValidationPathNotFound( Text path, AbstractElement* foundValue, Text validationPath); __declspec(dllexport) ~ValidationPathNotFound(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class ValidValue : public ValidationResult { private: Text path; AbstractElement* value; public: __declspec(dllexport) ValidValue(Text path, AbstractElement* value); __declspec(dllexport) ~ValidValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray<ValidationResult>* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const ValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; template<typename T> class StringValidationBuilder; template<typename T> class NumberValidationBuilder; template<typename T> class BoolValidationBuilder; template<typename T> class ObjectValidationBuilder; template<typename T> class ArrayValidationBuilder; template<typename T> class OneOfValidationBuilder; class DataValidator : public Framework::ReferenceCounter { private: XML::Element* constraints; RCTrie<XML::Element>* typeConstraints; public: __declspec(dllexport) DataValidator(XML::Element* constraints); __declspec(dllexport) DataValidator(XML::Element* constraints, RCTrie<XML::Element>* typeConstraints); __declspec(dllexport) ~DataValidator(); __declspec(dllexport) ValidationResult* validate( AbstractElement* zValue) const; __declspec(dllexport) ValidationResult* validate( ElementPath* path, AbstractElement* zValue) const; __declspec(dllexport) bool isValid(AbstractElement* zValue) const; /** * returns the valid part of the json by performing the * following operations in the specified order untill no further * changes are made: * - invalid or unknown object properties are removed * - missing object properties with default values are added if * missing * - invalid array elements are removed * * @param zValue the json value to to extract the valid part * without increased reference counter * @return the valid part or 0 if no valid part exists */ __declspec(dllexport) JSON::JSONValue* getValidParts( JSON::JSONValue* zValue, RCArray<ValidationResult>* zRemovedPartsValidationResults) const; __declspec(dllexport) XML::Element* zConstraints(); /** * returns the json schema for the constraints */ __declspec(dllexport) JSON::JSONObject* getJsonSchema() const; /** * updates the validator for the datatype with a specified reference * id. * * \param id the reference id of the datatype * \param validator the validator that will validate a type with the * given reference id */ __declspec(dllexport) void updateValidator( Text id, DataValidator* validator); private: __declspec(dllexport) ValidationResult* validate( ElementPath* pathToValidate, AbstractElement* zValue, XML::Element* zConstraints, Text path) const; __declspec(dllexport) ValidationResult* validateMultipleTypes( ElementPath* pathToValidate, AbstractElement* zChildValue, XML::Element* zPossibleChildConstraints, Text childPath) const; __declspec(dllexport) JSON::JSONObject* getJsonSchema( XML::Element* zConstraint, JSON::JSONObject* zDefs) const; public: __declspec(dllexport) static StringValidationBuilder<DataValidator>* buildForString(); __declspec(dllexport) static NumberValidationBuilder<DataValidator>* buildForNumber(); __declspec(dllexport) static BoolValidationBuilder<DataValidator>* buildForBool(); __declspec(dllexport) static ObjectValidationBuilder<DataValidator>* buildForObject(); __declspec(dllexport) static ArrayValidationBuilder<DataValidator>* buildForArray(); __declspec(dllexport) static OneOfValidationBuilder<DataValidator>* buildForOneOf(); __declspec(dllexport) static DataValidator* buildForReference( Text id); }; template<typename T> class StringValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: StringValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<string/>"), builder(builder) {} StringValidationBuilder<T>* setReferenceId(Text id) { element.setAttribute("id", id); return this; } StringValidationBuilder<T>* withExactMatch(Text value) { element.setAttribute("equals", value); return this; } StringValidationBuilder<T>* whichContainsMatch(Text value) { element.setAttribute("contains", value); return this; } StringValidationBuilder<T>* whichStartsWithMatch(Text value) { element.setAttribute("startsWith", value); return this; } StringValidationBuilder<T>* whichEndsWithMatch(Text value) { element.setAttribute("endsWith", value); return this; } StringValidationBuilder<T>* whichIsOneOf(RCArray<Text> values) { JSON::JSONArray arr; for (Text* str : values) arr.addValue(new JSON::JSONString(str->getText())); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder<T>* whichIsOneOf( std::initializer_list<Text> values) { JSON::JSONArray arr; for (Text str : values) arr.addValue(new JSON::JSONString(str)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder<T>* whichIs(Text value) { JSON::JSONArray arr; arr.addValue(new JSON::JSONString(value)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder<T>* withDefault(Text value) { element.setAttribute( "default", JSON::JSONString(value).toString()); return this; } StringValidationBuilder<T>* withDefaultNull() { element.setAttribute("default", "null"); return this; } StringValidationBuilder<T>* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } StringValidationBuilder<T>* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishString() { T* result = builder(element); delete this; return result; } }; template<typename T> class NumberValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: NumberValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<number/>"), builder(builder) {} NumberValidationBuilder<T>* setReferenceId(Text id) { element.setAttribute("id", id); return this; } NumberValidationBuilder<T>* whichIs(double value) { element.setAttribute("equals", Text(value)); return this; } NumberValidationBuilder<T>* whichIsLessOrEqual(double value) { element.setAttribute("lessOrEqual", Text(value)); return this; } NumberValidationBuilder<T>* whichIsGreaterOrEqual(double value) { element.setAttribute("greaterOrEqual", Text(value)); return this; } NumberValidationBuilder<T>* whichIsLessThen(double value) { element.setAttribute("less", Text(value)); return this; } NumberValidationBuilder<T>* whichIsGreaterThen(double value) { element.setAttribute("greater", Text(value)); return this; } NumberValidationBuilder<T>* withDefault(double value) { element.setAttribute( "default", JSON::JSONNumber(value).toString()); return this; } NumberValidationBuilder<T>* withDefaultNull() { element.setAttribute("default", "null"); return this; } NumberValidationBuilder<T>* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } NumberValidationBuilder<T>* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishNumber() { T* result = builder(element); delete this; return result; } }; template<typename T> class BoolValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: BoolValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<bool/>"), builder(builder) {} BoolValidationBuilder<T>* setReferenceId(Text id) { element.setAttribute("id", id); return this; } BoolValidationBuilder<T>* whichIs(bool value) { element.setAttribute("equals", value ? "true" : "false"); return this; } BoolValidationBuilder<T>* withDefault(bool value) { element.setAttribute( "default", JSON::JSONBool(value).toString()); return this; } BoolValidationBuilder<T>* withDefaultNull() { element.setAttribute("default", "null"); return this; } BoolValidationBuilder<T>* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } BoolValidationBuilder<T>* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishBool() { T* result = builder(element); delete this; return result; } }; template<typename T> class ArrayValidationBuilder; template<typename T> class ObjectValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: ObjectValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<object></object>"), builder(builder) {} ObjectValidationBuilder<T>* setReferenceId(Text id) { element.setAttribute("id", id); return this; } NumberValidationBuilder<ObjectValidationBuilder<T>>* withRequiredNumber(Text name) { return new NumberValidationBuilder<ObjectValidationBuilder<T>>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } StringValidationBuilder<ObjectValidationBuilder<T>>* withRequiredString(Text name) { return new StringValidationBuilder<ObjectValidationBuilder<T>>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } BoolValidationBuilder<ObjectValidationBuilder<T>>* withRequiredBool( Text name) { return new BoolValidationBuilder<ObjectValidationBuilder<T>>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ArrayValidationBuilder<ObjectValidationBuilder<T>>* withRequiredArray(Text name) { return new ArrayValidationBuilder<ObjectValidationBuilder<T>>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder<ObjectValidationBuilder<T>>* withRequiredObject(Text name) { return new ObjectValidationBuilder<ObjectValidationBuilder<T>>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder<T>* withRequiredAttribute( Text name, DataValidator* validator) { if (!element.selectChildsByAttribute("name", name).exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ObjectValidationBuilder<T>* withDefault(JSON::JSONObject* obj) { element.setAttribute("default", obj->toString()); obj->release(); return this; } ObjectValidationBuilder<T>* withDefaultNull() { element.setAttribute("default", "null"); return this; } ObjectValidationBuilder<T>* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ObjectValidationBuilder<T>* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder<T>* typeOfValuesSpecifiedByAttribute( Text valueName, Text attributeName) { if (!element.selectChildsByAttribute("name", valueName) .exists()) { XML::Element* attr = new XML::Element("<value></value>"); attr->setAttribute("name", valueName); element.addChild(attr); } element.selectChildsByAttribute("name", valueName) .setAttribute("typeSpecifiedBy", attributeName); return this; } ObjectValidationBuilder<T>* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } ObjectValidationBuilder<T>* allowAdditionalAttriutes() { element.setAttribute("allowAdditionalAttributes", "true"); return this; } T* finishObject() { T* result = builder(element); delete this; return result; } }; template<typename T> class ArrayValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: ArrayValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<array></array>"), builder(builder) {} StringValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedStringInArray() { return new StringValidationBuilder<ArrayValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedNumberInArray() { return new NumberValidationBuilder<ArrayValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedBooleanInArray() { return new BoolValidationBuilder<ArrayValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedObjectInArray() { return new ObjectValidationBuilder<ArrayValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedArrayInArray() { return new ArrayValidationBuilder<ArrayValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder<T>* addAcceptedTypeInArray( DataValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ArrayValidationBuilder<T>* acceptNullsInArray() { element.setAttribute("nullsEnabled", "true"); return this; } ArrayValidationBuilder<T>* withDefault(JSON::JSONArray* array) { element.setAttribute("default", array->toString()); array->release(); return this; } ArrayValidationBuilder<T>* withDefaultNull() { element.setAttribute("default", "null"); return this; } ArrayValidationBuilder<T>* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ArrayValidationBuilder<T>* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder<T>* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } ArrayValidationBuilder<T>* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } T* finishArray() { T* result = builder(element); delete this; return result; } }; template<typename T> class OneOfValidationBuilder { private: XML::Element element; std::function<T*(XML::Element& element)> builder; public: OneOfValidationBuilder( std::function<T*(XML::Element& element)> builder) : element("<oneOf></oneOf>"), builder(builder) {} StringValidationBuilder<OneOfValidationBuilder<T>>* addAcceptedStringInArray() { return new StringValidationBuilder<OneOfValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder<OneOfValidationBuilder<T>>* addAcceptedNumberInArray() { return new NumberValidationBuilder<OneOfValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder<OneOfValidationBuilder<T>>* addAcceptedBooleanInArray() { return new BoolValidationBuilder<OneOfValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder<OneOfValidationBuilder<T>>* addAcceptedObjectInArray() { return new ObjectValidationBuilder<OneOfValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder<OneOfValidationBuilder<T>>* addAcceptedArrayInArray() { return new ArrayValidationBuilder<OneOfValidationBuilder<T>>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } OneOfValidationBuilder<T>* addAcceptedType(DataValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } OneOfValidationBuilder<T>* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } T* finishOneOf() { T* result = builder(element); delete this; return result; } }; } // namespace Validator } // namespace Framework