source: cows_wps/trunk/cows_wps/renderer/xml_renderer.py @ 5615

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows_wps/trunk/cows_wps/renderer/xml_renderer.py@5615
Revision 5615, 6.5 KB checked in by spascoe, 11 years ago (diff)

COWS WPS package copied from
 http://proj.badc.rl.ac.uk/svn/dcip/cows-wps/trunk.

This is a stripped down version of the DDP WPS. Some features are
removed and others have been deactivated until we reimplement them in a
more generic way.

Line 
1"""
2xml_renderer.py
3===============
4
5Holds XMLRenderer class to render XML documents for responses.
6
7"""
8
9# Import standard library modules
10import os
11import sys
12#import StringIO
13import copy
14
15import logging
16log = logging.getLogger(__name__)
17
18# Import local modules
19
20from cows_wps import utils
21
22#import genshi template loader for xml templates for responses, such as GetCapabilities
23from genshi.template import TemplateLoader
24from genshi.builder import *
25from pkg_resources import resource_filename
26
27#test imports from cows
28from pylons import request, response, c
29from routes import url_for
30from cows import helpers
31from cows.builder import loadConfigFile
32
33#import config files
34from cows_wps.utils.parse_capabilities_config import caps_config_dict
35
36# Instantiate Genshi template loader
37templateLoader = TemplateLoader(
38    resource_filename('cows_wps', 'templates'),
39    auto_reload=True,
40    )
41
42
43# Define global variables
44
45class Operation(object):
46    def __init__(self, name, href):
47        self.name = name
48        self.href = href
49
50
51def addOperation(ops, name):
52    href=helpers.operation(url_for(qualified=True, action="index")+'?',[]).get.href
53    ops.append(Operation(name,href))
54
55
56
57def GetCapabilitiesResponse(version,service,request,format = "text/xml",updatesequence = "none"):
58    "returns service-level metadata"
59    #loading service metadata from a config file
60   
61    configFile = config.get('capabilities_config')
62    if configFile is None:
63        raise RuntimeError('No OWS configuration file')
64    c.capabilities = loadConfigFile(configFile)
65       
66    # check for version
67    if version == '0.4.0':
68        t= templateLoader.load("wps_getcapabilitiesresponse_template.xml")
69    else:
70        raise RuntimeError("Version %s not supported" % version)
71   
72    #generate capabilities XML
73    ops =[]
74    addOperation(ops, "GetCapabilities")
75    addOperation(ops,"DescribeProcess")
76    addOperation(ops, "Execute") 
77
78    ServiceCapabilitiesXML = t.generate(caps_config_dict=caps_config_dict, ops=ops, c=c).render()
79   
80    return (ServiceCapabilitiesXML, "xml")
81
82
83def DescribeProcessResponse(version, service, request, identifier):
84    "Returns XML for describe process"
85   
86
87    #new function definition using genshi xml template rendering
88    t= templateLoader.load("wps_describeprocess_response.xml")
89   
90    ids =[]
91    if identifier == "all":
92        ids = caps_config_dict["Identifiers"]
93    else:
94        ids.append(identifier)
95
96    describeProcessResponseXML = t.generate(caps_config_dict=caps_config_dict,ids=ids).render()
97   
98    return (describeProcessResponseXML, "xml")
99   
100def validateLength(def_len, out_len):
101
102    _len = def_len.split("_|,")
103    for i in _len:
104        try:
105            if out_len > i:
106                return False
107
108        except:
109            raise Exception ("%s not a integer" % i)
110    return True
111
112def validateType(def_type, param):
113    if def_type == "string":
114       def_type = 'str'
115
116    if checkType(param).__name__ == def_type:
117       return True
118
119    return False
120
121
122def checkType(param):
123
124    return type(param)
125
126
127
128def wrapExecuteResponse(context, identifier, version, input_dict, job_id, is_cached=False):
129    """
130    Wraps full ExecuteResponse XML around specific response.
131    outputs is either a dictionary or an XML snippet.
132    """
133    #new function definition using genshi xml template rendering
134    t= templateLoader.load("wps_execute_response.xml")
135   
136    job_details = context.outputs['job_details']
137    proc_out_defs = caps_config_dict[identifier]["ProcessOutputs"]
138    status_url = url_for(controller='/status', requestId=job_id, qualified=True)
139
140#    log.debug("context.outputs = %s" % (context.outputs,))
141#    log.debug("job_details = %s" % (job_details,))
142   
143    if 'ProcessSpecificContent' in context.outputs:
144        replaceProcessSpecificContextLists(context.outputs['ProcessSpecificContent'])
145
146    for out_tag, out_def in proc_out_defs.items():
147       
148        type = out_def["type"]
149       
150        if type == "xml_complex_value":
151            comp_t = templateLoader.load(out_def["template"])
152           
153            output_xml = Element("ComplexValue", format=out_def["mime_type"], schema=out_def["schema"])
154               
155            #!FIXME: change this template
156            output_xml.append(comp_t.generate(context=context))
157           
158        else:
159
160            if job_details.has_key(out_tag):
161               out_val = job_details[out_tag]
162            else:
163               raise Exception("%s not found in job_details" % out_tag)
164            item_type = out_def["item_type"]
165            if item_type == "list":
166           
167               if checkType(out_val) == checkType([1,2]):
168                   
169                    if validateLength(out_def["allowed_length"], len(out_val)):
170                       value = " ".join(str(i) for i in out_val)
171                       output_xml = Element ("LiteralValue")(value)                           
172                    else:
173                       raise Exception ("%s exceedes allowed length %s" % (out_val, out_def['allowed_length']))     
174               else:
175                    raise Exception ("list type expected but found %s" % type(out_val))
176
177            elif item_type == "item":
178                if validateType(type, out_val):
179                    output_xml = Element ("LiteralValue")(out_val)
180                else:
181                    raise Exception("Expected %s type but value: %s is of type %s" % (type, out_val, checkType(out_val).__name__))
182               
183    log.debug("sending xml response")
184   
185    #!TODO: This is a hack to notify the client of a cached job
186    if is_cached:
187        statusTuple = (context.status, 'Cached Job', context.percentComplete)
188    else:   
189        statusTuple = (context.status, context.statusMessage, context.percentComplete)
190   
191    return t.generate(caps_config_dict=caps_config_dict, identifier=identifier, version=version, 
192                      status=statusTuple, lineage=job_details['lineage'],
193                      output_xml=output_xml, input_dict=input_dict, status_url=status_url).render()
194
195def replaceProcessSpecificContextLists(processSpecificDict):
196    """
197    Looks through the process specific context dictionary and replaces any lists
198    with a string of comma separated values.
199   
200    This is used to avoid the genshi default behaviour of just joinging the
201    list values without any separator.
202    """ 
203   
204    for key, value in processSpecificDict.items():
205
206        if type(value) == list:
207            newValue = ", ".join([ str(x) for x in value])
208            processSpecificDict[key] = newValue   
Note: See TracBrowser for help on using the repository browser.