[Checkins] SVN: z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/ Implement shared locking a bit better. We do this by pretending that we can

Michael Kerrin michael.kerrin at openapp.ie
Thu Jun 7 17:03:20 EDT 2007


Log message for revision 76479:
  Implement shared locking a bit better. We do this by pretending that we can
  create multiple shared lock tokens on a resource by storing all the extra
  information for the second shared lock token in the locks annotation.
  

Changed:
  U   z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/configure.zcml
  U   z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/ftests.py
  U   z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/manager.py
  U   z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/properties.py

-=-
Modified: z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/configure.zcml
===================================================================
--- z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/configure.zcml	2007-06-07 20:35:17 UTC (rev 76478)
+++ z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/configure.zcml	2007-06-07 21:03:19 UTC (rev 76479)
@@ -16,7 +16,7 @@
   <class class=".manager.DAVLockmanager">
     <require
        permission="zope.View"
-       attributes="getActivelock islocked islockable"
+       attributes="islocked islockable"
        />
 
     <require
@@ -25,20 +25,6 @@
        />
   </class>
 
-  <adapter
-     factory=".properties.DAVActiveLock"
-     for="zope.interface.Interface
-          zope.publisher.interfaces.http.IHTTPRequest"
-     provides="z3c.dav.coreproperties.IActiveLock"
-     />
-
-  <class class=".properties.DAVActiveLockAdapter">
-    <require
-       permission="zope.View"
-       interface="z3c.dav.coreproperties.IActiveLock"
-       />
-  </class>
-
   <class class=".indirecttokens.IndirectToken">
     <require
        permission="zope.View"

Modified: z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/ftests.py
===================================================================
--- z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/ftests.py	2007-06-07 20:35:17 UTC (rev 76478)
+++ z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/ftests.py	2007-06-07 21:03:19 UTC (rev 76479)
@@ -306,28 +306,34 @@
         locktoken = locktoken[1:-1] # remove the <> characters
 
         token = self.utility.get(self.getRootFolder())
-        self.assertEqual(
-            token.annotations["z3c.dav.lockingutils.info"]["token"],
-            locktoken)
+        tokendata = token.annotations["z3c.dav.lockingutils.info"]
+        self.assert_(locktoken in tokendata)
+        assertXMLEqual(
+            tokendata[locktoken]["owner"],
+            """<owner xmlns="DAV:">
+<href>http://example.org/~ejw/contact.html</href>
+</owner>""")
         token = self.utility.get(self.getRootFolder()["a"])
-        self.assertEqual(
-            token.annotations["z3c.dav.lockingutils.info"]["token"],
-            locktoken)
+        self.assert_(
+            locktoken in token.annotations["z3c.dav.lockingutils.info"])
 
         root = self.getRootFolder()
         self.assertEqual(
-            IDAVLockmanager(root).getActivelock().locktoken[0], locktoken)
+            IDAVLockmanager(root).getActivelock(locktoken).locktoken[0],
+            locktoken)
         self.assertEqual(
-            IDAVLockmanager(root["a"]["r2"]).getActivelock().locktoken[0],
+            IDAVLockmanager(root["a"]["r2"]).getActivelock(
+                locktoken).locktoken[0],
             locktoken)
 
         request = z3c.dav.publisher.WebDAVRequest(
             StringIO(""), {"HTTP_HOST": "localhost"})
 
-        lockroot = IDAVLockmanager(root).getActivelock(request).lockroot
+        lockroot = IDAVLockmanager(root).getActivelock(
+            locktoken, request).lockroot
         self.assertEqual(lockroot, "http://localhost")
         lockroot = IDAVLockmanager(root["a"]["r3"]).getActivelock(
-            request).lockroot
+            locktoken, request).lockroot
         self.assertEqual(lockroot, "http://localhost")
 
     def test_lock_collection_depth_inf_withlockedsubitem(self):
@@ -418,7 +424,8 @@
         self.assertEqual(response.getStatus(), 200)
         self.assertEqual(response.getHeader("content-type"), "application/xml")
         locktoken = response.getHeader("lock-token")
