[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - PublicationTraverse.py:1.1.2.8

Steve Alexander steve@cat-box.net
Wed, 27 Mar 2002 17:51:43 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication
In directory cvs.zope.org:/tmp/cvs-serv12631/lib/python/Zope/App/ZopePublication

Added Files:
      Tag: Zope-3x-branch
	PublicationTraverse.py 
Log Message:
re-added this file, as it was accidentally removed a couple of minutes
ago.


=== Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1.2.7 => 1.1.2.8 ===
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+"""
+
+Revision information: $Id$
+"""
+
+from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher
+from Zope.ComponentArchitecture import getRequestView
+from Zope.App.Security.SecurityManagement import getSecurityManager
+from Zope.Publisher.Exceptions import NotFound
+from types import StringTypes
+from Zope.ContextWrapper import wrapper
+
+class DuplicateNamespaces(Exception):
+    """More than one namespave was specified in a request"""
+    
+class UnknownNamespace(Exception):
+    """A parameter specified an unknown namespace"""
+
+class ExcessiveWrapping(NotFound):
+    """Too many levels of acquisition wrapping. We don't beleive them."""
+
+class PublicationTraverse:
+
+    def traverseName(self, request, ob, name):
+
+        nm = name # the name to look up the object with
+
+        if name.find(';'):
+            # Process URI segment parameters. It makes sense to centralize
+            # this here. Later it may be abstracted and distributed again,
+            # but, if so it will be distributed to various path
+            # traversers, rather than to traversal adapters/views.
+            ns = ''
+            parts = name.split(';')
+            nm = parts[:1]
+            for param in parts[1:]:
+                l = param.find('=')
+                if l >= 0:
+                    pname = param[:l]
+                    pval = param[l+1:]
+                    if pname == 'ns':
+                        if ns:
+                            raise DuplicateNamespaces(name)
+                        ns = pval
+                    else:
+                        pset = getattr(self, "_parameterSet%s" % pname,
+                                       self # marker
+                                       )
+                        if pset is self:
+                            # We don't know about this one, so leave it in the
+                            # name
+                            nm.append(param)
+                        else:
+                            pset(pname, pval, request)
+                else:
+                    if ns:
+                        raise DuplicateNamespaces(name)
+                    ns = param
+
+            nm = ';'.join(nm)
+            if ns:
+                traverse = getattr(self, "_traverse%s" % ns,
+                                   self # marker
+                                   )
+                if traverse is self:
+                    raise UnknownNamespace(ns, name)
+
+                ob2 = traverse(request, ob, nm)
+                return self._wrap(ob2, ob, name, nm)
+            elif not nm:
+                # Just set params, so skip
+                return ob
+
+        if nm == '.':
+            return ob
+                
+        if IBrowserPublisher.isImplementedBy(ob):
+            ob2 = ob.browser_traverse(request, nm)
+        else:
+            adapter = getRequestView(ob, '_traverse', request, self # marker
+                                     ) 
+
+            if adapter is not self:
+                ob2 =  adapter.browser_traverse(request, nm)
+            else:
+                raise NotFound(ob, name, request)
+
+        return self._wrap(ob2, ob, name, nm)
+
+    def _wrap(self, ob, parent, name, nm):
+        wrapped = wrapper.Wrapper(ob, parent, name=name)
+        getSecurityManager().validate(nm, wrapped)
+        return wrapped
+
+    def _traverseview(self, request, ob, name):
+        # use self as marker
+        r = getRequestView(ob, name, request, self)
+        if r is self: 
+            raise NotFound(ob, name, request)
+        return r
+
+    def _traverseetc(self, request, ob, name):
+        # XXX
+        
+        # This is here now to allow us to get service managers from a
+        # separate namespace from the content. We add and etc
+        # namespace to allow us to handle misc objects.  We'll apply
+        # YAGNI for now and hard code this. We'll want something more
+        # general later. We were thinking of just calling "get"
+        # methods, but this is probably too magic. In particular, we
+        # will treat returned objects as sub-objects wrt security and
+        # not all get methods may satisfy this assumption. It might be
+        # best to introduce some sort of etc registry.
+
+        if name != 'Services':
+            raise NotFound(ob, name, request)
+            
+        
+        method_name = "getServiceManager"
+        method = getattr(ob, method_name, self)
+        if method is self: 
+            raise NotFound(ob, name, request)
+        # Check access
+        self._wrap(method, ob, name, name)
+
+        return method()
+
+    def _traverseacquire(self, request, ob, name):
+        i = 0
+        while i < 200:
+            i = i + 1
+            r = getattr(ob, name, self)
+            if r is not self:
+                return r
+            r = getcontext(ob)
+            if r is None:
+                raise NotFound(ob, name, request)
+        raise ExcessiveWrapping(ob, name, request)
+
+class PublicationTraverser(PublicationTraverse):    
+
+    def traversePath(self, request, ob, path):
+
+        if isinstance(path, StringTypes):
+            path = path.split('/')
+            if len(path) > 1 and not path[-1]:
+                # Remove trailing slash
+                path.pop()
+        else:
+            path = list(path)
+
+        # Remove dingle dots
+        path = [x for x in path if x != '.']
+
+        path.reverse()
+
+        # Remove double dots
+        while '..' in path:
+            l = path.index('..')
+            if l < 0 or l+2 > len(path):
+                break
+            del path[l:l+2]
+                     
+        pop = path.pop
+
+        while path:
+            name = pop()
+            ob = self.traverseName(request, ob, name)
+
+        return ob