#pragma once #include #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* 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* 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* 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* 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 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* 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 expected; RCArray reasons; public: __declspec(dllexport) NoTypeMatching(Text path, AbstractElement* foundValue, RCArray& expected, RCArray& reasons); __declspec(dllexport) ~NoTypeMatching(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo( int indent) const override; __declspec(dllexport) JSON::JSONValue* getValidPart( RCArray* 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* 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* 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 class StringValidationBuilder; template class NumberValidationBuilder; template class BoolValidationBuilder; template class ObjectValidationBuilder; template class ArrayValidationBuilder; template class OneOfValidationBuilder; class DataValidator : public Framework::ReferenceCounter { private: XML::Element* constraints; RCTrie* typeConstraints; public: __declspec(dllexport) DataValidator(XML::Element* constraints); __declspec(dllexport) DataValidator(XML::Element* constraints, RCTrie* 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* 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* buildForString(); __declspec(dllexport) static NumberValidationBuilder* buildForNumber(); __declspec(dllexport) static BoolValidationBuilder* buildForBool(); __declspec(dllexport) static ObjectValidationBuilder* buildForObject(); __declspec(dllexport) static ArrayValidationBuilder* buildForArray(); __declspec(dllexport) static OneOfValidationBuilder* buildForOneOf(); __declspec(dllexport) static DataValidator* buildForReference( Text id); }; template class StringValidationBuilder { private: XML::Element element; std::function builder; public: StringValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder* setReferenceId(Text id) { element.setAttribute("id", id); return this; } StringValidationBuilder* withExactMatch(Text value) { element.setAttribute("equals", value); return this; } StringValidationBuilder* whichContainsMatch(Text value) { element.setAttribute("contains", value); return this; } StringValidationBuilder* whichStartsWithMatch(Text value) { element.setAttribute("startsWith", value); return this; } StringValidationBuilder* whichEndsWithMatch(Text value) { element.setAttribute("endsWith", value); return this; } StringValidationBuilder* whichIsOneOf(RCArray values) { JSON::JSONArray arr; for (Text* str : values) arr.addValue(new JSON::JSONString(str->getText())); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* whichIsOneOf( std::initializer_list values) { JSON::JSONArray arr; for (Text str : values) arr.addValue(new JSON::JSONString(str)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* whichIs(Text value) { JSON::JSONArray arr; arr.addValue(new JSON::JSONString(value)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* withDefault(Text value) { element.setAttribute( "default", JSON::JSONString(value).toString()); return this; } StringValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } StringValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } StringValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishString() { T* result = builder(element); delete this; return result; } }; template class NumberValidationBuilder { private: XML::Element element; std::function builder; public: NumberValidationBuilder( std::function builder) : element(""), builder(builder) {} NumberValidationBuilder* setReferenceId(Text id) { element.setAttribute("id", id); return this; } NumberValidationBuilder* whichIs(double value) { element.setAttribute("equals", Text(value)); return this; } NumberValidationBuilder* whichIsLessOrEqual(double value) { element.setAttribute("lessOrEqual", Text(value)); return this; } NumberValidationBuilder* whichIsGreaterOrEqual(double value) { element.setAttribute("greaterOrEqual", Text(value)); return this; } NumberValidationBuilder* whichIsLessThen(double value) { element.setAttribute("less", Text(value)); return this; } NumberValidationBuilder* whichIsGreaterThen(double value) { element.setAttribute("greater", Text(value)); return this; } NumberValidationBuilder* withDefault(double value) { element.setAttribute( "default", JSON::JSONNumber(value).toString()); return this; } NumberValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } NumberValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } NumberValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishNumber() { T* result = builder(element); delete this; return result; } }; template class BoolValidationBuilder { private: XML::Element element; std::function builder; public: BoolValidationBuilder( std::function builder) : element(""), builder(builder) {} BoolValidationBuilder* setReferenceId(Text id) { element.setAttribute("id", id); return this; } BoolValidationBuilder* whichIs(bool value) { element.setAttribute("equals", value ? "true" : "false"); return this; } BoolValidationBuilder* withDefault(bool value) { element.setAttribute( "default", JSON::JSONBool(value).toString()); return this; } BoolValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } BoolValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } BoolValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishBool() { T* result = builder(element); delete this; return result; } }; template class ArrayValidationBuilder; template class ObjectValidationBuilder { private: XML::Element element; std::function builder; public: ObjectValidationBuilder( std::function builder) : element(""), builder(builder) {} ObjectValidationBuilder* setReferenceId(Text id) { element.setAttribute("id", id); return this; } NumberValidationBuilder>* withRequiredNumber(Text name) { return new NumberValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } StringValidationBuilder>* withRequiredString(Text name) { return new StringValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* withRequiredBool( Text name) { return new BoolValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* withRequiredArray(Text name) { return new ArrayValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* withRequiredObject(Text name) { return new ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder* withRequiredAttribute( Text name, DataValidator* validator) { if (!element.selectChildsByAttribute("name", name).exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ObjectValidationBuilder* withDefault(JSON::JSONObject* obj) { element.setAttribute("default", obj->toString()); obj->release(); return this; } ObjectValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } ObjectValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ObjectValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder* typeOfValuesSpecifiedByAttribute( Text valueName, Text attributeName) { if (!element.selectChildsByAttribute("name", valueName) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", valueName); element.addChild(attr); } element.selectChildsByAttribute("name", valueName) .setAttribute("typeSpecifiedBy", attributeName); return this; } ObjectValidationBuilder* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } ObjectValidationBuilder* allowAdditionalAttriutes() { element.setAttribute("allowAdditionalAttributes", "true"); return this; } T* finishObject() { T* result = builder(element); delete this; return result; } }; template class ArrayValidationBuilder { private: XML::Element element; std::function builder; public: ArrayValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder>* addAcceptedStringInArray() { return new StringValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder>* addAcceptedNumberInArray() { return new NumberValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* addAcceptedBooleanInArray() { return new BoolValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* addAcceptedObjectInArray() { return new ObjectValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* addAcceptedArrayInArray() { return new ArrayValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder* addAcceptedTypeInArray( DataValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ArrayValidationBuilder* acceptNullsInArray() { element.setAttribute("nullsEnabled", "true"); return this; } ArrayValidationBuilder* withDefault(JSON::JSONArray* array) { element.setAttribute("default", array->toString()); array->release(); return this; } ArrayValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } ArrayValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ArrayValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } ArrayValidationBuilder* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } T* finishArray() { T* result = builder(element); delete this; return result; } }; template class OneOfValidationBuilder { private: XML::Element element; std::function builder; public: OneOfValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder>* addAcceptedStringInArray() { return new StringValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder>* addAcceptedNumberInArray() { return new NumberValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* addAcceptedBooleanInArray() { return new BoolValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* addAcceptedObjectInArray() { return new ObjectValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* addAcceptedArrayInArray() { return new ArrayValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } OneOfValidationBuilder* addAcceptedType(DataValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } OneOfValidationBuilder* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } T* finishOneOf() { T* result = builder(element); delete this; return result; } }; } // namespace Validator } // namespace Framework