-        self.assert_(locktoken and locktoken[0] == "<" and locktoken[-1] == ">")
+        self.assert_(
+            locktoken and locktoken[0] == "<" and locktoken[-1] == ">")
 
         httpresponse = self.checkPropfind(
             "/a/r2", env = {"DEPTH": "0", "CONTENT_TYPE": "text/xml"},
@@ -485,16 +492,17 @@
             StringIO(""), {"HTTP_HOST": "localhost"})
 
         lockmanager = IDAVLockmanager(rootfolder)
-        self.assertEqual(lockmanager.getActivelock(request).lockroot,
-                         "http://localhost/a")
+        self.assertEqual(lockmanager.getActivelock(
+            locktoken, request).lockroot, "http://localhost/a")
         self.assertEqual(
-            lockmanager.getActivelock().locktoken[0], locktoken[1:-1])
+            lockmanager.getActivelock(locktoken).locktoken[0], locktoken)
 
         lockmanager = IDAVLockmanager(subresource)
-        self.assertEqual(lockmanager.getActivelock(request).lockroot,
-                         "http://localhost/a")
         self.assertEqual(
-            lockmanager.getActivelock().locktoken[0], locktoken[1:-1])
+            lockmanager.getActivelock(locktoken, request).lockroot,
+            "http://localhost/a")
+        self.assertEqual(
+            lockmanager.getActivelock(locktoken).locktoken[0], locktoken)
 
     def test_lock_invalid_depth(self):
         file = self.addResource("/testresource", "some file content",
@@ -528,10 +536,13 @@
         owner = """<D:owner xmlns:D="DAV:">
 <D:href>mailto:michael</D:href>
 </D:owner>"""
-        lockmanager.lock(u"exclusive", u"write", owner,
-                         datetime.timedelta(seconds = 1000), "infinity")
-        locktoken = lockmanager.getActivelock().locktoken[0]
-        self.assertEqual(lockmanager.getActivelock().timeout, u"Second-1000")
+        locktoken = lockmanager.lock(u"exclusive", u"write", owner,
+                                     datetime.timedelta(seconds = 1000),
+                                     "infinity")
+        ltoken = lockmanager.getActivelock(locktoken).locktoken[0]
+        self.assert_(ltoken == locktoken)
+        self.assertEqual(
+            lockmanager.getActivelock(locktoken).timeout, u"Second-1000")
         transaction.commit()
         self.logout()
 
@@ -629,17 +640,17 @@
 
         lockmanager = IDAVLockmanager(file)
         self.assertEqual(lockmanager.islocked(), False)
-        lockmanager.lock(scope = "exclusive", type = "write",
-                         owner = """<D:owner xmlns:D="DAV:">
+        locktoken = lockmanager.lock(
+            scope = "exclusive", type = "write",
+            owner = """<D:owner xmlns:D="DAV:">
   <D:href>mailto:michael at linux</D:href>
 </D:owner>""",
-                         duration = datetime.timedelta(100),
-                         depth = "0")
+            duration = datetime.timedelta(100),
+            depth = "0")
         transaction.commit()
 
         lockmanager = IDAVLockmanager(file)
         self.assertEqual(lockmanager.islocked(), True)
-        locktoken = lockmanager.getActivelock().locktoken[0]
 
         # end the current interaction
         self.logout()

Modified: z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/manager.py
===================================================================
--- z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/manager.py	2007-06-07 20:35:17 UTC (rev 76478)
+++ z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/manager.py	2007-06-07 21:03:19 UTC (rev 76479)
@@ -16,15 +16,13 @@
 the zope.locking utiltity to integrate it into z3c.dav.
 """
 
-import time
-import random
 from BTrees.OOBTree import OOBTree
 import zope.component
 import zope.interface
-from zope.security.proxy import removeSecurityProxy
-from zope.traversing.browser.absoluteurl import absoluteURL
+import zope.security.management
 from zope.app.container.interfaces import IReadContainer
 import z3c.dav.interfaces
+import z3c.dav.locking
 
 import interfaces
 import indirecttokens
@@ -32,14 +30,13 @@
 
 WEBDAV_LOCK_KEY = "z3c.dav.lockingutils.info"
 
-_randGen = random.Random(time.time())
-
 class DAVLockmanager(object):
     """
 
       >>> from zope.interface.verify import verifyObject
       >>> from zope.locking import utility, utils
       >>> from zope.locking.adapters import TokenBroker
+      >>> from zope.traversing.browser.absoluteurl import absoluteURL
 
       >>> file = Demo()
 
@@ -79,17 +76,13 @@
 
     Lock with an exclusive lock token.
 
-      >>> roottoken = adapter.lock(u'exclusive', u'write',
+      >>> locktoken = adapter.lock(u'exclusive', u'write',
       ...    u'Michael', datetime.timedelta(seconds = 3600), '0')
-      >>> util.get(file) == roottoken
-      True
-      >>> zope.locking.interfaces.IExclusiveLock.providedBy(roottoken)
-      True
 
       >>> adapter.islocked()
       True
 
-      >>> activelock = adapter.getActivelock()
+      >>> activelock = adapter.getActivelock(locktoken)
       >>> activelock.lockscope
       [u'exclusive']
       >>> activelock.locktype
@@ -102,53 +95,76 @@
       '/dummy'
       >>> activelock.owner
       u'Michael'
+      >>> len(activelock.locktoken)
+      1
+      >>> activelock.locktoken #doctest:+ELLIPSIS
+      ['opaquelocktoken:...
 
+      >>> util.get(file) == activelock.token
+      True
+      >>> zope.locking.interfaces.IExclusiveLock.providedBy(activelock.token)
+      True
+
+    Now refresh the timeout on the locktoken.
+
       >>> adapter.refreshlock(datetime.timedelta(seconds = 7200))
-      >>> adapter.getActivelock().timeout
+      >>> adapter.getActivelock(locktoken).timeout
       u'Second-7200'
 
-      >>> adapter.unlock()
+    Unlock the resource.
+
+      >>> adapter.unlock(locktoken)
       >>> util.get(file) is None
       True
       >>> adapter.islocked()
       False
-      >>> adapter.getActivelock() is None
+      >>> adapter.getActivelock(locktoken) is None
       True
 
+    We can't unlock the resource twice.
+
+      >>> adapter.unlock(locktoken)
+      Traceback (most recent call last):
+      ...
+      ConflictError: The context is not locked, so we can't unlock it.
+
     Shared locking support.
 
-      >>> roottoken = adapter.lock(u'shared', u'write', u'Michael',
+      >>> locktoken = adapter.lock(u'shared', u'write', u'Michael',
       ...    datetime.timedelta(seconds = 3600), '0')
-      >>> util.get(file) == roottoken
-      True
-      >>> zope.locking.interfaces.ISharedLock.providedBy(roottoken)
-      True
 
-      >>> activelock = adapter.getActivelock()
+      >>> activelock = adapter.getActivelock(locktoken)
       >>> activelock.lockscope
       [u'shared']
+      >>> len(activelock.locktoken)
+      1
       >>> activelock.locktoken #doctest:+ELLIPSIS
       ['opaquelocktoken:...
 
-      >>> adapter.unlock()
+      >>> util.get(file) == activelock.token
+      True
+      >>> zope.locking.interfaces.ISharedLock.providedBy(activelock.token)
+      True
 
+      >>> adapter.unlock(locktoken)
+
     Recursive lock suport.
 
       >>> demofolder = DemoFolder()
       >>> demofolder['demo'] = file
 
       >>> adapter = DAVLockmanager(demofolder)
-      >>> roottoken = adapter.lock(u'exclusive', u'write', u'MichaelK',
-      ...    datetime.timedelta(seconds = 3600), 'infinity')
+      >>> locktoken = adapter.lock(u'exclusive', u'write',
+      ...    u'MichaelK', datetime.timedelta(seconds = 3600), 'infinity')
 
       >>> demotoken = util.get(file)
       >>> interfaces.IIndirectToken.providedBy(demotoken)
       True
 
-      >>> activelock = adapter.getActivelock()
+      >>> activelock = adapter.getActivelock(locktoken)
       >>> activelock.lockroot
       '/dummy/'
-      >>> DAVLockmanager(file).getActivelock().lockroot
+      >>> DAVLockmanager(file).getActivelock(locktoken).lockroot
       '/dummy/'
       >>> absoluteURL(file, None)
       '/dummy/dummy'
@@ -164,8 +180,11 @@
       AlreadyLocked...
       >>> adapter.islocked()
       True
+      >>> activelock = adapter.getActivelock(locktoken)
+      >>> len(activelock.locktoken)
+      1
 
-      >>> adapter.unlock()
+      >>> adapter.unlock(locktoken[0])
 
     Some error conditions.
 
@@ -193,71 +212,129 @@
     def __init__(self, context):
         self.context = self.__parent__ = context
 
-    def generateLocktoken(self):
-        return "opaquelocktoken:%s-%s-00105A989226:%.03f" % \
-               (_randGen.random(), _randGen.random(), time.time())
-
     def islockable(self):
         utility = zope.component.queryUtility(
             zope.locking.interfaces.ITokenUtility,
             context = self.context, default = None)
         return utility is not None
 
-    def lock(self, scope, type, owner, duration, depth,
-             roottoken = None, context = None):
-        if context is None:
-            context = self.context
+    def maybeRecursivelyLockIndirectly(self, utility,
+                                       context, roottoken, depth):
+        if depth == "infinity" and IReadContainer.providedBy(context):
+            for subob in context.values():
+                token = utility.get(subob)
+                if token:
+                    raise z3c.dav.interfaces.AlreadyLocked(
+                        subob, message = u"Sub-object is already locked")
+                indirecttoken = indirecttokens.IndirectToken(subob, roottoken)
+                utility.register(indirecttoken)
+                self.maybeRecursivelyLockIndirectly(
+                    utility, subob, roottoken, depth)
 
-        tokenBroker = zope.locking.interfaces.ITokenBroker(context)
-        if tokenBroker.get():
+    def register(self, utility, token):
+        try:
+            return utility.register(token)
+        except zope.locking.interfaces.RegistrationError:
             raise z3c.dav.interfaces.AlreadyLocked(
-                context, message = u"Context or subitem is already locked.")
+                token.context, message = u"Context is locked")
 
-        if roottoken is None:
-            if scope == u"exclusive":
-                roottoken = tokenBroker.lock(duration = duration)
-            elif scope == u"shared":
-                roottoken = tokenBroker.lockShared(duration = duration)
-            else:
-                raise z3c.dav.interfaces.UnprocessableError(
-                    self.context,
-                    message = u"Invalid lockscope supplied to the lock manager")
+    def lock(self, scope, type, owner, duration, depth):
+        principal_id = getPrincipalId()
+        utility = zope.component.getUtility(
+            zope.locking.interfaces.ITokenUtility, context = self.context)
 
-            annots = roottoken.annotations.get(WEBDAV_LOCK_KEY, None)
-            if annots is None:
+        locktoken = z3c.dav.locking.generateLocktoken()
+
+        if scope == u"exclusive":
+            roottoken = self.register(
+                utility, zope.locking.tokens.ExclusiveLock(
+                    self.context, principal_id, duration = duration))
+            annots = roottoken.annotations[WEBDAV_LOCK_KEY] = OOBTree()
+        elif scope == u"shared":
+            # A successful request for a new shared lock MUST result in the
+            # generation of a unique lock associated with the requesting
+            # principal. Thus if five principals have taken out shared write
+            # locks on the same resource there will be five locks and five
+            # lock tokens, one for each principal.
+            roottoken = utility.get(self.context)
+            if roottoken is None:
+                roottoken = self.register(
+                    utility, zope.locking.tokens.SharedLock(
+                        self.context, (principal_id,), duration = duration))
                 annots = roottoken.annotations[WEBDAV_LOCK_KEY] = OOBTree()
-            annots["owner"] = owner
-            annots["token"] = self.generateLocktoken()
-            annots["depth"] = depth
+                annots["principal_ids"] = [principal_id]
+            else:
+                roottoken.add((principal_id,))
+                if WEBDAV_LOCK_KEY not in roottoken.annotations:
+                    # Locked by an alternative application
+                    annots = roottoken.annotations[WEBDAV_LOCK_KEY] = OOBTree()
+                    # Use OOBTree here
+                    annots["principal_ids"] = [principal_id]
+                else:
+                    annots = roottoken.annotations[WEBDAV_LOCK_KEY]
+                    annots["principal_ids"].append(principal_id)
         else:
-            indirecttoken = indirecttokens.IndirectToken(context, roottoken)
-            ## XXX - using removeSecurityProxy - is this right, has
-            ## it seems wrong
-            removeSecurityProxy(roottoken).utility.register(indirecttoken)
+            raise z3c.dav.interfaces.UnprocessableError(
+                self.context,
+                message = u"Invalid lockscope supplied to the lock manager")
 
-        if depth == "infinity" and IReadContainer.providedBy(context):
-            for subob in context.values():
-                self.lock(scope, type, owner, duration, depth,
-                          roottoken, subob)
+        annots[locktoken] = OOBTree()
+        annots[locktoken].update({"owner": owner, "depth": depth})
 
-        return roottoken
+        self.maybeRecursivelyLockIndirectly(
+            utility, self.context, roottoken, depth)
 
-    def getActivelock(self, request = None):
+        return locktoken
+
+    def getActivelock(self, locktoken, request = None):
         if self.islocked():
             token = zope.locking.interfaces.ITokenBroker(self.context).get()
-            return properties.DAVActiveLockAdapter(
-                token, self.context, request)
+            return properties.DAVActiveLock(
+                locktoken, token, self.context, request)
         return None
 
     def refreshlock(self, timeout):
         token = zope.locking.interfaces.ITokenBroker(self.context).get()
         token.duration = timeout
 
-    def unlock(self):
-        tokenBroker = zope.locking.interfaces.ITokenBroker(self.context)
-        token = tokenBroker.get()
-        token.end()
+    def unlock(self, locktoken):
+        utility = zope.component.getUtility(
+            zope.locking.interfaces.ITokenUtility, context = self.context)
+        token = utility.get(self.context)
+        if token is None:
+            raise z3c.dav.interfaces.ConflictError(
+                self.context,
+                message = "The context is not locked, so we can't unlock it.")
 
+        if interfaces.IIndirectToken.providedBy(token):
+            token = token.roottoken
+
+        if zope.locking.interfaces.IExclusiveLock.providedBy(token):
+            token.end()
+        elif zope.locking.interfaces.ISharedLock.providedBy(token):
+            principal_id = getPrincipalId()
+            annots = token.annotations[WEBDAV_LOCK_KEY]
+            del annots[locktoken]
+            annots["principal_ids"].remove(principal_id)
+            if principal_id not in annots["principal_ids"]:
+                # will end token if no principals left
+                token.remove((principal_id,))
+        else:
+            raise ValueError("Unknown lock token")
+
     def islocked(self):
         tokenBroker = zope.locking.interfaces.ITokenBroker(self.context)
         return tokenBroker.get() is not None
+
+
+def getPrincipalId():
+    principal_ids = [
+        participation.principal.id
+        for participation in
+        zope.security.management.getInteraction().participations]
+
+    if len(principal_ids) != 1:
+        raise ValueError("There must be only one participant principal")
+    principal_id = principal_ids[0]
+
+    return principal_id

Modified: z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/properties.py
===================================================================
--- z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/properties.py	2007-06-07 20:35:17 UTC (rev 76478)
+++ z3c.davapp.zopelocking/trunk/src/z3c/davapp/zopelocking/properties.py	2007-06-07 21:03:19 UTC (rev 76479)
@@ -117,10 +117,7 @@
         return [ExclusiveLockEntry(), SharedLockEntry()]
 
 
- at component.adapter(interface.Interface,
-                   zope.publisher.interfaces.http.IHTTPRequest)
- at interface.implementer(IActiveLock)
-def DAVActiveLock(context, request):
+class DAVActiveLock(object):
     """
     This adapter is responsible for the data for the `{DAV:}activelock`
     XML element. This XML element occurs within the `{DAV:}lockdiscovery`
@@ -134,7 +131,6 @@
       >>> import zope.locking.utils
       >>> from zope.locking import tokens
       >>> from zope.locking.utility import TokenUtility
-      >>> from zope.locking.adapters import TokenBroker
       >>> from z3c.dav.publisher import WebDAVRequest
       >>> import indirecttokens
 
@@ -143,13 +139,8 @@
       >>> oldNow = zope.locking.utils.now
       >>> zope.locking.utils.now = hackNow
 
-    The activelock property only exists whenever the zope.locking package
-    is configured properly.
-
       >>> resource = DemoFolder()
       >>> request = WebDAVRequest(StringIO(''), {})
-      >>> DAVActiveLock(resource, request) is None
-      True
 
     Now register a ITokenUtility utility and lock the resource with it.
 
@@ -165,14 +156,7 @@
     content object to zope.locking.interfaces.ITokenBroker. This is part
     of the zope.locking installation that hasn't been completed yet.
 
-      >>> DAVActiveLock(resource, request) is None
-      True
-
-      >>> component.getGlobalSiteManager().registerAdapter(
-      ...    TokenBroker, (interface.Interface,),
-      ...    zope.locking.interfaces.ITokenBroker)
-
-      >>> activelock = DAVActiveLock(resource, request)
+      >>> activelock = DAVActiveLock(None, locktoken, resource, request)
       >>> IActiveLock.providedBy(activelock)
       True
       >>> verifyObject(IActiveLock, activelock)
@@ -215,15 +199,6 @@
       ...    z3c.dav.coreproperties.lockdiscovery,
       ...    lockdiscovery, request)
       >>> print etree.tostring(davwidget.render()) #doctest:+XMLDATA
-      <lockdiscovery xmlns="DAV:" />
-
-      >>> component.getGlobalSiteManager().registerAdapter(DAVActiveLock)
-
-      >>> lockdiscovery = DAVLockdiscovery(resource, request)
-      >>> davwidget = z3c.dav.properties.getWidget(
-      ...    z3c.dav.coreproperties.lockdiscovery,
-      ...    lockdiscovery, request)
-      >>> print etree.tostring(davwidget.render()) #doctest:+XMLDATA
       <lockdiscovery xmlns="DAV:">
         <activelock>
           <lockscope><exclusive /></lockscope>
@@ -237,16 +212,17 @@
     We use the lock tokens annotation to store the data for the owner, depth
     and locktoken attributes.
 
-      >>> locktoken.annotations[WEBDAV_LOCK_KEY] = OOBTree()
-      >>> locktoken.annotations[WEBDAV_LOCK_KEY]['depth'] = 'testdepth'
-      >>> locktoken.annotations[WEBDAV_LOCK_KEY]['owner'] = '<owner xmlns="DAV:">Me</owner>'
-      >>> locktoken.annotations[WEBDAV_LOCK_KEY]['token'] = 'simpletoken'
+      >>> locktokendata=  locktoken.annotations[WEBDAV_LOCK_KEY] = OOBTree()
+      >>> locktokendata['simpletoken'] = OOBTree()
+      >>> locktokendata['simpletoken']['depth'] = 'testdepth'
+      >>> locktokendata['simpletoken']['owner'] = '<owner xmlns="DAV:">Me</owner>'
 
     After updating the lock token's annotations we need to regenerate the
     activelock adapter so that the tokendata internal attribute is setup
     correctly.
 
-      >>> activelock = DAVActiveLock(resource, request)
+      >>> activelock = DAVActiveLock(
+      ...    'simpletoken', locktoken, resource, request)
 
     The owner attribute is not required by the WebDAV specification, but
     we can see it anyways, and similarly for the locktoken attribute.
@@ -288,7 +264,8 @@
       ...    resource['demo'], locktoken)
       >>> sublocktoken = util.register(sublocktoken)
 
