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