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

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

Close to alpha 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
47from ZSI import dispatch
48#from ZSI.version import Version
49Version=(2,0,0)#(1,6,1) # of client ZSI - not this one!
50# Sort the ZSI version out
51zsiversion=float("%s.%s" % Version[:2])
52
53# Import package modules
54from pydxs.common import *
55from pydxs.DXController import *
56#from pydxs.serverConfig import *
57from pydxs.DXRMLHandler import *
58from pydxs.DXErrors import *
59
60# Set global variables
61timePattern=re.compile("(\d{4})-(\d{1,2})-(\d{1,2}).(\d{1,2}):(\d{1,2}):(\d{1,2}(\.\d+)?)")
62         
63
64def callControllerDirectly(argList):
65    """
66    Function wrapper to Controller class. This can be called directly
67    to perform all operations or the other Web Service methods can be
68    called in the appropriate order.
69    """   
70    # Parse startTime and endTime arguments into expected form
71    for key, value in argList:
72        args[key]=value
73        for ts in ("start", "end"):
74            if key.find("%sTime_" % ts)>-1:
75                timeComponents=time.strp(value, "%Y-%m-%d %H:%M:%S")[:6]
76       
77                for tk in TIME_KEYS:
78                    # Set each component e.g. startYear_1, endHour_2
79                    args["%s%s_%s" % (ts, tk, key.split("_")[-1])]=timeComponents[TIME_KEYS.index(tk)]
80
81    # Parse horizontalDomain argumnets into expected form
82    if args.has_key("horizontalDomain"):
83        for hk in HORIZ_KEYS:
84            args[hk]=args["horizontalDomain"][HORIZ_KEYS.index(hk)]
85                       
86    return Controller(args)
87
88
89
90def startSession(username="undefined", password="undefined", secureToken="undefined"):
91    """
92    Logs a user in and supplies them with a session ID as well
93    as an encoded security token. The session ID connects them to their
94    current request serverside whilst the security token is used to
95    authorise their access.
96    """
97    print "\nMethod called: startSession\n"
98    args={"username":username, "password":password, "secureToken":secureToken} 
99       
100    try:
101        controller=DXController(args)
102    except Exception, error:
103        return str(error)           
104       
105    sessionID=controller.bag["sessionID"]
106    secureToken=controller.secureToken
107    # Have to return list of lists for ZSI to work (?!)
108
109    if zsiversion<2.0:
110        sessionID=[sessionID]
111        secureToken=[secureToken]
112    print sessionID, secureToken
113    return [sessionID, secureToken]
114       
115
116def getOptions(sessionID, secureToken="undefined", optionCategoryRequested="undefined"):
117    """
118    Returns a category description of the next set of options (or the option category
119    requested by the user), a list of options based
120    on what the user has yet to request, a string explaining some more about this and a
121    security token.
122   
123    The options will be presented following the heirarchy:
124        DatasetGroups
125        Datasets
126        Variables
127        HorizontalDomain
128        VerticalDomain
129        TemporalDomain
130        OutputFormat
131    """   
132    print "\nMethod called: getOptions\n"
133    print "ARGS: sessionID: %s\nsecureToken: %s, optionCategoryRequested:%s" %        (sessionID, secureToken, optionCategoryRequested)
134    if type(sessionID)==type(u""):
135        sessionID=deUnicodeObject(sessionID)
136       
137    args={"sessionID":sessionID, "secureToken":secureToken, 
138                "optionCategoryRequested":optionCategoryRequested}
139
140    try:
141        controller=DXController(args)
142    except Exception, error:
143        return str(error)
144 
145    optionsObject=controller.options
146    secureToken=controller.secureToken
147    print "Options object:", optionsObject
148
149    summaryString=createSummaryString(controller.bag)
150
151    return [[optionsObject+[summaryString]+[secureToken]]]
152
153
154def selectOptions(sessionID, argList):
155    """
156    Makes a selection based on user requirements. This will typically follow a call
157    to getOptions() to find out what the options are.
158    Returns a call to getOptions() to grab the next set of options available to the
159    user. Alternatively, if it fails, an errorString is returned.
160    """
161    print "\nMethod called: selectOptions\n"   
162    if type(sessionID)==type(u""):
163        sessionID=deUnicodeObject(sessionID)
164    args={"sessionID":sessionID}
165   
166    print "Key, Value..."
167    for key,value in argList:
168        key=deUnicodeObject(key)
169        value=deUnicodeObject(value)
170        if type(key)==type(u""):
171            newkey=str(key)
172        else:
173            newkey=key
174        if type(value)==type(u""):
175            value=str(value)
176        args[newkey]=value   
177        print newkey, value
178
179    try:
180        controller=DXController(args)
181    except Exception, error:
182        return str(error)
183   
184    optionsObject=controller.options
185    secureToken=controller.secureToken
186    print "Options object:", optionsObject
187
188    summaryString=createSummaryString(controller.bag)
189
190    return [[optionsObject+[summaryString]+[secureToken]]]
191    """secureToken=controller.secureToken       
192   
193    if args.has_key("optionCategoryRequested"):
194        optionCategoryRequested=args["optionCategoryRequested"]
195    else:
196        optionCategoryRequested="undefined"
197
198    opts=getOptions(sessionID, secureToken, optionCategoryRequested)
199    print "\n\nReturned from select options:\n", opts, "\n\n"
200    return opts"""
201 
202   
203def isComplete(sessionID, secureToken="undefined"):
204    """
205    Returns 1 if the request is complete (i.e. ready to create output file(s))
206    and 0 if not. Also returns a security token.
207    """
208    print "\nMethod called: isComplete\n"
209    optionsObject=getOptions(sessionID, secureToken)
210    secureToken=optionsObject[-1]
211    if optionsObject==[secureToken]:
212        return [[1], secureToken]
213    else:
214        return [[0], secureToken] 
215   
216
217def createOutput(sessionID, secureToken="undefined"):
218    """
219    Creates the outputs specified by user selections. It writes these files
220    locally and returns a list of paths to the data as either FTP or HTTP
221    locations.
222    Returns a list of paths and a security token.
223    """
224    print "\nMethod called: createOutput\n"
225    args={"sessionID":sessionID, "secureToken":secureToken, "getOutput":"getOutput"}
226     
227    try:
228        controller=DXController(args)
229    except Exception, error:
230        return str(error)
231   
232    secureToken=controller.secureToken
233    print controller.bag
234    pathList=controller.bag["outputFilePaths"]
235
236    if zsiversion<2.0:
237        pathList=[pathList]
238        secureToken=[secureToken]
239
240    return [pathList, secureToken]
241
242
243def newSession(sessionID, secureToken="undefined"):
244    """
245    Deletes content of current request.
246    Returns the sessionID and the security token..
247    """
248    print "\nMethod called: newSession\n"   
249    args={"sessionID":sessionID, "secureToken":secureToken, "clearSession":"clearSession"}
250     
251    try:
252        controller=DXController(args)
253    except Exception, error:
254        return str(error) 
255   
256    secureToken=controller.secureToken
257    return [[sessionID], [secureToken]]
258
259
260def setNumberOfDatasets(sessionID, n, secureToken="undefined"):
261    """
262    Re-selects the number of datasets the user wants to deal with in the request.
263    Default is 1.
264    Returns 1 if successful and an errorString if not, as well as a security token.
265    """
266    print "\nMethod called: setNumberOfDatasets\n"
267   
268    args={"sessionID":sessionID, "numberOfDatasets":n, "secureToken":secureToken}
269
270    try:
271        controller=DXController(args)
272    except Exception, error:
273        return str(error)   
274
275    secureToken=controller.secureToken
276    return [[1], [secureToken]]
277       
278       
279def summariseRequest(sessionID, secureToken="undefined"):
280    """
281    Returns a listing of the current request in a string and a security token.
282    """   
283    print "\nMethod called: summariseRequest\n"
284    args={"sessionID":sessionID, "secureToken":secureToken}
285   
286    try:
287        controller=DXController(args)
288    except Exception, error:
289        return str(error)   
290
291    #req=controller.bag
292    summaryString=createSummaryString(controller.bag)
293    """summaryString="\n"+"*"*40
294    summaryString=summaryString+"\nSummary of current request follows\n"
295    summaryString=summaryString+"*"*40+"\n\n"
296   
297    exclusions=("callMethod", "secureToken", "optionCategoryRequested",
298                "action", "targetPage")
299               
300    for key in req.keys():
301        if req[key]!="" and key not in exclusions: 
302            summaryString=summaryString+("%s:\t%s\n" % (key, req[key]))"""
303
304    secureToken=controller.secureToken 
305    return [[summaryString], [secureToken]]
306     
307
308def uploadRequest(sessionID, requestXMLString, secureToken="undefined"):
309    """
310    Allows the user to send a request in the form of a string containing the
311    contents of an XML file conforming to the dx request specification (not
312    yet written). This is also called a Data Subset Specifier.
313    This function parses the XML into a dictionary and then uploads the arguments.
314    Returns a status flag (1=success, None=failure) and the secure token.
315    """
316    print "Calling: uploadRequest\n"
317   
318    try:
319        args=DXRMLParser(requestXMLString).getDictionary()
320    except DXError, error:
321        return "Error parsing the Request XML file you provided:   \n"+str(error)       
322    except Exception, error:
323        return "Error parsing the Request XML file you provided:   \n"+str(error)
324       
325    args["sessionID"]=sessionID
326    args["secureToken"]=secureToken
327   
328    try:
329        controller=DXController(args)
330    except Exception, error:
331        return [[0], [secureToken]]   
332             
333    secureToken=controller.secureToken 
334    return [[1], [secureToken]]
335
336
337def getDataSubsetSpecifier(sessionID, secureToken="undefined"):
338    """
339    Returns the dataSubsetSpecifier XML document (which might be S-metadata)
340    required by a Delivery Service to describe the subset requested, and a
341    security token.
342    """
343    print "\nMethod called: getDataSubsetSpecifier\n"
344    args={"sessionID":sessionID, "secureToken":secureToken}
345   
346    try:
347        controller=DXController(args)
348    except Exception, error:
349        return str(error)     
350   
351    secureToken=controller.secureToken
352    sessionObj=controller.bag
353   
354    try:
355        dataSubsetSpecifierXMLString=DXRMLGenerator(sessionObj).xmlString
356    except Exception, error:
357        return "Could not provide the Request XML string:   "+str(error)
358   
359    print dataSubsetSpecifierXMLStringprint
360    return [[dataSubsetSpecifierXMLString], [secureToken]]
361
362
363def getExtractionCosts(sessionID, secureToken="undefined"):
364    """
365    Returns an estimated duration for the creation of the output data and the
366    estimated volume of the output.
367    """
368    print "\nMethod called: getExtractionCosts\n"   
369    args={"sessionID":sessionID, "secureToken":secureToken, "action":"requestCosts"}
370   
371    try:
372        controller=DXController(args)
373    except Exception, error:
374        return str(error)   
375           
376    secureToken=controller.secureToken
377    print "ESTIMATED COSTS:", (controller.estimatedDuration, controller.estimatedVolume) 
378    (estimatedDuration, estimatedVolume)=(controller.estimatedDuration, controller.estimatedVolume)
379    print "Returning...", [estimatedDuration, estimatedVolume, secureToken]
380
381    if zsiversion<2.0:
382        estimatedDuration=[estimatedDuration]
383        estimatedVolume=[estimatedVolume]
384        secureToken=[secureToken]
385
386    return [estimatedDuration, estimatedVolume, secureToken]       
387
388
389def getDatasetGroupOptions(sessionID, secureToken="undefined"):
390    """
391    Get the dataset group options available.
392    """
393    print "\nMethod called: getDatasetGroupOptions\n\n"
394    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="datasetGroup")
395   
396
397def makeDatasetGroupSelections(sessionID, secureToken, datasetGroupList):
398    """
399    Make selections for dataset group.
400    """
401    print "Called: makeDatasetGroupSelections\n"
402    argList=[]
403    argList.append(["secureToken", secureToken])
404    counter=1
405    for selection in datasetGroupList:
406        argList.append(["datasetGroup_%s" % counter, selection])
407        counter=counter+1
408       
409    return selectOptions(sessionID, argList)
410
411
412def getDatasetOptions(sessionID, secureToken="undefined"):
413    """
414    Get the dataset options available.
415    """
416    print "\nMethod called: getDatasetOptions\n\n"
417    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="dataset")
418   
419   
420def makeDatasetSelections(sessionID, secureToken, datasetList):
421    """
422    Make selections for Dataset.
423    """
424    print "Called: makeDatasetSelections\n"
425    argList=[]
426    argList.append(["secureToken", secureToken])
427    counter=1
428    for selection in datasetList:
429        argList.append(["dataset_%s" % counter, selection])
430        counter=counter+1
431       
432    return selectOptions(sessionID, argList)
433
434
435def getVariableOptions(sessionID, secureToken="undefined"):
436    """
437    Get the variable options available.
438    """
439    print "\nMethod called: getVariableOptions\n\n"
440    return getOptions(sessionID, secureToken="undefined", optionCategoryRequested="variable")
441   
442   
443def makeVariableSelections(sessionID, secureToken, variableList):
444    """
445    Make selections for variables.
446    """
447    print "Called: makeVariableSelections\n"
448    argList=[]
449    argList.append(["secureToken", secureToken])
450    counter=1
451    for selection in variableList:
452        argList.append(["variable_%s" % counter, selection])
453        counter=counter+1
454       
455    return selectOptions(sessionID, argList)
456   
457
458if __name__=="__main__": 
459    # Serve all functions as Web Service methods.
460   
461    print "Setting up server"
462    portNumber=SOAP_SERVER_PORT
463    print "Serving Web Service on port: %s" % portNumber   
464    dispatch.AsServer(port=portNumber, rpc=True)   
Note: See TracBrowser for help on using the repository browser.