1
##############################################################################
3
# Copyright (c) 2004 Zope Corporation and Contributors.
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
13
##############################################################################
14
"""ZCML File Representation
16
$Id: zcml.py 71107 2006-11-10 23:58:55Z shane $
18
__docformat__ = "reStructuredText"
20
from xml.sax import make_parser
21
from xml.sax.xmlreader import InputSource
22
from xml.sax.handler import feature_namespaces
24
from zope.cachedescriptors.property import Lazy
25
from zope.configuration import xmlconfig, config
26
from zope.interface import implements, directlyProvides
27
from zope.location.interfaces import ILocation
29
import zope.app.appsetup.appsetup
31
from interfaces import IDirective, IRootDirective, IZCMLFile
34
class MyConfigHandler(xmlconfig.ConfigurationHandler, object):
35
"""Special configuration handler to generate an XML tree."""
37
def __init__(self, context):
38
super(MyConfigHandler, self).__init__(context)
39
self.rootElement = self.currentElement = None
42
def startPrefixMapping(self, prefix, uri):
43
self.prefixes[uri] = prefix
45
def evaluateCondition(self, expression):
46
# We always want to process/show all ZCML directives.
49
def startElementNS(self, name, qname, attrs):
50
# The last stack item is parent of the stack item that we are about to
52
stackitem = self.context.stack[-1]
53
super(MyConfigHandler, self).startElementNS(name, qname, attrs)
55
# Get the parser info from the correct context
56
info = self.context.stack[-1].context.info
58
# complex stack items behave a bit different than the other ones, so
59
# we need to handle it separately
60
if isinstance(stackitem, config.ComplexStackItem):
61
schema = stackitem.meta.get(name[1])[0]
63
schema = stackitem.context.factory(stackitem.context, name).schema
65
# Now we have all the necessary information to create the directive
66
element = Directive(name, schema, attrs, stackitem.context, info,
68
# Now we place the directive into the XML directive tree.
69
if self.rootElement is None:
70
self.rootElement = element
72
self.currentElement.subs.append(element)
74
element.__parent__ = self.currentElement
75
self.currentElement = element
78
def endElementNS(self, name, qname):
79
super(MyConfigHandler, self).endElementNS(name, qname)
80
self.currentElement = self.currentElement.__parent__
83
class Directive(object):
84
"""Representation of a ZCML directive."""
85
implements(IDirective)
87
def __init__(self, name, schema, attrs, context, info, prefixes):
91
self.context = context
93
self.__parent__ = None
95
self.prefixes = prefixes
98
return '<Directive %s>' %str(self.name)
101
class ZCMLFile(object):
102
"""Representation of an entire ZCML file."""
103
implements(ILocation, IZCMLFile)
105
def __init__(self, filename, package, parent, name):
106
# Retrieve the directive registry
107
self.filename = filename
108
self.package = package
109
self.__parent__ = parent
112
def rootElement(self):
113
# Get the context that was originally generated during startup and
114
# create a new context using its registrations
115
real_context = zope.app.appsetup.appsetup.getConfigContext()
116
context = config.ConfigurationMachine()
117
context._registry = copy.copy(real_context._registry)
118
context._features = copy.copy(real_context._features)
119
context.package = self.package
121
# Shut up i18n domain complaints
122
context.i18n_domain = 'zope'
124
# Since we want to use a custom configuration handler, we need to
125
# instantiate the parser object ourselves
126
parser = make_parser()
127
handler = MyConfigHandler(context)
128
parser.setContentHandler(handler)
129
parser.setFeature(feature_namespaces, True)
132
file = open(self.filename)
133
src = InputSource(getattr(file, 'name', '<string>'))
134
src.setByteStream(file)
139
# Finally we retrieve the root element, have it provide a special root
140
# directive interface and give it a location, so that we can do local
142
root = handler.rootElement
143
directlyProvides(root, IRootDirective)
144
root.__parent__ = self
147
rootElement = Lazy(rootElement)