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

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

WOrking with pygments to markup XML.

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