source: cows/trunk/cows/service/imps/csmlbackend/wfs_csmllayer.py @ 4311

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

Supporting code for bbox and temporal filtering. Methods not yet implemented.

Line 
1"""
2implementation of ILayerMapper, IwfsLayer, IDimension, ILayerSlab interfaces, as defined in wfs_iface.py & wxs_iface.py
3
4"""
5
6from cows.service.imps.csmlbackend.csmlcommon import CSMLLayerMapper, CSMLConnector, BboxAggregator
7from cows.service.wfs_iface import *
8import csml
9from xml.etree import ElementTree as etree
10
11import logging
12log = logging.getLogger(__name__)
13
14class CSMLwfsLayerMapper(CSMLLayerMapper):
15    """
16    Map keyword arguments to a collection of layers.
17    Supports the retrieval of sets of layers according to arbitrary
18    keyword/value pairs.
19    Implements  ILayerMapper
20   
21    WFS differs from WMS/WCS in that the 'layers' are feature types, not instances.
22    So the CSMLwfsLayerMapper map method returns both a map of feature types and a map
23    of feature instances as both are needed for the GetFeature method to work.
24   
25    """
26    def __init__(self):
27        super(CSMLwfsLayerMapper, self).__init__()
28        self.featureinstancecache={}
29   
30
31    def map(self, **kwargs):
32        """
33        Given csml.parser.Dataset object list the names of
34        all layers available.
35       
36        @return: A mapping of layer names to ILayer implementations.
37        @raise ValueError: If no layers are available for these keywords.
38        """
39        fileoruri=kwargs['fileoruri']
40        if fileoruri in self.layermapcache.keys():
41            #we've accessed this layer map before, get it from the cache dictionary
42            return self.layermapcache[fileoruri], self.featureinstancecache[fileoruri]
43         
44        ds = self.connector.get_csml_doc(fileoruri)
45       
46        #The WFS differs from WMS & WCS in that the contents layer is a list of
47        #feature *types* not *instances*. However a record of instances is also
48        #needed to fulfil GetFeature requests:
49        featureset=CSMLFeatureSet() #holds feature instances               
50        layermap={} #feature types       
51        bboxAggregators={}#for aggregations of bounding boxes.
52
53        for feature in csml.csmllibs.csmlextra.listify(ds.featureCollection.featureMembers):
54            title, abstract=self._getInfo(feature)
55            featureset.featureinstances[feature.id]=CSMLFeatureInstance(title, abstract, feature)             
56        for id, instance in featureset.featureinstances.iteritems():
57            ftype='csml:' + instance.featuretype
58            if ftype not in layermap.keys():
59                layermap[ftype]=CSMLwfsLayer(ftype, instance.wgs84BBox)
60                #instantiate an aggregator to compare future bounding boxes with.
61                bboxAggregators[ftype]= BboxAggregator(instance.wgs84BBox)               
62            else:
63                #the featuretype has already been stored in the dictionary.
64                #but, the bounding box may need changing to accommodate this new feature instance.
65#                log.debug('Checking bbox for feature id: %s and title: %s'%(instance._feature.id, instance.title))
66                aggregator=bboxAggregators[ftype]
67                aggregator.aggregate(instance.wgs84BBox)
68                layermap[ftype]=CSMLwfsLayer(ftype, aggregator.bbox)
69           
70
71        if len(layermap) > 0:
72            #cache results
73            self.layermapcache[fileoruri]=layermap
74            self.featureinstancecache[fileoruri]=featureset
75            return layermap, featureset
76        else:
77            raise ValueError
78
79class CSMLFeatureSet(IFeatureSet):
80    """ A set of features available via a WFS. Supports querying methods as used by OGG filters """
81    def __init__(self):
82        self.featureinstances={}
83   
84    def getFeatureByGMLid(self, gmlid):
85        return self.featureinstances[gmlid]
86   
87    def getFeaturesByBBox(self,bboxtuple, srsname):
88        #dummy 
89        log.debug('GET FEATURES BY BBOX')
90        #dummy return value
91        #TODO, process bounding boxes for each feature                   
92        return [self.featureinstances['BLcqIIBG']]
93
94   
95    def getFeaturesByTemporalRange(self, range):
96        #TODO: getFeaturesByTemporalRange
97        return []
98   
99   
100class CSMLFeatureInstance(IFeatureInstance):
101    def __init__(self, title, abstract, feature):
102        """ representing a CSML Feature Instance
103        @ivar title: The title of the feature instance
104        @ivar abstract: The abstract of the feature instance
105        @ivar feature: the csml feature instance object
106         """
107        self.title=title
108        self.abstract=abstract
109        self._feature=feature
110        self.featuretype=self._feature.__class__.__name__
111        bb= self._feature.getCSMLBoundingBox().getBox()
112        #convert 0 - 360 to -180, 180 as per common WMS convention
113        if abs(bb[2]-bb[0]) >= 359 and abs(bb[2]-bb[0]) < 361:
114            bb[0], bb[2]=-180, 180
115        self.wgs84BBox = bb
116       
117    def toGML(self):
118        """ Create a GML (CSML) representation of the feature """
119       
120        #TODO un-hardcode this:
121        emptyelem=etree.Element('{http://ndg.nerc.ac.uk/csml}GridSeriesFeature')
122        csmlelem=self._feature.toXML(emptyelem)
123        return etree.tostring(csmlelem)
124       
125       
126     
127class CSMLwfsLayer(IwfsLayer):
128    """ representing a WFS FeatureType (termed layer here). Implements IwfsLayer
129    @ivar featuretype: The namespaced name of the feature type, e.g. csml:PointSeriesFeature
130   
131    """
132    def __init__(self, featuretype, wgs84bb):
133        self.type=featuretype
134        #Have to hard code some definitions for CSML feature types to
135        #use in the capabilities document as they don't exist anywhere else.
136        #Hardcoding is okay as this is a CSML specific interface, so will only ever deal
137        #with CSML feature types.
138        #TODO: However, might be better to move to some sort of schema.cfg file?
139        self.wgs84BBox=wgs84bb     
140        self.outputformats=['text/xml: subtype=csml/2.0']   
141        if self.type=='csml:GridSeriesFeature':
142            self.title='GridSeriesFeature as defined in Climate Science Modelling Language.'
143            self.abstract='The CSML GridSeriesFeature is used to represent 4D gridded data such as atmospheric model output.'
144            self.keywords=['Grid', 'Climate', 'CSML']
145        elif self.type=='csml:PointSeriesFeature':
146            self.title='PointSeriesFeature as defined in Climate Science Modelling Language.'
147            self.abstract='The CSML PointSeriesFeature represents a time series of measurements at a single point in space.'
148            self.keywords=['Point', 'Timeseries', 'Climate', 'CSML']
149        #TODO: definitions for all feature types.
150       
151       
152
Note: See TracBrowser for help on using the repository browser.