source: TI07-MOLES/trunk/PythonCode/wsgi/ServiceBinding.py @ 2295

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI07-MOLES/trunk/PythonCode/wsgi/ServiceBinding.py@2295
Revision 2295, 8.7 KB checked in by lawrence, 13 years ago (diff)

Cleaning up edge cases in discovery so that while NDG browse isn't
enabled, what you see still makes sense :-).

Line 
1#
2# There are (at least) two classes of service map issues which NDG needs to support.
3# Firstly, one can expect that given a specific NDG record, there is a native
4# service for that record ... eg. for an A record, the native service is the
5# data extractor, but there may be others ... at some point we need to be
6# able to find those out (this is a processing affordance issue, and something
7# that we want to use registries for) ... anyway, meanwhile, we have these "native"
8# service types.
9# Secondly, in D  we have related URL's, which are essentially mappings to
10# services which may exist on the dataset described by that D-catalogue record.
11# This is a special case of the generic case described above ...
12#
13# This module provides classes to support these activities.
14
15from htmlUtilities import hyperlink,image
16from ETxmlView import nsdumb,et2text
17
18class DIFService:
19    ''' A DIF only knows about a related URL '''
20    def __init__(self,c,u,d):
21        ''' Take a related url tuple (content_type,url,description) and store it, using
22        an ndgModifier if necessary '''
23        self.contentType,self.url,self.description=c,u,d
24    def __str__(self):
25        return '<a href="%s" title="%s">%s</a>'%(self.url,self.contentType,self.description)
26
27
28def idconvert(e,helper=None):
29    ''' Converts an XML ndg identifier into a uri version '''
30    if helper is None:
31        helper=nsdumb()
32    s='%s:%s:%s'%(helper.getText(e,'repositoryIdentifier'),
33                    helper.getText(e,'schemeIdentifier'),
34                    helper.getText(e,'localIdentifier'))
35    return s
36
37class ServiceMap:
38    ''' This should itself eventually be a service that can be looked up, or maybe
39    even use the dns '''
40    def __init__(self,config):
41        self.config=config
42        self.seticon('RELATED')
43    def seticon(self,t):
44        ''' Set icon type t, or if it doesn't exist, use RELATED '''
45        self.icon=self.get(t,'icon')
46        self.title=self.get(t,'icon_title')
47        self.iconalt=self.get(t,'icon_alt')
48        if self.icon is None:  self.seticon('RELATED')
49    def do(self,serviceType,dataProvider):
50        '''  Return an actual endpoint for a given service from the data provider, e.g.
51        for ndg_a_service,badc.nerc.ac.uk get http://superglue.badc.rl.ac.uk/cgi-bin/browse.py '''
52        serviceType=serviceType.upper() # ought to be redundant ...
53        r=self.get(serviceType,dataProvider)
54        if r is None:
55            # just return the URL
56            if dataProvider[0:4]!='http':
57                r='http://%s'%dataProvider
58            else: r=dataProvider
59        self.seticon(serviceType)
60        return r
61    def get(self,section,value,default=None):
62        return self.config.get(section,value,default)
63       
64class Service:
65    ''' This simple class simply holds the service information known in a DIF ''' 
66    def __init__(self):
67        self.type='dif_related_url'
68        self.name=''
69        self.url=''
70        self.description=''
71
72class ServiceBinding (Service):
73        ''' Given a specific entryID, we can go from the scheme identifier to the
74        native service which one expects to be able to operate upon it, for example,
75        an NDG-A type identifier should expect the NDG-A-Service running at the
76        specific repository. Note that we support the NDG id in the abbreviated format
77        entryID is a repository:scheme:localidentifier string '''
78        def __init__(self,config,n='',entryID=None):
79            Service.__init__(self)
80            # regrettably we used different things in our ID's than we did in
81            # our difs :
82            self.mapping={'NDG-A0':'NDG_A_SERVICE','NDG-B0':'NDG_B_SERVICE',
83            'NDG-B1':'NDG_B_SERVICE','DIF':'DISCOVERY'}
84            self.serviceMap=ServiceMap(config)
85            self.name=n
86            if entryID is not None:
87                self.fromEntry(entryID)
88        def fromNative(self,nativeID,helper=None,seqno=1):
89            ''' Support native XML ID form of entryID, see also fromEntry '''
90            entryID=idconvert(nativeID,helper)
91            return self.fromEntry(entryID,seqno)
92        def fromEntry(self,entryID,seqno=1):
93            ''' Given an entryID, get the native service '''
94            #e.g. badc.nerc.ac.uk:NDG-A0:someLocalIdentifier
95            s,r,l,b=self.__getsrlb(entryID)
96            uri=self.__makeuri(s,r,l)
97            self.url=self.__makeurl(s,b,uri,seqno)
98            self.serviceType=s
99            self.uri=uri
100            return self
101        def fromRelated(self,elem,entryID,helper=None,seqno=1):
102            ''' Given a DIF related URL, get a service binding,
103            using an instantiated ET helper that's available
104            to avoid problems with namespaces '''
105            # e.g:
106            #<Related_URL>
107            #<URL_Content_Type>NDG_B_Service</URL_Content_Type>
108            #<URL>badc.nerc.ac.uk</URL>
109            #</Related_URL>
110            #<Related_URL>
111            #<URL>http://badc.nerc.ac.uk/browse/badc/CDs/spade9293</URL>
112            #</Related_URL>
113            #following call simply sets some defaults
114            s,r,l,b=self.__getsrlb(entryID)
115            #which we now overwrite with detail from this particular rleated url
116            #following helps us avoid namespace problems
117            if helper is None:helper=nsdumb()
118            self.description=helper.getText(elem,'Description')
119            s=helper.getText(elem,'URL_Content_Type').upper()
120            self.serviceType=s
121            if s!='':
122                #we (NDG) know about this type of URL ...
123                r=helper.getText(elem,'URL')
124                b=self.serviceMap.do(s,r)
125                uri=self.__makeuri(s,r,l)
126                self.url=self.__makeurl(s,b,uri,seqno)
127            else:
128                #unknown type
129                self.serviceType='RELATED'
130                self.url=self.serviceMap.do(self.serviceType,helper.getText(elem,'URL'))
131                uri=self.url
132            self.uri=uri
133            return self
134        def __str__(self):
135            ''' return string only html link '''
136            return hyperlink(self.name,self.url)
137        def icon(self):
138            ''' return html icon linking to specific service '''
139            return hyperlink(image(
140                self.serviceMap.icon,self.serviceMap.iconalt,t=self.serviceMap.title),self.url)
141        def __makeuri(self,s,r,l):
142            ''' Actually create the URI '''
143            if r=='': return l
144            if s in ('NDG_B_SERVICE','DISCOVERY'):
145                uri='%s/%s'%(r,l)
146            else:
147                uri=l
148            return uri
149        def __makeurl(self,s,b,uri,seqno):
150            ''' Actually create the URL, which may be sequentially
151            numbered if it's going to the data extractor (and so
152            iType read from config file will have a %s in it ) '''
153            iType=self.serviceMap.get(s,'instance','uri')
154            if '%s' in iType: iType=iType%seqno
155            return '%s?%s=%s'%(b,iType,uri)
156        def __getsrlb(self,entryID):
157            '''Take an entry ID, and parse it for NDG identifiers otherwise
158            and if not, do something sensible '''
159            try:
160                r,s,l=entryID.split(':')
161                if s in self.mapping: s=self.mapping[s].upper()
162                b=self.serviceMap.do(s,r)
163            except:
164                #not from NDG ... provide only discovery binding
165                s,r,l='DISCOVERY','',entryID
166                b=self.serviceMap.get(s,'default')
167                self.serviceMap.seticon(s)
168            return s,r,l,b
169           
170if __name__=="__main__":
171        import ElementTree as ET
172        s='''<dataModelID>
173                <schemeIdentifier>NDG-A0</schemeIdentifier>
174                <repositoryIdentifier>badc.nerc.ac.uk</repositoryIdentifier>
175                <localIdentifier>acsoe_badc_eae96_macehead_mcf_1</localIdentifier>
176            </dataModelID>'''
177        idelem=ET.fromstring(s)
178        entryID=idconvert(idelem)
179        n=ServiceBinding('macehead',entryID=entryID,serviceFile='serviceMap.config')
180        maceheadServices=[n]
181        s='''<dummy><Related_URL>
182        <URL_Content_Type>NDG_B_Service</URL_Content_Type>
183        <URL>badc.nerc.ac.uk</URL>
184        </Related_URL>
185        <Related_URL>
186        <URL>http://badc.nerc.ac.uk/browse/badc/CDs/spade9293</URL>
187        </Related_URL>
188        <Related_URL>
189        <URL_Content_Type>NDG_A_Service</URL_Content_Type>
190        <URL>glue.badc.rl.ac.uk/somelongpath</URL>
191        <Description> dummy dx example </Description>
192        </Related_URL></dummy>
193        '''
194        stuff=ET.fromstring(s)
195        for x in stuff.findall('Related_URL'):
196            n=ServiceBinding('macehead',serviceFile='serviceMap.config')
197            maceheadServices.append(n.fromRelated(x,idelem))
198        for i in maceheadServices: 
199            print str(i)
200            print i.icon()
Note: See TracBrowser for help on using the repository browser.