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

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

tidying

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#                x = x.replace("send_to_extract_weather_data",
136#                  '<a href="/submit/form?proc_id=ExtractUKStationData&StationsFile=%s">Use stations to extract UK weather data</a>' % file_url)
137                file_path = mapDownloadURLToFilePath(file_url)
138                x = x.replace("send_to_extract_weather_data",
139                  '<a href="/submit/form?proc_id=ExtractUKStationData&StationsFile=%s">Use stations to extract UK weather data</a>' % file_path) 
140
141            elif item == "JobVolume":
142                x = self._toMB(x)
143
144            elif item == "JobDuration":
145                secs = int(float(x))
146                secs = secs or 1
147                ext = ""
148                if secs > 1: ext = "s"
149                x = "%d second%s" % (secs, ext)
150
151            elif item == "JobCompletionTimeDate":
152                x = x.split(".")[0]
153 
154            resp += "<b>%s</b> = %s<br>" % (mapped_names[i], x)
155
156        # Render output files if completed
157        if self.status == "complete":
158
159            resp += "<h2>OUTPUT FILES</h2>"
160
161            if len(file_set_list) > 0:
162                resp += "The following file outputs are available from your job.<br>"
163            else:
164                resp += 'There are no output files associated with your job. Please click the "View as XML" link above to view your output.<br>'
165
166            for fnode in file_set_list:
167
168                furl = fnode.find("{" + self.namespace +  "}FileURL").text
169                fname = furl.split("/")[-1]
170                len_fname = len(fname)
171
172                p = 70
173                padding = p - len_fname
174                if padding < 0: padding = 0
175
176                resp += ('<br><kbd>%s [<a href="%s">Download</a>]</kbd>' + (padding * "&nbsp;")) % (fname, furl)
177
178                x = fnode.find("{" + self.namespace +  "}FileSize").text
179                x = self._toMB(x) 
180                resp += x
181
182        return resp
183
184   
185    def _toMB(self, bytes, float_format = "%.2f"):
186        "Returns MB string from string or int or float."
187        mb = float_format % (int(bytes) / (2**20))
188        if mb == "0.00": mb = "0.01"
189        mb += " MB"
190        return mb
191       
192
193    def _htmlifyXML(self, xml):
194        "Returns html string that will make XML look ok on HTML page."
195        xml1 = xml.replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")
196
197        def retag(x): return x.replace("<", "&lt;").replace(">", "&gt;")
198
199        open_and_close = re.compile(r"^<([^/]+?)>(.*?)</\1>$")
200        open_and_open = re.compile(r"^<([^/]+?)>\s*<([^/]+?)>$")
201        close_and_close = re.compile(r"^<(/.+?)>\s*<(/.+?)>$")
202        open = re.compile(r"^<([^/]+)>$")
203        close = re.compile(r"^</(.+?)>$")
204        empty = re.compile(r"^<(.+?)/>$")
205        bad = re.compile(r"^</(.+?)>\s*<([^/]+)>$")
206
207        lines = [i.strip() for i in xml.split("\n")]
208
209        spant = '%s<span style="color: #%s;">%s</span><br>'
210        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>'
211
212        x = ""
213        pad = 0
214        pc = "&nbsp;" * 4
215
216        for line in lines:
217
218            colour = pad * 50000 
219            col = ("000000" + hex(colour).split("x")[-1])[-6:]
220            line2 = retag(line)
221
222            open_and_close_m = open_and_close.match(line)
223            open_and_open_m = False#open_and_open.match(line)
224            close_and_close_m = False#close_and_close.match(line)
225            open_m = open.match(line) 
226            close_m = close.match(line)
227            empty_m = empty.match(line)
228            bad_m = bad.match(line)
229
230            if line == lines[0]:
231                line = spant % (pc * pad, "0000ff", line2)
232                pad += 1
233            elif open_and_close_m:
234                groups = open_and_close_m.groups()
235                (tag, content) = groups[:2]
236                line = span2 % (pc * pad, "%s" % col, tag, "000000", content, "%s" % col, tag)
237            elif open_and_open_m:
238                groups = open_and_open_m.groups()
239                (tag1, tag2) = groups[:2]
240                pad += 1
241                line1 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag1)
242                pad += 1
243                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag2)
244                line = line1 + line2
245            elif close_and_close_m:
246                groups = close_and_close_m.groups()
247                (tag1, tag2) = groups[:2]
248                pad -= 1
249                line1 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag1)
250                pad -= 1
251                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % tag2)
252                line = line1 + line2
253            elif bad_m:
254                (first, second) = bad_m.groups()[:2]
255                pad -= 1
256                line1 = spant % (pc * pad, "%s" % col, "&lt;/%s&gt;" % first)
257                line2 = spant % (pc * pad, "%s" % col, "&lt;%s&gt;" % second)
258                line = line1 + line2
259                pad += 1
260            elif open_m:
261                line = spant % (pc * pad, "%s" % col, line2) 
262                pad += 1
263            elif close_m:
264                pad -= 1
265                line = spant % (pc * pad, "%s" % col, line2)
266            elif empty_m:
267                line = spant % (pc * pad, "%s" % col, line2)
268            else:
269                line = spant % (pc * pad, "0000ff", line2)
270
271            x += line
272
273        return x
274
275
Note: See TracBrowser for help on using the repository browser.