diff options
| author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-01-16 17:33:56 +0100 | 
|---|---|---|
| committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-01-16 17:33:56 +0100 | 
| commit | 821648607f5e0c6702eefbc206c0421d1a347bda (patch) | |
| tree | d6a5241ba39d75d7aec1f7e8544e05a03142e47d /src | |
| parent | 9929838e62d9c17647d74be54af5853e8b613c4b (diff) | |
first attempt on validation method for Document classes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/model/Document.cpp | 68 | ||||
| -rw-r--r-- | src/core/model/Document.hpp | 15 | ||||
| -rw-r--r-- | src/core/model/Node.hpp | 85 | 
3 files changed, 164 insertions, 4 deletions
| diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 2f12acb..92791a4 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -92,7 +92,8 @@ int DocumentEntity::getFieldDescriptorIndex(  	}  } -bool DocumentEntity::validate(Logger &logger) const +bool DocumentEntity::doValidate(Logger &logger, +                                std::set<ManagedUid> &visited) const  {  	// TODO: check the validated form of Attributes  	// iterate over every field @@ -134,9 +135,16 @@ bool DocumentEntity::validate(Logger &logger) const  		// iterate over every actual child of this DocumentEntity  		for (auto &rc : fields[f]) { -			if (!rc->isa(RttiTypes::StructuredEntity)) { +			if (!rc->isa(RttiTypes::Anchor)) { +				// Anchors are uninteresting and can be ignored.  				continue;  			} +			if (!rc->isa(RttiTypes::DocumentPrimitive)) { +				// For DocumentPrimitives we have to check the content type. +				// TODO: Do that! +				continue; +			} +			// otherwise this is a StructuredEntity  			Handle<StructuredEntity> c = rc.cast<StructuredEntity>();  			ManagedUid id = c->getDescriptor()->getUid(); @@ -193,6 +201,23 @@ bool DocumentEntity::validate(Logger &logger) const  			}  		}  	} + +	// go into recursion. +	for (auto &f : fields) { +		for (auto &n : f) { +			if (!visited.insert(n->getUid()).second) { +				logger.error("The given document contains a cycle!"); +				return false; +			} +			if (n->isValidated()) { +				continue; +			} +			if (!n->validate(logger, visited)) { +				return false; +			} +		} +	} +  	return true;  } @@ -222,6 +247,17 @@ StructuredEntity::StructuredEntity(Manager &mgr, Handle<Document> doc,  	doc->setRoot(this);  } +bool StructuredEntity::doValidate(Logger &logger, +                                  std::set<ManagedUid> &visited) const +{ +	// check if the parent is set. +	if (getParent() == nullptr) { +		return false; +	} +	// check the validity as a DocumentEntity. +	return DocumentEntity::doValidate(logger, visited); +} +  /* Class AnnotationEntity */  AnnotationEntity::AnnotationEntity(Manager &mgr, Handle<Document> parent, @@ -236,6 +272,34 @@ AnnotationEntity::AnnotationEntity(Manager &mgr, Handle<Document> parent,  	parent->annotations.push_back(this);  } +bool AnnotationEntity::doValidate(Logger &logger, +                                  std::set<ManagedUid> &visited) const +{ +	// check if this AnnotationEntity is correctly registered at its document. +	if (getParent() == nullptr || !getParent()->isa(RttiTypes::Document)) { +		return false; +	} +	Handle<Document> doc = getParent().cast<Document>(); +	bool found = false; +	for (auto &a : doc->getAnnotations()) { +		if (a == this) { +			found = true; +			break; +		} +	} +	if (!found) { +		logger.error("This annotation was not registered at the document."); +		return false; +	} + +	// check the validity as a DocumentEntity. +	if (!DocumentEntity::doValidate(logger, visited)) { +		return false; +	} +	// TODO: then check if the anchors are in the correct document. +	return true; +} +  /* Class Document */  void Document::continueResolve(ResolutionState &state) diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index c70a6a3..b73e07d 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -108,6 +108,8 @@  #ifndef _OUSIA_MODEL_DOCUMENT_HPP_  #define _OUSIA_MODEL_DOCUMENT_HPP_ +#include <set> +  #include <core/managed/ManagedContainer.hpp>  #include <core/common/Variant.hpp> @@ -159,6 +161,8 @@ protected:  		fields[getFieldDescriptorIndex(fieldName, true)].push_back(s);  	} +	bool doValidate(Logger &logger, std::set<ManagedUid> &visited) const; +  public:  	/**  	 * The constructor for a DocumentEntity. Node that this does not inherit @@ -256,8 +260,6 @@ public:  		return fields[getFieldDescriptorIndex(fieldDescriptor, true)];  	} -	bool validate(Logger& logger) const; -  	// TODO: Change this to move methods.  	//	/**  	//	 * This adds a StructureNode to the field with the given name. If an @@ -343,6 +345,8 @@ public:   * common superclass for StructuredEntity, Anchor and DocumentPrimitive.   */  class StructureNode : public Node { +	friend DocumentEntity; +  public:  	/**  	 * Constructor for a StructureNode at the root. @@ -364,6 +368,10 @@ public:   * information please refer to the header documentation above.   */  class StructuredEntity : public StructureNode, public DocumentEntity { +protected: +	bool doValidate(Logger &logger, +	                std::set<ManagedUid> &visited) const override; +  public:  	/**  	 * Constructor for a StructuredEntity in the Structure Tree. @@ -505,6 +513,9 @@ class AnnotationEntity : public Node, public DocumentEntity {  private:  	Owned<Anchor> start;  	Owned<Anchor> end; +protected: +	bool doValidate(Logger &logger, +	                std::set<ManagedUid> &visited) const override;  public:  	/** diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp index e8adbaa..3763395 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -29,6 +29,7 @@  #define _OUSIA_NODE_HPP_  #include <map> +#include <set>  #include <string>  #include <vector> @@ -40,6 +41,7 @@  namespace ousia {  // Forward declarations +class Logger;  class RttiType;  template <class T>  class Rtti; @@ -103,6 +105,11 @@ private:  	 * Reference to a parent node instace.  	 */  	Owned<Node> parent; +	/** +	 * A "dirty" flag that signifies if this Node has been validated already +	 * or not. +	 */ +	mutable bool validated = false;  	/**  	 * Private version of the "path" function used to construct the path. Calls @@ -263,6 +270,59 @@ protected:  		return false;  	} +	/** +	 * This method should be called if the internal state of this Node is +	 * changed such that a new validation run has to be made. +	 */ +	void invalidate() const { validated = false; } + +	/** +	 * The convention for this function is as follows: +	 * 1.) The child should validate itself and return false, if constraints are +	 *     not met. Errors should be logged if and only if false is returned. +	 * 3.) It should call validate on all children. +	 *     If some child returns false this method should return false as well. +	 * 4.) If all children could be validated this method should return true. +	 * +	 * Note that this implementation does not have to touch the visited set. +	 * You can use it for validation purposes, however (e.g. to detect cycles +	 * in the graph). +	 * +	 * The default and trivial behaviour of this function is to return true. +	 * +	 * @param logger  is a logger for error messages if false is returned. +	 * @param visited is a set containing the ManagedUids of all children +	 *                that already have been visited. +	 * @return        true if this is a valid node and false if it is not. +	 */ +	virtual bool doValidate(Logger &logger, std::set<ManagedUid> &visited) const +	{ +		return true; +	} +	 +	/** +	 * A wrapper for doValidate that takes care of not visiting children twice, +	 * and handling the validated flag. +	 */ +	bool validate(Logger &logger, std::set<ManagedUid> &visited) const { +		if (!visited.insert(getUid()).second) { +			// if we have visited this Node already within this run, return +			// the validated flag. +			return validated; +		} +		if(validated){ +			// if this is validated, return true. +			return true; +		} +		if(!doValidate(logger, visited)){ +			// if this can not be validated, return false. +			return false; +		} +		// if it could be validated, set the validated flag. +		validated = true; +		return true; +	} +  public:  	/**  	 * Initializes the node with empty name and parent. @@ -361,6 +421,31 @@ public:  	 */  	std::vector<ResolutionResult> resolve(const std::string &name,  	                                      const RttiType &type); + +	/** +	 * Returns true if this node has been validated. Note that a 'false' return +	 * value does _not_ imply that this Node is invalid. It merely says that +	 * validity of this node is uncertain. The opposite is true, however: If +	 * this node is invalid, the validated flag will be false. +	 */ +	bool isValidated() const { return validated; } + +	/** +	 * Checks whether this node is valid and returns true if it is and false +	 * if it is not. If the node is invalid further information will be appended +	 * to the logger. If this is valid this will also set the "validated" flag +	 * to "true". +	 * +	 * @param logger    is a logger where errors will be logged if this +	 *                  Node is invalid. +	 * +	 * @return          true if this Node is valid. +	 */ +	bool validate(Logger &logger) +	{ +		std::set<ManagedUid> visited; +		return validate(logger, visited); +	}  };  /** | 
