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

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

Modified the WCS code to work with the csml files in folders in the same way as the WMS code.

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
31def extractToNetCDF(feature, sel, publish=False):
32    """
33       performs the CSML subset and returns a filename of the netcdf extract
34       publish flag is used to indicate that the netcdf file should be made available to the webserver (for asynchronous delivery)
35    """
36
37    if publish:
38        #if publishing to download directory is required, do so and return publishable file name
39        #used e.g. in WCS when "STORE = true"
40        extract_dir=config['publish_dir']
41    else:
42        extract_dir = config['tmpdir']
43         
44    # Subset the feature
45    (fd, filename) = tempfile.mkstemp('.nc', 'csml_wxs_', extract_dir); os.close(fd)
46    if type(feature) is csml.parser.GridSeriesFeature:
47        feature.subsetToGridSeries(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
48    elif type(feature) is csml.parser.TrajectoryFeature:
49        feature.subsetToTrajectory(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
50    elif type(feature) is csml.parser.PointSeriesFeature:
51        del sel['longitude'] #delete dummy values
52        del sel['latitude'] #delete dummy values
53        feature.subsetToPointSeries(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
54    elif type(feature) is csml.parser.RaggedSectionFeature:
55        del sel['longitude'] #delete dummy values
56        del sel['latitude'] #delete dummy values
57        feature.subsetByTime(ncname=os.path.basename(filename), outputdir=os.path.dirname(filename) ,**sel)
58    return filename
59
60
61class CSMLLayerMapper(ILayerMapper):
62    """
63    Map keyword arguments to a collection of layers.
64    Supports the retrieval of sets of layers according to arbitrary
65    keyword/value pairs.
66    Implements  ILayerMapper
67   
68    """
69    def __init__(self):
70        self.layermapcache={}
71        self.connector = getGlobalCSMLConnector()
72   
73    #!TODO: Should be _getInfo() as proposed in wms_csmllayer.  Should move to wfs_csmllayer as
74    #    this is the only place where it isn't overridden.
75    def getInfo(self, feature):
76        ''' given a csml feature, return basic info about the layer/feature/coverage
77        @return:   title, abstract'''
78
79        try:
80            title=feature.name.CONTENT
81        except:
82            title=''
83        try:
84            abstract=feature.description.CONTENT
85        except:
86            abstract=title
87       
88        return title, abstract
89
90class CSMLConnector(object):
91    """ Contains common methods for CSML backend used across all WXS services """   
92   
93    def __init__(self):
94        self.csml_dir = config.get('csmlstore')
95   
96    def getCsmlDoc(self, fileoruri):
97        """
98        Gets a csml document from file or exist when passed a file name or uri
99
100        Note, access control is not implemented on file access, only on exist
101        access.
102       
103        """
104        if string.find(fileoruri,'__NDG-A0__') == -1:
105            #it's a local file not an identifier, read from local csmlstore
106            file=fileoruri
107            path = os.path.join(self.csml_dir, file)
108            if os.path.exists(path+'.csml'):
109                f = path+'.csml'
110            elif os.path.exists(path+'.xml'):
111                f = path +'.xml'
112            else:
113                raise ValueError("Cannot find CSML file %s" % file)
114           
115            d = csml.parser.Dataset()
116            d.parse(f)
117       
118        else:
119            #it's an NDG identifier, get the document from exist.
120            uri=fileoruri
121            uriN=ndgObject(uri)
122            conflocation=config['ndgconfig']
123            cf=ConfigParser.ConfigParser()
124            cf.read(conflocation)
125            status,x=ndgRetrieve(uriN, cf, discovery=0)
126            d=csml.parser.Dataset()
127            d.parse(x)
128                       
129        return d
130   
131    def list(self, folder=None):
132        """
133        Generator that lists available CSML documents.
134
135        @note: not implemented for eXist.  I'm not sure if this is possible
136            or desireable.
137
138        """
139        if self.csml_dir is None:
140            log.warning('Trying to list CSMLConnector with no filestore.  '
141                        'Maybe using eXist?')
142            return
143       
144        path = self.csml_dir
145       
146        if folder != None:
147            path = os.path.join(path, folder)
148       
149        for fp in os.listdir(path):
150           
151            if os.path.isdir(os.path.join(path,fp)):
152                if folder != None:
153                    # return 'folder/folder'
154                    yield os.path.join(folder, fp)
155                else:
156                    # return 'folder'
157                    yield fp
158               
159            if os.path.splitext(fp)[1] in ['.csml', '.xml']:
160                if folder != None:
161                    # return 'folder/file' without the .csml
162                    yield os.path.join(folder, os.path.splitext(fp)[0])
163                else:
164                    # return 'file' without the .csml
165                    yield os.path.splitext(fp)[0]
166       
167#        for dirpath, dirnames, filenames in os.walk(self.csml_dir):
168#            for filename in filenames:
169#                file_id, ext = os.path.splitext(filename)
170#                if ext in ('.xml', '.csml'):
171#                    # Remove common path bit
172#                    relpath = dirpath[len(self.csml_dir):]
173#                   
174#                    if len(relpath) > 0 and relpath[0] == '/':
175#                        relpath = relpath[1:]
176#                   
177#                    yield os.path.join(relpath, file_id)
178                   
179    def listwfsonly(self):
180            """
181        Generator that lists all CSML endpoints that can't be served through WMS/WCS.
182        This list is (optionally)   defined in the wfsonly.txt file in the csml directory.
183            """
184            cfgfile = os.path.join(self.csml_dir, 'wfsonly.txt')
185            if os.path.exists(cfgfile):
186                f=open(cfgfile, 'r')
187                for line in f:
188                    yield line.strip('\n')
189                f.close()
190            else:
191                return
192   
193    def isGroup(self, fc):
194        return os.path.isdir(os.path.join(self.csml_dir, fc))
195
Note: See TracBrowser for help on using the repository browser.