source: TI03-DataExtractor/trunk/dxs/bin/DXWSInterface.py @ 1715

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/trunk/dxs/bin/DXWSInterface.py
Revision 1715, 15.7 KB checked in by astephen, 13 years ago (diff)

Merged with titania version.

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2
3#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
4#   This software may be distributed under the terms of the
5#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
6
7"""
8DXWSInterface.py
9================
10
11A web service wrapper around the entire package.
12
13Notes about the sessionID and secureToken object
14------------------------------------------------
15
16The sessionID carries information about the current session but has no security
17implications. It is simply a way for the server to keep track of the request
18between calls.
19
20The secureToken is a security object (which should be encoded) that is time limited and provides
21information on what the user is allowed to access on the server. Some servers
22do not run security and so just send around a None type as the secureToken. Those
23implementing security will require that the secureToken (held in a string) is sent
24with each method call. During each call it will updated (to ensure it remains
25time valid) and returned.
26
27
28"""
29
30# Import standard library modules
31import sys
32import re
33import urllib
34import os, types
35
36# Get configuration file as first argument
37args=sys.argv[1:]
38if len(args)!=1:
39    print "ERROR: please provide the location of the configuration file as the only argument to this script."
40    sys.exit()
41   
42configFile=args[0]
43configPath, configFilename=os.path.split(configFile)
44sys.path.insert(0, configPath)
45exec ("from %s import *" % configFilename[:-3])
46
47# Path for virtual variables
48extraPath=os.path.split(configPath)[0]
49sys.path.insert(0, extraPath)
50
51from ZSI import dispatch
52#from ZSI.version import Version
53Version=(2,0,0)#(1,6,1) # of client ZSI - not this one!
54# Sort the ZSI version out
55zsiversion=float("%s.%s" % Version[:2])
56
57# Import package modules
58from pydxs.common import *
59from pydxs.DXController import *
60#from pydxs.serverConfig import *
61from pydxs.DXRMLHandler import *
62from pydxs.DXErrors import *
63
64# Set global variables
65timePattern=re.compile("(\d{4})-(\d{1,2})-(\d{1,2}).(\d{1,2}):(\d{1,2}):(\d{1,2}(\.\d+)?)")
66         
67
68def callControllerDirectly(argList):
69    """
70    Function wrapper to Controller class. This can be called directly
71    to perform all operations or the other Web Service methods can be
72    called in the appropriate order.
73    """   
74    # Parse startTime and endTime arguments into expected form
75    for key, value in argList:
76        args[key]=value
77        for ts in ("start", "end"):
78            if key.find("%sTime_" % ts)>-1:
79                timeComponents=time.strp(value, "%Y-%m-%d %H:%M:%S")[:6]
80       
81                for tk in TIME_KEYS:
82                    # Set each component e.g. startYear_1, endHour_2
83                    args["%s%s_%s" % (ts, tk, key.split("_")[-1])]=timeComponents[TIME_KEYS.index(tk)]
84
85    # Parse horizontalDomain argumnets into expected form
86    if args.has_key("horizontalDomain"):
87        for hk in HORIZ_KEYS:
88            args[hk]=args["horizontalDomain"][HORIZ_KEYS.index(hk)]
89                       
90    return Controller(args)
91
92
93def getStatus(sessionID, secureToken="undefined"):
94    """
95    Returns the status of a request.
96    """
97    print "\nMethod called: getStatus\n"
98    args={"sessionID":sessionID, "secureToken":secureToken, "action":"getStatus"}
99
100    try:
101        controller=DXController(args)
102    except Exception, error:
103        return str(error)
104
105    if hasattr(controller, "fork") and controller.fork==1:
106         print "CLEAN EXIT?"
107         os._exit()
108
109    status=controller.status
110    errorString=getattr(controller, "errorString", "")
111    print controller.__dict__
112    outputFilePaths=controller.bag["outputFilePaths"]
113
114    secureToken=controller.secureToken
115    return [[status], [errorString], [outputFilePaths], [secureToken]]
116
117
118def startSession(username="undefined", password="undefined", secureToken="undefined"):
119    """
120    Logs a user in and supplies them with a session ID as well
121    as an encoded security token. The session ID connects them to their
122    current request serverside whilst the security token is used to
123    authorise their access.
124    """
125    print "\nMethod called: startSession\n"
126    args={"username":username, "password":password, "secureToken":secureToken} 
127       
128    try:
129        controller=DXController(args)
130    except Exception, error:
131        print "QQQQQQQQQQQQQQQQQQQQQQQQQ"
132        return str(error)           
133       
134    sessionID=controller.bag["sessionID"]
135    secureToken=controller.secureToken
136    # Have to return list of lists for ZSI to work (?!)
137
138    if zsiversion<2.0:
139        sessionID=[sessionID]
140        secureToken=[secureToken]
141    print sessionID, secureToken
142    return [sessionID, secureToken]
143       
144
145def getOptions(sessionID, secureToken="undefined", optionCategoryRequested="undefined"):
146    """
147    Returns a category description of the next set of options (or the option category
148    requested by the user), a list of options based
149    on what the user has yet to request, a string explaining some more about this and a
150    security token.
151   
152    The options will be presented following the heirarchy:
153        DatasetGroups
154        Datasets
155        Variables
156        HorizontalDomain
157        VerticalDomain
158        TemporalDomain
159        OutputFormat
160    """   
161    print "\nMethod called: getOptions\n"
162    print "ARGS: sessionID: %s\nsecureToken: %s, optionCategoryRequested:%s" %        (sessionID, secureToken, optionCategoryRequested)
163    if type(sessionID)==type(u""):
164        sessionID=deUnicodeObject(sessionID)
165       
166    args={"sessionID":sessionID, "secureToken":secureToken, 
167                "optionCategoryRequested":optionCategoryRequested}
168
169    try:
170        controller=DXController(args)
171    except Exception, error:
172        return str(error)
173 
174    optionsObject=controller.options
175    secureToken=controller.secureToken
176    print "Options object:", optionsObject
177
178    summaryString=createSummaryString(controller.bag)
179
180    return [[optionsObject+[summaryString]+[secureToken]]]
181
182
183def selectOptions(sessionID, argList):
184    """
185    Makes a selection based on user requirements. This will typically follow a call
186    to getOptions() to find out what the options are.
187    Returns a call to getOptions() to grab the next set of options available to the
188    user. Alternatively, if it fails, an errorString is returned.
189    """
190    print "\nMethod called: selectOptions\n"   
191    if type(sessionID)==type(u""):
192        sessionID=deUnicodeObject(sessionID)
193    args={"sessionID":sessionID}
194   
195    print "Key, Value..."
196    for key,value in argList:
197        key=deUnicodeObject(key)
198        value=deUnicodeObject(value)
199        if type(key)==type(u""):
200            newkey=str(key)
201        else:
202            newkey=key
203        if type(value)==type(u""):
204            value=str(value)
205        args[newkey]=value   
206        print newkey, value
207
208    try:
209        controller=DXController(args)
210    except Exception, error:
211        try:
212            e0=error[0]
213            if type(e0)==type("jljl") and len(e0)>1:
214                error=e0
215        except:
216            pass
217        return str(error)
218   
219    optionsObject=controller.options
220    secureToken=controller.secureToken
221    print "Options object:", optionsObject
222
223    summaryString=createSummaryString(controller.bag)
224
225    return [[optionsObject+[summaryString]+[secureToken]]]
226    """secureToken=controller.secureToken       
227   
228    if args.has_key("optionCategoryRequested"):
229        optionCategoryRequested=args["optionCategoryRequested"]
230    else:
231        optionCategoryRequested="undefined"
232
233    opts=getOptions(sessionID, secureToken, optionCategoryRequested)
234    print "\n\nReturned from select options:\n", opts, "\n\n"
235    return opts"""
236 
237   
238def isComplete(sessionID, secureToken="undefined"):
239    """
240    Returns 1 if the request is complete (i.e. ready to create output file(s))
241    and 0 if not. Also returns a security token.
242    """
243    print "\nMethod called: isComplete\n"
244    optionsObject=getOptions(sessionID, secureToken)
245    secureToken=optionsObject[-1]
246    if optionsObject==[secureToken]:
247        return [[1], secureToken]
248    else:
249        return [[0], secureToken] 
250   
251
252def createOutput(sessionID, secureToken="undefined"):
253    """
254    Creates the outputs specified by user selections. It writes these files
255    locally and returns a list of paths to the data as either FTP or HTTP
256    locations.
257    Returns a list of paths and a security token.
258    """
259    print "\nMethod called: createOutput\n"
260    args={"sessionID":sessionID, "secureToken":secureToken, "getOutput":"getOutput"}
261     
262    try:
263        controller=DXController(args)
264    except Exception, error:
265        return str(error)
266
267    if hasattr(controller, "fork") and controller.fork==1:
268         print "CLEAN EXIT?"
269         os._exit()
270   
271    secureToken=controller.secureToken
272    print controller.bag
273    pathList=controller.bag["outputFilePaths"]
274
275    if zsiversion<2.0:
276        pathList=[pathList]
277        secureToken=[secureToken]
278
279    return [pathList, secureToken]
280
281
282def newSession(sessionID, secureToken="undefined"):
283    """
284    Deletes content of current request.
285    Returns the sessionID and the security token..
286    """
287    print "\nMethod called: newSession\n"   
288    args={"sessionID":sessionID, "secureToken":secureToken, "clearSession":"clearSession"}
289     
290    try:
291        controller=DXController(args)
292    except Exception, error:
293        return str(error) 
294   
295    secureToken=controller.secureToken
296    return [[sessionID], [secureToken]]
297
298
299def setNumberOfDatasets(sessionID, n, secureToken="undefined"):
300    """
301    Re-selects the number of datasets the user wants to deal with in the request.
302    Default is 1.
303    Returns 1 if successful and an errorString if not, as well as a security token.
304    """
305    print "\nMethod called: setNumberOfDatasets\n"
306   
307    args={"sessionID":sessionID, "numberOfDatasets":n, "secureToken":secureToken}
308
309    try:
310        controller=DXController(args)
311    except Exception, error:
312        return str(error)   
313
314    secureToken=controller.secureToken
315    return [[1], [secureToken]]
316       
317       
318def summariseRequest(sessionID, secureToken="undefined"):
319    """
320    Returns a listing of the current request in a string and a security token.
321    """   
322    print "\nMethod called: summariseRequest\n"
323    args={"sessionID":sessionID, "secureToken":secureToken}
324   
325    try:
326        controller=DXController(args)
327    except Exception, error:
328        return str(error)   
329
330    #req=controller.bag
331    summaryString=createSummaryString(controller.bag)
332    """summaryString="\n"+"*"*40
333    summaryString=summaryString+"\nSummary of current request follows\n"
334    summaryString=summaryString+"*"*40+"\n\n"
335   
336    exclusions=("callMethod", "secureToken", "optionCategoryRequested",
337                "action", "targetPage")
338               
339    for key in req.keys():
340        if req[key]!="" and key not in exclusions: 
341            summaryString=summaryString+("%s:\t%s\n" % (key, req[key]))"""
342
343    print "\n"*10, summaryString
344    secureToken=controller.secureToken 
345    return [[summaryString], [secureToken]]
346     
347
348def uploadRequest(sessionID, requestXMLString, secureToken="undefined"):
349    """
350    Allows the user to send a request in the form of a string containing the
351    contents of an XML file conforming to the dx request specification (not
352    yet written). This is also called a Data Subset Specifier.
353    This function parses the XML into a dictionary and then uploads the arguments.
354    Returns a status flag (1=success, None=failure) and the secure token.
355    """
356    print "Calling: uploadRequest\n"
357   
358    try:
359        args=DXRMLParser(requestXMLString).getDictionary()
360    except DXError, error:
361        return "Error parsing the Request XML file you provided:   \n"+str(error)       
362    except Exception, error:
363        return "Error parsing the Request XML file you provided:   \n"+str(error)
364       
365    args["sessionID"]=sessionID
366    args["secureToken"]=secureToken
367   
368    try:
369        controller=DXController(args)
370    except Exception, error:
371        return [[0], [secureToken]]   
372             
373    secureToken=controller.secureToken 
374    return [[1], [secureToken]]
375
376
377def getDataSubsetSpecifier(sessionID, secureToken="undefined"):
378    """
379    Returns the dataSubsetSpecifier XML document (which might be S-metadata)
380    required by a Delivery Service to describe the subset requested, and a
381    security token.
382    """
383    print "\nMethod called: getDataSubsetSpecifier\n"
384    args={"sessionID":sessionID, "secureToken":secureToken}
385   
386    try:
387        controller=DXController(args)
388    except Exception, error:
389        return str(error)     
390   
391    secureToken=controller.secureToken
392    sessionObj=controller.bag
393   
394    try:
395        dataSubsetSpecifierXMLString=DXRMLGenerator(sessionObj).xmlString
396    except Exception, error:
397        return "Could not provide the Request XML string:   "+str(error)
398   
399    print dataSubsetSpecifierXMLStringprint
400    return [[dataSubsetSpecifierXMLString], [secureToken]]
401
402
403def getExtractionCosts(sessionID, secureToken="undefined"):
404    """
405    Returns an estimated duration for the creation of the output data and the
406    estimated volume of the output.
407    """
408    print "\nMethod called: getExtractionCosts\n"   
409    args={"sessionID":sessionID, "secureToken":secureToken, "action":"requestCosts"}
410   
411    try:
412        controller=DXController(args)
413    except Exception, error:
414        print "STOPPED HERE..."
415        return str(error)   
416
417    print "TESTTEST"       
418    secureToken=controller.secureToken
419    (estimatedDuration, estimatedVolume)=(controller.bag["estimatedDuration"], controller.bag["estimatedVolume"])
420    print "Returning...", [estimatedDuration, estimatedVolume, secureToken]
421
422    if zsiversion<2.0:
423        estimatedDuration=[estimatedDuration]
424        estimatedVolume=[estimatedVolume]
425        secureToken=[secureToken]
426
427    return [estimatedDuration, estimatedVolume, secureToken]       
428
429
430def getDatasetGroupOptions(sessionID, secureToken="undefined"):
431    """
432    Get the dataset group options available.
433    """
434    print "\nMethod called: getDatasetGroupOptions\n\n"
435    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="datasetGroup")
436   
437
438def makeDatasetGroupSelections(sessionID, secureToken, datasetGroupList):
439    """
440    Make selections for dataset group.
441    """
442    print "Called: makeDatasetGroupSelections\n"
443    argList=[]
444    argList.append(["secureToken", secureToken])
445    counter=1
446    for selection in datasetGroupList:
447        argList.append(["datasetGroup_%s" % counter, selection])
448        counter=counter+1
449       
450    return selectOptions(sessionID, argList)
451
452
453def getDatasetOptions(sessionID, secureToken="undefined"):
454    """
455    Get the dataset options available.
456    """
457    print "\nMethod called: getDatasetOptions\n\n"
458    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="dataset")
459   
460   
461def makeDatasetSelections(sessionID, secureToken, datasetList):
462    """
463    Make selections for Dataset.
464    """
465    print "Called: makeDatasetSelections\n"
466    argList=[]
467    argList.append(["secureToken", secureToken])
468    counter=1
469    for selection in datasetList:
470        argList.append(["dataset_%s" % counter, selection])
471        counter=counter+1
472       
473    return selectOptions(sessionID, argList)
474
475
476def getVariableOptions(sessionID, secureToken="undefined"):
477    """
478    Get the variable options available.
479    """
480    print "\nMethod called: getVariableOptions\n\n"
481    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="variable")
482   
483   
484def makeVariableSelections(sessionID, secureToken, variableList):
485    """
486    Make selections for variables.
487    """
488    print "Called: makeVariableSelections\n"
489    argList=[]
490    argList.append(["secureToken", secureToken])
491    counter=1
492    for selection in variableList:
493        argList.append(["variable_%s" % counter, selection])
494        counter=counter+1
495       
496    return selectOptions(sessionID, argList)
497   
498
499if __name__=="__main__": 
500    # Serve all functions as Web Service methods.
501   
502    print "Setting up server"
503    portNumber=SOAP_SERVER_PORT
504    print "Serving Web Service on port: %s" % portNumber   
505    dispatch.AsServer(port=portNumber, rpc=True)   
Note: See TracBrowser for help on using the repository browser.