#pragma once #include <Array.h> #include <cstdlib> #include <DataValidator.h> #include <JSON.h> #include <Logging.h> #include <Trie.h> #include <typeinfo> class TypeRegistry; #define JSONObjectValidationBuilder \ Framework::Validator::ObjectValidationBuilder< \ Framework::Validator::DataValidator> template<typename T> class SimpleTypeFactory : public Framework::ReferenceCounter { public: SimpleTypeFactory() : ReferenceCounter() {}; virtual T fromJson(Framework::JSON::JSONValue* zJson) const = 0; virtual Framework::JSON::JSONValue* toJson(T value) const = 0; virtual Framework::Validator::DataValidator* getValidator() const = 0; }; /* * Used to convert an object of type T to a JSONValue and vice versa. * Can be registered at the TypeRegistry to be used by the JSON system */ template<typename T> class ObjectTypeFactory : public SimpleTypeFactory<T*> { public: ObjectTypeFactory() : SimpleTypeFactory<T*>() {}; T* fromJson(Framework::JSON::JSONValue* zJson) const final override { return fromJson(zJson->asObject()); } Framework::JSON::JSONValue* toJson(T* value) const final override { return toJsonObject(value); } virtual Framework::Validator::DataValidator* getValidator() const override { return addToValidator( Framework::Validator::DataValidator::buildForObject()) ->finishObject(); }; virtual JSONObjectValidationBuilder* addToValidator( JSONObjectValidationBuilder* builder) const = 0; protected: virtual T* fromJson(Framework::JSON::JSONObject* zJson) const = 0; virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const = 0; }; /* * Used to convert an object of type S witch inherits from type T to a * JSONValue and vice versa. Can be registered at the TypeRegistry to be * used by the JSON */ template<typename T, typename S, typename = std::enable_if<std::is_base_of<T, S>::value>> class SubTypeFactory : public ObjectTypeFactory<S> { public: SubTypeFactory() : ObjectTypeFactory<S>() {}; virtual Framework::Validator::DataValidator* getValidator() const final override { Framework::Text referenceId = "_type_"; referenceId.append() << typeid(T).name() << "_" << getTypeToken(); return this ->addToValidator( Framework::Validator::DataValidator::buildForObject() ->withRequiredString("type") ->withExactMatch(getTypeToken()) ->finishString() ->setReferenceId(referenceId)) ->finishObject(); }; virtual const char* getTypeToken() const = 0; virtual const char* getTypeName() const { return typeid(S).name(); } }; template<typename T> class SubTypeFactoryRef : public Framework::ReferenceCounter { private: std::function<const char*()> typetokenFunc; std::function<T*(Framework::JSON::JSONValue*)> fromJsonFunc; std::function<Framework::JSON::JSONValue*(T*)> toJsonFunc; std::function<Framework::Validator::DataValidator*()> getValidatorFunc; Framework::ReferenceCounter* factory; public: SubTypeFactoryRef(std::function<const char*()> typetokenFunc, std::function<T*(Framework::JSON::JSONValue*)> fromJsonFunc, std::function<Framework::JSON::JSONValue*(T*)> toJsonFunc, std::function<Framework::Validator::DataValidator*()> getValidatorFunc, Framework::ReferenceCounter* factory) : ReferenceCounter(), typetokenFunc(typetokenFunc), fromJsonFunc(fromJsonFunc), toJsonFunc(toJsonFunc), getValidatorFunc(getValidatorFunc), factory(factory) {} ~SubTypeFactoryRef() { factory->release(); } T* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJsonFunc(zJson); } Framework::JSON::JSONValue* toJson(T* zObject) const { return toJsonFunc(zObject); } Framework::Validator::DataValidator* getValidator() const { return getValidatorFunc(); } const char* getTypeToken() const { return typetokenFunc(); } }; template<typename T> class PolymorphTypeFactory : public ObjectTypeFactory<T> { private: Framework::RCArray<SubTypeFactoryRef<T>> factories; Framework::RCArray<Framework::Text> typeNames; static thread_local bool insideGetValidator; public: PolymorphTypeFactory() : ObjectTypeFactory<T>() {} T* fromJson(Framework::JSON::JSONObject* zJson) const override { for (SubTypeFactoryRef<T>* factory : factories) { if (zJson->zValue("type")->asString()->getString().istGleich( factory->getTypeToken())) { return factory->fromJson(zJson); } } Framework::Logging::error() << "No Sub Type Factory for typetoken " << zJson->zValue("type")->asString()->getString() << " of type " << typeid(T).name() << " was found."; return 0; } Framework::JSON::JSONObject* toJsonObject(T* zObject) const override { auto name = typeNames.begin(); for (SubTypeFactoryRef<T>* factory : factories) { if (name->istGleich(typeid(*zObject).name())) { Framework::JSON::JSONObject* result = factory->toJson(zObject)->asObject(); result->addValue("type", new Framework::JSON::JSONString(factory->getTypeToken())); return result; } name++; } Framework::Logging::error() << "No Sub Type Factory for subtype " << typeid(*zObject).name() << " of type " << typeid(T).name() << " was found."; return new Framework::JSON::JSONObject(); } JSONObjectValidationBuilder* addToValidator( JSONObjectValidationBuilder* builder) const override { Framework::Logging::error() << "Can not add polymorph json validator to an object " "validation builder"; throw "Can not add polymorph json " "validator to an object " "validation builder"; } Framework::Validator::DataValidator* getValidator() const override { Framework::Validator::DataValidator* result; if (!insideGetValidator) { insideGetValidator = true; auto validator = Framework::Validator::DataValidator::buildForOneOf() ->typeSpecifiedByAttribute("type"); for (SubTypeFactoryRef<T>* factory : factories) { validator = validator->addAcceptedType(factory->getValidator()); } result = validator->finishOneOf(); insideGetValidator = false; } else { auto validator = Framework::Validator::DataValidator::buildForOneOf() ->typeSpecifiedByAttribute("type"); for (SubTypeFactoryRef<T>* factory : factories) { validator = validator->addAcceptedType( Framework::Validator::DataValidator::buildForReference( ((Framework::Text("_type_") += typeid(T).name()) += "_") += factory->getTypeToken())); } result = validator->finishOneOf(); } return result; } template<typename S, typename = std::enable_if<std::is_base_of<T, S>::value>> void addFactory(SubTypeFactory<T, S>* factory) { factories.add(new SubTypeFactoryRef<T>( [factory]() { return factory->getTypeToken(); }, [factory](Framework::JSON::JSONValue* zJson) { S* value = factory->fromJson(zJson); if (value) { return dynamic_cast<T*>(value); } return (T*)0; }, [factory](T* zObject) { return factory->toJson(dynamic_cast<S*>(zObject)); }, [factory]() { return factory->getValidator(); }, dynamic_cast<Framework::ReferenceCounter*>(factory))); typeNames.add(new Framework::Text(factory->getTypeName())); } }; template<typename T> thread_local bool PolymorphTypeFactory<T>::insideGetValidator = false; class TypeFatoryRef : public Framework::ReferenceCounter { private: std::function<void*(Framework::JSON::JSONValue*)> fromJsonFunc; std::function<Framework::JSON::JSONValue*(void*)> toJsonFunc; std::function<Framework::Validator::DataValidator*()> getValidatorFunc; Framework::ReferenceCounter* factory; public: TypeFatoryRef( std::function<void*(Framework::JSON::JSONValue*)> fromJsonFunc, std::function<Framework::JSON::JSONValue*(void*)> toJsonFunc, std::function<Framework::Validator::DataValidator*()> getValidatorFunc, Framework::ReferenceCounter* factory) : ReferenceCounter(), fromJsonFunc(fromJsonFunc), toJsonFunc(toJsonFunc), getValidatorFunc(getValidatorFunc), factory(factory) {} ~TypeFatoryRef() { factory->release(); } void* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJsonFunc(zJson); } Framework::JSON::JSONValue* toJson(void* zObject) const { return toJsonFunc(zObject); } Framework::Validator::DataValidator* getValidator() const { return getValidatorFunc(); } Framework::ReferenceCounter* zFactory() const { return factory; } }; class TypeRegistry : public Framework::ReferenceCounter { private: Framework::RCTrie<TypeFatoryRef> parsableTypes; Framework::RCArray<Framework::Text> parsableTypeNames; public: TypeRegistry(); template<typename T, typename S, typename = std::enable_if<std::is_base_of<T, S>::value>> void registerSubType(SubTypeFactory<T, S>* factory) { Framework::Text typeId = typeid(T).name(); TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { PolymorphTypeFactory<T>* polymorphFactory = new PolymorphTypeFactory<T>(); registerType(polymorphFactory); typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); parsableTypeNames.add(new Framework::Text(typeId)); } PolymorphTypeFactory<T>* polymorphFactory = dynamic_cast<PolymorphTypeFactory<T>*>( typeFactoryRef->zFactory()); if (!polymorphFactory) { Framework::Logging::error() << Framework::Text("Type not registered as Polymorphic type: ") + typeId; throw Framework::Text("Type not registered as Polymorphic type: ") + typeId; } polymorphFactory->addFactory<S>(factory); } template<typename T> void registerType(ObjectTypeFactory<T>* factory) { registerType(typeid(T).name(), factory); } template<typename T> void registerType(Framework::Text typeId, SimpleTypeFactory<T>* factory) { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type already registered: ") + typeId; throw Framework::Text("Type already registered: ") + typeId; } typeFactoryRef = new TypeFatoryRef( [factory](Framework::JSON::JSONValue* zJson) { return (void*)factory->fromJson(zJson); }, [factory](void* zObject) { return factory->toJson((T)zObject); }, [factory]() { return factory->getValidator(); }, factory); parsableTypes.set(typeId, typeId.getLength(), typeFactoryRef); parsableTypeNames.add(new Framework::Text(typeId)); } template<typename T> T fromJson(Framework::Text typeId, Framework::JSON::JSONValue* zJson) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return (T)(typeFactoryRef->fromJson(zJson)); } template<typename T> T* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJson<T*>(typeid(T).name(), zJson); } template<typename T> Framework::JSON::JSONValue* toJson(T* zObject) const { return toJson<T*>(typeid(T).name(), zObject); } template<typename T> Framework::JSON::JSONValue* toJson( Framework::Text typeId, const T zObject) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return typeFactoryRef->toJson((void*)zObject); } template<typename T> Framework::Validator::DataValidator* getValidator() const { return getValidator<T>(typeid(T).name()); } template<typename T> Framework::Validator::DataValidator* getValidator( Framework::Text typeId) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return typeFactoryRef->getValidator(); } template<typename T> Framework::JSON::JSONValue* getValidParts( Framework::JSON::JSONValue* zJson) const { Framework::RCArray<Framework::Validator::ValidationResult> invalidParts; Framework::Validator::DataValidator* validator = getValidator<T>(); Framework::JSON::JSONValue* result = validator->getValidParts(zJson, &invalidParts); for (Framework::Validator::ValidationResult* invalidPart : invalidParts) { Framework::Logging::error() << invalidPart->getInvalidInfo(); } return result; } void writeSyntaxInfo(Framework::Text folderPath) const; };