source: cows/trunk/cows/service/imps/csmlbackend/csmlcommon.py @ 6513

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/trunk/cows/service/imps/csmlbackend/csmlcommon.py@6513
Revision 6513, 8.2 KB checked in by domlowe, 11 years ago (diff)

changing from celementtree to elementtree to avoid restricted io error

Line 
1# BSD Licence
2# Copyright (c) 2009, Science & Technology Facilities Council (STFC)
3# All rights reserved.
4#
5# See the LICENSE file in the source distribution of this software for
6# the full license text.
7
8""" Common CSML code shared between WMS, WFS and WCS backends
9@Author: Dominic Lowe
10"""
11
12import os, string
13import logging
14import csml
15import tempfile
16
17from cows.service.imps.csmlbackend.config import config
18from cows.service.imps.csmlbackend import getGlobalCSMLConnector
19
20import ConfigParser
21log = logging.getLogger(__name__)
22from cows.bbox_util import union
23 
24try:
25    from ndgUtils import ndgObject, ndgRetrieve
26except:
27    log.warning("ndgUtils library could not be loaded, files in the eXist database won't be available, although you should still be able to access files from the csmlstore directory referenced in the ini file.")
28
29from cows.service.wxs_iface import ILayerMapper
30
31try: #for python 2.5
32    from xml.etree import ElementTree as ET
33except ImportError:
34    try:
35        # if you've installed it yourself it comes this way
36        import ElementTree as ET
37    except ImportError:
38        # if you've egged it this is the way it comes
39        from elementtree import ElementTree as ET
40
41
42
43
44
45
46def extractToNetCDF(feature, sel, publish=False):
47    """
48       performs the CSML subset and returns a filename of the netcdf extract
49       publish flag is used to indicate that the netcdf file should be made available to the webserver (for asynchronous delivery)
50    """
51
52    if publish:
53        #if publishing to download directory is required, do so and return publishable file name
54        #used e.g. in WCS when "STORE = true"
55        extract_dir=config['publish_dir']
56    else:
57        extract_dir = config['tmpdir']
58         
59    # Subset the feature
60    (fd, filename) = tempfile.mkstemp('.nc', 'csml_wxs_', extract_dir); os.close(fd)
61    if type(feature) is csml.parser.GridSeriesFeature:
62        feature.subsetToGridSeries(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
63    elif type(feature) is csml.parser.TrajectoryFeature:
64        feature.subsetToTrajectory(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
65    elif type(feature) is csml.parser.PointSeriesFeature:
66        del sel['longitude'] #delete dummy values
67        del sel['latitude'] #delete dummy values
68        feature.subsetToPointSeries(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
69    elif type(feature) is csml.parser.RaggedSectionFeature:
70        del sel['longitude'] #delete dummy values
71        del sel['latitude'] #delete dummy values
72        feature.subsetByTime(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
73    return filename
74
75
76class CSMLLayerMapper(ILayerMapper):
77    """
78    Map keyword arguments to a collection of layers.
79    Supports the retrieval of sets of layers according to arbitrary
80    keyword/value pairs.
81    Implements  ILayerMapper
82   
83    """
84    def __init__(self):
85        self.layermapcache={}
86        self.connector = getGlobalCSMLConnector()
87   
88    #!TODO: Should be _getInfo() as proposed in wms_csmllayer.  Should move to wfs_csmllayer as
89    #    this is the only place where it isn't overridden.
90    def getInfo(self, feature):
91        ''' given a csml feature, return basic info about the layer/feature/coverage
92        @return:   title, abstract'''
93
94        try:
95            title=feature.name.CONTENT
96        except:
97            title=''
98        try:
99            abstract=feature.description.CONTENT
100        except:
101            abstract=title
102       
103        return title, abstract
104
105class CSMLConnector(object):
106    """ Contains common methods for CSML backend used across all WXS services """   
107   
108    def __init__(self):
109        self.csml_dir = config.get('csmlstore')
110   
111    def _locateFile(self, fileoruri):
112        ''' gets the csml file from Exist or the csml filestore''' 
113        if string.find(fileoruri,'__NDG-A0__') == -1:
114            #it's a local file not an identifier, read from local csmlstore
115            file=fileoruri
116            path = os.path.join(self.csml_dir, file)
117            if os.path.exists(path+'.csml'):
118                f = path+'.csml'
119            elif os.path.exists(path+'.xml'):
120                f = path +'.xml'
121            else:
122                raise ValueError("Cannot find CSML file %s" % file)       
123        else:
124            #it's an NDG identifier, get the document from exist.
125            uri=fileoruri
126            uriN=ndgObject(uri)
127            conflocation=config['ndgconfig']
128            cf=ConfigParser.ConfigParser()
129            cf.read(conflocation)
130            status,f=ndgRetrieve(uriN, cf, discovery=0)
131        return f
132   
133    def getCSMLDatasetInfo(self,fileoruri):
134        """ lightweight method that gets a CSML document, but only returns certain attributes that can easily be extracted using xpath
135        This allows you to quickly get some key metadata without parsing the whole document.
136        Returns a dictionary of attribute:value pairs. First version only returns dataset name"""
137        datasetInfo={}
138        f=self._locateFile(fileoruri)
139        tree=ET.parse(f) #parse usign cElementTree
140        nameelem=tree.find('{http://ndg.nerc.ac.uk/csml}name')
141        #skip if name is not there or has one of the default entries
142        if nameelem is not None:
143            if nameelem.text in ['NAME OF DATASET GOES HERE', 'Please add a human readable name for the dataset here']:
144                pass
145            else:
146                datasetInfo['name']=nameelem.text
147        return datasetInfo
148   
149    def getCsmlDoc(self, fileoruri):
150        """
151        Gets a csml document from file or exist when passed a file name or uri
152
153        Note, access control is not implemented on file access, only on exist
154        access.
155       
156        """
157        f=self._locateFile(fileoruri)
158        d=csml.parser.Dataset()
159        d.parse(f)                     
160        return d
161   
162    def list(self, folder=None):
163        """
164        Generator that lists available CSML documents.
165
166        @note: not implemented for eXist.  I'm not sure if this is possible
167            or desireable.
168
169        """
170        if self.csml_dir is None:
171            log.warning('Trying to list CSMLConnector with no filestore.  '
172                        'Maybe using eXist?')
173            return
174       
175        path = self.csml_dir
176       
177        if folder != None:
178            path = os.path.join(path, folder)
179       
180        for fp in os.listdir(path):
181           
182            if os.path.isdir(os.path.join(path,fp)):
183                if folder != None:
184                    # return 'folder/folder'
185                    yield os.path.join(folder, fp)
186                else:
187                    # return 'folder'
188                    yield fp
189               
190            if os.path.splitext(fp)[1] in ['.csml', '.xml']:
191                if folder != None:
192                    # return 'folder/file' without the .csml
193                    yield os.path.join(folder, os.path.splitext(fp)[0])
194                else:
195                    # return 'file' without the .csml
196                    yield os.path.splitext(fp)[0]
197       
198#        for dirpath, dirnames, filenames in os.walk(self.csml_dir):
199#            for filename in filenames:
200#                file_id, ext = os.path.splitext(filename)
201#                if ext in ('.xml', '.csml'):
202#                    # Remove common path bit
203#                    relpath = dirpath[len(self.csml_dir):]
204#                   
205#                    if len(relpath) > 0 and relpath[0] == '/':
206#                        relpath = relpath[1:]
207#                   
208#                    yield os.path.join(relpath, file_id)
209                   
210    def listwfsonly(self):
211            """
212        Generator that lists all CSML endpoints that can't be served through WMS/WCS.
213        This list is (optionally)   defined in the wfsonly.txt file in the csml directory.
214            """
215            cfgfile = os.path.join(self.csml_dir, 'wfsonly.txt')
216            if os.path.exists(cfgfile):
217                f=open(cfgfile, 'r')
218                for line in f:
219                    yield line.strip('\n')
220                f.close()
221            else:
222                return
223   
224    def isGroup(self, fc):
225        return os.path.isdir(os.path.join(self.csml_dir, fc))
226
Note: See TracBrowser for help on using the repository browser.