source: TI03-DataExtractor/trunk/pydxs/DXController.py @ 1225

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/trunk/pydxs/DXController.py@1225
Revision 1225, 11.9 KB checked in by astephen, 13 years ago (diff)

Latest version from laptop.
Not yet merged with glue branch.

Line 
1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
5"""
6DXController.py
7================
8
9The core class for controlling the package.
10
11"""
12
13# Import required modules
14import sys
15import os 
16import time 
17
18# Bring package into local scope
19from serverConfig import BASEDIR
20sys.path.insert(0, os.path.split(BASEDIR)[0])
21sys.path.insert(0, "..")
22from pydxs import *
23
24 
25# Add any other locally required directories in which you have modules.
26for path in LOCAL_PYTHONPATH:
27   sys.path.insert(0, path) 
28
29
30class DXController:
31    """
32    Controls the overall process flow of the a session.
33    This class is called through each stage of the extraction process
34    and responds according to the environment and arguments provided.
35    Note that this class is called by the WSInterface
36    class which then reads various instance variables. As a result, very
37    little is returned from the methods below. Instead the data is stored
38    in the instance object.
39    """
40   
41    def __init__(self, args):
42        """
43        Takes in a group of arguments and then calls the appropriate
44        methods to process the user request.
45        """
46        self.username=None 
47        self.password=None
48        self.userRoles=[]
49        self.sessionID=None
50        self.sessionObj=None
51        self.bag=self.sessionObj # alias               
52        self.secureToken="undefined"
53        self.error=None
54   
55        # Parse the arguments
56        try:
57            self._parseArgs(args)
58        except Exception, error:
59            raise DXArgumentError, error
60           
61        # If switched on check security       
62        if self.error==None:
63            if RESTRICTED_DATA==1:
64                try:
65                    self._checkSecurity()
66                except Exception, error:
67                    raise DXSecurityError, error   
68            else:
69                self.secureToken="undefined"
70                   
71        # Construct the session object
72        if self.error==None:   
73            try:   
74                self._constructSessionObject()   
75            except Exception, error:
76                print error
77                raise DXSessionObjectError, error   
78
79        # Generate the options object
80        if self.error==None:   
81            try:   
82                self._generateOptions() 
83            except Exception, error:
84                raise DXOptionHandlingError, error
85
86
87        # Write request to a file if it has some content
88        if self.error==None:
89            if overlap(["datasetGroup_1", "datasetURI_1", "sessionID", "numberOfDatasets"], 
90                      self.bag.keys()):         
91                try:     
92                    self.bag["accessTime"]=time.time() 
93                    self.sessionObjectManager.writeSessionObject(self.bag) 
94                except Exception, error:
95                    raise DXSessionObjectError, error
96                   
97                """# Validate the selection against known information
98                try:       
99                    self._validate()               
100                except Exception, error:
101                    raise DXValidationError, error"""
102           
103        # Estimate the cost of the extraction
104        creditChecked=None
105        if self.error==None:   
106            if self.bag.has_key("action") and self.bag["action"]=="checkCredit":           
107                # Check user has sufficient credit
108                try:       
109                    self._checkCredit()   
110                    creditChecked="yes"             
111                except Exception, error:
112                    raise DXCreditError, error
113                   
114
115        # Estimate the cost of the extraction
116        if self.error==None:   
117            if (self.bag.has_key("action") and self.bag["action"]=="requestCosts") and self.options==[]:
118           
119                try:
120                    (self.estimatedDuration, self.estimatedVolume)=self._createOutput(costOnly=1)
121                    sizeLimitInBytes=REQUEST_SIZE_LIMIT*2L**20
122                    # If size is over limit then send a tidy error to the user
123                    if self.estimatedVolume>sizeLimitInBytes:
124
125                        sizeInMB=self.estimatedVolume/(2L**20.)
126
127                        err="""Your request of %.1f MB is over the current %s MB size limit.   
128The Data Extractor cannot yet deal with such large requests.
129Consider mailing <A HREF="mailto:%s">%s</A> for advice or submit multiple smaller requests.""" % (sizeInMB, 
130                               REQUEST_SIZE_LIMIT, ADMIN_MAIL_ADDRESS, ADMIN_MAIL_ADDRESS)     
131                        raise DXSizeLimitError, err
132                except Exception, error:
133                    raise Exception, error
134                     
135        # Process the selections to generate some data
136        if self.error==None:   
137            if (self.bag.has_key("getOutput") and creditChecked==None) and self.options==[]:
138                # Check user has sufficient credit
139                try:       
140                    self._checkCredit()                     
141                except Exception, error:
142                    raise Exception, error
143                           
144                try:       
145                    self._createOutput() 
146                    self.logger=LogManager(self.bag)       
147                    self.bag["status"]="complete"       
148                    self.logger.logCompletedRequest(self.bag["outputFilePaths"])               
149                except Exception, error:
150                    raise DXProcessingError, error
151       
152        if self.error==None:
153            print "\nSaving session details:\n", self.bag, "\n\n" 
154            if self.bag.has_key("action") and self.bag["action"]=="clearRequest":
155                del self.bag["action"]
156            self.sessionObjectManager.writeSessionObject(self.bag)
157        else:
158            self.logger=LogManager(self.bag) 
159            self.logger.logError(self.error)
160         
161           
162    def _parseArgs(self, args):
163        """
164        Parses the argument dictionary that are sent.
165        """                     
166        self.args={}
167        print "ARGS in...", args
168        for key, value in args.items():
169            if type(key)==type(u""):
170                newkey=str(key)
171            else:
172                newkey=key
173                   
174            if type(value)==type(u""):
175                newvalue=str(value)
176            else:
177                newvalue=value
178               
179            self.args[newkey]=newvalue
180           
181   
182        for item in ("username", "password", "secureToken"):
183            if self.args.has_key(item):             
184                value=self.args[item]               
185                setattr(self, item, value)
186                del self.args[item]
187               
188        print "ARGS and SecureToken:", self.args, self.secureToken
189                             
190
191    def _checkSecurity(self):
192        """
193        Checks security by getting username and
194        allowed groups from whatever implementation you have put in place.
195        """
196        if SECURITY_MODEL=="basic":
197            secChecker=SecurityManager(self.username, self.password, self.secureToken)
198        elif SECURITY_MODEL=="ndg":
199            secChecker=NDGSecurityManager(self.username, self.password, self.secureToken) 
200        else:
201            raise DXSecurityError, "Security model '%s' not supported." % SECURITY_MODEL
202         
203        # Do something about logout here as well
204     
205        secCheck=secChecker.validateUser() 
206        self.username=secChecker.username
207
208        if type(secCheck)==type(""):
209            raise DXSecurityError, secCheck
210        elif type(secCheck)==type([]):
211            (self.secureToken, self.userRoles)=secCheck 
212        else: 
213            raise DXSecurityError, str(secCheck)+str(type(secCheck))#"No response from Security class!"
214           
215
216    def _constructSessionObject(self):
217        """
218        Ensures that all appropriate arguments are being written
219        to the session object in the correct manner. Note that the
220        session object "sessionObj" is just a dictionary but is read
221        in from a shelve object (if it exists already).
222        """     
223        # self.args now holds the input arguments
224        if not self.args.has_key("sessionID"): 
225            self.sessionObjectManager=SessionObject()
226            self.bag=self.sessionObjectManager.dict
227            #self.sessionObj["targetPage"]=STAGES=[0]
228        else: 
229            self.sessionObjectManager=SessionObject(self.args["sessionID"]) 
230            self.bag=self.sessionObjectManager.readSessionObject() 
231            # Clear the session object if requested
232            if self.args.has_key("clearRequest") or self.args.has_key("newRequest"):
233                self.sessionObjectManager.clearSessionObject(self.bag) 
234               
235        if type(self.sessionID)==type(u""):
236            self.sessionID=str(self.sessionID) 
237               
238        # Update session object with allowed roles at each stage (this is checked every reload)
239        self.bag["userRoles"]=self.userRoles
240
241        # Say it is under construction at present
242        self.bag["status"]="constructing"
243       
244        # Add the rest of the arguments to the session object
245        tempbag={}
246        for key in self.args.keys(): 
247            # Do some strict tidying of existing object
248            matchFields=["datasetGroup", "dataset", "variable", "axis", "outputFormat"]
249            goDeeper=0
250            for matchField in matchFields:
251                if key.find(matchField+"_")==0 or goDeeper==1:
252                    deleteDictSubsetMatching(self.bag, r"%s_\d+" % matchField, "regex")
253                    goDeeper=1
254                   
255            tempbag[key]=self.args[key] 
256
257        # Now the tempbag has all we need we can add to self.bag
258        for key, value in tempbag.items():
259            self.bag[key]=value
260       
261        # Might need username later
262        if self.bag.has_key("username"):
263            self.username=self.bag["username"]
264        else:
265            self.bag["username"]=self.username
266           
267        # Sort out time selections if lists
268        axisSelections=getDictSubsetMatching(self.bag, "axis_")
269        axKeys=axisSelections.keys()
270        if len(axKeys)>0:
271            for key, value in axisSelections.items():
272                if type(value[0])==type([1,2]) and len(value[0])==6:
273                    self.bag[key]=("%.4d-%.2d-%.2dT%.2d:%.2d:%f" % tuple(value[0]),
274                                   "%.4d-%.2d-%.2dT%.2d:%.2d:%f" % tuple(value[1]))
275
276
277    def _generateOptions(self):
278        """
279        Method that examines the current status of the request to create an appropriate
280        list of options for the user. Made up of many if clauses to control a logical
281        response to the current request.
282        """
283        optHandler=OptionHandler(self.bag)
284        self.options=optHandler.options
285        print "\nself.options:", self.options
286       
287       
288    def DEPRECATED_validate(self):
289        """
290        Validates the selections made by the user. Returns 1 if successful
291        and a string if failure.
292        """
293        try:
294            ValidateSelection(self.bag)
295        except Exception, error:
296            raise DXValidationError, error
297           
298     
299    def _checkCredit(self):
300        """
301        Checks if the user has the available credit to the selection task. Returns 1 if successful
302        and a string if failure.
303        """
304        creditChecker=CreditManager(self.username, self.bag)
305        creditResponse=creditChecker.creditCheck()
306        if creditResponse!=1:
307            raise creditResponse
308           
309           
310    def _createOutput(self, costOnly=None):
311        """
312        Creates either data files or a dataSubsetSpecifier xml file.
313        """   
314        outputManager=OutputManager(self.bag)
315        pathDict=outputManager.getOutputFilePathDict()
316        sizeDict=outputManager.getOutputSizes()
317        durationDict=outputManager.getOutputDurationEstimates()
318       
319        (outputFilePaths, outputSize, duration)=constructOutputInformation(pathDict, sizeDict, durationDict)
320        self.bag["outputFilePaths"]=outputFilePaths
321           
322        if costOnly==1:
323            return (duration, outputSize)
324       
325        print """Should really fork this process at this point so that we can return
326              something if likely to be large job."""
327        outputManager.createOutputs()
328        pathDict=outputManager.getOutputFilePathDict()
329        sizeDict=outputManager.getOutputSizes()
330        durationDict=outputManager.getOutputDurationEstimates()
331       
332        (outputFilePaths, outputSize, duration)=constructOutputInformation(pathDict, sizeDict, durationDict)
333        self.bag["outputFilePaths"]=outputFilePaths
334       
335
336
337if __name__=="__main__":
338    x=DXController({}).bag
339    sessionID=x["sessionID"]
340    DXController({"sessionID":sessionID, "secureToken":None})
341    DXController({"sessionID":sessionID, "secureToken":None, "datasetGroup_1":"Test Data Group 1"})
342    DXController({"sessionID":sessionID, "secureToken":None, "dataset_1.1":"Test Dataset 1"})   
343    DXController({"sessionID":sessionID, "secureToken":None, "variable_1.1.1":"pqn"})
344    DXController({"sessionID":sessionID, "secureToken":None, "axis_1.1.1.2":(-30,30)}) 
345    DXController({"sessionID":sessionID, "secureToken":None, "axis_1.1.1.1":("1999-01-01T00:00:00", "1999-01-01T06:00:00")})
346    DXController({"sessionID":sessionID, "secureToken":None, "outputFormat_1.1.1":"NetCDF"}) 
347    DXController({"sessionID":sessionID, "secureToken":None, "outputFormat_1.1.1":"NetCDF", "action":"requestCosts"})           
348    DXController({"sessionID":sessionID, "secureToken":None, "getOutput":"getOutput"})   
349   
Note: See TracBrowser for help on using the repository browser.