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

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

Fixes for ticket:722, changing to internal unicode (probably not complete),
with decode on the edge coming out ... fixes 722 but may have some
other problems now ...

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