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

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

Stable-ish version with fully-ish working dxc client.

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