Package gavo :: Package registry :: Module capabilities
[frames] | no frames]

Source Code for Module gavo.registry.capabilities

  1  """  
  2  VOResource capability/interface elements. 
  3   
  4  The basic mapping from our RD elements to VOResource elements is that 
  5  each renderer on a service translates to a capability with one interface. 
  6  Thus, in the module we mostly deal with publication objects.  If you 
  7  need the service object, use publication.parent. 
  8  """ 
  9   
 10  #c Copyright 2008-2019, the GAVO project 
 11  #c 
 12  #c This program is free software, covered by the GNU GPL.  See the 
 13  #c COPYING file in the source distribution. 
 14   
 15   
 16  import urlparse 
 17   
 18  from gavo import base 
 19  from gavo import svcs 
 20  from gavo import utils 
 21  from gavo.base import meta 
 22  from gavo.base import osinter 
 23  from gavo.registry import tableset 
 24  from gavo.registry.model import ( 
 25          VOR, VOG, VS, SIA, SCS, SLAP, SSAP, TR, DOC) 
 26   
 27   
 28  ###################### Helpers (TODO: Move to tableset, I guess) 
 29   
 30   
31 -def _getParamFromColumn(column, rootElement, typeFactory):
32 """helper for get[Table|Input]ParamFromColumn. 33 """ 34 return rootElement[ 35 VS.name[column.name], 36 VS.description[column.description], 37 VS.unit[column.unit], 38 VS.ucd[column.ucd], 39 typeFactory(column.type)]
40 41
42 -def getInputParamFromColumn(column, rootElement=VS.param):
43 """returns a InputParam element for a rscdef.Column. 44 """ 45 return _getParamFromColumn(column, rootElement, 46 tableset.simpleDataTypeFactory)( 47 std=(column.std and "true") or "false")
48 49
50 -def getInputParams(publication, service):
51 """returns a sequence of vs:param elements for the input of service. 52 """ 53 if hasattr(service, "getInputKeysFor"): # no params on published tables 54 return [getInputParamFromColumn(f) 55 for f in service.getInputKeysFor(svcs.getRenderer(publication.render))]
56 57 58 ####################### Interfaces 59
60 -class InterfaceMaker(object):
61 """An encapsulation of interface construction. 62 63 Each interface maker corresponds to a renderer and thus a publication on a 64 service. It knows enough about the characteristics of a renderer to create 65 interface stan by just calling. 66 67 This class is abstract. To build concrete interface makers, at 68 least fill out the class variables. You will probably want 69 to override the _makeInterface method for some renderers corresponding 70 so specially defined interfaces; the default implementation corresponds 71 to the VOResource definition. 72 """ 73 renderer = None 74 interfaceClass = VOR.interface 75
76 - def _makeInterface(self, publication):
77 accessURL = base.getMetaText(publication, "accessURL", 78 macroPackage=publication.parent) 79 80 parts = urlparse.urlparse(accessURL) 81 map = svcs.getVanityMap().longToShort 82 localpart = parts.path[1:] 83 if localpart in map: 84 # some DAL protocols want ? or & at the end of their accessURLs. 85 # Make sure we keep them 86 appendChar = '' 87 if accessURL[-1] in "?&": 88 appendChar = accessURL[-1] 89 accessURL = urlparse.urlunsplit(parts[:2]+ 90 (map[localpart],)+parts[3:5]) 91 accessURL = accessURL+appendChar 92 93 interface = self.interfaceClass[ 94 VOR.accessURL(use=base.getMetaText(publication, "urlUse"))[ 95 accessURL], 96 VOR.securityMethod( 97 standardId=base.getMetaText(publication, "securityId")), 98 [VOR.mirrorURL[v.getContent()] 99 for v in publication.iterMeta("mirrorURL") 100 if v.getContent()!=accessURL], 101 ] 102 103 try: 104 if base.getConfig("ivoa", "registerAlternative"): 105 interface[VOR.mirrorURL[osinter.switchProtocol(accessURL)]] 106 except ValueError: 107 # probably an external URL that we can't switch 108 pass 109 110 return interface
111
112 - def __call__(self, publication):
113 return self._makeInterface(publication)
114 115
116 -class VOSIInterface(InterfaceMaker):
117 - class interfaceClass(VS.ParamHTTP):
118 _a_role = "std"
119 120
121 -class VOSIAvInterface(VOSIInterface):
122 renderer = "availability"
123
124 -class VOSICapInterface(VOSIInterface):
125 renderer = "capabilities"
126
127 -class VOSITMInterface(VOSIInterface):
128 renderer = "tableMetadata"
129 130
131 -class InterfaceWithParams(InterfaceMaker):
132 """An InterfaceMaker on a publication sporting input parameters. 133 134 This corresponds to a ParamHTTP interface. 135 """ 136 interfaceClass = VS.ParamHTTP 137
138 - def _makeInterface(self, publication):
139 paramSrc = publication.parent 140 if publication.service: 141 paramSrc = publication.service 142 143 return InterfaceMaker._makeInterface(self, publication)[ 144 VS.queryType[base.getMetaText( 145 publication, "requestMethod", propagate=False)], 146 VS.resultType[base.getMetaText( 147 publication, "resultType", propagate=False)], 148 getInputParams(publication, paramSrc) 149 ]
150 151
152 -class SIAPInterface(InterfaceWithParams):
153 renderer = "siap.xml" 154 interfaceClass = SIA.interface
155
156 -class SIAP2Interface(InterfaceWithParams):
157 renderer = "siap2.xml" 158 interfaceClass = SIA.interface
159
160 -class SCSInterface(InterfaceWithParams):
161 renderer = "scs.xml" 162 interfaceClass = SCS.interface
163
164 -class SSAPInterface(InterfaceWithParams):
165 renderer = "ssap.xml" 166 interfaceClass = SSAP.interface
167
168 -class SLAPInterface(InterfaceWithParams):
169 renderer = "slap.xml" 170 interfaceClass = SLAP.interface
171
172 -class SODASyncInterface(InterfaceMaker):
173 # here, we must not inquire parameters, as the core can only 174 # tell when it actually has an ID, which we don't have here. 175 renderer = "dlget"
176 - class interfaceClass(VS.ParamHTTP):
177 role = "std"
178
179 -class SODAAsyncInterface(SODASyncInterface):
180 # same deal as with SODASyncInterface 181 renderer = "dlasync"
182
183 -class EditionInterface(InterfaceMaker):
184 renderer = "edition" 185 interfaceClass = VOR.WebBrowser 186
187 - def _makeInterface(self, publication):
188 return InterfaceMaker._makeInterface(self, publication)( 189 role="rendered")
190 191
192 -class TAPInterface(InterfaceMaker):
193 # for TAP, result type is tricky, and we don't have good metadata 194 # on the accepted input parameters (QUERY, etc). We should really 195 # provide them when we have extensions... 196 renderer = "tap" 197 interfaceClass = TR.interface 198
199 - def _makeInterface(self, publication):
200 return InterfaceMaker._makeInterface(self, publication)(version="1.1")
201 202
203 -class ExamplesInterface(InterfaceMaker):
204 renderer = "examples" 205 interfaceClass = VOR.WebBrowser
206 207
208 -class SOAPInterface(InterfaceMaker):
209 renderer = "soap" 210 interfaceClass = VOR.WebService 211
212 - def _makeInterface(self, publication):
213 return InterfaceMaker._makeInterface(self, publication)[ 214 VOR.wsdlURL[base.getMetaText(publication, "accessURL")+"?wsdl"], 215 ]
216 217
218 -class OAIHTTPInterface(InterfaceMaker):
219 renderer = "pubreg.xml" 220 interfaceClass = VOG.OAIHTTP 221
222 - def _makeInterface(self, publication):
223 return InterfaceMaker._makeInterface(self, publication)(role="std")
224 225
226 -class WebBrowserInterface(InterfaceMaker):
227 """An InterfaceMaker on a publication to be consumed by a web browser. 228 229 This is abstract since various renderers boil down to this. 230 """ 231 interfaceClass = VOR.WebBrowser
232 233
234 -class FormInterface(WebBrowserInterface):
235 renderer = "form"
236
237 -class QPInterface(WebBrowserInterface):
238 renderer = "qp"
239
240 -class DocformInterface(WebBrowserInterface):
241 renderer = "docform"
242 243 # Actually, statics, externals and customs could be anything, but if you 244 # register it, it's better be something a web browser can handle. 245
246 -class FixedInterface(WebBrowserInterface):
247 renderer = "fixed"
248
249 -class StaticInterface(WebBrowserInterface):
250 renderer = "static"
251
252 -class CustomInterface(WebBrowserInterface):
253 renderer = "custom"
254
255 -class VolatileInterface(WebBrowserInterface):
256 renderer = "volatile"
257
258 -class ExternalInterface(WebBrowserInterface):
259 renderer = "external"
260
261 -class GetProductInterface(WebBrowserInterface):
262 renderer = "get"
263 264 265 _getInterfaceMaker = utils.buildClassResolver(InterfaceMaker, 266 globals().values(), instances=True, 267 key=lambda obj: obj.renderer, 268 default=InterfaceWithParams()) 269 270
271 -def getInterfaceElement(publication):
272 """returns the appropriate interface definition for service and renderer. 273 """ 274 return _getInterfaceMaker(publication.render)(publication)
275 276 277 ####################### Capabilities 278 279
280 -class CapabilityMaker(object):
281 """An encapsulation of capability construction. 282 283 Each capability (currently) corresponds to a renderer. 284 285 You will want to override (some of) the class variables at the top, plus the 286 _makeCapability method (that you'll probably still want to upcall for the 287 basic functionality). 288 289 In particular, you will typically want to override capabilityClass 290 with a stanxml element spitting out the right standardIds. 291 292 Additionally, if the capability should also appear in data collections 293 served by a service with the capability, also define auxiliaryId (that's 294 an IVOID like ivo://ivoa.net/std/TAP#aux). These are used in 295 getCapabilityElement. 296 297 CapabilityMakers are used by calling them. 298 """ 299 renderer = None 300 capabilityClass = VOR.capability 301 auxiliaryId = None 302
303 - def _makeCapability(self, publication):
308
309 - def __call__(self, publication):
310 return self._makeCapability(publication)
311 312
313 -class PlainCapabilityMaker(CapabilityMaker):
314 """A capability maker for gerneric VR.capabilities. 315 316 These essentially just set standardId. in addition to what 317 the plain capabilities do. 318 """ 319 standardId = None 320
321 - def _makeCapability(self, publication):
322 return CapabilityMaker._makeCapability(self, publication)( 323 standardID=self.standardId)
324 325
326 -class APICapabilityMaker(CapabilityMaker):
327 renderer = "api"
328 329
330 -class SIACapabilityMaker(CapabilityMaker):
331 renderer = "siap.xml" 332 capabilityClass = SIA.capability 333 auxiliaryId = "ivo://ivoa.net/std/SIA#aux" 334
335 - def _makeCapability(self, publication):
336 service = publication.parent 337 return CapabilityMaker._makeCapability(self, publication)[ 338 SIA.imageServiceType[service.getMeta("sia.type", raiseOnFail=True)], 339 SIA.maxQueryRegionSize[ 340 SIA.long[service.getMeta("sia.maxQueryRegionSize.long", default=None)], 341 SIA.lat[service.getMeta("sia.maxQueryRegionSize.lat", default=None)], 342 ], 343 SIA.maxImageExtent[ 344 SIA.long[service.getMeta("sia.maxImageExtent.long", default=None)], 345 SIA.lat[service.getMeta("sia.maxImageExtent.lat", default=None)], 346 ], 347 SIA.maxImageSize[ 348 service.getMeta("sia.maxImageSize", default=None), 349 ], 350 SIA.maxFileSize[ 351 service.getMeta("sia.maxFileSize", default=None), 352 ], 353 SIA.maxRecords[ 354 service.getMeta("sia.maxRecords", 355 default=str(base.getConfig("ivoa", "dalHardLimit"))), 356 ], 357 SIA.testQuery[ 358 SIA.pos[ 359 SIA.long[service.getMeta("testQuery.pos.ra")], 360 SIA.lat[service.getMeta("testQuery.pos.dec")], 361 ], 362 SIA.size[ 363 SIA.long[service.getMeta("testQuery.size.ra")], 364 SIA.lat[service.getMeta("testQuery.size.dec")], 365 ], 366 ], 367 ]
368 369
370 -class SIAV2CapabilityMaker(SIACapabilityMaker):
371 renderer = "siap2.xml" 372 capabilityClass = SIA.capability2 373 auxiliaryId = "ivo://ivoa.net/std/SIA#query-aux-2.0"
374 375
376 -class SCSCapabilityMaker(CapabilityMaker):
377 renderer = "scs.xml" 378 capabilityClass = SCS.capability 379
380 - def _makeCapability(self, publication):
381 service = publication.service 382 return CapabilityMaker._makeCapability(self, publication)[ 383 SCS.maxSR[base.getMetaText(service, "maxSR", "180")], 384 SCS.maxRecords[str(base.getConfig("ivoa", "dalDefaultLimit")*10)], 385 SCS.verbosity["true"], 386 SCS.testQuery[ 387 SCS.ra[service.getMeta("testQuery.ra", raiseOnFail=True)], 388 SCS.dec[service.getMeta("testQuery.dec", raiseOnFail=True)], 389 SCS.sr[service.getMeta("testQuery.sr", default="0.001")], 390 ], 391 ]
392 393
394 -class SSACapabilityMaker(CapabilityMaker):
395 renderer = "ssap.xml" 396 capabilityClass = SSAP.capability 397
398 - def _makeCapability(self, publication):
399 service = publication.parent 400 return CapabilityMaker._makeCapability(self, publication)[ 401 # XXX TODO: see what we need for "full" 402 SSAP.complianceLevel[ 403 service.getMeta("ssap.complianceLevel", default="minimal")], 404 SSAP.dataSource[service.getMeta("ssap.dataSource", raiseOnFail=True)], 405 SSAP.creationType[service.getMeta("ssap.creationType", 406 default="archival")], 407 SSAP.supportedFrame["ICRS"], 408 SSAP.maxSearchRadius["180"], 409 SSAP.maxRecords[str(base.getConfig("ivoa", "dalHardLimit"))], 410 SSAP.defaultMaxRecords[str(base.getConfig("ivoa", "dalDefaultLimit"))], 411 SSAP.maxAperture["180"], 412 SSAP.testQuery[ 413 SSAP.queryDataCmd[base.getMetaText(service, "ssap.testQuery", 414 raiseOnFail=True)+"&REQUEST=queryData"]], 415 ]
416 417
418 -class SLAPCapabilityMaker(CapabilityMaker):
419 renderer = "slap.xml" 420 capabilityClass = SLAP.capability 421
422 - def _makeCapability(self, publication):
423 service = publication.parent 424 return CapabilityMaker._makeCapability(self, publication)[ 425 SLAP.complianceLevel[ 426 service.getMeta("slap.complianceLevel", default="full")], 427 SSAP.dataSource[service.getMeta("slap.dataSource", raiseOnFail=True)], 428 SSAP.testQuery[ 429 SSAP.queryDataCmd[base.getMetaText(service, "slap.testQuery", 430 raiseOnFail=True)]], 431 ]
432 433 434 _tapModelBuilder = meta.ModelBasedBuilder([ 435 ('supportsModel', meta.stanFactory(TR.dataModel), (), 436 {"ivoId": "ivoId"})]) 437
438 -class TAPCapabilityMaker(CapabilityMaker):
439 renderer = "tap" 440 capabilityClass = TR.capability 441 auxiliaryId = "ivo://ivoa.net/std/TAP#aux" 442
443 - def _makeCapability(self, publication):
444 res = CapabilityMaker._makeCapability(self, publication) 445 446 with base.getTableConn() as conn: 447 from gavo.protocols import tap 448 from gavo.adql import ufunctions 449 450 res[[ 451 TR.dataModel(ivoId=dmivoid)[dmname] 452 for dmname, dmivoid in conn.query( 453 "select dmname, dmivorn from tap_schema.supportedmodels")]] 454 455 res[ 456 # Once we support more than one language, we'll have to 457 # revisit this -- the optional features must then become 458 # a property of the language. 459 [TR.language[ 460 TR.name[langName], 461 [TR.version(ivoId=ivoId)[version] 462 for version, ivoId in versions], 463 TR.description[description], 464 TR.languageFeatures( 465 type="ivo://ivoa.net/std/TAPRegExt#features-udf")[ 466 [TR.feature[ 467 TR.form[udf.adqlUDF_signature], 468 TR.description[udf.adqlUDF_doc]] 469 for udf in ufunctions.UFUNC_REGISTRY.values()]], 470 471 TR.languageFeatures( 472 type="ivo://ivoa.net/std/TAPRegExt#features-adqlgeo")[ 473 [TR.feature[ 474 TR.form[funcName]] 475 for funcName in ("BOX", "POINT", "CIRCLE", "POLYGON", 476 "REGION", "CENTROID", "COORD1", "COORD2", 477 "DISTANCE", "CONTAINS", "INTERSECTS", "AREA")]], 478 479 TR.languageFeatures( 480 type="ivo://ivoa.net/std/TAPRegExt#features-adql-string")[ 481 [TR.feature[ 482 TR.form[funcName]] 483 for funcName in ("LOWER", "ILIKE")]], 484 485 TR.languageFeatures( 486 type="ivo://ivoa.net/std/TAPRegExt#features-adql-offset")[ 487 [TR.feature[ 488 TR.form[funcName]] 489 for funcName in ("OFFSET",)]], 490 491 TR.languageFeatures( 492 type="ivo://ivoa.net/std/TAPRegExt#features-adql-type")[ 493 [TR.feature[ 494 TR.form[funcName]] 495 for funcName in ("CAST",)]], 496 497 TR.languageFeatures( 498 type="ivo://ivoa.net/std/TAPRegExt#features-adql-unit")[ 499 [TR.feature[ 500 TR.form[funcName]] 501 for funcName in ("IN_UNIT",)]], 502 503 TR.languageFeatures( 504 type="ivo://ivoa.net/std/TAPRegExt#features-adql-common-table")[ 505 [TR.feature[ 506 TR.form[funcName]] 507 for funcName in ("WITH",)]], 508 509 TR.languageFeatures( 510 type="ivo://ivoa.net/std/TAPRegExt#features-adql-sets")[ 511 [TR.feature[ 512 TR.form[funcName]] 513 for funcName in ("UNION", "EXCEPT", "INTERSECT")]]] 514 for langName, description, versions 515 in tap.getSupportedLanguages()], 516 [TR.outputFormat(ivoId=ivoId)[ 517 TR.mime[mime], 518 [TR.alias[alias] for alias in aliases]] 519 for mime, aliases, description, ivoId 520 in tap.getSupportedOutputFormats()], 521 [TR.uploadMethod(ivoId="ivo://ivoa.net/std/TAPRegExt#%s"%proto) 522 for proto in tap.UPLOAD_METHODS], 523 TR.retentionPeriod[ 524 TR.default[str(base.getConfig("async", "defaultLifetime"))]], 525 TR.executionDuration[ 526 TR.default[str(base.getConfig("async", "defaultExecTime"))]], 527 TR.outputLimit[ 528 TR.default(unit="row")[ 529 str(base.getConfig("async", "defaultMAXREC"))], 530 TR.hard(unit="row")[ 531 str(base.getConfig("async", "hardMAXREC"))]], 532 TR.uploadLimit[ 533 TR.hard(unit="byte")[ 534 str(base.getConfig("web", "maxUploadSize"))]]] 535 536 return res
537 538
539 -class RegistryCapabilityMaker(CapabilityMaker):
540 renderer = "pubreg.xml" 541 capabilityClass = VOG.Harvest
542 - def _makeCapability(self, publication):
543 return CapabilityMaker._makeCapability(self, publication)[ 544 VOG.maxRecords[str(base.getConfig("ivoa", "oaipmhPageSize"))]]
545 546
547 -class VOSICapabilityMaker(PlainCapabilityMaker):
548 # A common parent for the VOSI cap. makers. All of those are 549 # parallel and only differ by standardID 550 capabilityClass = VOG.capability
551 552
553 -class VOSIAvCapabilityMaker(VOSICapabilityMaker):
554 renderer = "availability" 555 standardId = "ivo://ivoa.net/std/VOSI#availability"
556
557 -class VOSICapCapabilityMaker(VOSICapabilityMaker):
558 renderer = "capabilities" 559 standardId = "ivo://ivoa.net/std/VOSI#capabilities"
560
561 -class VOSITMCapabilityMaker(VOSICapabilityMaker):
562 renderer = "tableMetadata" 563 standardId = "ivo://ivoa.net/std/VOSI#tables"
564
565 -class ExamplesCapabilityMaker(PlainCapabilityMaker):
566 renderer = "examples" 567 standardId = "ivo://ivoa.net/std/DALI#examples"
568
569 -class SOAPCapabilityMaker(CapabilityMaker):
570 renderer = "soap"
571
572 -class FormCapabilityMaker(CapabilityMaker):
573 renderer = "form"
574
575 -class QPCapabilityMaker(CapabilityMaker):
576 renderer = "qp"
577
578 -class ExternalCapabilityMaker(CapabilityMaker):
579 renderer = "external"
580
581 -class StaticCapabilityMaker(CapabilityMaker):
582 renderer = "static"
583
584 -class VolatileCapabilityMaker(CapabilityMaker):
585 renderer = "volatile"
586
587 -class CustomCapabilityMaker(CapabilityMaker):
588 renderer = "custom"
589
590 -class JPEGCapabilityMaker(CapabilityMaker):
591 renderer = "img.jpeg"
592
593 -class FixedCapabilityMaker(CapabilityMaker):
594 renderer = "fixed"
595
596 -class DocformCapabilityMaker(CapabilityMaker):
597 renderer = "docform"
598
599 -class ProductCapabilityMaker(CapabilityMaker):
600 renderer = "get"
601 602
603 -class DatalinkCapabilityMaker(CapabilityMaker):
604 renderer = "dlmeta" 605
606 - class capabilityClass(VOR.capability):
607 _a_standardID = "ivo://ivoa.net/std/DataLink#links-1.0"
608 609
610 -class SODACapabilityMaker(CapabilityMaker):
611 renderer = "dlget" 612
613 - class capabilityClass(VOR.capability):
614 _a_standardID = "ivo://ivoa.net/std/SODA#sync-1.0"
615 616
617 -class SODAAsyncCapabilityMaker(CapabilityMaker):
618 renderer = "dlasync" 619
620 - class capabilityClass(VOR.capability):
621 _a_standardID = "ivo://ivoa.net/std/SODA#async-1.0"
622 623
624 -class EditionCapabilityMaker(CapabilityMaker):
625 renderer = "edition" 626 627 capabilityClass = DOC.capability 628
629 - def _makeCapability(self, publication):
630 res = CapabilityMaker._makeCapability(self, publication) 631 632 # if there's sourceURL meta, add an interface 633 for su in publication.iterMeta("sourceURL"): 634 res[ 635 VOR.WebBrowser(role="source")[ 636 VOR.accessURL[su.getContent()]]] 637 638 return res[ 639 DOC.languageCode[ 640 base.getMetaText(publication, "languageCode", "en")], 641 DOC.locTitle[ 642 base.getMetaText(publication, "locTitle", None)]]
643 644 645 _getCapabilityMaker = utils.buildClassResolver(CapabilityMaker, 646 globals().values(), instances=True, 647 key=lambda obj: obj.renderer) 648 649
650 -def getAuxiliaryCapability(publication):
651 """returns a VR.capability element for an auxiliary publication. 652 653 That's a plain capability with essentially the interface and a 654 standardId obtained from the auxiliaryId attribute of the 655 capability's normal maker. 656 657 If no auxiliaryId is defined, None is returned (which means no 658 capability will be generated). 659 """ 660 capMaker = _getCapabilityMaker(publication.render) 661 if capMaker.auxiliaryId: 662 return CapabilityMaker()(publication)(standardID=capMaker.auxiliaryId)
663 664
665 -def getCapabilityElement(publication):
666 """returns the appropriate capability definition for a publication object. 667 """ 668 if publication.auxiliary: 669 return getAuxiliaryCapability(publication) 670 else: 671 try: 672 maker = _getCapabilityMaker(publication.render) 673 except KeyError: 674 raise base.ui.logOldExc(base.ReportableError("Do not know how to" 675 " produce a capability for the '%s' renderer"%publication.render)) 676 return maker(publication)
677