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

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

Major refactoring of the wms code. the csml wms code is now based on the geoplot wms code. I've also increased the use of inheritance in the geoplot wms code to reduce duplication.

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