[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - ITraverser.py:1.2 PublicationTraverse.py:1.2 Traversers.py:1.2 ZopePublication.py:1.2 __init__.py:1.2 zopepublication.zcml:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:29:50 -0400


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

Added Files:
	ITraverser.py PublicationTraverse.py Traversers.py 
	ZopePublication.py __init__.py zopepublication.zcml 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/App/ZopePublication/ITraverser.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################


=== Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.ComponentArchitecture import queryView, getService
+from Zope.Publisher.Exceptions import NotFound
+from types import StringTypes
+from Zope.Proxy.ContextWrapper import ContextWrapper, getWrapperContext
+
+from Zope.App.OFS.Container.IContainer import IWriteContainer
+from Zope.App.OFS.ApplicationControl.ApplicationControl \
+     import ApplicationController
+from Zope.Proxy.ProxyIntrospection import removeAllProxies
+from Zope.App.Traversing.Namespaces import namespaceLookup
+from Zope.App.Traversing.ParameterParsing import parameterizedNameParse
+from Zope.Publisher.IPublishTraverse import IPublishTraverse
+
+class DuplicateNamespaces(Exception):
+    """More than one namespace was specified in a request"""
+    
+class UnknownNamespace(Exception):
+    """A parameter specified an unknown namespace"""
+
+class PublicationTraverse:
+
+    def traverseName(self, request, ob, name):
+
+        nm = name # the name to look up the object with
+
+        if name and name[:1] in '@+':
+            # Process URI segment parameters. 
+            ns, nm, parms = parameterizedNameParse(name)
+
+            unknown_parms = ()
+            for pname, pval in parms:
+                pset = getattr(self, "_parameterSet%s" % pname,
+                               self # marker
+                               )
+                if pset is self:
+                    # We don't know about this one
+                    unknown_parms += ((pname, pval),)
+                else:
+                    pset(pname, pval, request)
+
+            if ns:
+                ob2 = namespaceLookup(name, ns, nm, unknown_parms, ob, request)
+                return ContextWrapper(ob2, ob, name=name)
+
+            if unknown_parms:
+                nm = "%s;%s" % (
+                    nm,
+                    ';'.join(["%s=%s" % (parm[0], parm[1])
+                              for parm in unknown_parms])
+                    )
+                
+            if not nm:
+                # Just set params, so skip
+                return ob
+
+        if nm == '.':
+            return ob
+                
+        if IPublishTraverse.isImplementedBy(removeAllProxies(ob)):
+            ob2 = ob.publishTraverse(request, nm)
+        else:
+            adapter = queryView(ob, '_traverse', request, self # marker
+                                     ) 
+
+            if adapter is not self:
+                ob2 =  adapter.publishTraverse(request, nm)
+            else:
+                raise NotFound(ob, name, request)
+
+        return ContextWrapper(ob2, ob, name=name)
+
+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


=== Zope3/lib/python/Zope/App/ZopePublication/Traversers.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+from Zope.Publisher.Exceptions import Unauthorized, NotFound, DebugError
+from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher
+from Zope.ComponentArchitecture \
+     import getView, getDefaultViewName
+from Zope.ComponentArchitecture.Exceptions import ComponentLookupError
+
+class SimpleComponentTraverser:
+    """Browser traverser for simple components that can only traverse to views
+    """
+    __implements__ = IBrowserPublisher
+
+    def __init__(self, target, request):
+        self.target = target
+
+    def browserDefault(self, request):
+        ob = self.target
+        
+        view_name = getDefaultViewName(ob, request)
+
+        return ob, (view_name,)
+
+    def publishTraverse(self, request, name):
+        ob = self.target
+        try:
+            return getView(ob, name, request)
+        except ComponentLookupError:
+            raise NotFound(ob, name)
+
+
+
+class FileContentTraverser(SimpleComponentTraverser):
+    """Browser traverser for file content.
+
+    The default view for file content has effective URLs that don't end in
+    /.  In particular, if the content inclused HTML, relative links in
+    the HTML are relative to the container the content is in.
+
+    """
+
+    def browserDefault(self, request):
+        ob = self.target
+        
+        view_name = getDefaultViewName(ob, request)
+        view = self.publishTraverse(request, view_name)
+        if hasattr(view, 'browserDefault'):
+            view, path = view.browserDefault(request)
+            if len(path) == 1:
+                view = view.publishTraverse(request, path[0])
+                path = ()
+        else:
+            path = ()
+                
+        return view, path
+
+class TestTraverser:
+    "Bobo-style traverser, mostly useful for testing" 
+
+    __implements__ = IBrowserPublisher
+
+    def __init__(self, target, request):
+        self.target = target
+
+    def browserDefault(self, request):
+        ob = self.target
+
+        if hasattr(ob, '__implements__'):
+        
+            view_name = getDefaultViewName(ob, request)
+
+            return ob, (("@@%s" % view_name),)
+        
+        return ob, ()
+
+    def publishTraverse(self, request, name):
+        ob = self.target
+        if name.startswith('@@'):
+            return getView(ob, name[6:], request)
+            
+        if name.startswith('_'):
+            raise Unauthorized("Name %s begins with an underscore" % `name`)
+
+        subob = getattr(ob, name, self) # self is marker here
+        if subob is self:
+            # no attribute
+            try:
+                subob = ob[name]
+            except (KeyError, IndexError,
+                    TypeError, AttributeError):
+                raise NotFound(ob, name, request)
+
+        return subob


=== Zope3/lib/python/Zope/App/ZopePublication/ZopePublication.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+import sys
+from types import StringType, ClassType
+
+from zLOG import LOG, ERROR, INFO
+from Zope.Publisher.DefaultPublication import DefaultPublication
+from Zope.Publisher.mapply import mapply
+from Zope.Publisher.Exceptions import Retry
+from Zope.Security.SecurityManagement import getSecurityManager
+from Zope.Security.SecurityManagement import newSecurityManager
+from Zope.App.Security.PrincipalRegistry import principalRegistry as prin_reg
+from Zope.Exceptions import Unauthorized
+
+from ZODB.POSException import ConflictError
+from Zope.App.OFS.Content.Folder.RootFolder import RootFolder
+from PublicationTraverse import PublicationTraverse
+
+from Zope.Security.Checker import ProxyFactory
+
+class RequestContainer:
+    # TODO: add security assertion declaring access to REQUEST
+
+    def __init__(self, request):
+        self.REQUEST = request
+
+
+class Cleanup:
+    def __init__(self, f):
+        self.__del__ = f
+
+
+try: get_transaction
+except NameError:
+    class get_transaction:
+        def abort(self): pass
+        def begin(self): pass
+        def commit(self): pass
+
+
+class ZopePublication(PublicationTraverse, DefaultPublication):
+    """Base Zope publication specification."""
+
+    version_cookie = 'Zope-Version'
+    root_name = 'Application'
+
+    def __init__(self, db):
+        # db is a ZODB.DB.DB object.
+        self.db = db
+
+    def beforeTraversal(self, request):
+        id = prin_reg.authenticate(request)
+        if id is None:
+            id = prin_reg.defaultPrincipal()
+            if id is None:
+                raise Unauthorized # If there's no default principal
+        newSecurityManager(id)
+        get_transaction().begin()
+
+    def openedConnection(self, conn):
+        # Hook for auto-refresh
+        pass
+
+    def getApplication(self, request):
+
+        # If the first name is '++etc++ApplicationControl', then we should
+        # get it rather than look in the database!
+        stack = request.getTraversalStack()
+        if stack:
+            name = stack[-1]
+            if name == '++etc++ApplicationController':
+                stack.pop() # consume the name
+                request.setTraversalStack(stack) # Reset the stack
+                return self.traverseName(request, None, name)
+        
+        # Open the database.
+        version = request.get(self.version_cookie, '')
+        conn = self.db.open(version)
+
+        cleanup = Cleanup(conn.close)
+        request.hold(cleanup)  # Close the connection on request.close()
+
+        self.openedConnection(conn)
+##        conn.setDebugInfo(getattr(request, 'environ', None), request.other)
+
+        root = conn.root()
+        app = root.get(self.root_name, None)
+        
+        if app is None:
+            raise SystemError, "Zope Application Not Found"
+
+        return ProxyFactory(app)
+
+    def callTraversalHooks(self, request, ob):
+        # Call __before_publishing_traverse__ hooks
+        pass
+
+    def getDefaultTraversal(self, request, ob):
+        return ob, None
+
+    def afterTraversal(self, request, ob):
+        #recordMetaData(object, request)
+        pass
+
+    def callObject(self, request, ob):
+        return mapply(ob, request.getPositionalArguments(), request)
+
+    def afterCall(self, request):
+        get_transaction().commit()
+
+    def handleException(self, request, exc_info, retry_allowed=1):
+        try:
+            # Abort the transaction.
+            get_transaction().abort()
+
+            # Delegate Unauthorized errors to the authentication service
+            # XXX Is this the right way to handle Unauthorized?  We need
+            # to understand this better.
+            if isinstance(exc_info[1], Unauthorized):
+                sm = getSecurityManager()
+                id = sm.getPrincipal()
+                prin_reg.unauthorized(id, request) # May issue challenge
+                request.getResponse().handleException(exc_info)
+                return
+
+
+            # XXX This is wrong. Should use getRequstView:
+            # 
+            # 
+            # # Look for a component to handle the exception.
+            # traversed = request.traversed
+            # if traversed:
+            #     context = traversed[-1]
+            #     #handler = getExceptionHandler(context, t, IBrowserPublisher)
+            #     handler = None  # no getExceptionHandler() exists yet.
+            #     if handler is not None:
+            #         handler(request, exc_info)
+            #         return
+
+            # Convert ConflictErrors to Retry exceptions.
+            if retry_allowed and isinstance(exc_info[1], ConflictError):
+                LOG('Zope Publication', INFO,
+                    'Competing writes/reads at %s'
+                    % request.get('PATH_INFO', '???'),
+                    error=sys.exc_info())
+                raise Retry
+
+            # Let the response handle it as best it can.
+            # XXX Is this what we want in the long term?
+            response = request.getResponse()
+            response.handleException(exc_info)
+            return
+        finally:
+            # Avoid leaking
+            exc_info = 0
+
+
+    def _parameterSetskin(self, pname, pval, request):
+        request.setViewSkin(pval)
+        


=== Zope3/lib/python/Zope/App/ZopePublication/__init__.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+Zope publication package.
+"""


=== Zope3/lib/python/Zope/App/ZopePublication/zopepublication.zcml 1.1 => 1.2 ===
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:security='http://namespaces.zope.org/security'
+   xmlns:browser='http://namespaces.zope.org/browser'
+   xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc'
+>
+
+<browser:view name="_traverse" 
+ for="Interface.Interface"
+ factory="Zope.App.ZopePublication.Traversers.SimpleComponentTraverser" />
+
+<browser:view name="_traverse" 
+ for="Zope.App.OFS.Content.IFileContent."
+ factory="Zope.App.ZopePublication.Traversers.FileContentTraverser" />
+
+  <xmlrpc:view name="_traverse" 
+   for="Interface.Interface"
+   factory=".Traversers.SimpleComponentTraverser." />
+
+<include package=".AbsoluteURL" file="config.zcml" />
+
+</zopeConfigure>