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 | """ |
---|
6 | GSController.py |
---|
7 | =============== |
---|
8 | |
---|
9 | The core class for controlling the package. |
---|
10 | |
---|
11 | """ |
---|
12 | |
---|
13 | # Import required modules |
---|
14 | import sys |
---|
15 | import os |
---|
16 | import time |
---|
17 | |
---|
18 | # Bring package into local scope |
---|
19 | #from serverConfig import BASEDIR |
---|
20 | #sys.path.insert(0, os.path.split(BASEDIR)[0]) |
---|
21 | from pygss import * |
---|
22 | |
---|
23 | |
---|
24 | # Add any other locally required directories in which you have modules. |
---|
25 | for path in LOCAL_PYTHONPATH: |
---|
26 | sys.path.insert(0, path) |
---|
27 | |
---|
28 | |
---|
29 | class GSController: |
---|
30 | """ |
---|
31 | Controls the overall process flow of the a session. |
---|
32 | This class is called through each stage of the interactive process |
---|
33 | and responds according to the environment and arguments provided. |
---|
34 | Note that this class is called by the WSInterface |
---|
35 | class which then reads various instance variables. As a result, very |
---|
36 | little is returned from the methods below. Instead the data is stored |
---|
37 | in the instance object. |
---|
38 | """ |
---|
39 | |
---|
40 | def __init__(self, args): |
---|
41 | """ |
---|
42 | Takes in a group of arguments and then calls the appropriate |
---|
43 | methods to process the user request. |
---|
44 | """ |
---|
45 | self.username=None |
---|
46 | self.password=None |
---|
47 | self.userRoles=[] |
---|
48 | self.sessionID=None |
---|
49 | self.sessionObj=None |
---|
50 | self.bag=self.sessionObj # alias |
---|
51 | self.secureToken=None |
---|
52 | self.error=None |
---|
53 | |
---|
54 | # Parse the arguments |
---|
55 | try: |
---|
56 | self._parseArgs(args) |
---|
57 | except Exception, error: |
---|
58 | raise Exception, error |
---|
59 | |
---|
60 | # If switched on check security |
---|
61 | if self.error==None: |
---|
62 | if RESTRICTED_DATA==1: |
---|
63 | try: |
---|
64 | self._checkSecurity() |
---|
65 | except Exception, error: |
---|
66 | raise Exception, error |
---|
67 | else: |
---|
68 | self.secureToken=None |
---|
69 | |
---|
70 | # Construct the session object |
---|
71 | if self.error==None: |
---|
72 | try: |
---|
73 | self._constructSessionObject() |
---|
74 | except Exception, error: |
---|
75 | raise Exception, error |
---|
76 | |
---|
77 | # Generate the options object |
---|
78 | if self.error==None: |
---|
79 | try: |
---|
80 | self._generateOptions() |
---|
81 | except Exception, error: |
---|
82 | raise Exception, error |
---|
83 | |
---|
84 | |
---|
85 | # Write request to a file if it has some content |
---|
86 | if self.error==None: |
---|
87 | if overlap(["dataset_1", "variable_1", "sessionID", "numberOfDatasets"], |
---|
88 | self.bag.keys()): |
---|
89 | self.bag["accessTime"]=time.time() |
---|
90 | self.sessionObjectManager.writeSessionObject(self.bag) |
---|
91 | |
---|
92 | # Validate the selection against known information |
---|
93 | try: |
---|
94 | self._validate() |
---|
95 | except Exception, error: |
---|
96 | raise Exception, error |
---|
97 | |
---|
98 | # Estimate the cost of the extraction |
---|
99 | creditChecked=None |
---|
100 | if self.error==None: |
---|
101 | if self.bag.has_key("action") and self.bag["action"]=="checkCredit": |
---|
102 | # Check user has sufficient credit |
---|
103 | try: |
---|
104 | self._checkCredit() |
---|
105 | creditChecked="yes" |
---|
106 | except Exception, error: |
---|
107 | raise Exception, error |
---|
108 | |
---|
109 | # Estimate the cost of the extraction |
---|
110 | if self.error==None: |
---|
111 | if self.bag.has_key("action") and self.bag["action"]=="requestCosts": |
---|
112 | |
---|
113 | try: |
---|
114 | (self.estimatedDuration, self.estimatedVolume)=self._createOutput(costOnly=1) |
---|
115 | sizeLimitInBytes=REQUEST_SIZE_LIMIT*2L**20 |
---|
116 | # If size is over limit then send a tidy error to the user |
---|
117 | if self.estimatedVolume>sizeLimitInBytes: |
---|
118 | sizeInMB=self.estimatedVolume/(2L**20.) |
---|
119 | err="""Your request of %.1f MB is over the current %s MB size limit. |
---|
120 | The Data Extractor cannot yet deal with such large requests. |
---|
121 | Consider mailing <A HREF="mailto:%s">%s</A> for advice or submit multiple smaller requests.""" % (sizeInMB, |
---|
122 | REQUEST_SIZE_LIMIT, ADMIN_MAIL_ADDRESS, ADMIN_MAIL_ADDRESS) |
---|
123 | errorCatcher=ErrorHandler(None, self.username, self.sessionID) |
---|
124 | self.error=errorCatcher.displayError(err) |
---|
125 | sys.exit() |
---|
126 | except Exception, error: |
---|
127 | raise Exception, error |
---|
128 | |
---|
129 | # Process the selections to generate some data |
---|
130 | if self.error==None: |
---|
131 | if (self.bag.has_key("getOutput") or (self.bag.has_key("action") and self.bag["action"]=="createOutput")) and creditChecked==None: |
---|
132 | # Check user has sufficient credit |
---|
133 | try: |
---|
134 | self._checkCredit() |
---|
135 | except Exception, error: |
---|
136 | raise Exception, error |
---|
137 | |
---|
138 | try: |
---|
139 | self._createOutput() |
---|
140 | self.logger=LogManager(self.bag) |
---|
141 | self.bag["status"]="complete" |
---|
142 | self.logger.logCompletedRequest(self.bag["outputFilePath"]) |
---|
143 | except Exception, error: |
---|
144 | raise Exception, error |
---|
145 | |
---|
146 | if self.error==None: |
---|
147 | print "Saving session details:\n", self.bag, "\n\n" |
---|
148 | if self.bag.has_key("action") and self.bag["action"]=="clearRequest": |
---|
149 | del self.bag["action"] |
---|
150 | elif self.bag.has_key("action") and self.bag["action"]=="createOutput": |
---|
151 | del self.bag["action"] |
---|
152 | elif self.bag.has_key("getOutput"): |
---|
153 | del self.bag["getOutput"] |
---|
154 | self.sessionObjectManager.writeSessionObject(self.bag) |
---|
155 | else: |
---|
156 | self.logger=LogManager(self.bag) |
---|
157 | self.logger.logError(self.error) |
---|
158 | |
---|
159 | |
---|
160 | def _parseArgs(self, args): |
---|
161 | """ |
---|
162 | Parses the argument dictionary that are sent. |
---|
163 | """ |
---|
164 | self.args={} |
---|
165 | for key, value in args.items(): |
---|
166 | if type(key)==type(u""): |
---|
167 | newkey=str(key) |
---|
168 | else: |
---|
169 | newkey=key |
---|
170 | |
---|
171 | if type(value)==type(u""): |
---|
172 | newvalue=str(value) |
---|
173 | else: |
---|
174 | newvalue=value |
---|
175 | |
---|
176 | self.args[newkey]=newvalue |
---|
177 | |
---|
178 | |
---|
179 | for item in ("username", "password", "secureToken"): |
---|
180 | if self.args.has_key(item): |
---|
181 | value=self.args[item] |
---|
182 | setattr(self, item, value) |
---|
183 | del self.args[item] |
---|
184 | |
---|
185 | print "ARGS and SecureToken:", self.args, self.secureToken |
---|
186 | |
---|
187 | |
---|
188 | def _checkSecurity(self): |
---|
189 | """ |
---|
190 | Checks security by getting username and |
---|
191 | allowed groups from whatever implementation you have put in place. |
---|
192 | """ |
---|
193 | secChecker=SecurityManager(self.username, self.password, self.secureToken) |
---|
194 | # Do something about logout here as well |
---|
195 | |
---|
196 | secCheck=secChecker.validateUser() |
---|
197 | self.username=secChecker.username |
---|
198 | |
---|
199 | if type(secCheck)==type(""): |
---|
200 | raise secCheck |
---|
201 | elif type(secCheck)==type([]): |
---|
202 | (self.secureToken, self.userRoles)=secCheck |
---|
203 | else: |
---|
204 | raise str(secCheck)+str(type(secCheck))#"No response from Security class!" |
---|
205 | |
---|
206 | |
---|
207 | def _constructSessionObject(self): |
---|
208 | """ |
---|
209 | Ensures that all appropriate arguments are being written |
---|
210 | to the session object in the correct manner. Note that the |
---|
211 | session object "sessionObj" is just a dictionary but is read |
---|
212 | in from a shelve object (if it exists already). |
---|
213 | """ |
---|
214 | # self.args now holds the input arguments |
---|
215 | if not self.args.has_key("sessionID"): |
---|
216 | self.sessionObjectManager=SessionObject() |
---|
217 | self.bag=self.sessionObjectManager.dict |
---|
218 | #self.sessionObj["targetPage"]=STAGES=[0] |
---|
219 | else: |
---|
220 | self.sessionObjectManager=SessionObject(self.args["sessionID"]) |
---|
221 | self.bag=self.sessionObjectManager.readSessionObject() |
---|
222 | # Clear the session object if requested |
---|
223 | if self.args.has_key("clearRequest") or self.args.has_key("newRequest"): |
---|
224 | self.sessionObjectManager.clearSessionObject(self.bag) |
---|
225 | |
---|
226 | if type(self.sessionID)==type(u""): |
---|
227 | self.sessionID=str(self.sessionID) |
---|
228 | |
---|
229 | # Update session object with allowed roles at each stage (this is checked every reload) |
---|
230 | self.bag["userRoles"]=self.userRoles |
---|
231 | |
---|
232 | # Say it is under construction at present |
---|
233 | self.bag["status"]="constructing" |
---|
234 | |
---|
235 | # Add the rest of the arguments to the session object |
---|
236 | for key in self.args.keys(): |
---|
237 | self.bag[key]=self.args[key] |
---|
238 | |
---|
239 | # Might need username later |
---|
240 | if self.bag.has_key("username"): |
---|
241 | self.username=self.bag["username"] |
---|
242 | else: |
---|
243 | self.bag["username"]=self.username |
---|
244 | |
---|
245 | |
---|
246 | def _generateOptions(self): |
---|
247 | """ |
---|
248 | Method that examines the current status of the request to create an appropriate |
---|
249 | list of options for the user. Made up of many if clauses to control a logical |
---|
250 | response to the current request. |
---|
251 | """ |
---|
252 | if keyPatternMatch(self.bag, "fileURI")==0: |
---|
253 | print self.bag |
---|
254 | self.options={"AWAITING_FILEURIS":"AWAITING_FILEURIS"} |
---|
255 | return |
---|
256 | |
---|
257 | self.options=OptionHandler(self.bag["userRoles"], self.username, self.bag).options |
---|
258 | return |
---|
259 | |
---|
260 | |
---|
261 | def _validate(self): |
---|
262 | """ |
---|
263 | Validates the selections made by the user. Returns 1 if successful |
---|
264 | and a string if failure. |
---|
265 | """ |
---|
266 | validater=ValidateSelection(self.bag) |
---|
267 | validResponse=validater.validate() |
---|
268 | if validResponse!=1: |
---|
269 | raise validResponse |
---|
270 | |
---|
271 | |
---|
272 | def _checkCredit(self): |
---|
273 | """ |
---|
274 | Checks if the user has the available credit to the selection task. Returns 1 if successful |
---|
275 | and a string if failure. |
---|
276 | """ |
---|
277 | creditChecker=CreditManager(self.username, self.bag) |
---|
278 | creditResponse=creditChecker.creditCheck() |
---|
279 | if creditResponse!=1: |
---|
280 | raise creditResponse |
---|
281 | |
---|
282 | |
---|
283 | def _createOutput(self, costOnly=None): |
---|
284 | """ |
---|
285 | Creates either data file. |
---|
286 | """ |
---|
287 | if costOnly==1: |
---|
288 | requestCoster=RequestCost(self.bag) |
---|
289 | return requestCoster.getDurationAndVolume() |
---|
290 | |
---|
291 | # Now really get data... |
---|
292 | outman=OutputManager(self.bag) |
---|
293 | |
---|
294 | if outman.textOnly: |
---|
295 | print "FOUND POINT VALUE OUTPUT - send to client." |
---|
296 | self.message=outman.textOnly |
---|
297 | # Fill in some request values needed by logger |
---|
298 | for key in ["outputFilePath", "fileFormat"]: |
---|
299 | self.bag[key]="NOT_APPLICABLE" |
---|
300 | return |
---|
301 | |
---|
302 | print """Should really fork this process at this point so that we can return |
---|
303 | something if likely to be large job.""" |
---|
304 | try: |
---|
305 | outman.createOutputs() |
---|
306 | except: |
---|
307 | raise Exception, "Problem generating requested output file." |
---|
308 | |
---|
309 | self.bag["outputFilePath"]=outman.localPath |
---|
310 | self.bag["outputURLPath"]=outman.URLPath |
---|
311 | |
---|