-      >>> activelock = DAVActiveLock(resource['demo'], request)
+      >>> activelock = DAVActiveLock(
+      ...    'simpletoken', sublocktoken, resource['demo'], request)
       >>> verifyObject(IActiveLock, activelock)
       True
 
@@ -341,7 +318,7 @@
       ...    resource, datetime.timedelta(hours = 1))
       >>> locktoken = util.register(locktoken)
 
-      >>> activelock = DAVActiveLock(resource, request)
+      >>> activelock = DAVActiveLock(None, locktoken, resource, request)
       >>> IActiveLock.providedBy(activelock)
       True
 
@@ -396,7 +373,7 @@
       >>> locktoken = tokens.ExclusiveLock(resource, 'michael')
       >>> locktoken = util.register(locktoken)
 
-      >>> activelock = DAVActiveLock(resource, request)
+      >>> activelock = DAVActiveLock(None, locktoken, resource, request)
       >>> verifyObject(IActiveLock, activelock)
       True
       >>> activelock.timeout is None
@@ -423,32 +400,16 @@
       >>> component.getGlobalSiteManager().unregisterUtility(
       ...    util, zope.locking.interfaces.ITokenUtility)
       True
-      >>> component.getGlobalSiteManager().unregisterAdapter(
-      ...    TokenBroker, (interface.Interface,),
-      ...    zope.locking.interfaces.ITokenBroker)
-      True
-      >>> component.getGlobalSiteManager().unregisterAdapter(DAVActiveLock)
-      True
 
     """
-    try:
-        token = zope.locking.interfaces.ITokenBroker(context).get()
-    except TypeError:
-        token = None
-    if token is None:
-        return None
-    return DAVActiveLockAdapter(token, context, request)
-
-
-class DAVActiveLockAdapter(object):
-    component.adapts(interface.Interface,
-                     z3c.dav.interfaces.IWebDAVRequest)
     interface.implements(IActiveLock)
 
-    def __init__(self, token, context, request):
+    def __init__(self, locktoken, token, context, request):
         self.context = self.__parent__ = context
+        self._locktoken = locktoken
         self.token = token
-        self.tokendata = token.annotations.get(WEBDAV_LOCK_KEY, {})
+        self.tokendata = token.annotations.get(
+            WEBDAV_LOCK_KEY, {}).get(locktoken, {})
         self.request = request
 
     @property
@@ -486,10 +447,7 @@
 
     @property
     def locktoken(self):
-        token = self.tokendata.get("token", None)
-        if token is None:
-            return None
-        return [token]
+        return self._locktoken and [self._locktoken]
 
     @property
     def lockroot(self):
@@ -501,7 +459,8 @@
         return absoluteURL(root, self.request)
 
 
- at component.adapter(interface.Interface, z3c.dav.interfaces.IWebDAVRequest)
+ at component.adapter(
+    interface.Interface, zope.publisher.interfaces.http.IHTTPRequest)
 @interface.implementer(z3c.dav.coreproperties.IDAVLockdiscovery)
 def DAVLockdiscovery(context, request):
     """
