def __init__(self, context): super(BaseReportable, self).__init__(context) self.class_context = self.context.__class__ self.rel_property_name = dict() seen_target_entity = set() relations = getattr(self.context, "_relations", tuple()) for relName, relation in relations: try: if type(relation.remoteClass) == str: remoteClass = importClass(relation.remoteClass, None) else: remoteClass = relation.remoteClass() if remoteClass.meta_type in ("ZenModelRM"): # Way too generic. Just go with the relname. target_entity = un_camel(relName) else: target_entity = self.entity_class_for_class(remoteClass) if target_entity in seen_target_entity: # if we have more than one relationship to the same # target entity, prefix all but the first # with the relname to disambiguate. target_entity = un_camel(relName + "_" + target_entity) seen_target_entity.add(target_entity) self.rel_property_name[relName] = target_entity except Exception, e: LOG.error("Error processing relationship %s on %s: %s") % (relName, self.context, e)
def __init__(self, context): super(BaseReportable, self).__init__(context) self.class_context = self.context.__class__ self.rel_property_name = dict() seen_target_entity = set() relations = getattr(self.context, '_relations', tuple()) for relName, relation in relations: try: if type(relation.remoteClass) == str: remoteClass = importClass(relation.remoteClass, None) else: remoteClass = relation.remoteClass() if remoteClass.meta_type in ('ZenModelRM'): # Way too generic. Just go with the relname. target_entity = un_camel(relName) else: target_entity = self.entity_class_for_class(remoteClass) if target_entity in seen_target_entity: # if we have more than one relationship to the same # target entity, prefix all but the first # with the relname to disambiguate. target_entity = un_camel(relName + '_' + target_entity) seen_target_entity.add(target_entity) self.rel_property_name[relName] = target_entity except Exception, e: LOG.error("Error processing relationship %s on %s: %s") % ( relName, self.context, e)
def remoteClass(self): """Return the class at the remote end of our relationship.""" classdef = getattr(aq_base(self), "_v_remoteClass", None) if not classdef: schema = self.__primary_parent__.lookupSchema(self.id) classdef = importClass(schema.remoteClass) self._v_remoteClass = classdef return classdef
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 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)