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

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

Adjust code to fit with changes to ndgCommon codebase + tidy up
structure of ndgInterface to make easier to follow + add documentation
+ add universal debug mode + various other small code tidy ups.

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