source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/base.py @ 4066

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/base.py
Revision 4066, 6.8 KB checked in by pjkersha, 12 years ago (diff)

Fix related to AuthKit? IndexError?: OwsController?.call excpetion handling was not calling its parent controller call method so start_response was not called. Added call to start_response() call. Set code to '400 Bad Request' for now but OGC spec may require '200 OK'.

Line 
1# Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council).
2# This software may be distributed under the terms of the
3# Q Public License, version 1.0 or later.
4# http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5#
6"""
7 Base controller providing generic functionality and extended by most other controllers
8"""
9from pylons import c, g, cache, request, session, response
10from pylons.controllers import WSGIController
11from pylons.decorators import jsonify, validate
12from pylons.templating import render
13from pylons.controllers.util import abort, redirect_to, etag_cache
14from pylons.i18n import N_, _, ungettext
15from paste.request import construct_url
16import ows_server.models as model
17import ows_server.lib.helpers as h
18from ows_common import exceptions as OWS_E
19from ows_common.operations_metadata import OperationsMetadata, Operation, RequestMethod
20from ows_common.get_capabilities import ServiceMetadata
21import ows_common.xml
22
23# NDG Security import enables Single Sign On capability but note this is not
24# required for a standalone discovery service deployment
25try:
26    from ndg.security.client.ssoclient.ssoclient.lib.base import \
27        BaseController as _BaseController
28except ImportError, e:
29    from warnings import warn
30    warn('%s: ndg.security.client unavailable - ' % __name__ + \
31         'Single Sign on functionality disabled: %s' % e,
32         RuntimeWarning)
33
34    # Extend BaseController from WSGIController instead
35    _BaseController = WSGIController
36
37 
38try:
39    from xml.etree import ElementTree as ET
40except ImportError:
41    from elementtree import ElementTree as ET
42
43import logging
44logger = logging.getLogger(__name__)
45
46# Configure
47EXCEPTION_TYPE = request.environ['ndgConfig'].get('OWS_SERVER', 'exception_type', 'ogc').lower()
48
49class BaseController(_BaseController):
50   
51    def __call__(self, environ, start_response):       
52        # Insert any code to be run per request here. The Routes match
53        # is under environ['pylons.routes_dict'] should you want to check
54        # the action or route vars here
55
56        logger.debug("BaseController.__call__ ...")       
57               
58        #organise the information needed by pagetabs ...
59        # TODO avoid this for the server controllers ...
60        c.pageTabs=[('Search',g.discoveryURL)]
61        if 'results' in session: 
62            c.pageTabs.append(('Results',session['results']))
63            # make selections tab available once results are shown - to simplify associated business logic
64            c.pageTabs.append(('Selections',h.url_for(controller='selectedItems',action='index')))
65           
66        if 'lastViewed' in session: c.pageTabs.append(('Details',session['lastViewed']))
67       
68        if 'viewItems' in session: c.pageTabs.append(('View', h.url_for(controller='viewItems',action='index')))
69       
70        return _BaseController.__call__(self, environ, start_response)
71   
72class OwsController(BaseController):
73    def __call__(self, environ, start_response):
74
75        # All OWS parameter names are case insensitive.
76        req = request._current_obj()
77        self.ows_params = {}
78        for k in req.params:
79            self.ows_params[k.lower()] = req.params[k]       
80
81        # If the EXCEPTION_TYPE is 'pylons' let Pylons catch any exceptions.
82        # Otherwise send an OGC exception report for any OWS_E.OwsError
83        if 'pylons' in EXCEPTION_TYPE:
84            self._fixOwsAction(environ)
85            return super(OwsController, self).__call__(environ, start_response)
86        else:
87            try:
88                self._fixOwsAction(environ)
89                return super(OwsController, self).__call__(environ, start_response)
90            except OWS_E.OwsError, e:
91                logger.exception(e)
92                start_response('400 Bad Request',[('Content-type','text/xml')])
93#                response.headers['content-type'] = 'text/xml'
94                return render('exception_report', report=e.report, format='xml')
95
96
97    def _fixOwsAction(self, environ):
98        # Override the Routes action from the request query parameter
99        try:
100            action = self.ows_params['request']
101        except KeyError:
102            raise OWS_E.MissingParameterValue('REQUEST parameter not specified', 'REQUEST')
103
104        # Check action is a method in self
105        if not getattr(self, action):
106            raise OWS_E.InvalidParameterValue('request=%s not supported' % action, 'REQUEST')
107
108        # override routes action with request
109        environ['pylons.routes_dict']['action'] = action
110        del self.ows_params['request']
111
112    def _loadCapabilities(self):
113        """
114        creates an ows_common.get_capabilities.ServiceMetadata object
115        by consulting the paste configuration and annotations in the
116        controller definition.
117
118        """
119        # Deduce ows_endpoint from routes
120        ows_endpoint = h.url_for(controller=request.environ['pylons.routes_dict']['controller'])
121       
122        #Deduce base_url from config
123        base_url =request.environ['ndgConfig'].get('DEFAULT','server')
124
125       
126        # Get the server-level configuration data from an XML file
127        config = request.environ['paste.config']
128        sm_tree = ET.parse(config['ows_common_config'])
129        sm = ows_common.xml.service_metadata(sm_tree.getroot())
130       
131        # Extract service-level parameters and constraint
132        parameters = getattr(self, '_ows_parameters', {})
133        constraints = getattr(self, '_ows_constraints', {})
134        versions = getattr(self, '_ows_versions', [])
135       
136        # Extract operation-level parameters and constraints
137        od = {}
138        for attr in dir(self):
139            op = getattr(self, attr)
140            if hasattr(op, '_ows_name'):
141                p = getattr(op, '_ows_parameters', {})
142                c = getattr(op, '_ows_constraints', {})
143                od[op._ows_name] = Operation(get=RequestMethod(href=base_url+ows_endpoint),
144                                             post=None,
145                                             parameters=p,
146                                             constraints=c,
147                                             name=op._ows_name)
148       
149        sm.operationsMetadata = OperationsMetadata(od, constraints, parameters)
150        sm.serviceIdentification.serviceTypeVersions = versions
151        return sm
152
153    def _renderCapabilities(self, template='ows/get_capabilities'):
154        """
155        The standard way of returning a Capabilities document.
156
157        Each subclass should implement self._load_capabilities() and call
158        this method to return a response object.
159
160        """
161        c.service_metadata = self._loadCapabilities()       
162        response.headers['content-type'] = 'text/xml'
163        return render(template, format='xml')
164
165
166# Include the '_' function in the public names
167__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
168           or __name == '_']
Note: See TracBrowser for help on using the repository browser.