source: cows_wps/trunk/cows_wps/controllers/jobviewer.py @ 7086

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows_wps/trunk/cows_wps/controllers/jobviewer.py@7086
Revision 7086, 11.4 KB checked in by astephen, 10 years ago (diff)

Cleaning up jobviewer.

Line 
1import os
2import re
3import glob
4import logging
5import urllib
6import xml.etree.ElementTree as ET
7
8from pylons import request, response, session, tmpl_context as c
9from pylons.controllers.util import abort, redirect_to
10from routes import url_for
11
12
13from cows.exceptions import *
14from cows.pylons.ows_controller import render_ows_exception
15
16from cows_wps.controllers import *
17from cows_wps import utils
18from cows_wps.utils.common import *
19from cows_wps.renderer.ui_renderer import *
20from cows_wps.model.managers import requestManager
21from cows_wps.process_handler.context.process_context import ProcessContext
22from cows_wps.renderer import xml_renderer
23
24from cows_wps.utils.parse_wps_config import wps_config_dict
25from cows_wps.utils.parse_capabilities_config import caps_config_dict
26
27
28from cows_wps.model.managers import requestManager
29
30log = logging.getLogger(__name__)
31
32
33class JobviewerController(BaseController):
34
35
36    def index(self):
37        status_url = str(request.params.getone("status_url"))
38        getter = urllib.urlopen(status_url)
39        job_xml = getter.read()
40        getter.close()
41 
42        job_as_table = self._xmlToTable(job_xml)
43        job_xml_encoded = self._htmlifyXML(job_xml)
44        job_as_plots = "There are no plots available in the outputs of this job."
45
46        resp = """<div id="view_options" style="background: #EEF4FF; border: 2px outset blue; padding: 5px;">
47                <a href="javascript:switchViewTo('table_view');">Normal View</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
48
49        poll_info_div = ""
50        if self.status == "complete":
51            resp += """<a href="javascript:switchViewTo('xml_view');">View as XML</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
52                <a href="javascript:switchViewTo('plots_view');">View Plots (if available)</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
53        elif self.status == "running":
54            poll_info_div = '<div id="poll_info" class="poller"></div>'
55
56        resp  += """
57</div>
58<div id="view_container" style="background: white; border: 2px outset blue; padding: 5px;">
59        <div id="view_contents">
60                <div id="table_view" style="visibility: visible; height: auto;">%s%s</div>""" % (poll_info_div, job_as_table)
61
62        if self.status == "complete":
63            resp += """
64                <div id="xml_view" style="visibility: hidden; height: 0px;">%s</div>
65                <div id="plots_view" style="visibility: hidden; height: 0px;">%s</div>
66</div>""" % (job_xml_encoded, job_as_plots)
67
68        elif self.status == "running":
69            jobviewer_url = url_for(controller='jobviewer', status_url = status_url)
70            base_url = "http://" + request.url[7:].split("/")[0]
71            full_url = base_url + jobviewer_url
72
73            resp += """<input type="hidden" id="poll_url" value="%s" />""" % status_url
74            resp += """<input type="hidden" id="jobviewer_url" value="%s" />""" % jobviewer_url
75            resp += """<script type="text/javascript">
76        function init() {
77                pollWPS();
78        }
79
80</script>"""
81
82        renderer = UIPageRenderer()
83        resp = renderer.render("WPS Job Information",
84                              [("Job: %s" % self.job_id, resp)])
85        return resp
86
87    def _resolveStatus(self, status_node):
88        snode = status_node.getchildren()[0].tag
89        mdict = {"Succeeded": "complete",
90                 "Failed": "failed",
91                 "Accepted": "running",
92                 "Started": "running"}
93
94        for k,v in mdict.items():
95            if snode.find(k) > -1:
96                return v
97        else:
98            raise Exception("Could not match status tag.")
99
100    def _xmlToTable(self, xml):
101        "Chops up xml to get table of outputs."
102        self.node = ET.fromstring(xml)
103        self.namespace_ows = "http://www.opengeospatial.net/ows"
104        self.namespace = "http://www.opengeospatial.net/wps"
105
106        self.status = self._resolveStatus(self.node.find("{" + self.namespace + "}Status")) 
107
108        job_details = self.node.find("{" + self.namespace +  "}ProcessOutputs").find("{" + self.namespace +  "}Output").find("{" + self.namespace +  "}ComplexValue").find("{" + self.namespace +  "}WPSResponseDetails").find("{" + self.namespace +  "}JobDetails")
109
110        file_set_list = job_details.find("{" + self.namespace +  "}FileSet").getchildren()
111
112        items = ["JobID", "JobCompletionTimeDate", "RequestDescription",
113                 "RequestType", "JobCapabilities", "JobDuration", "JobVolume"]
114        mapped_names = ["Job ID", "Completion Time", 
115                        "Request Description", "Request Type", "Job Capabilities"]
116
117        if self.status == "complete":
118            mapped_names.extend(["Job Duration", "Output Size"])
119        else:
120            mapped_names.extend(["Estimated Job Duration", "Estimated Output Size"])
121
122        resp = "<h2>DETAILS</h2>"
123
124        self.job_id = job_details.find("{" + self.namespace + "}JobID").text
125
126        for (i, item) in enumerate(items):
127            x = job_details.find("{" + self.namespace +  "}" + item).text
128            if type(x) != str: 
129                x = "Undefined"
130
131            x = x.strip()
132
133            if item == "JobCapabilities" and x.find("send_to_extract_weather_data") > -1:
134                file_url = file_set_list[0].find("{" + self.namespace +  "}FileURL").text
135                file_path = mapDownloadURLToFilePath(file_url)
136                x = x.replace("send_to_extract_weather_data",
137                  '<a href="/submit/form?proc_id=ExtractUKStationData&StationsFile=%s">Use stations to extract UK weather data</a>' % file_path) 
138
139            elif item == "JobVolume":
140                x = self._toMB(x)
141
142            elif item == "JobDuration":
143                secs = int(float(x))
144                secs = secs or 1
145                ext = ""
146                if secs > 1: ext = "s"
147                x = "%d second%s" % (secs, ext)
148
149            elif item == "JobCompletionTimeDate":
150                x = x.split(".")[0]
151 
152            resp += "<b>%s</b> = %s<br>" % (mapped_names[i], x)
153
154        # Render output files if completed
155        if self.status == "complete":
156
157            resp += "<h2>OUTPUT FILES</h2>"
158
159            if len(file_set_list) > 0:
160                resp += "The following file outputs are available from your job.<br>"
161            else:
162                resp += 'There are no output files associated with your job. Please click the "View as XML" link above to view your output.<br>'
163
164            for fnode in file_set_list:
165
166                furl = fnode.find("{" + self.namespace +  "}FileURL").text
167                fname_html = self._prettyFileNameHTML(furl)
168 
169                resp += fname_html
170
171                size = fnode.find("{" + self.namespace +  "}FileSize").text
172                size = self._toMB(size) 
173                resp += size
174
175                # Check for nested file set
176                fcontents = fnode.find("{" + self.namespace + "}FileContents")
177
178                for nested_fnode in fcontents.getchildren():
179                    nfurl = nested_fnode.find("{" + self.namespace +  "}FileURL").text
180                    nfname_html = self._prettyFileNameHTML(nfurl, nested = True) 
181                    resp += nfname_html
182
183                    nsize = nested_fnode.find("{" + self.namespace +  "}FileSize").text
184                    nsize = self._toMB(nsize)
185                    resp += nsize
186
187        return resp
188
189
190    def _prettyFileNameHTML(self, furl, nested = False):
191        """
192        Returns pretty displayable HTML filename string. If nested is True then
193        don't display download option and nest slightly.
194        """
195        fname = furl.split("/")[-1]
196        len_fname = len(fname)
197
198        p = 70
199        prefix = ""
200        download = '[<a href="%s">Download</a>]' % furl
201        fname_html = "<b>%s</b>" % fname
202
203        if nested:
204            p = 90 
205            prefix = "&nbsp;*&nbsp;" 
206            download = ""
207            fname_html = fname
208
209        padding = p - len_fname
210        if padding < 0: padding = 0
211
212        return ('<br><kbd>%s%s %s</kbd>' + (padding * "&nbsp;")) % (prefix, fname_html, download)
213 
214   
215    def _toMB(self, bytes, float_format = "%.2f"):
216        "Returns MB string from string or int or float."
217        mb = float_format % (int(bytes) / (2**20))
218        if mb == "0.00": mb = "0.01"
219        mb += " MB"
220        return mb
221       
222
223    def _htmlifyXML(self, xml):
224        "Returns html string that will make XML look ok on HTML page."
225        xml1 = xml.replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")
226
227        def retag(x): return x.replace("<", "&lt;").replace(">", "&gt;")
228
229        open_and_close = re.compile(r"^<([^/]+?)>(.*?)</\1>$")
230        open_and_open = re.compile(r"^<([^/]+?)>\s*<([^/]+?)>$")
231        close_and_close = re.compile(r"^<(/.+?)>\s*<(/.+?)>$")
232        open = re.compile(r"^<([^/]+)>$")
233        close = re.compile(r"^</(.+?)>$")
234        empty = re.compile(r"^<(.+?)/>$")
235        bad = re.compile(r"^</(.+?)>\s*<([^/]+)>$")
236
237        lines = [i.strip() for i in xml.split("\n")]
238
239        spant = '%s<span style="color: #%s;">%s</span><br>'
240        span2 = '%s<span style="color: #%s;">&lt;%s&gt;</span><span style="color: #%s;">%s</span><span style="color: #%s;">&lt;/%s&gt;</span><br>'
241
242        x = ""
243        pad = 0
244        pc = "&nbsp;" * 4
245
246        for line in lines:
247
248            colour = pad * 50000 
249            col = ("000000" + hex(colour).split("x")[-1])[-6:]
250            line2 = retag(line)
251
252            open_and_close_m = open_and_close.match(line)
253            open_and_open_m = False#open_and_open.match(line)
254            close_and_close_m = False#close_and_close.match(line)
255            open_m = open.match(line) 
256            close_m = close.match(line)
257            empty_m = empty.match(line)
258            bad_m = bad.match(line)
259
260            if line == lines[0]:
261                line = spant % (pc * pad, "0000ff", line2)
262                pad += 1
263            elif open_and_close_m:
264                groups = open_and_close_m.groups()
265                (tag, content) = groups[:2]
266                line = span2 % (pc * pad, "%s" % col, tag, "000000", content, "%s" % col, tag)
267            elif open_and_open_m:
268                groups = open_and_open_m.groups()
269                (tag1, tag2) = groups[:2]
270                pad += 1
271                line1 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag1)
272                pad += 1
273                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag2)
274                line = line1 + line2
275            elif close_and_close_m:
276                groups = close_and_close_m.groups()
277                (tag1, tag2) = groups[:2]
278                pad -= 1
279                line1 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag1)
280                pad -= 1
281                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag2)
282                line = line1 + line2
283            elif bad_m:
284                (first, second) = bad_m.groups()[:2]
285                pad -= 1
286                line1 = spant % (pc * pad, "%s" % col, "&lt;/%s&gt;" % first)
287                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % second)
288                line = line1 + line2
289                pad += 1
290            elif open_m:
291                line = spant % (pc * pad, "%s" % col, line2) 
292                pad += 1
293            elif close_m:
294                pad -= 1
295                line = spant % (pc * pad, "%s" % col, line2)
296            elif empty_m:
297                line = spant % (pc * pad, "%s" % col, line2)
298            else:
299                line = spant % (pc * pad, "0000ff", line2)
300
301            x += line
302
303        return x
304
305
Note: See TracBrowser for help on using the repository browser.