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