source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/csml_wcs.py @ 2681

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/csml_wcs.py@2681
Revision 2681, 8.8 KB checked in by domlowe, 13 years ago (diff)

unicode problem in ndgObject wrapped with str

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"""
6WCS controller driven by CSML.
7
8@author: DominicLowe, Stephen Pascoe
9"""
10
11#NOTE, much of this is straight from WMS and needs to be overhauled.
12import os, time, string, StringIO
13
14from ows_server.lib.base import *
15from ows_server.lib.decorators import *
16import ows_server.lib.validators as V
17
18from elementtree import ElementTree as ET
19from ows_common import exceptions as OWS_E
20from ows_common.wcs import *
21from ows_common.common import BoundingBox
22from ows_common.domain import ValuesUnit, PossibleValues
23
24from ows_server.lib.csml_util import get_csml_doc, extractToNetCDF
25from ows_server.lib.csml_cache import csmlCache, extractCache
26
27from email.mime.multipart import MIMEMultipart
28from email.mime.base import MIMEBase
29from email.mime.text import MIMEText
30from email import encoders
31
32class CsmlWcsController(OwsController):
33    _ows_parameters = {
34        'Format': make_domain(['text/xml']),
35        'ExceptionFormat': make_domain(['text/xml']),
36        }
37
38
39
40    def _createMultipartMime(self, xml, netcdf):
41        #returns a multipart mime file containing the coverage xml + a netcdf file
42       
43        # Create the container (outer) email message.
44        msg = MIMEMultipart()       
45       
46        xmlfile =StringIO.StringIO(xml)
47        xmlfile.readline(), xmlfile.readline() #don't read in first 2 lines (the content type) as MIMEBase also provides it.
48           
49       
50        #add the XML part
51        submsg=MIMEText(xmlfile.read(), _subtype='xml')
52        submsg.add_header('Content-ID', '<coverage.xml>')
53        submsg.add_header('Content-Disposition', 'attachment; filename="coverage.xml"')
54        #submsg.set_type('text/xml; name="coverage.xml"')
55        msg.attach(submsg)
56
57       
58        #add the NetCDF part
59        submsg= MIMEBase('application', 'CF-netcdf') #check in ogc docs
60        submsg.set_payload(netcdf.read())
61        submsg.set_type('application/CF-netcdf')
62        submsg.add_header('Content-Disposition', 'attachment; filename="coverage.nc"')
63        submsg.add_header('Content-ID', '<coverage.nc>')
64        netcdf.close()
65        # Encode the payload using Base64
66        encoders.encode_base64(submsg)
67        msg.attach(submsg)
68       
69        #return the message
70        return msg
71       
72
73    def _loadFeatureDimensions(self, feature):
74        dims = {}
75        #!WARNING
76        # This bit is a hack until the CSML API implements a mechanism
77        # to determine which elements of a domain are longitude and latitude.
78        lon=feature.getLongitudeAxis()
79        lat=feature.getLongitudeAxis()
80        domain=feature.getDomain()
81        for axis_name, axis in domain.iteritems():
82            if axis_name in [lon,lat]:
83                continue           
84            dims[axis_name] =            Domain(possibleValues=PossibleValues.fromAllowedValues(axis),
85                                 #!TODO: this is a fudge until we can deduce UOM.
86                                 valuesUnit=ValuesUnit(uoms=[''],
87                                                       referenceSystems=['']))
88        return dims
89
90    def _loadFeatureSummary(self, feature):
91        dims = self._loadFeatureDimensions(feature)
92        #TODO - need to ensure proper values for Name. ID and Description are populated.
93        cvgTitle=[feature.description.CONTENT]
94        cvgDescription=feature.description.CONTENT
95        cvgAbstract=[feature.description.CONTENT]
96        bbox=c.dataset.getBoundingBox()  #TODO, use the bounding box of the feature not the dataset.
97        return WcsDatasetSummary(identifier=feature.id,
98                                 titles=cvgTitle,
99                                 boundingBoxes=[BoundingBox([bbox[0],bbox[1]], [bbox[2],bbox[3]],
100                                 crs='CRS:84')], dimensions=dims,  description=cvgDescription,abstracts=cvgAbstract
101                                 )
102
103    def _loadCapabilities(self):
104        """
105        Overriding subclass to add layer capabilities
106
107        """
108        # Get default capabilities from superclass
109        sm = super(CsmlWcsController, self)._loadCapabilities()
110        ds = WcsDatasetSummary(titles=['Root Dataset'], datasetSummaries=[], CRSs=['CRS:84'])
111        # Add a DatasetSummary for each feature       
112        for f_n in c.dataset.getFeatureList():       
113            feature_ds = self._loadFeatureSummary(c.dataset.getFeature(f_n))
114            ds.datasetSummaries.append(feature_ds)
115        sm.contents = Contents(datasetSummaries=[ds])
116        return sm
117
118   
119    @operation
120    @parameter('Format', possibleValues=['text/xml'])
121    @parameter('Service', possibleValues=['WCS'], required=True)
122    @parameter('Version', possibleValues=['1.1.0'])
123    def GetCapabilities(self, fileoruri, service=None, version=None):
124        """
125        @note: format and updatesequence parameters are not supported
126            by this WMS.
127
128        """
129        # Populate the context object with information required by the template
130       
131        #get doc from cache or disk:
132        c.dataset = csmlCache[fileoruri]
133        return self._renderCapabilities('ows/wcs_capabilities')
134
135   
136    @operation
137    @parameter('Version', possibleValues=['1.1.0'], required=True)
138    @parameter('Identifier', required=True)
139    @parameter('BoundingBox', required=True, validator=V.bbox_2d)
140    @parameter('TimeSequence',required=True, validator=V.iso8601_time)
141    @parameter('Format', possibleValues=['application/netcdf'], required=True)
142    @parameter('Store', validator = V.boolean('Store'))
143    @parameter('Status', validator = V.boolean('Status'))
144    #TODO some more parameter to add here
145    # Dimension parameters Time, Elevation, etc. are handled separately
146    def GetCoverage(self, file, version, format, identifier, boundingbox, timesequence, store=False, status=False):
147        try:
148                    # Retrieve dataset and selected feature
149           
150            dataset = get_csml_doc(file)
151            feature = dataset.getFeature(identifier)
152            if feature is None:
153                raise OWS_E.InvalidParameterValue('Coverage not found', 'identifier')
154   
155            #set bounding box TODO
156            sel = dict(latitude=(boundingbox[1], boundingbox[3]), longitude=(boundingbox[0], boundingbox[2]))           
157            sel['time']=timesequence
158           
159            # Extract via CSML.subsetToGridSeries()
160            if store:
161                filename = extractToNetCDF(feature, sel, publish=True)
162            else:
163                filename = extractToNetCDF(feature, sel)
164           
165            #use the randomly allocated filename as a basis for an identifier
166            f=os.path.basename(filename)
167            c.fileID=os.path.splitext(f)[0]
168           
169            #Depending on if the 'store' parameter is set, either return the netcdf file + coverage xml as a multipart mime or return a coverage document containing a link.
170                     
171            if store:
172                if status:
173                    #STORE = true, STATUS = true:
174                    #hand off file "id" to StatusController to determine correct ExectuteResponse type response.
175                    status=StatusController()
176                    jobID=os.path.splitext(os.path.basename(filename)[9:])[0] #remove the 'csml_wxs_' prefix and file extension to create a jobID
177                    return status.getStatus(jobID)                   
178                else:
179                    #STORE=true, STATUS = false: Return Coverage XML document with link to file.
180                    #use the temp file name (minus extension) as an ID
181                    c.hyperlink = 'http://'+request.environ['HTTP_HOST']+'/'+os.path.basename(request.environ['paste.config']['app_conf']['publish_dir'])+'/'+os.path.basename(filename)
182                    r=render_response('wcs_getCoverageResponse', format='xml')
183                    r.headers['content-type'] = 'text/xml'
184                    return r                                 
185            else:               
186                #STORE = FALSE, STATUS therefore irrelevant, return Multipart Mime.
187                netcdfFile=open(filename, 'r')
188                c.hyperlink="cid:coverage.nc"
189                xmlfile=render_response('wcs_getCoverageResponse', format='xml')
190                xmlfile.headers['content-type'] = 'text/xml'
191                multipart=self._createMultipartMime(xmlfile, netcdfFile)       
192                msg=multipart
193                #msg=open(multipart, 'r').readlines()
194                return Response(content=msg, mimetype='multipart') 
195                 
196        except Exception, e:
197            if isinstance(e, OWS_E.OwsError):
198                raise e
199            else:
200                raise OWS_E.NoApplicableCode(e)
201       
202       
Note: See TracBrowser for help on using the repository browser.