1 #!/usr/bin/env python 2 3 "A WebStack application for a system configurator." 4 5 import WebStack.Generic 6 import XSLForms.Fields 7 import XSLForms.Output 8 import XSLForms.Prepare 9 import XSLOutput 10 import libxml2dom 11 import os 12 13 # NOTE: Move these functions into a common utility library. 14 15 def add_elements(positions, element_name, element_parent_name=None): 16 if not positions: 17 return 18 for position in positions: 19 if element_parent_name: 20 parent_elements = position.xpath(element_parent_name) 21 if not parent_elements: 22 parent_element = position.ownerDocument.createElementNS(None, element_parent_name) 23 position.appendChild(parent_element) 24 else: 25 parent_element = parent_elements[0] 26 else: 27 parent_element = position 28 parent_element.appendChild(position.ownerDocument.createElementNS(None, element_name)) 29 30 def remove_elements(positions): 31 if not positions: 32 return 33 for position in positions: 34 position.parentNode.removeChild(position) 35 36 class ConfiguratorResource: 37 38 "A resource providing a system configurator." 39 40 resource_dir = os.path.join(os.path.split(__file__)[0], "Resources") 41 encoding = "utf-8" 42 43 def respond(self, trans): 44 45 global XSLForms # NOTE: Strangely required to avoid UnboundLocalError! 46 47 # Only obtain field information according to the stated method. 48 49 method = trans.get_request_method() 50 path_info = trans.get_path_info() 51 52 if method == "GET": 53 fields = XSLForms.Fields.Fields(encoding="iso-8859-1", values_are_lists=1) 54 parameters = trans.get_fields_from_path() 55 documents = fields.make_documents(parameters.items()) 56 elif method == "POST": 57 fields = XSLForms.Fields.Fields(encoding=self.encoding, values_are_lists=1) 58 59 # Handle requests for fragments. 60 61 if path_info in ("/cpu", "/memory", "/hard-disks"): 62 text = trans.get_request_stream().read() 63 parameters = {} 64 for text_line in text.split("\r\n"): 65 text_parts = text_line.split("=") 66 text_name, text_value = text_parts[0], "=".join(text_parts[1:]) 67 if not parameters.has_key(text_name): 68 parameters[text_name] = [] 69 parameters[text_name].append(text_value) 70 else: 71 parameters = trans.get_fields_from_body(self.encoding) 72 73 # Get the XML representation of the request. 74 75 documents = fields.make_documents(parameters.items()) 76 else: 77 trans.set_response_code(405) 78 raise WebStack.Generic.EndOfResponse 79 80 # Ensure the presence of a document. 81 82 if documents.has_key("configuration"): 83 configuration = documents["configuration"] 84 else: 85 configuration = fields.new_instance("configuration") 86 print "*", configuration.toString() 87 88 # Add and remove elements according to the selectors found. 89 90 selectors = fields.get_selectors(parameters.items(), documents) 91 add_elements(selectors.get("add-memory-unit"), "memory-unit") 92 remove_elements(selectors.get("remove-memory-unit")) 93 add_elements(selectors.get("add-storage-unit"), "storage-unit") 94 remove_elements(selectors.get("remove-storage-unit")) 95 add_elements(selectors.get("add-hard-disk"), "hard-disk") 96 remove_elements(selectors.get("remove-hard-disk")) 97 98 # Send a response according to certain parameters. 99 # When exported, an XML version of the data is returned. 100 101 if parameters.has_key("export"): 102 trans.set_content_type(WebStack.Generic.ContentType("text/xml", self.encoding)) 103 configuration.toStream(trans.get_response_stream(), trans.get_response_stream_encoding()) 104 105 # When not exported, the data is transformed to produce a normal Web 106 # page. 107 108 else: 109 110 # Transform, adding enumerations/ranges. 111 112 database_xsl = os.path.join(self.resource_dir, "config_database.xsl") 113 database_xml = os.path.join(self.resource_dir, "config_database.xml") 114 proc = XSLOutput.Processor([database_xsl], references={"database" : database_xml}) 115 configuration = proc.get_result(configuration) 116 117 # Start the response. 118 119 trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding)) 120 121 # Define the stylesheet parameters. 122 123 stylesheet_parameters = {} 124 125 # Ensure that an output stylesheet exists. 126 127 trans_xsl = os.path.join(self.resource_dir, "config_output.xsl") 128 template_xml = os.path.join(self.resource_dir, "config_template.xhtml") 129 XSLForms.Prepare.ensure_stylesheet(template_xml, trans_xsl) 130 131 if path_info in ("/cpu", "/memory", "/hard-disks"): 132 template_xml = os.path.join(self.resource_dir, "config_output.xsl") 133 if path_info == "/cpu": 134 trans_xsl = os.path.join(self.resource_dir, "config_output_cpu.xsl") 135 XSLForms.Prepare.ensure_stylesheet_fragment(template_xml, trans_xsl, "cpu-node") 136 elif path_info == "/memory": 137 trans_xsl = os.path.join(self.resource_dir, "config_output_memory.xsl") 138 XSLForms.Prepare.ensure_stylesheet_fragment(template_xml, trans_xsl, "memory-node") 139 elif path_info == "/hard-disks": 140 trans_xsl = os.path.join(self.resource_dir, "config_output_harddisks.xsl") 141 XSLForms.Prepare.ensure_stylesheet_fragment(template_xml, trans_xsl, "hard-disks-node") 142 element_path = parameters.get("element-path", [""])[0] 143 stylesheet_parameters["element-path"] = element_path 144 print "*", stylesheet_parameters["element-path"] 145 146 stylesheet_parameters["application-url"] = \ 147 "http://%s:%s%s" % (trans.get_server_name(), trans.get_server_port(), trans.get_path_without_query()) 148 149 # Complete the response. 150 151 proc = XSLOutput.Processor([trans_xsl], parameters=stylesheet_parameters) 152 proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), 153 configuration) 154 155 import sys 156 proc = XSLOutput.Processor([trans_xsl], parameters=stylesheet_parameters) 157 proc.send_output(sys.stderr, "iso-8859-1", configuration) 158 159 # vim: tabstop=4 expandtab shiftwidth=4