[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>