The XML Switch is the centerpiece of the distributed system. It’s the grand intermediary between information consumers and information suppliers. Overall, the XML Switch is about two things:
It is meant to act as an intermediary between frontend application systems and backend information systems.
It has a fundamental XML messaging structure for greater flexibility between the message sender and the message receiver.
The overall architecture of the XML Switch is about messaging and RPC. The switch is an intermediary between frontend system applications, such as web servers and desktop applications, to backend systems, such as databases and remote services. By using a messaging paradigm rather than wiring the systems directly to each other, you gain a traffic pattern that is decoupled from the applications, and one that is manageable independently.
If you were to patch a CGI script directly into a database, you must use a specialized object to attach to the database as well as understand its schema and data types. By moving to XML, on the other hand, your application and others need only become familiar with an XML data structure. This data structure is produced by the database when asked with the right XML message. The main difference here is that these types of messages can be interpreted by any type of system that may need to understand them either today or years into the future. This sort of flexibility pays off greatly in the design of distributed systems that must evolve over long periods.
The XML Switch presented here is a simple messaging prototype to facilitate the use of XML messages in distributed Python systems. Ideally, your message format should be SOAP, or some other format that is easily shared between emerging commercial systems. The confines of this book do not allow for the complete development of a SOAP messaging server and example client applications, so instead a simple XML message format has been chosen that supports the same type of RPC and messaging functionality.
The XML Switch is composed of three main pieces. First, there is the XMLMessage
. This class is the base unit of
the system. This class and its associated XML message structure are
used as the basis of communication between the XML Switch and its
neighboring applications. Any client, on any platform, can conceivably
create the right kind of XML message for the switch to understand. The
message format is paramount in allowing the system to work.
Of equal importance in the trilogy of supporting players is the
actual XMLSwitchHandler
. This class
implements the HTTP handler used to catch calls against the server. It
is the XMLSwitchHandler
’s duty to
ensure that RPC messages are properly parsed and
executed, and that their return results are quickly sent back to the
caller in XML.
All of this messaging between the Switch and the backend systems
that it’s connected to (via objects) is initiated by clients. Clients
of the XML Switch use the xsc
class
to send XML messages to the switch. True to their black-box designs,
the messages disappear into the switch and information comes back out
in XML format!
XMLMessage
This class is defined in XMLMessage.py, shown in Example 10-7. This class encapsulates developers from the standard message format of the application. An example message (message.xml) is shown in Example 10-5.
XMLSwitchHandler
This class is defined in XMLSwitchHandler.py, shown in Example 10-12, later in this chapter. This class runs the XML switching server that accepts XML messages from the end- user applications and pairs them with backend resources. The results returned by these resources are delivered back to the originating application in another XML message.
xsc
This class offers a one-method client API to send
messages into the XML Switch. The sendMessage
method expects a
well-formed XML message string as an argument, and sends the XML
to the switch. If everything goes well, the server invokes the
method and parameters on one of the hosted objects, and returns
the result back to you.
In this distributed system, messages are sent between systems in a simple XML envelope. This envelope is similar in structure to SOAP. But given the nascent SOAP support in Python and the limited space available in a book such as this, the distributed system in this chapter uses the following simple message structure (in empty form):
<message> <header></header> <body></body> </message>
As long as the document is organized this way, the elements can contain anything you like, including SOAP fragments, web pages, data records, or whatever you can place XML tags around.
Example 10-5 shows a complete, well-formed XML message:
<message> <header><rpc/></header> <body> <object class="CustomerProfile" method="getProfile"> <param>234-E838839</param> </object> </body> </message>
The message format is really a thin envelope consisting of a
message
, a header
, and a body
. The message in Example 10-5 is an RPC call.
When the server receives Example 10-5, it first
examines the header to see that it’s an RPC call. Next, it extracts
the payload and invokes the correct object, method, and parameters.
It then changes the XML message and sends it back to the original
caller through the XML Switch.
Using the XMLMessage
class
is simple. Messages can either be created from an XML string, an XML
document object, or loaded from a file. Once created, access
functions allow you to get at specific parts of the message document
more quickly. The methods getHeader
and getBody
allow you to quickly extract
header or body data. The method setHeader
and setBody
allow you to manipulate an XML
message before sending it to another system for processing. The
whole message can be swapped in and out as either a string or a DOM
object using getXMLMessage
and
setXMLMessage
, along with their
DOM counterparts getXMLMessageDom
and setXMLMessageDom
. The methods
typically used to load and inspect an XML message (like the
message.xml shown in Example 10-5) are shown in
the short script illustrated in Example 10-6.
""" runxm.py - run xml message object """ import XMLMessage from xml.dom.ext import PrettyPrint #from xml.dom.ext.reader.Sax2 import FromXml xm = XMLMessage.XMLMessage( ) xm.loadXMLMessage("message.xml") from xml.dom.ext import PrettyPrint PrettyPrint(xm.getXMLMessageDom( )) print "Change the body to: <body>Hello!</body>" if xm.setBody("<body>Hello!</body>"): print xm.getXMLMessage( )
This code produces the following output:
G:pythonxmlc10>python runxm.py <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE message> <message> <header> <rpc/> </header> <body> <!-- cp.getProfile("234-E838839") --> <object method='getProfile' class='CustomerProfile'> <param>234-E838839</param> </object> </body> </message> Change the body to: <body>Hello!</body> <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE message> <message> <header> <rpc/> </header> <body>Hello!</body> </message>
This output shows the successful loading of the original XML
message, and the successful modification of its body element. The
methods of the XMLMessage
class
are simple, and most behave the same. Here is a quick reference of
the methods implemented by the XMLMessage
class:
setBody(
strXML
)
setBody
takes a
string of XML representing a well-formed body
element and replaces the
existing message’s body
element with the new content.
getBody( )
Returns the body
element as a string of XML (held in self._body
).
setHeader(
strXML
)
Replaces the existing header
element with the supplied XML
string.
getHeader( )
Returns the header
element as a string (held in self._header
).
setXMLMessage(
strXMLMessage
)
Takes an XML message document as a string. The supplied
parameter is then used as the entire XML message. The new
content is returned in all other calls to getBody
, getHeader
, and getXMLMessage
.
setXMLMessageDom(
xmldom
)
Identical to setXMLMessage
but takes an XML DOM
object representing a well-formed message instead of a string
of XML.
loadXMLMessage(
file
)
Sets the contents of the current XML message with the
contents of file
, provided they are
well-formed.
getXMLMessage( )
Returns the entire message XML document as a string.
getXMLMessageDom(
)
Returns the entire message XML document as a DOM instance.
The implementation process in creating these methods utilized much of the DOM work done in this book thus far. However, there are a few notable new techniques, mentioned in the next section.
Most of the work of the XMLMessage
class is done by the setXMLMessage
method. This method takes a
hidden DOM parameter that indicates whether the new message is a
string of XML or a DOM instance.
The complete document is created, and then the member elements
are populated by extracting their respective element names from the
document. This enables the XMLMessage
class to expose access methods
for the message’s two most common elements: the header
and the body
.
if dom: self._dom = strXMLMessage Holder = StringIO.StringIO( ) PrettyPrint(self._dom, Holder) self._xml = Holder.getvalue( ) else: dom = FromXml(strXMLMessage) self._dom = dom self._xml = strXMLMessage # header as string Holder = StringIO.StringIO( ) PrettyPrint(self._dom.getElementsByTagName("header")[0], Holder) self._header = Holder.getvalue( ) # body as string Holder = StringIO.StringIO( ) PrettyPrint(self._dom.getElementsByTagName("body")[0], Holder) self._body = Holder.getvalue( )
By populating the member elements at the initial time of
parsing, the data they represent are stored as strings and are
immediately accessible to any caller. It’s worthy of noting however,
that when you replace an element such as the body
or header
, it’s reconstituted, so to speak, and the
document is reprocessed as a string:
def setBody(self, strXML): """ setBody(strXML) - The supplied XML is used for the body of the XML message. """ xmlstr = FromXml(str("<message>" + self._header + strXML + "</message>")) return self.setXMLMessageDom(xmlstr)
This shortcut requires reparsing the entire document. Another approach is to parse the document out into a collection of nodes, each made read-and-write capable by access functions. However, this DOM-friendly approach requires considerably more code than what is presented here.
Example 10-7 shows the complete listing of XMLMessage.py.
""" XMLMessage.py - a wrapper for message.xml documents """ import StringIO from xml.dom.ext import PrettyPrint from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml class XMLMessage: """ XMLMessage encapsulates a message.xml document from class users. """ def __init__(self): self._dom = "" self._xml = "" def setBody(self, strXML): """ setBody(strXML) - The supplied XML is used for the body of the XML message. """ xmlstr = FromXml(str("<message>" + self._header + strXML + "</message>")) return self.setXMLMessageDom(xmlstr) def getBody(self): """ return body as string """ return self._body def setHeader(self, strXML, dom=0): """ setHeader(strXML) - The supplied XML is used for the header of the XML message. """ xmlstr = FromXml(str("<message>" + strXML + self._body + "</message>")) return self.setXMLMessageDom(xmlstr) def getHeader(self): """ return header as string """ return self._header def setXMLMessage(self, strXMLMessage, dom=0): """ setXMLMessage - uses supplied XML as entire XML message """ try: if dom: # assign dom directly with parameter self._dom = strXMLMessage # populate StringIO object for self._xml Holder = StringIO.StringIO( ) PrettyPrint(self._dom, Holder) # assign string value of dom to self._xml self._xml = Holder.getvalue( ) else: # create dom from supplied string XML dom = FromXml(strXMLMessage) # set member dom property self._dom = dom # set member string property self._xml = strXMLMessage # header as DOM self._headerdom = self._dom.getElementsByTagName("header")[0] # header as string Holder = StringIO.StringIO( ) PrettyPrint(self._dom.getElementsByTagName("header")[0], Holder) self._header = Holder.getvalue( ) # body as DOM self._bodydom = self._dom.getElementsByTagName("body")[0] # body as string Holder = StringIO.StringIO( ) PrettyPrint(self._dom.getElementsByTagName("body")[0], Holder) self._body = Holder.getvalue( ) except: print "Could not create dom from message!" return 0 return 1 def setXMLMessageDom(self, xmldom): """ call setXMLMessage with dom flag """ return self.setXMLMessage(xmldom, dom=1) def loadXMLMessage(self, file): """ loadXMLMessage - build an XML message from a file or URL """ try: dom = FromXmlStream(file) except: print "Could not load XML Message." return 0 return self.setXMLMessageDom(dom) def getXMLMessage(self, dom=0): """ getXMLMessage - returns the entire message as either string of XML or Dom """ if dom: return self._dom else: return self._xml def getXMLMessageDom(self): """ return XML message dom property """ return self.getXMLMessage(dom=1)
The XMLMessage
class
encapsulates a simple XML message format from developers with access
methods. This approach can be used to wrap messages more complex
than these, such as SOAP. This allows you to build parts of your
distributed system to speak SOAP, or to begin migrating your
distributed integration project to SOAP and Python.
The XML Switch is a server process and client API that
allow objects to have their methods and properties exposed over the
Web. XML messages similar to SOAP calls are used to invoke methods on
the server objects. Since SOAP support for Python is thin, and this
book has limited space, a simple XML message format (described in the
last section) was designed for this application. These messages, if
marked with an rpc
element in their
header, are used by the XML Switch to invoke methods on an object, and
return the results in another XML message.
The XML Switch service is provided in large part by the
XMLSwitchHandler
class, developed
later in Example 10-12.
The client applications developed in later portions of this chapter
create XML messages and forward them to the server. The server then
inspects these XML messages to see if they are RPC calls—if so, the
correct object is loaded, the method executed, and the return results
framed in another XML message and sent back to the caller.
There is no reason why a lookup table could not be built, and have routing rules applied to the XML messages as they arrive. There is also no reason why an XML Switch can’t route an XML message to another XML Switch—letting it hop its way to its final destination. This enables message delivery to be decoupled between the sender and receiver. By chaining XML Switch units together, you can create a scalable, routed XML network.
There are two primary clients of the XML Switch. The first, postMsg.html, is simply a web page that posts to the correct server and URL. The switch responds with raw XML that the browser (if Internet Explorer) displays in a tree-view, or with something like Netscape, uses the content handler specified or shows you the file as plain text.
The XML Switch client is a Python API that also can be used as a command-line tool. The API features a single method to submit XML messages to the server, and get back the responses. In this section, we look at the clients of the XML Switch; afterward, we build the server itself.
The postMsg.html
file allows you to post to the server and invoke the echoReponse
method to test your server’s
functionality. The postMsg.html
source is shown in Example
10-8.
<html> <body> <form action="http://centauri:2112/" method="POST"> <p>Input here:</p> <p><textarea name="n" rows=20 cols=80> <message> <header><non-rpc/></header> <body><!-- cp.getProfile("234-E838839") --> <object class="CustomerProfile" method="getProfile"> <param>234-E838839</param> </object> </body> </message> </textarea> </p> <p><input type="submit" value=" submit data "> </p> </form> </body> </html>
Using the echoResponse
method is a good way to test the server’s functionality. If you use
the postMsg.html file created
in Example 10-8, you
can post a sample message and get a response from the XML Switch, as
shown in Figure
10-2.
If you create a message with a header that says <rpc/>
instead of <non-rpc/>
, you actually get the XML
response that the message generates when the RPC is invoked by the
server.
For example, if you enter the following XML in postMsg.html:
<message> <header><rpc/></header> <body> <object class="CustomerProfile" method="getProfile"> <param>983-E2229J3</param> </object> </body> </message>
and hit submit data
, you
get back the raw XML packet from the server. With a browser like
Internet Explorer, it is shown with the default stylesheet, as shown
in Figure 10-3. This
only works if you have a profile with the ID number 983-E2229J3 in
your database. If not, just substitute the ID value with a value
that exists in your database and things should work just
fine.
In fact, postMsg.html
should work for any valid XML message submitted to the server. To
witness some real API work first hand, you need to run the xsc
client from the command line or from
Python code.
The xsc
client
xsc.py, shown in Example 10-11, allows you to
make calls against the XML Switch and inspect the XML messages that
are sent back in return. The XML messages must be kept in a local
file if using xsc
as a
command-line tool.
The XML file is just a message document. Example 10-9 shows a sample
message (msgGetProfile.xml) you
can use with xsc
.
<message> <header><rpc/></header> <body> <object class="CustomerProfile" method="getProfile"> <param>983-E2229J3</param> </object> </body> </message>
Run the file with the message file as a parameter, as shown in Example 10-10.
G:pythonxmlc10> python xsc.py msgGetProfile.xml XMLSwitch Server: localhost:2112 [200 OK 522 bytes] Response: <message> <header> <rpc-response/> </header> <body> <object method='getProfile' class='CustomerProfile'> <response> <CustomerProfile id='983-E2229J3'> <firstname>Larry</firstname> <lastname>BoBerry</lastname> <address1>Northpoint Apartments</address1> <address2>Apt. 2087</address2> <city>Lemmonville</city> <state>MD</state> <zip>12345</zip> </CustomerProfile> </response> </object> </body> </message>
The xsc
command-line
operation prints out a status line indicating the server used, a
line indicating the HTTP response code and message, as well as the
size of the returned XML document. The returned XML is then dumped
out to the command line.
You can also make calls to the XML Switch from your own programs. In fact, the client
applications presented later in this chapter communicate with other
systems via the xsc
client and
small XML rpc
message
invocations.
To use the xsc
API, you
must import xsc
into your
class.
import sys import xsc xc = xsc.xsc( )
Next you need to indicate the server and port combination where the XML Switch is running:
xc.server = "localhost:2112"
You also need some XML to send to the server. It never hurts to load the message from a file.
fd = open(sys.argv[1], "r") xmlmsg = fd.read( ) fd.close( )
Finally, one method call is enough to send your XML message to the server and get the return result:
response = xc.sendMessage(xmlmsg) print response
That is all it takes to invoke remote Python objects that peer into SQL databases and inspect XML stores for relevant information. The XML Switch acts as a broker, taking in your XML requests, and sending you back XML information.
The complete code to xsc.py, the file needed to do both command-line queries against the XML Switch as well as to use it programmatically, is shown in Example 10-11.
""" xsc.py - XMLSwitch Client usage: python xsc.py myRequestFile.xml """ import sys import httplib from urllib import quote_plus class xsc: """ xsc - XMLSwitch Client This class is both the command line and module interface to the XMLSwitch. From the cmd line: $> python xsc.py msgFile.xml The third parameter is an XML file with a valid <message> within it. The response <message> will be written back to the console. As an API: import xsc responseXML = xsc.sendMessage(strXMLMessage) The result is now in responseXML. """ def __init__(self): """ init - establish some public props """ self.server = "localhost:2112" # host:port (80 is http) self.stats = "" def sendMessage(self, strXMLMessage): """ sendMessage(strXML) - this method sends the supplied XML message to the server in self.server. The XML response is returned to the caller. """ # prepare XML message by url encoding... strXMLRequest = quote_plus(strXMLMessage) # connect with server... req = httplib.HTTP(self.server) # add HTTP headers, including content-length # as size of our XML message req.putrequest("POST", "/") req.putheader("Accept", "text/html") req.putheader("Accept", "text/xml") req.putheader("User-Agent", "xsc.py") req.putheader("Content-length", str(len("n=" + strXMLRequest))) req.endheaders( ) # send XML as POST data req.send("n=" + strXMLRequest) # get HTTP response ec, em, h = req.getreply( ) # content-length indicates number of # bytes in response XML message cl = h.get("content-length", "0") # stats us [http-code, http-msg, content-length] self.stats = ("[" + str(ec) + " " + str(em) + " " + str(cl) + " bytes]") # attempt to read XML resonse nfd = req.getfile( ) try: textlines = nfd.read( ) nfd.close( ) # return XML data return textlines except: nfd.close( ) return "" # cmd line operation if __name__ == "__main__": # instantiate server xc = xsc( ) xc.server = "localhost:2112" # read in the message file fd = open(sys.argv[1], "r") xmlmsg = fd.read( ) fd.close( ) # make call to server and print stats, and response print "XMLSwitch Server: ", xc.server response = xc.sendMessage(xmlmsg) print xc.stats print "Response: " print response
The XMLSwitchHandler
class is a BaseHTTPRequestHandler
.
The entire XMLSwitchHandler
class
is shown in Example
10-12. You can use the additional script runxs.py to actually run the server from
the command line. The runxs.py
script is shown in Example
10-13 (in the section Section 10.7).
The architecture behind the XMLSwitchHandler
involves a great deal of
XML. Probably the best method to highlight is processXMLMessagePost
. This method is the
real workhorse. The messages come in as URL-encoded data. To
understand the message sent by the client, it’s necessary to decode
the data and try to get a DOM-friendly XMLMessage
object from the results:
def processXMLMessagePost(self, strPostData): """ processXMLMessagePost(strXMLMessage) - this method creates an XMLMessage from the supplied data and looks up a mapping from XMLMapping.xml to determine what object and method pair to invoke. """ # create message by unquoting post data xmsg = XMLMessage( ) xmsg.setXMLMessage( unquote_plus(strPostData).replace("n=", ""))
At this point, xmsg
is a
new XMLMessage
object
encapsulating the client’s request. The header
is inspected. If the header
’s text content is <rpc/>
, then the server knows to
process it as an rpc
call.
However, if it’s anything else, it’s considered non-rpc
and is sent to the echoResponse
method that uses HTML to send
the request back to the client.
# check header for <rpc/> element strHeader = xmsg.getHeader( ) if strHeader.rfind("<rpc/>") < 0: # send back an HTML echo response self.echoResponse(strPostData) return 0
If indeed the message is an RPC candidate, it’s important to extract out the object name, the method name, and the parameters being supplied to the method invocation. This is not easy work, as the following code shows:
# eval out object.method(params) msgDom = xmsg.getXMLMessageDom( ) objElem = msgDom.getElementsByTagName("object")[0] object = objElem.getAttributeNS('',"class") method = objElem.getAttributeNS('',"method") params = [] paramElems = msgDom.getElementsByTagName("param") # Get parameters as strings for thisparam in paramElems: strParam = StringIO.StringIO( ) PrettyPrint(thisparam, strParam) parameter = strParam.getvalue().strip( ) parameter = parameter.replace("<param>", "") parameter = parameter.replace("</param>", "") params.append(parameter)
After extracting the data necessary for the command, you can begin preparing the command string. The command string holds the name of the local object instance, along with the name of the method to invoke, as well as the parameters supplied. The command is prepared accordingly:
# instantiate correct object if object == "CustomerProfile": from CustomerProfile import CustomerProfileinst = CustomerProfile( )
if object == "XMLOffer": from XMLOffer import XMLOfferinst = XMLOffer( )
# ''''''''''''''''''''''''''''''''''''''''' # add additional object instantiations here # ''''''''''''''''''''''''''''''''''''''''' # prepare cmd stringcmd = "inst." + method + "("
# add parameters to command if necessary, separated # by """ and commas if len(params) == 1: cmd += '"""' + params[0] + '""")' elif len(params) > 1: for pmIndex in range(len(params) - 1):cmd += '"""' + params[pmIndex] + '""", '
cmd += '"""' + params[len(params)-1] + '""")'
# if no params, just close off parens: ( ) if not params:cmd += ")"
The preceding code shows the careful process of using the DOM
to extract the necessary command values from the XML message. These
different values are then combined to make a single cmd
string. The highlighted lines of code
show where the cmd
value is being
altered to fill out the command. The command for the previous
msgGetProfile.xml calls would
have to have been compiled by the XMLSwitchHandler
to look like this:
inst.getProfile("983-E2229J3")
The triple quotes are used to escape any single or double quotations that may be enclosed in the parameters. Of course, if triple quotes are used in the argument, then the process breaks down!
After preparing the methods, we can use the Python eval
command to actually hit the objects
and invoke the appropriate methods:
result = eval(cmd)
After method invocation, the results are then used to build a response XML message. This is done by constructing a temporary DOM with the new values, and then writing a serialized form of that DOM to the socket connection to the client. Of course, once in DOM form it can be validated if you choose to, as well as be modified to remove a document prolog or other type of information that might not be appropriate for embedding inside another XML document.
Example 10-12 shows the full listing of XMLSwitchHandler.py:
""" XMLSwitchHandler.py """ import sys import BaseHTTPServer import StringIO from urllib import unquote_plus from XMLMessage import XMLMessage from xml.dom.ext import PrettyPrint from xml.dom.ext.reader.Sax2 import FromXml class XMLSwitchHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): """ do_GET processes HTTP GET requests on the server port. """ # send generic HTML response self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers( ) self.wfile.write("<html><body>") self.wfile.write("<font face=tahoma size=2>") self.wfile.write("<b>Hello from XMLSwitchHandler!</b>") self.wfile.write("</font></body></html>") def do_POST(self): """ do_POST processes HTTP POST requests and XML packets. """ if self.headers.dict.has_key("content-length"): # convert content-length from string to int content_length = int(self.headers.dict["content-length"]) # read in the correct number of bytes from the client # and process the data raw_post_data = self.rfile.read(content_length) self.processXMLMessagePost(raw_post_data) return 1 else: # bad post self.send_reponse(500) return 0 def processXMLMessagePost(self, strPostData): """ processXMLMessagePost(strXMLMessage) - this method creates an XMLMessage from the supplied data and looks up a mapping from XMLMapping.xml to determine what object and method pair to invoke. """ # create message by unquoting post data xmsg = XMLMessage( ) xmsg.setXMLMessage( unquote_plus(strPostData).replace("n=", "")) # check header for <rpc/> element strHeader = xmsg.getHeader( ) if strHeader.rfind("<rpc/>") < 0: # send back an HTML echo response self.echoResponse(strPostData) return 0 # eval out object.method(params) msgDom = xmsg.getXMLMessageDom( ) objElem = msgDom.getElementsByTagName("object")[0] object = objElem.getAttributeNS('',"class") method = objElem.getAttributeNS('',"method") params = [] paramElems = msgDom.getElementsByTagName("param") # Get parameters as strings for thisparam in paramElems: strParam = StringIO.StringIO( ) PrettyPrint(thisparam, strParam) parameter = strParam.getvalue().strip( ) parameter = parameter.replace("<param>", "") parameter = parameter.replace("</param>", "") params.append(parameter) # instantiate correct object if object == "CustomerProfile": from CustomerProfile import CustomerProfile inst = CustomerProfile( ) if object == "XMLOffer": from XMLOffer import XMLOffer inst = XMLOffer( ) # ''''''''''''''''''''''''''''''''''''''''' # add additional object instantiations here # ''''''''''''''''''''''''''''''''''''''''' # prepare cmd string cmd = "inst." + method + "(" # add parameters to command if necessary, separated # by """ and commas if len(params) == 1: cmd += """"" + params[0] + """"" + ")" elif(len(params) > 1): for pmIndex in range(0, (len(params) - 1)): cmd += """"" + params[pmIndex] + """"" + ", " cmd += """"" + params[len(params)-1] + """")" # if no params, just close off parens: ( ) if not params: cmd += ")" # execute cmd and capture result rezult = "" rezult = eval(cmd) # build response XML returnDom = FromXml( "<message> <header> <rpc-response/> </header> " + " <body> <object class="" + str(object) + "" method="" + str(method) + ""> <response>" + str(rezult) + "</response> </object> </body> </message> ") # optional hook: validate against return dom or # any other special logic # prepare string of document element # (cut out prolog for xml message) strReturnXml = StringIO.StringIO( ) PrettyPrint(returnDom.documentElement, strReturnXml) xmlval = strReturnXml.getvalue( ) # return XML over HTTP to caller self.send_response(200) self.send_header("Content-type", "text/xml") self.send_header("Content-length", str(len(xmlval))) self.end_headers( ) self.wfile.write(str(xmlval)) return 1 def echoResponse(self, strPostData): """ echoResponse(postData) - returns the post data parsed into a header and body chunk. """ # send response self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers( ) # send HTML text self.wfile.write("<html><body>" "<font color=blue face=tahoma size=5>" "<b>Hello from XMLSwitchHandler!</b></font><br><br>" "<font face=arial,verdana,helvetica size=4>" "Attempting to create XML Message " "from source...<br><br>Header:<br><xmp>") msg = XMLMessage( ) msg.setXMLMessage(unquote_plus(strPostData).replace("n=", "")) # parse message into header and body, display as # example on web page self.wfile.write(msg.getHeader( )) self.wfile.write('</xml></font><font face="arial,verdana,helvetica"' ' size="4">Body:<br><xmp>') self.wfile.write(msg.getBody( )) self.wfile.write("</xmp></font></font></body></html>")
3.139.83.199