def reportProperties(self): fromReportable = IReportable(self.fromObject) toReportable = IReportable(self.toObject) return [ (fromReportable.entity_class_name + "_key", 'reference', fromReportable.sid, MARKER_LENGTH), (toReportable.entity_class_name + "_key", 'reference', toReportable.sid, MARKER_LENGTH), ]
def exports(self): context_reportable = IReportable(self.context) if self.class_context and hasattr(context_reportable, "set_class_context"): context_reportable.set_class_context(self.class_context) yield context_reportable if hasattr(context_reportable, "export_as_bases"): # The idea here is to give the abiliity to export something both as # itself, but also as a more generic type (one of its base classes). # For example, an OpenStack Endpoint is both an openstack endpoint # and a Device. Therefore I would like it to end up in both # dim_openstack_endpoint and dim_device. for class_ in context_reportable.export_as_bases: if class_ == self.class_context: # no need to re-export as ourself.. continue reportable_factory_class = adapter_for_class(class_, IReportableFactory) reportable_class = adapter_for_class(class_, IReportable) # The problem is that normally, a Reportable or ReportableFactory # does not know what class it is adapting. It therefore tends # to rely on the model object to tell it what to export, and # most of the reportables export all properties and relationships # of the supplied object. # # In this situation, though, we want to export, say, an Endpoint # as if it was a Device, and therefore to only export the # properties and relationships defined in the Device class. # # The only way to make this work is to introduce the idea of # class-context to Reportable (and ReportableFactory). # # A class-context-aware Reportable or ReportableFactory has # an additional method, set_class_context(), which is passed # a class object. # # The default behavior is still the same- if set_class_context # has not been used, the reportable should behave as it does # today. # # However, in this specific situation (export_as_bases), if a # class-context-aware ReportableFactory is available, I will # use it (and expect it to pass that class context on to the # reportables it generates). # # Otherwise, I will create the single reportable directly, not # using any reportablefactory, because I can't trust the # an existing factory that doesn't realize that it's dealing # with a base class, not the actual object class, to not # duplicate all the exports I have already done. factory = reportable_factory_class(self.context) if hasattr(reportable_factory_class, "set_class_context"): factory.set_class_context(class_) for export in factory.exports(): yield export else: yield reportable_class(self.context) relations = getattr(self.context, "_relations", tuple()) for relName, relation in relations: if isinstance(relation, ToMany) and issubclass(relation.remoteType, ToMany): # For a many-many relationship, we need to implement a # reportable to represent the relationship, if we're # on the proper end of it. Really, either end will work, # but we need something deterministic, so just go with # whichever end has the alphabetically earliest relname. if min(relation.remoteName, relName) == relName: related = getattr(self.context, relName, None) if related: related = related() entity_class_name = "%s_to_%s" % ( IReportable(self.context).entity_class_name, un_camel(importClass(relation.remoteClass, None).meta_type), ) for remoteObject in related: yield BaseManyToManyReportable( fromObject=self.context, toObject=remoteObject, entity_class_name=entity_class_name )
def sid(self): return "%s__%s" % (IReportable( self.fromObject).sid, IReportable(self.toObject).sid)
def exports(self): context_reportable = IReportable(self.context) if self.class_context and hasattr(context_reportable, 'set_class_context'): context_reportable.set_class_context(self.class_context) yield context_reportable if hasattr(context_reportable, 'export_as_bases'): # The idea here is to give the abiliity to export something both as # itself, but also as a more generic type (one of its base classes). # For example, an OpenStack Endpoint is both an openstack endpoint # and a Device. Therefore I would like it to end up in both # dim_openstack_endpoint and dim_device. for class_ in context_reportable.export_as_bases: if class_ == self.class_context: # no need to re-export as ourself.. continue reportable_factory_class = adapter_for_class( class_, IReportableFactory) reportable_class = adapter_for_class(class_, IReportable) # The problem is that normally, a Reportable or ReportableFactory # does not know what class it is adapting. It therefore tends # to rely on the model object to tell it what to export, and # most of the reportables export all properties and relationships # of the supplied object. # # In this situation, though, we want to export, say, an Endpoint # as if it was a Device, and therefore to only export the # properties and relationships defined in the Device class. # # The only way to make this work is to introduce the idea of # class-context to Reportable (and ReportableFactory). # # A class-context-aware Reportable or ReportableFactory has # an additional method, set_class_context(), which is passed # a class object. # # The default behavior is still the same- if set_class_context # has not been used, the reportable should behave as it does # today. # # However, in this specific situation (export_as_bases), if a # class-context-aware ReportableFactory is available, I will # use it (and expect it to pass that class context on to the # reportables it generates). # # Otherwise, I will create the single reportable directly, not # using any reportablefactory, because I can't trust the # an existing factory that doesn't realize that it's dealing # with a base class, not the actual object class, to not # duplicate all the exports I have already done. factory = reportable_factory_class(self.context) if hasattr(reportable_factory_class, 'set_class_context'): factory.set_class_context(class_) for export in factory.exports(): yield export else: yield reportable_class(self.context) relations = getattr(self.context, '_relations', tuple()) for relName, relation in relations: if isinstance(relation, ToMany) and \ issubclass(relation.remoteType, ToMany): # For a many-many relationship, we need to implement a # reportable to represent the relationship, if we're # on the proper end of it. Really, either end will work, # but we need something deterministic, so just go with # whichever end has the alphabetically earliest relname. if min(relation.remoteName, relName) == relName: related = getattr(self.context, relName, None) if related: related = related() entity_class_name = "%s_to_%s" % ( IReportable(self.context).entity_class_name, un_camel( importClass(relation.remoteClass, None).meta_type)) for remoteObject in related: yield BaseManyToManyReportable( fromObject=self.context, toObject=remoteObject, entity_class_name=entity_class_name)
def refValue(context, rel): # Given a ToOne relationship, return a proper value for reportProperties() if rel(): return IReportable(context, rel()).sid else: return None
def sid(self): return "{}__{}".format( IReportable(self.fromObject).sid, IReportable(self.toObject).sid)