Base class for PropertyRelationRules.
For the implementOther information (e.g. regex usage/pimpl) on could/should orient on s are directly encoded in the documentation of the draft proposal.
PropertyPersistenceInfo.osal for the interface draft:
Open Question. should the checklogic be handled by injection (std::function/lambdas instead) instead of derivations? lang=c++
Pro: Only one class to handle all /**Base class to standardize/abstract/encapsulate rules and business logic to detect and define
(property/data based) releations in MITK.
Following important definitions must be regarded when using/implementing/specifing rule classes:
- Releation represented by rules are directed relations that point from a source IPropertyOwner (Source)
to a destination IPropertyOwner (Destination).
- A concrete rule class always implements a concrete releation type. E.g. In DICOM the
way to express the source image relation to an input image and to a mask would be nearly the same
and only differs by the encoded purpuse. One may implement an interim class that manages the mutual
stuff, but the nonabstract rule classes must be one for "DICOM source input image" and one for
"DICOM source mask" etc.
- Source may have several relations of a rule to different Destinations.
Destination may have several relations of a rule from different Sources. But a specific Source Destination
pair may have only on relation of a specific rule.
- The deletion of a Destination in the storage does not remove the relation implecitly. It becomes a "zombie" relation
but should still be documented, even if the destination is unkown. The and a (zombie) relation, one has to explicitly
disconnect it.
- Each releation has its on UID (relationID) that can be used to address it.
Con: May be you want more freedome.
Answaring the question has an implication on which methods may be abstract or alread implemented.
Proposal for the interface draft:
lang=c++The basic concept of the rule design is that we have to layers of relation identification: Layer 1 is the ID-layer
which uses the IIdentifiable interface and UIDs if available to encode "hard" relations. Layer 2 is the Data-layer
whicht uses the properties of Source and Destination to deduce if there is a relation of the rule type.
The ID-layer is completly implemented by this based class. The base class only falls back to the Data-layer
(implemented by the concrete rule class) if the ID-layer is not sufficient or it is explicitly stated.
Reasons for the introduction of the ID-layer are: 1st, data defined releations may be weak (several Destinations are
possible; e.g. DICOM source images may point to several loaded mitk images). But if expicitly a releation was connected
it should be deduceable. 2nd, Checks on the UID are faster then unnecessary data deduction.
Rules use properties (relationID-properties) in order to manage their relationIDs that are stored in the Source.
The relationID-properties follow the following naming schema:
"MITK.relations.<RuleID>.<Index>.[relationID|destinationID|<data-layer-specific>]"
class PropertyReleationRul- <RuleID>: The identifier of the concrete rule that sets the property
- <InstanceID>: The unique index of the relations of the rule for the Source. Used to assigne/group the properties to their
relation.
- relationID: The UID of the relation. Set by the ID-layer (so by this class)
- destinationID: The UID of the Destination. Set by the ID-layer (so by this class) if Destination implements IIdentifiable.
- <data-layer-specific>: Information needed by the Data-layer (so derived classes) to find the relationID
*/
class PropertyReleationRuleBase : public itk::LightObject
{
public:
using DeserializationFunctionType = std::funcmitkClassMacroItkParent(PropertyReleation<mitk::RuleBaseProperty::Pointer(const std::string &)>;, itk::LightObject);
using SerializationFunctionType = std::function<std::string(const mitk::BaseProperty *)>;
itkFactorylessNewMacro(Self);
mitkClassoneMacroItkParent(PropertyReleationRule, itk::LightObject);(Self);
itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, constusing RuleIDType = std::string &);;
mitkNewMacro2Param(Self, const std::string &, const std::string &);
using RelationIDType = IIdentifiable::UIDType;
std::string GetName() const;using RelationIDVectorType = std::vector<RelationIDType>;
void SetName(const std::string &name);/** Enum class for different types of relations. */
std::string GetSource(const std::string &name) const;enum class RelationType {
None = 0, /**< Two IPropertyOwner have no relation under the rule.*/
Implicit_Data = 1, /**< Two IPropertyOwner have a relation, but it is only deduced from the Data-layer and they were never explicitly connected.*/
Connected_Data = 2, /**< Two IPropertyOwner have a relation and there where connected on the Data-layer (so a bit "weaker" as ID). Reasons for the missing ID connection could be that Destintination has not IIdentifiable implemented.*/
Connected_ID = 4 /**< Two IPropertyOwner have a relation and are fully explictly connected.*/
}
/** Returns an ID string that identifies the rule class */
std::string GetDestination(const std::string &namevirtual RuleIDType GetRuleID() const; = 0;
void SetSource(const std::string &name);/** Returns a humanreadable string that can be used to described the rule. Must not be unique.*/
void SetDestinationSource(const std::string &name);irtual std::string GetDesplayName() const = 0;
/** This method checks if owner is eligible to be a Source for the rule. The default implementation returns a
True for every valid IPropertyOwner (so only a null_ptr results into false). May be reimplement by derived rules if
they have requirements on potential Sources).*/
virtual bool IsRegEx(SourceCandidate(const IPropertyOwner *owner) const;
/** Sets the name and the key identifier as a regular expression that describes valid names and keys.This method checks if owner is eligible to be a Destination for the rule. The default implementation returns a
True for every valid IPropertyOwner (so only a null_ptr results into false). May be reimplement by derived rules if
they have requirements on potential Sources).*/
* @pre nameRegEx must be a valid regular expression, otherweis a regex_error esceptionvirtual bool IsDestinationCandidate(const IPropertyOwner *owner) const;
* is thrown and the info object is not changed./** Returns true if the passed owner is a Source of a relation defined by the rule so has at least one relation of type
Connected_Data or Connected_ID.
@pre owner must be a pointer to a valid IPropertyOwner instance.*/
* @pre keyRegEx must be a valid regular expression, otherweis a regex_error esceptionbool IsSource(const IPropertyOwner *owner) const;
* is thrown and the info object is not changed.*//** Returns the relation type of the passed IPropertyOwner instances.
@pre source must be a pointer to a valid IPropertyOwner instance.
@pre destination must be a pointer to a valid IPropertyOwner instance.
void UseSourceRegEx(const std::string &sourceRegEx, const std::string &destionationTemplate);*/
void UseDestinRelationType HasRelationRegEx(const std::string &destinationRegExIPropertyOwner *source, const std::string &sourceTemplate);IPropertyOwner *destination) const;
/** Returns a vector of IDs for all relations of this rule that are defined for the passed
source (so relations of type Connected_Data and Connected_ID).
*@pre source must be a pointer to a valid IPropertyOwner instance.
const std::string &GetSourceTemplate() const;*/
RelationIDVectorType GetExistingRelations(const IPropertyOwner *source) const;
/** Returns the relation ID for the passed source and destination. If the passed instances have no
explicit relation (so of type Connected_Data or Connected_ID) no ID can be deduced and an exception
will be thrown.
@pre source must be a pointer to a valid IPropertyOwner instance.
@pre destination must be a pointer to a valid IPropertyOwner instance.
@pre Source and destination have a relation of type Connected_Data or Connected_ID*/
const std::string &GetDestinationTemplate(RelationIDType GetRelationID(const IPropertyOwner *source, const IPropertyOwner *destination) const;
bool IsSource(const std::string &propertyName) const;/**Predicate that can be used to find nodes that qualify as source for that rule (but must not be a source yet).
Thus all nodes where IsSourceCandidate() returns true. */
bool IsDestination(cNodePredicateBase::Const std::string &propertyNamePointer GetSourceCandidateIndicator() const;
bool IsSource(const IPropertyOwner *owner) const;/**Predicate that can be used to find nodes that qualify as destination for that rule (but must not be a destination yet).
Thus all nodes where IsDestinationCandidate() returns true. */
bool IsDestination(const IPropertyOwner *ownerNodePredicateBase::ConstPointer GetDestinationCandidateIndicator() const;
/**Predicate that can be used to find nodes that qualify as source for that ruleare Sources of that rule and explicitly connected.
Thus all nodes that have relations of type Connected_Data or Connected_ID.*/
NodePredicateBase::ConstPointer GetetConnectedSourceIndicasDetector() const = 0;;
/**Predicate that can be used to find nodes that qualify as destination for that rulare as source related to the passed Destination under the rule
@param destination Pointer to the Destination instance that should be used for detection.
@param minimalRelation Defines the minimal strength of the relation type that should be detected.
@pre Destination must be a valid instance.*/
NodePredicate::ConstPointer GetDestinationIndicator() const = 0Base::ConstPointer GetSourcesDetector(const IPropertyOwner *destination, RelationType minimalRelation = RelationType::Implicit_Data) const;
/**Predicate that can be used to find nodes that are as Destination related to the passed owner (as source)Source under the rule
@param source Pointer to the Source instance that should be used for detection.
@param minimalRelation Defines the minimal strength of the relation type that should be detected.
@pre Destination must be a valid instance.*/
NodePredicate::ConstPointer GetRelationPredicateSource(const IPropertyOwner *owner) const = 0Base::ConstPointer GetDestinationsDetector(const IPropertyOwner *source, RelationType minimalRelation = RelationType::Implicit_Data) const;
/**P/**Returns a predicate that can be used to find nodes that are related to the passed owner (as destination).the Destination of the passed Source for a given relationID.
@param source Pointer to the Source instance that should be used for detection.
@param minimalRelation Defines the minimal strength of the relation type that should be detected.
@pre source must be a valid instance.
@pre relationID must identify a relation of the passed source and rule. (This must be in the return of this->GetExistingRelations(source). */
NodePredicateBase::ConstPointer GetRelationPredicateDestinationDestinationDetector(const IPropertyOwner *owner) const = 0;source, RelationIDType relationID) const;
/**Logic that can handle changes of the source-side relation relevant property for the destination (e.gExplicitly connects the passed instances. Afterwards they have a relation of Connected_Data or Connected_ID (if a destination implements IIdentifiable).
If the passed instance are already connected the old connection will be overwritten (and raised to the highest possible connection level).
@pre source must be a valid instance.
@pre destination must be a valid instance.*/
void Connect(IPropertyOwner *source, const IPropertyOwner *destination) const;
/**Disconnect the passed instances. the value of the destination may be updated.)*/Afterwards they have a relation of None or Implicit_Data.
All relationID-properties in the source for the passed destination will be removed.
@pre source must be a valid instance.
@pre destination must be a valid instance.*/
void Disconnect(IPropertyOwner *source, const IPropertyOwner *destination) const;
void SourceChanged(const IPropertyOwner* source,/**Disconnect the source from the passed relationID (usefull for "zombie relations").
All relationID-properties in the source for the passed relationID will be removed.
If the relationID is not part of the source. IPropertyOwner* destionation) const;Nothing will be changed.
@pre source must be a valid instance.*/
/**Logic that can handle changes of the destination-side relation relevant property for the source (e.g. the value of the source may be updated.)*/void Disconnect(IPropertyOwner *source, RelationIDType relationID) const;
protected:
void DestinationChanged(PropertyOwner* source, const IPropertyOwner* destionation) const;// TODO the pure virtual methods for the Data-layer.
};
Remarks to implementation details:
# I would propose to use the same UID technique for RelationIDs that is used in IIdentifiable.
# Would be sensible to use the PropertyKeyPath class for handling the relationID-properties.