source: MILK/trunk/milk_server/milk_server/models/stubB.py @ 4469

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/models/stubB.py@4469
Revision 4469, 12.2 KB checked in by cbyrom, 12 years ago (diff)

Strip out code not relevant to MILK - mainly WCS and WMS stuff - also including the CSML server code + trackback code
Also tidy up structure of 'public' dir - setting up new 'style' dir and
centralising icons in icons dir + remove all unused icons, javascript and stylesheets.
Also strip out testcase code and populate new test directory structure.

Line 
1#!/usr/bin/env python
2#
3# This python code (will) handle all forms of stub-B and provide HTML
4# methods to the extent required by the NDG browse functionality.
5# NB, It would be cleaner to use Dom's way of doing things but we'd
6# need a schema for that ...
7# BNL April 2006
8#
9
10from milk_server.lib.Utilities import *
11from ndgUtils.BeautifulSoup import BeautifulSoup
12from AccessControl import AccessControl
13from milk_server.lib.geoUtilities import Bounding
14from People import *
15from ndgUtils import ndgObject
16import logging
17
18try: #python 2.5
19    from xml.etree import ElementTree as ET
20except ImportError:
21    try:
22        # if you've installed it yourself it comes this way
23        import ElementTree as ET
24    except ImportError:
25        # if you've egged it this is the way it comes
26        from elementtree import ElementTree as ET
27
28
29def collapse2(keywords,split='>'):
30    ''' Take the last element of a DIF parameter tree entry, and put them in a dictionary
31    under the DIF category '''
32    d={}
33    for item in keywords:
34        line=item.split(split)
35        category=line[0]
36        if category not in d: d[category]=[]
37        while line<>[]:
38            c=line.pop()
39            if c<>'': 
40                if c<>category:
41                    d[category].append(c)
42                line=[]
43    return d
44
45
46def idconvert(helper,elem,config=None,idelem='dgMetadataID'):
47    ''' Given an elementTree element for a dgMetadataID, create
48    a standard ndg URI, and produce an ndgObject '''
49    id=helper.find(elem,idelem)
50    entryID='%s__%s__%s'%(helper.getText(id,'repositoryIdentifier'),
51                            helper.getText(id,'schemeIdentifier'),
52                            helper.getText(id,'localIdentifier'))
53    uri=ndgObject(entryID,config)
54    return uri
55
56class ndgLink:
57    ''' This is a holder for an ndgObject which has a name (and possibly abbreviation) '''
58    def __init__(self,name,abbrev,ndgO,label='',image=None):
59        self.ndgObject=ndgO
60        self.name=name
61        self.abbrev=abbrev
62        self.image=image
63        self.label=label
64        self.URL=ndgO.BURL
65    def toHTML(self):
66        ### needs to be finished
67        return self.ndgObject.URL
68
69class dataGranule:
70        ''' Provides support for data granule structures '''
71        def __init__(self,helper,elem,config,name=''):
72            logging.info("Setting up data granule, %s" %name)
73            self.elem=elem
74            self.constraints=AccessControl(helper.find(elem,'accessControlPolicy'))
75            self.name=name
76            self.uri=idconvert(helper,elem,config,idelem='dataModelID')
77            self.entryID=self.uri.uri
78            self.bbox=Bounding(self.elem,helper,entity='moles')
79            self.timeCoverage=temporal(self.elem,helper)
80            self.parameters=helper.getText(elem,'dgGranuleSummary/dgParameterSummary/ParameterName',multiple=1)
81           
82class ObservationStation:
83    def __init__(self,h,e):
84        logging.info("Setting up stubB to represent observation station data")
85        self.e=
86        self.hdg='Observation Station'
87        if e is None: return
88       
89class DataProductionTool:
90    def __init__(self,h,e):
91        logging.info("Setting up stubB to represent data production tool data")
92        self.e=e
93        i=h.find(e,'dgInstrument')
94        if i is not None: 
95            self.hdg='Instrument'
96        else:
97            self.hdg='Model'
98        if e is None: return
99       
100class Activity:
101    def __init__(self,h,e):
102        logging.info("Setting up stubB to represent activity data")
103        self.e=e
104        self.hdg='Activity'
105        if e is None: return
106       
107def Deployments(elem,helper,config):
108    ''' This is the late June 2007 version '''
109    logging.info("Setting up deployments data")
110    if elem is None: return None
111    types={'dptList':'dataproductiontool','activityList':'activity','obsStnList':'observationstation','dataEntityList':'dataentity'}
112    names={'dptList':'Data Production Tools','activityList':'Activities','obsStnList':'Observation Stations','dataEntityList':'Data Entities'}
113    result={}
114    for alist in types:
115        logging.debug("Looking for --%s-" %alist)
116        blist=helper.find(elem,alist)
117        collection=[]
118        if blist is not None:
119            for object in blist:
120                logging.debug(object)
121                uri=idconvert(helper,object,config=config)
122                name=helper.getText(object,'name')
123                shortName=helper.getText(object,'abbreviation')
124                collection.append((uri,name,shortName))
125            result[names[alist]]=collection
126    logging.info("Deployments data set up")
127    return result
128           
129def temporal(elem,helper):
130    ''' Parse for time coverage attributes '''
131    timeElems=helper.findall(elem,'*//dgTemporalCoverage')
132    tc=[]
133    for e in timeElems:
134        t=e.find('DateRange')
135        if t is not None:
136            c=[helper.getText(t,'DateRangeStart'),]
137            c.append(helper.getText(t,'DateRangeEnd'))
138        else:
139            c=[helper.getText(e,'DateSingle'),'']
140        c.append(helper.getText(elem,'*/dgDatasetStatus/dgDatasetClosure'))
141        tc.append(c)
142    return tc
143           
144def parseParameters(plist,helper):
145    ''' Takes a list of ET Parameter Summary elements, and parses them into a
146    sensible pythonic structure. In particular, given:
147    <dgParameterSummary>
148        <IsOutput>true</IsOutput>
149        <dgStdParameterMeasured>
150            <dgValidTerm>BAROCLINIC V_VELOCITY (OCEAN) CM/S</dgValidTerm>
151            <dgValidTermID>
152                <ParentListID>COAPEC_500YrRun_wholerun_decadal_ocean</ParentListID>
153                <TermID>null</TermID>
154            </dgValidTermID>
155        </dgStdParameterMeasured>
156        <ParameterName>BAROCLINIC V_VELOCITY (OCEAN) CM/S</ParameterName>
157    </dgParameterSummary>
158    we take the parameter name and the parentlistID and use them to build up a
159    parameter dictionary '''
160    ptypes={}
161    dif={}
162    for p in plist:
163        ptype=helper.getText(p,'dgStdParameterMeasured/dgValidTermID/ParentListID')
164        if ptype not in ptypes: ptypes[ptype]=[]
165        ptypes[ptype].append(helper.getText(p,'ParameterName'))
166    gcmd='http://vocab.ndg.nerc.ac.uk/term/P111'
167    if gcmd in ptypes: 
168        dif=collapse2(ptypes[gcmd],split='/')
169        del ptypes[gcmd]
170    return dif,ptypes
171           
172class DataEntity:
173    def __init__(self,helper,element):
174        ''' Attempt to instantiate this stubB as a data entity'''
175        logging.info("Setting up stubB to represent data entity")
176        self.elem=element
177        self.helper=helper
178        #just one curator
179        self.curator=dgContact(self.elem.find('dgDataRoles/dgDataCurator'),ctype='organisation')
180        #possibly multiple creators
181        self.creators=[dgContact(i) for i in self.elem.findall('dgDataRoles/dgDataCreator')]
182        host,service = '','' # dummy for now
183        #possibly multiple granules
184        self.getGranules()
185        #bounding box, handled as a class because this is going to be difficult ...
186        self.bbox=Bounding(self.elem,helper,entity='moles')
187        self.timeCoverage=temporal(self.elem,self.helper)
188        #parameters
189        pelem=self.helper.findall(self.elem,'dgDataSummary/dgParameterSummary')
190        self.parameters,self.extraParameters=parseParameters(pelem,self.helper)
191        self.hdg='Data Entity'
192       
193    def getGranules(self):
194        ''' Load up the granule content within the entity '''
195        logging.info("Adding data granule data")
196        granList=self.elem.findall('dgDataGranule')
197        self.granules=[]
198        i=0
199        for item in granList:
200            i+=1
201            #following needs to be refactored when granule definition includes a proper name ...
202            name=wrapGetText(item,'dgGranuleSummary/dgGranuleName')
203            if name=='': name='Granule %s'%i
204            self.granules.append(dataGranule(self.helper,item,self.config,name=name))
205        logging.info("Granule data added")
206
207class dgMetadataDescription:
208   
209    def __init__(self,helper,elem,viewService):
210        ''' Initialise a Metadata Description '''
211        n=idconvert(helper,elem)
212        self.uri=n.uri
213        self.logo=None
214        self.abstract=helper.getText(elem,'abstract/abstractText')
215        self.texts=[]
216        self.onlineRefs=[]
217        for e in helper.findall(elem,'descriptionSection'):
218            textElem=helper.find(e,'dgDescriptionText')
219            if textElem is not None:
220                text=(textElem.text or '')
221                tail=''
222                for i in textElem: 
223                    text+=ET.tostring(i)
224                    tail=(i.tail or '')
225                text+=tail
226                ctype=helper.getText(e,'contentType')
227                if ctype in ['','text/html']:
228                    soup=BeautifulSoup(text)
229                    text=soup.prettify()
230                self.texts.append((text,ctype))
231        online=helper.findall(elem,'descriptionSection/descriptionOnlineReference/dgSimpleLink')
232        for o in online:
233            rtype=helper.getText(o,'name')
234            #url and uri supported in 1.4 moles, but no one has implemented that yet ...
235            uri,url=helper.getText(o,'URI'),helper.getText(o,'URL')
236            if rtype=='Logo':
237                self.logo=uri
238            else:
239                try:
240                    value=help
241                    self.onlineRefs.append((rtype,{'NumSim':'%s/%s'%(viewService,uri)}[rtype]))
242                except KeyError:
243                    self.onlineRefs.append((rtype,uri))
244
245
246class stubB(DataEntity,ObservationStation,DataProductionTool,Activity):
247       
248        ''' Holds the stub-b document and provides methods which get and manipulate it '''
249       
250        def __init__(self,elem,config):
251                logging.info("Setting up stubB object with moles data")
252                '''Instantiate with an element tree elem '''
253               
254                self.tree=elem
255                self.metadataType='NDG-B1'
256                self.services=[]
257                self.config=config
258                self.citation=''
259                self.personnel=[] # for DIF compatiability for the moment.
260                self.parameters={}
261                self.extraParameters={}
262                self.granules=[]
263                self.logos=[]
264               
265                try:
266                        helper=nsdumb(self.tree)
267                        self.name=helper.getText(self.tree,'name')
268                except Exception,e:
269                        raise ValueError('Error instantiating stubB [%s]'%e)
270
271                self.ndgObject=idconvert(helper,self.tree,self.config)
272                self.entryID=self.ndgObject.uri
273                self.viewService=self.ndgObject.viewService
274               
275                #Note that the root of the ElementTree instance is dgMetadataRecord
276                #so we don't need (or want) that in our xpath expressions.
277               
278                self.constraints=AccessControl(helper.find(self.tree,'dgMetadataSecurity'))
279                self.abbreviation=helper.getText(self.tree,'abbreviation')
280                if self.abbreviation=='': self.abbreviation=self.name[0:min(15,len(self.name))]
281                logos=helper.findall(self.tree,'dgMetadata/dgMetadatdataRecord/logos/logoURI')
282                for l in logos:
283                    self.logos.append((helper.find(l,'dgSimpleLink/name'),
284                                       helper.find(l,'dgSimpleLink/URI')))
285               
286                for i in ('dgDataEntity','dgActivity','dgDataProductionTool','dgObservationStation'):
287                    elem=helper.find(self.tree,i)
288                    if elem is not None:
289                        logging.info("- moles data represents: %s" %i) 
290                        break
291                if elem is None:
292                    raise ValueError('StubB record does not contain an Activity, DE, DPT, ObsStn')
293                elif elem.tag=='dgDataEntity':
294                        DataEntity.__init__(self,helper,elem)
295                elif elem.tag=='dgActivity':
296                        Activity.__init__(self,helper,elem)
297                elif elem.tag=='dgDataProductionTool':
298                        DataProductionTool.__init__(self,helper,elem)
299                elif elem.tag=='dgObservationStation':
300                        ObservationStation.__init__(self,helper,elem)
301
302                self.description=dgMetadataDescription(
303                    helper,helper.find(self.tree,'dgMetadataDescription'),self.viewService)
304                if self.description.logo is not None:
305                    self.logos.append((('Logo',self.description.logo)))
306                self.abstract=self.description.abstract
307                self.stubBtype=elem.tag
308               
309                # now go get all the related links
310                self.related=Deployments(helper.find(elem,'DeploymentSummary'),helper,self.config)
Note: See TracBrowser for help on using the repository browser.