47
48
from zope.app.pagetemplate.engine import TrustedAppPT
48
49
from zope import component
49
50
from zope.component import (
50
adapts, getAdapters, getAllUtilitiesRegisteredFor, getMultiAdapter,
51
getUtility, queryAdapter, getGlobalSiteManager)
51
adapts, getAdapters, getAllUtilitiesRegisteredFor,
52
getGlobalSiteManager, getMultiAdapter, getSiteManager, getUtility,
52
54
from zope.component.interfaces import ComponentLookupError
53
55
from zope.event import notify
54
56
from zope.publisher.http import init_status_codes, status_reasons
55
57
from zope.interface import (
56
implementer, implements, implementedBy, providedBy, Interface)
58
alsoProvides, implementer, implements, implementedBy, providedBy,
57
60
from zope.interface.common.sequence import IFiniteSequence
58
61
from zope.interface.interfaces import IInterface
59
62
from zope.location.interfaces import ILocation
82
85
IResourceDELETEOperation, IResourceGETOperation, IResourcePOSTOperation,
83
86
IScopedCollection, IServiceRootResource, ITopLevelEntryLink,
84
87
IUnmarshallingDoesntNeedValue, IWebServiceClientRequest,
85
IWebServiceConfiguration, LAZR_WEBSERVICE_NAME)
88
IWebServiceConfiguration, IWebServiceLayer, IWebServiceVersion,
86
90
from lazr.restful.utils import get_current_browser_request
112
116
return unicode(value)
119
def register_versioned_request_utility(interface, version):
120
"""Registers a marker interface as a utility for version lookup.
122
This function registers the given interface class as the
123
IWebServiceVersion utility for the given version string.
125
alsoProvides(interface, IWebServiceVersion)
126
getSiteManager().registerUtility(
127
interface, IWebServiceVersion, name=version)
115
130
class LazrPageTemplateFile(TrustedAppPT, PageTemplateFile):
116
131
"A page template class for generating web service-related documents."
143
158
return tuple(obj)
144
159
if isinstance(underlying_object, dict):
146
if queryAdapter(obj, IEntry):
147
obj = EntryResource(obj, get_current_browser_request())
161
request = get_current_browser_request()
162
if queryMultiAdapter((obj, request), IEntry):
163
obj = EntryResource(obj, request)
149
165
return IJSONPublishable(obj).toDataForJSON()
1243
1260
def __init__(self, context, request):
1244
1261
"""Associate this resource with a specific object and request."""
1245
1262
super(EntryResource, self).__init__(context, request)
1246
self.entry = IEntry(context)
1263
self.entry = getMultiAdapter((context, request), IEntry)
1248
1265
def _getETagCore(self, unmarshalled_field_values=None):
1249
1266
"""Calculate the ETag for an entry.
1442
1459
def __init__(self, context, request):
1443
1460
"""Associate this resource with a specific object and request."""
1444
1461
super(CollectionResource, self).__init__(context, request)
1445
self.collection = ICollection(context)
1462
if ICollection.providedBy(context):
1463
self.collection = context
1465
self.collection = getMultiAdapter((context, request), ICollection)
1447
1467
def do_GET(self):
1448
1468
"""Fetch a collection and render it as JSON."""
1492
1512
# Scoped collection. The type URL depends on what type of
1493
1513
# entry the collection holds.
1494
1514
schema = self.context.relationship.value_type.schema
1495
adapter = EntryAdapterUtility.forSchemaInterface(schema)
1515
adapter = EntryAdapterUtility.forSchemaInterface(
1516
schema, self.request)
1496
1517
return adapter.entry_page_type_link
1498
1519
# Top-level collection.
1499
1520
schema = self.collection.entry_schema
1500
adapter = EntryAdapterUtility.forEntryInterface(schema)
1521
adapter = EntryAdapterUtility.forEntryInterface(
1522
schema, self.request)
1501
1523
return adapter.collection_type_link
1662
1684
# It's not a top-level resource.
1664
1686
adapter = EntryAdapterUtility.forEntryInterface(
1687
entry_schema, self.request)
1666
1688
link_name = ("%s_collection_link" % adapter.plural_type)
1667
1689
top_level_resources[link_name] = utility
1668
1690
# Now, collect the top-level entries.
1687
1709
"""An individual entry."""
1688
1710
implements(IEntry)
1690
def __init__(self, context):
1712
def __init__(self, context, request):
1691
1713
"""Associate the entry with some database model object."""
1692
1714
self.context = context
1715
self.request = request
1695
1718
class Collection:
1696
1719
"""A collection of entries."""
1697
1720
implements(ICollection)
1699
def __init__(self, context):
1722
def __init__(self, context, request):
1700
1723
"""Associate the entry with some database model object."""
1701
1724
self.context = context
1725
self.request = request
1704
1728
class ScopedCollection:
1705
1729
"""A collection associated with some parent object."""
1706
1730
implements(IScopedCollection)
1707
adapts(Interface, Interface)
1731
adapts(Interface, Interface, IWebServiceLayer)
1709
def __init__(self, context, collection):
1733
def __init__(self, context, collection, request):
1710
1734
"""Initialize the scoped collection.
1712
1736
:param context: The object to which the collection is scoped.
1723
1748
# We are given a model schema (IFoo). Look up the
1724
1749
# corresponding entry schema (IFooEntry).
1725
1750
model_schema = self.relationship.value_type.schema
1726
return getGlobalSiteManager().adapters.lookup1(
1727
model_schema, IEntry).schema
1751
request_interface = getUtility(
1753
name=self.request.version)
1754
return getGlobalSiteManager().adapters.lookup(
1755
(model_schema, request_interface), IEntry).schema
1729
1757
def find(self):
1730
1758
"""See `ICollection`."""
1751
def forSchemaInterface(cls, entry_interface):
1779
def forSchemaInterface(cls, entry_interface, request):
1752
1780
"""Create an entry adapter utility, given a schema interface.
1754
1782
A schema interface is one that can be annotated to produce a
1755
1783
subclass of IEntry.
1785
request_interface = getUtility(
1786
IWebServiceVersion, name=request.version)
1757
1787
entry_class = getGlobalSiteManager().adapters.lookup(
1758
(entry_interface,), IEntry)
1788
(entry_interface, request_interface), IEntry)
1759
1789
assert entry_class is not None, (
1760
"No IEntry adapter found for %s." % entry_interface.__name__)
1790
("No IEntry adapter found for %s (web service version: %s)."
1791
% (entry_interface.__name__, request.version)))
1761
1792
return EntryAdapterUtility(entry_class)
1764
def forEntryInterface(cls, entry_interface):
1795
def forEntryInterface(cls, entry_interface, request):
1765
1796
"""Create an entry adapter utility, given a subclass of IEntry."""
1766
1797
registrations = getGlobalSiteManager().registeredAdapters()
1798
# There should be one IEntry subclass registered for every
1799
# version of the web service. We'll go through the appropriate
1800
# IEntry registrations looking for one associated with the
1801
# same IWebServiceVersion interface we find on the 'request'
1767
1803
entry_classes = [
1768
1804
registration.factory for registration in registrations
1769
1805
if (IInterface.providedBy(registration.provided)
1770
1806
and registration.provided.isOrExtends(IEntry)
1771
and entry_interface.implementedBy(registration.factory))]
1807
and entry_interface.implementedBy(registration.factory)
1808
and registration.required[1].providedBy(request))]
1772
1809
assert not len(entry_classes) > 1, (
1773
"%s provides more than one IEntry subclass." %
1774
entry_interface.__name__)
1810
"%s provides more than one IEntry subclass for version %s." %
1811
entry_interface.__name__, request.version)
1775
1812
assert not len(entry_classes) < 1, (
1776
"%s does not provide any IEntry subclass." %
1777
entry_interface.__name__)
1813
"%s does not provide any IEntry subclass for version %s." %
1814
entry_interface.__name__, request.version)
1778
1815
return EntryAdapterUtility(entry_classes[0])
1780
1817
def __init__(self, entry_class):