[Zope3-checkins] CVS: Zope3/src/zope/app/index - __init__.py:1.1.2.1 configure.zcml:1.1.2.1 processors.py:1.1.2.1 queries.py:1.1.2.1 subscribers.py:1.1.2.1 subscription_control.pt:1.1.2.1
Jim Fulton
jim@zope.com
Mon, 23 Dec 2002 14:31:40 -0500
Update of /cvs-repository/Zope3/src/zope/app/index
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/app/index
Added Files:
Tag: NameGeddon-branch
__init__.py configure.zcml processors.py queries.py
subscribers.py subscription_control.pt
Log Message:
Initial renaming before debugging
=== Added File Zope3/src/zope/app/index/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/zope/app/index/configure.zcml ===
<zopeConfigure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser='http://namespaces.zope.org/browser'
>
<include package=".text" />
<content class="zope.app.index.subscribers.Registration">
<require
permission="Zope.ManageServices"
interface="zope.app.indexzope.app.indexzope.app.index.subscribers.ISubscriptionControl"
/>
<factory
id="Zope.App.indexzope.app.index.subscribers.Registration"
permission="Zope.ManageServices"
/>
</content>
<browser:menuItem
menu="add_component"
for="zope.app.interfaces.container.IAdding"
action="Zope.App.indexzope.app.index.subscribers.Registration"
title="Registration subscriber"
description="An event subscriber that registers content with the objecthub"
/>
<browser:defaultView
for="zope.app.indexzope.app.indexzope.app.index.subscribers.ISubscriptionControl"
name="control.html" />
<browser:view
for="zope.app.indexzope.app.indexzope.app.index.subscribers.ISubscriptionControl"
permission="Zope.ManageServices"
name="control.html"
template="subscription_control.pt" />
</zopeConfigure>
=== Added File Zope3/src/zope/app/index/processors.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Generic query processors for use with multiple indexes..
$Id: processors.py,v 1.1.2.1 2002/12/23 19:31:37 jim Exp $
"""
from __future__ import generators
from zope.app.interfaces.index.interfaces import IRankedObjectIterator, IRankedObjectRecord, \
IRankedHubIdList, IBatchedResult
from zope.app.interfaces.services.query import IQueryProcessor
from zope.component import getAdapter, getService
from zope.proxy.context import ContextMethod
class ObjectRetrievingProcessor:
"""Converts a RankedHubIdList into an iteratable
list of ranked objects by retrieving the objects
from the ObjectHub.
"""
__implements__ = IQueryProcessor
input_interface = IRankedHubIdList, IBatchedResult
output_interface = IRankedObjectIterator
def __call__(wrapped_self, query):
list = getAdapter(query, IRankedHubIdList)
batch = getAdapter(query, IBatchedResult)
objectHub = getService(wrapped_self, "ObjectHub")
# XXX do we need wrapping for the objects returned by the hub?
iterator = RankedObjectIterator(list, objectHub.getObject, batch.startPosition,
batch.batchSize, batch.totalSize)
return iterator
__call__ = ContextMethod(__call__)
class RankedObjectIterator:
"""Iterates over a given list of IRankedObjectRecord."""
__implements__ = IRankedObjectIterator, IBatchedResult
def __init__(self, recordlist, objectfetcher, startposition, batchsize, totalsize):
self._records = recordlist
self.startPosition = startposition
self.batchSize = batchsize
self.totalSize = totalsize
self.__objectfetcher = objectfetcher
def __iter__(self):
objectfetcher = self.__objectfetcher
for hubid, rank in self._records:
# XXX maybe we should catch some exceptions like security related
# ones or NotFoundError, to avoid breaking the iteration. Think
# about yielding an NotFound-Indicator in such a case.
yield RankedObjectRecord(objectfetcher(hubid), rank)
raise StopIteration
class RankedObjectRecord:
"""Contains a reference to a ranked object."""
__slots__ = ["rank", "object"]
__implements__ = IRankedObjectRecord
def __init__(self, object, rank):
self.rank = rank
self.object = object
=== Added File Zope3/src/zope/app/index/queries.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Generic queries for indexes.
$Id: queries.py,v 1.1.2.1 2002/12/23 19:31:37 jim Exp $
"""
from zope.component import getAdapter
from zope.app.interfaces.index.interfaces import IBatchedResult, IRankedHubIdList
class BatchedRankedResult:
__implements__ = IBatchedResult, IRankedHubIdList
def __init__(self, hubidlist, startposition, batchsize, totalsize):
self.__hubidlist = hubidlist
self.startPosition = startposition
self.batchSize = batchsize
self.totalSize = totalsize
def __getitem__(self, index):
return self.__hubidlist[index]
=== Added File Zope3/src/zope/app/index/subscribers.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""A stupid registration thingie.
In order to do indexing, objects need to be registered with the object
hub. A real site should define a policy for when objects are to be
registered. This particular implementation subscribes to
IObjectAddedEvent events from the event service, and registers
absolutely everything. It also has a way of registering all
pre-existing objects.
XXX This is really just an example! There are no unit tests, and it
hardcodes all the policy decisions. Also, it has some "viewish"
properties. The traversal code in registerExisting could be useful
for creating a general "Find" facility like the Zope2 Find tab.
$Id: subscribers.py,v 1.1.2.1 2002/12/23 19:31:37 jim Exp $
"""
__metaclass__ = type
from zope.interface import Interface
from persistence import Persistent
from zope.interfaces.event import ISubscriber
from zope.app.interfaces.event import IObjectAddedEvent
from zope.app.content.folder import IFolder
from zope.proxy.context import ContextMethod
from zope.component import getService, queryAdapter
from Zope.App.Traversing import traverse, traverseName, \
getPhysicalPath, getPhysicalRoot
from zope.app.interfaces.services.hub import ObjectHubError
class ISubscriptionControl(Interface):
def subscribe():
"""Subscribe to the prevailing object hub service."""
def unsubscribe():
"""Unsubscribe from the object hub service."""
def isSubscribed():
"""Return whether we are currently subscribed."""
def registerExisting():
"""Register all existing objects (for some definition of all)."""
class Registration(Persistent):
__implements__ = ISubscriptionControl, ISubscriber
def notify(wrapped_self, event):
"""An event occured. Perhaps register this object with the hub."""
hub = getService(wrapped_self, "ObjectHub")
wrapped_self._registerObject(event.object, hub)
notify = ContextMethod(notify)
currentlySubscribed = False # Default subscription state
def subscribe(wrapped_self):
if wrapped_self.currentlySubscribed:
raise RuntimeError, "already subscribed; please unsubscribe first"
channel = wrapped_self._getChannel(None)
channel.subscribe(wrapped_self, IObjectAddedEvent)
wrapped_self.currentlySubscribed = True
subscribe = ContextMethod(subscribe)
def unsubscribe(wrapped_self):
if not wrapped_self.currentlySubscribed:
raise RuntimeError, "not subscribed; please subscribe first"
channel = wrapped_self._getChannel(None)
channel.unsubscribe(wrapped_self, IObjectAddedEvent)
wrapped_self.currentlySubscribed = False
unsubscribe = ContextMethod(unsubscribe)
def isSubscribed(self):
return self.currentlySubscribed
def registerExisting(wrapped_self):
object = findContentObject(wrapped_self)
hub = getService(wrapped_self, "ObjectHub")
wrapped_self._registerTree(object, hub)
registerExisting = ContextMethod(registerExisting)
def _registerTree(wrapped_self, object, hub):
wrapped_self._registerObject(object, hub)
# XXX Policy decision: only traverse into folders
if not IFolder.isImplementedBy(object):
return
# Register subobjects
names = object.keys()
for name in names:
# XXX Once traverseName is refactored, should get an
# ITraversable from object and pass it to traverseName
sub_object = traverseName(object, name)
wrapped_self._registerTree(sub_object, hub)
_registerTree = ContextMethod(_registerTree)
def _registerObject(wrapped_self, object, hub):
# XXX Policy decision: register absolutely everything
try:
hub.register(object)
except ObjectHubError:
# Already registered
pass
_registerObject = ContextMethod(_registerObject)
def _getChannel(wrapped_self, channel):
if channel is None:
channel = getService(wrapped_self, "ObjectHub")
return channel
_getChannel = ContextMethod(_getChannel)
def findContentObject(context):
# We want to find the (content) Folder in whose service manager we
# live. There are man y way to do this. Perhaps the simplest is
# looking for '++etc++Services' in the location. We could also
# walk up the path looking for something that implements IFolder;
# the service manager and packages don't implement this. Or
# (perhaps better, because a service manager might be attached to
# a non-folder container) assume we're in service space, and walk
# up until we find a service manager, and then go up one more
# step. Walking up the path could be done by stripping components
# from the end of the path one at a time and doing a lookup each
# time, or more directly by traversing the context. Traversing
# the context can be done by getting the context and following the
# chain back; there's a convenience class, ContainmentIterator to
# do that. Use the version of ContainmentIterator from
# Zope.Proxy, which is aware of the complications caused by
# security proxies.
# For now, we pick the first approach.
location = getPhysicalPath(context)
# Location is a tuple of strings, starting with '' (for the root)
for i in range(len(location)):
if location[i] == "++etc++Services":
location = location[:i]
break
else:
raise ValueError, "can't find '++etc++Services' in path"
root = getPhysicalRoot(context)
return traverse(root, location)
=== Added File Zope3/src/zope/app/index/subscription_control.pt ===
<html metal:use-macro="views/standard_macros/page">
<head>
<title>Registration "Service" Control Page</title>
</head>
<body>
<div metal:fill-slot="body">
<h1>Subscription control</h1>
<span tal:condition="request/callSubscribe|nothing" tal:omit-tag="">
<span tal:define="dummy context/subscribe" tal:omit-tag=""/>
Successfully subscribed.
</span>
<span tal:condition="request/callUnsubscribe|nothing" tal:omit-tag="">
<span tal:define="dummy context/unsubscribe" tal:omit-tag=""/>
Successfully unsubscribed.
</span>
<span tal:condition="request/callRegisterExisting|nothing" tal:omit-tag="">
<span tal:define="dummy context/registerExisting" tal:omit-tag=""/>
Registration done.
</span>
<form method="POST">
<span tal:condition="context/isSubscribed" tal:omit-tag="">
Subscription state: ON
<input type="submit" value="Unsubscribe" name="callUnsubscribe" />
</span>
<span tal:condition="not:context/isSubscribed" tal:omit-tag="">
Subscription state: OFF
<input type="submit" value="Subscribe" name="callSubscribe" />
</span>
</form>
<form method="POST">
<input type="submit" value="Register Existing Objects"
name="callRegisterExisting" />
</form>
</div>
</body>
</html>