Package Products :: Package ZenRelations :: Module ToManyContRelationship |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenRelations.ToManyContRelationship

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  __doc__ = """ToManyContRelationship
     15  A to-many container relationship
     16  """
     17
     18
     19  import logging
     20  log = logging.getLogger("zen.Relations")
     21
     22  from Globals import DTMLFile
     23  from Globals import InitializeClass
     24  from AccessControl import ClassSecurityInfo
     25  from Acquisition import aq_base
     26  from OFS.ObjectManager import checkValidId, BeforeDeleteException
     27  from ZODB.POSException import ConflictError
     28
     29  import OFS.subscribers
     30  from OFS.event import ObjectWillBeAddedEvent
     31  from OFS.event import ObjectWillBeRemovedEvent
     32  from zope.event import notify
     33  from zope.app.container.contained import ObjectAddedEvent
     34  from zope.app.container.contained import ObjectRemovedEvent
     35  from zope.app.container.contained import ContainerModifiedEvent
     36  from zope.app.container.contained import dispatchToSublocations
     37
     38  from BTrees.OOBTree import OOBTree
     39
     40  from ToManyRelationshipBase import ToManyRelationshipBase
     41
     42  from Products.ZenRelations.Exceptions import *
     43
     44  from Products.ZenUtils.Utils import unused
     45
     46 -def manage_addToManyContRelationship(context, id, REQUEST=None):
     47      """factory for ToManyRelationship"""
     48      rel =  ToManyContRelationship(id)
     49      context._setObject(rel.id, rel)
     50      if REQUEST:
     51          REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
     52      return rel.id
     53
     54
     55  addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',globals())
     56
     57
     58 -class ToManyContRelationship(ToManyRelationshipBase):
     59      """
     60      ToManyContRelationship is the ToMany side of a realtionship that
     61      contains its related objects (like the normal Zope ObjectManager)
     62      """
     63
     64      meta_type = "ToManyContRelationship"
     65
     66      security = ClassSecurityInfo()
     67
     68
     69 -    def __init__(self, id):
     70          """set our instance values"""
     71          self.id = id
     72          self._objects = OOBTree()
     73
     74
     75 -    def _safeOfObjects(self):
     76          """
     77          Try to safely return ZenPack objects rather than
     78          causing imports to fail.
     79          """
     80          objs = []
     81          for ob in self._objects.values():
     82              try:
     83                  objs.append(ob.__of__(self))
     84              except AttributeError:
     85                  log.info("Ignoring unresolvable object '%s'", str(ob))
     86          return objs
     87
     88 -    def __call__(self):
     89          """when we are called return our related object in our aq context"""
     90          return self._safeOfObjects()
     91
     92
     93 -    def __getattr__(self, name):
     94          """look in the two object stores for related objects"""
     95          if self.__dict__.has_key("_objects"):
     96              objects = self.__dict__['_objects']
     97              if objects.has_key(name): return objects[name]
     98          raise AttributeError( "Unable to find the attribute '%s'" % name )
     99
    100
    101 -    def __hasattr__(self, name):
    102          """check to see if we have an object by an id
    103          this will fail if passed a short id and object is stored
    104          with fullid (ie: it is related not contained)
    105          use hasobject to get around this issue"""
    106          return self._objects.has_key(name)
    107
    108
    109 -    def hasobject(self, obj):
    110          "check to see if we have this object"
    111          return self._objects.get(obj.id) == obj
    112
    113
    114 -    def addRelation(self, obj):
    115          """Override base to run manage_afterAdd like ObjectManager"""
    116          notify(ObjectWillBeAddedEvent(obj, self, obj.getId()))
    117          ToManyRelationshipBase.addRelation(self, obj)
    118          obj = obj.__of__(self)
    119          notify(ObjectAddedEvent(obj, self, obj.getId()))
    120          notify(ContainerModifiedEvent(self))
    121
    122
    123 -    def _setObject(self,id,object,roles=None,user=None,set_owner=1):
    124          """ObjectManager interface to add contained object."""
    125          unused(user, roles, set_owner)
    126          object.__primary_parent__ = aq_base(self)
    127          self.addRelation(object)
    128          return object.getId()
    129
    130
    131 -    def manage_afterAdd(self, item, container):
    132          # Don't do recursion anymore, a subscriber does that.
    133          pass
    134      manage_afterAdd.__five_method__ = True
    135
    136 -    def manage_afterClone(self, item):
    137          # Don't do recursion anymore, a subscriber does that.
    138          pass
    139      manage_afterClone.__five_method__ = True
    140
    141 -    def manage_beforeDelete(self, item, container):
    142          # Don't do recursion anymore, a subscriber does that.
    143          pass
    144      manage_beforeDelete.__five_method__ = True
    145
    146 -    def _add(self,obj):
    147          """add an object to one side of a ToManyContRelationship.
    148          """
    149          id = obj.id
    150          if self._objects.has_key(id):
    151              raise RelationshipExistsError
    152          v=checkValidId(self, id)
    153          if v is not None: id=v
    154          self._objects[id] = aq_base(obj)
    155          obj = aq_base(obj).__of__(self)
    156
    157
    158 -    def _remove(self, obj=None, suppress_events=False):
    159          """remove object from our side of a relationship"""
    160          if obj: objs = [obj]
    161          else: objs = self.objectValuesAll()
    162          if not suppress_events:
    163              for robj in objs:
    164                  notify(ObjectWillBeRemovedEvent(robj, self, robj.getId()))
    165          if obj:
    166              id = obj.id
    167              if not self._objects.has_key(id):
    168                  raise ObjectNotFound(
    169                      "object %s not found on %s" % (
    170                      obj.getPrimaryId(), self.getPrimaryId()))
    171              del self._objects[id]
    172          else:
    173              self._objects = OOBTree()
    174              self.__primary_parent__._p_changed = True
    175          if not suppress_events:
    176              for robj in objs:
    177                  notify(ObjectRemovedEvent(robj, self, robj.getId()))
    178              notify(ContainerModifiedEvent(self))
    179
    180
    181 -    def _remoteRemove(self, obj=None):
    182          """remove an object from the far side of this relationship
    183          if no object is passed in remove all objects"""
    184          if obj:
    185              if not self._objects.has_key(obj.id):
    186                  raise ObjectNotFound("object %s not found on %s" % (
    187                      obj.getPrimaryId(), self.getPrimaryId()))
    188              objs = [obj]
    189          else: objs = self.objectValuesAll()
    190          remoteName = self.remoteName()
    191          for obj in objs:
    192              rel = getattr(obj, remoteName)
    193              rel._remove(self.__primary_parent__)
    194
    195
    196 -    def _getOb(self, id, default=zenmarker):
    197          """look up in our local store and wrap in our aq_chain"""
    198          if self._objects.has_key(id):
    199              return self._objects[id].__of__(self)
    200          elif default == zenmarker:
    201              raise AttributeError( "Unable to find %s" % id )
    202          return default
    203
    204
    205      security.declareProtected('View', 'objectIds')
    206 -    def objectIds(self, spec=None):
    207          """only return contained objects"""
    208          if spec:
    209              if type(spec)==type('s'): spec=[spec]
    210              return [obj.id for obj in self._objects.values() \
    211                          if obj.meta_type in spec]
    212          return [ k for k in self._objects.keys() ]
    213      objectIdsAll = objectIds
    214
    215
    216      security.declareProtected('View', 'objectValues')
    217 -    def objectValues(self, spec=None):
    218          """override to only return owned objects for many to many rel"""
    219          if spec:
    220              if type(spec)==type('s'): spec=[spec]
    221              return [ob.__of__(self) for ob in self._objects.values() \
    222                          if ob.meta_type in spec]
    223          return self._safeOfObjects()
    224      security.declareProtected('View', 'objectValuesAll')
    225      objectValuesAll = objectValues
    226
    227
    228 -    def objectValuesGen(self):
    229          """Generator that returns all related objects."""
    230          for obj in self._objects.values():
    231              yield obj.__of__(self)
    232
    233
    234 -    def objectItems(self, spec=None):
    235          """over ride to only return owned objects for many to many rel"""
    236          if spec:
    237              if type(spec)==type('s'): spec=[spec]
    238              return [(key,value.__of__(self)) \
    239                  for (key,value) in self._objects.items() \
    240                      if value.meta_type in spec]
    241          return [(key,value.__of__(self)) \
    242                      for (key,value) in self._objects.items()]
    243      objectItemsAll = objectItems
    244
    245
    246  #FIXME - need to make this work
    247  #    def all_meta_types(self, interfaces=None):
    248  #        mts = []
    249  #        for mt in ToManyRelationshipBase.all_meta_types(self, interfaces):
    250  #            if (mt.has_key('instance') and mt['instance']):
    251  #                for cl in self.sub_classes:
    252  #                    if checkClass(mt['instance'], cl):
    253  #                        mts.append(mt)
    254  #        return mts
    255
    256
    257 -    def _getCopy(self, container):
    258          """
    259          make new relation add copies of contained objs
    260          and refs if the relation is a many to many
    261          """
    262          rel = self.__class__(self.id)
    263          rel.__primary_parent__ = container
    264          rel = rel.__of__(container)
    265          norelcopy = getattr(self, 'zNoRelationshipCopy', [])
    266          if self.id in norelcopy: return rel
    267          for oobj in self.objectValuesAll():
    268              cobj = oobj._getCopy(rel)
    269              rel._setObject(cobj.id, cobj)
    270          return rel
    271
    272 -    def checkValidId(self, id):
    273          """
    274          Is this a valid id for this container?
    275          """
    276          try:
    277              checkValidId(self, id)
    278          except:
    279              raise
    280          else:
    281              return True
    282
    283 -    def exportXml(self, ofile, ignorerels=[]):
    284          """Return an xml representation of a ToManyContRelationship
    285          <tomanycont id='interfaces'>
    286              <object id='hme0'
    287                  module='Products.Confmon.IpInterface' class='IpInterface'>
    288                  <property></property> etc....
    289              </object>
    290          </tomanycont>
    291          """
    292          if self.countObjects() == 0: return
    293          ofile.write("<tomanycont id='%s'>\n" % self.id)
    294          for obj in self.objectValues():
    295              obj.exportXml(ofile, ignorerels)
    296          ofile.write("</tomanycont>\n")
    297
    298
    299  InitializeClass(ToManyContRelationship)
    300
    301
    302 -class ToManyContSublocations(object):
    303      """
    304      Adapter so the event dispatching can propagate to children.
    305      """
    306 -    def __init__(self, container):
    307          self.container = container
    308 -    def sublocations(self):
    309          return (ob for ob in self.container.objectValuesAll())
    310