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 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)