@@ -553,7 +512,7 @@
       1
       >>> IActiveLock.providedBy(lockdiscovery[0])
       True
-      >>> isinstance(lockdiscovery[0], DAVActiveLockAdapter)
+      >>> isinstance(lockdiscovery[0], DAVActiveLock)
       True
 
     Cleanup
@@ -574,7 +533,7 @@
     utility = component.queryUtility(zope.locking.interfaces.ITokenUtility)
     if utility is None:
         return None
-    return DAVLockdiscoveryAdapter(context, request)
+    return DAVLockdiscoveryAdapter(context, request, utility)
 
 
 class DAVLockdiscoveryAdapter(object):
@@ -582,14 +541,26 @@
     component.adapts(interface.Interface,
                      z3c.dav.interfaces.IWebDAVRequest)
 
-    def __init__(self, context, request):
+    def __init__(self, context, request, utility):
         self.context = context
         self.request = request
+        self.utility = utility
 
     @property
     def lockdiscovery(self):
-        adapter = component.queryMultiAdapter((self.context, self.request),
-                                              IActiveLock, default = None)
-        if adapter is None:
+        token = self.utility.get(self.context)
+        if token is None:
             return None
-        return [adapter]
+
+        activelocks = []
+        for locktoken in token.annotations.get(WEBDAV_LOCK_KEY, {}).keys():
+            if locktoken != "principal_ids":
+                activelocks.append(DAVActiveLock(locktoken, token,
+                                                 self.context, self.request))
+        if activelocks:
+            return activelocks
+
+        # Probable a non-webdav client / application created this lock.
+        # We probable need an other active lock implementation to handle
+        # this case.
+        return [DAVActiveLock(None, token, self.context, self.request)]



More information about the Checkins mailing list