source: MILK/trunk/milk_server/milk_server/lib/ndgInterface.py @ 4625

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/lib/ndgInterface.py@4625
Revision 4625, 6.3 KB checked in by cbyrom, 11 years ago (diff)

Improve error handling in the atom controllers + refactor ndgInterface
to remove code from constructor to allow dependency injection - to
improve flexibility and testability. Also, change ambiguous naming
references in classes to minimise codeword overaps/confusion.

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"""
6Manages interface to NDG documents and data, including caching
7"""
8
9from cache import Cache
10from csml_cache import CSMLExtractCache
11import os, logging
12from ndgUtils import ndgRetrieve, ndgObject, xmlHandler2
13from pylons import request, session
14
15from pylons import g # for handle to access control PEP interface
16try:
17    from ndg.security.common.authz.pdp import PDPError
18    from ndg.security.common.authz.pep import PEPError
19except ImportError, e:
20    from warnings import warn
21    warn(__name__ + ": access control is disabled: %s" % e, RuntimeWarning)
22
23class ndgInterface:
24   
25    def __init__(self):
26        '''
27        Constructor to set up object
28        '''
29        self.CSMLDataCache = None
30        self.CSMLDocCache = None
31        self.XMLHCache = None
32
33       
34    def SetupCaches(self, csmlDataCache = None, csmlDocCache = None, \
35                    xmlHCache = None):
36        '''
37        Set up the required three level cache:
38                - a file cache
39                - a xmlhandler object cache, and
40                - a parsed CSML object cache.
41        @keyword csmlDataCache: an alternative csmlDataCache to use
42        @keyword csmlDocCache: an alternative csmlDocCache to use
43        @keyword xmlHCache: an alternative xmlHCache to use
44        '''
45        logging.info("Setting up ndgInterface caches")
46        if csmlDataCache:
47            self.CSMLDataCache = csmlDataCache
48        else:
49            self.CSMLDataCache=CSMLExtractCache(
50                request.environ['paste.config']['app_conf']['tmp_dir'],max_size=10)
51       
52        if csmlDocCache:
53            self.CSMLDocCache = csmlDocCache
54        else:
55            self.CSMLDocCache=Cache(max_size=10)
56       
57        if xmlHCache:
58            self.XMLHCache = xmlHCache
59        else:
60            self.XMLHCache=Cache(max_size=10)
61        logging.info("Finished setting up caches")
62       
63
64    def GetXML(self,uri,outputSchema='', useCache=True):
65        '''
66        This method provides a secure interface to the server
67        document cache and a remote NDG exist. It is assumed that
68        the local filesystem is protected in that you can't get to
69        files except via the CSML api
70        @param uri: ndg format uri to locate doc from
71        @keyword outputSchema: format to return doc in
72        @keyword useCache: check for data in the cache and use this, if set to
73        True (the default)   
74        '''
75        #    Note that this method should not be used to obtain
76        #unsecured discovery documents, these are called directly
77        #in the retrieve controller!
78
79        logging.info("Getting XML from uri, '%s' (outputschema: '%s')" \
80                     %(uri, outputSchema))
81        try:
82            ndgO=ndgObject(uri)
83            localFile=0
84        except ValueError:
85            ''' It's a local file not an ndg identifier '''
86            logging.info("File appears to be local - look for it there...")
87            ndgO=uri
88            localFile=1
89       
90        if session and 'ndgCleared' in session:
91            cleared=session['ndgCleared']
92        else:
93            cleared=None
94       
95        if outputSchema or not useCache:
96            #bypass the cache ...
97            status,xmlh=ndgRetrieve(ndgO,
98                                    request.environ['ndgConfig'],
99                                    output=outputSchema,
100                                    discovery=g.standalone)
101        else:
102            try:
103                if not self.XMLHCache:
104                    self.SetupCaches()
105                   
106                xmlh=self.XMLHCache[uri]
107                status=1
108                logging.info('XMLH Cache hit for [%s]'%uri)
109            except:
110                logging.info('XMLH Cache miss for [%s]'%uri)
111                if localFile:
112                    status,xmlH=self.__getLocal(uri)
113                else:   
114                    status,xmlh=ndgRetrieve(ndgO,
115                                            request.environ['ndgConfig'],
116                                            output=outputSchema,
117                                            discovery=g.standalone)
118                if status: 
119                    self.XMLHCache[uri]=xmlh
120           
121        if not status: return status,xmlh
122       
123        # convert doc to an XML tree
124        xmlh=xmlHandler2.xmlHandler(xmlh,string=1)
125       
126        # valid values of the return objects SHOULD BE
127        #   ok:         status=1, xmlh=an xml handler instance.
128        #   exceptions, status=0, xmlh='Exception(e)'
129       
130        status,xmlh=self.__gatekeep(ndgO,xmlh)
131        if status:
132            if cleared is None:
133                session['ndgCleared']=[uri]
134            else:
135                session['ndgCleared'].append(uri)
136            session.save()
137       
138        return status,xmlh
139           
140
141    def __gatekeep(self,uri,x):
142        ''' This is the NDG gatekeeper '''
143        if 'ndgSec' in session:
144            securityTokens=session['ndgSec']
145        else:
146            securityTokens=None
147
148        if not hasattr(g, 'pep'):
149            if not g.standalone:
150                raise PEPError(\
151                "Security is disabled but the standalone flag is set to False")
152               
153            logging.info("__gatekeep: access control is disabled - standalone " + \
154                     "config flag is set")
155           
156        try:
157            # Arguments are: a handle to the resource and a handle to the users
158            # security tokens
159            g.pep(dict(uri=uri, doc=x), securityTokens, None)
160            return True, x
161       
162        except PDPError, e:
163            # Caught a known access control condition
164            return False, 'Access Denied for %s %s' % (uri, e)
165
166               
167    def __getLocal(self,uri):
168        ''' Returns a local csml file (used for testing) '''
169        csml_dir = request.environ['paste.config']['app_conf']['csml_dir']
170        path = os.path.join(csml_dir, file)
171        if os.path.exists(path+'.csml'):
172            f = path+'.csml'
173        elif os.path.exists(path+'.xml'):
174            f = path +'.xml'
175        else:
176            return 0, '<p>Cannot find CSML file %s</p>' % file
177        r=f.read()
178        return 1,r     
Note: See TracBrowser for help on using the repository browser.