[Contents] [Prev] [Next] [Index] [Report an Error] [No Frames]


ADSL Workflow

The ADSL workflow performs the same tasks as the FredWorkflow presented earlier, but by a different method. Instead of sending an e-mail to the central office, it generates an HTTP request to an application server. The application receives requests as XML documents and returns the results as XML documents. Another difference is that instead of sending an e-mail to an operator, an external program generates an IP address for a user.

The ADSL workflow (Figure 5) thus demonstrates the use of four work items: HTTP work item, XML Encoder work item, XML Decoder work item, and External Program work item.


Figure 5: ADSL Workflow

The CPEInst, ReceiveCPE, and StaticOrDynamic work items are configured exactly as in FredWorkflow.

The XMLreqMaker is an XML Encoder work item. The validate property is set to false, because the provided document does not contain a <!DOCTYPE> tag. The OutputParameter is set to l2request. The TemplateDocument property is set to the following:

<Req>
    <user id="%ID%">
        <name>%Name%</name>
        <address>%Address%</address>
    </user>
</Req>

The strings set off by percent signs (%) are replaced by the values of the respective token parameters at run time.

The L2Requester is an HTTP work item. It is configured to perform a Post request by the RequestMethod property. The ContentType property is set to text/xml, indicating that an XML document is sent.

The URL property is set to http://localhost:8000, indicating that a Web server is present in the local host and listening at port 8000. Because the protocol was specified as HTTP, the connection is not secure.

The data to be uploaded comes from the l2request parameter, as specified by the InputParameter property, which matches the value of the OutputParameter property of the XMLreqMaker work item. The data obtained from the request is put in the l2response parameter as specified by the OutputParameter property.

The application server ignores the posted document. A typical response looks like the following:

<Response>
    <VPI>35</VPI>
    <VCI>1548</VCI>
</Response>

The XMLrespParser is an XML Decoder work item. It translates a response document to a Workflow Token document (see XML Decoder Work Item in Chapter 16, Work Item Library). The document to be translated is obtained from the l2response parameter, which is specified by the InputParameter property. Because the OutputParameter property is not specified, after the translation, the data will be merged to the token.

The XSL, specified by the TranslatorDocument property, is:

<?xml version="1.0"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
version="1.0">
  <xsl:output method="xml" indent="yes"/>
 
<xsl:template match="Response">
<token>
    <xsl:apply-templates/>
</token>
</xsl:template>
 
<xsl:template match="VCI">
<parameter>
    <xsl:attribute name="name">VCI</xsl:attribute>
    <value>
    <xsl:value-of select="."/>
    </value>
</parameter>
</xsl:template>
 
<xsl:template match="VPI">
<parameter>
    <xsl:attribute name="name">VPI</xsl:attribute>
    <value>
    <xsl:value-of select="."/>
    </value>
</parameter>
</xsl:template>
 
</xsl:stylesheet>

This process produces a document like the following:

<token>
    <parameter name="VPI">
        <value>35</value>
    </parameter>
    <parameter name="VCI">
        <value>1548</value>
    </parameter>
</token>

From this document, the XML Decoder work item is able to create or update the value of the VPI and VCI token parameters with the proper values.

The IPAllocator is an External Program work item. It is configured to send and expect a token, specified by the properties Send Token and Expect Token, respectively. It is also configured to send the VPI and VCI parameters only to the external program, via the Token Properties property. The Command Line property is configured to execute a Python script: python /opt/UMC/wkf/demo/ipalloc.py.

The script is as follows:

import os
import whrandom
 
generator = whrandom.whrandom()
 
vci = os.environ["TOKEN_VCI"]
vpi = os.environ["TOKEN_VPI"]
 
#do some strange computation to obtain the IP
 
ip = "" + `generator.randint(11, 255)` + "." + `generator.randint(0, 255)` + "." + 
`generator.randint(0, 255)` + "." + `generator.randint(0, 255)`
 
#generate the output token
 
print "RadiusFramedIP=" + ip + "\n" #the last char must be a newline

The script above shows what an external program does to obtain token parameters and how to generate an output token. Another important detail is that no return value is specified. Because this is a Python script, a default value of zero is passed back to the operating system, which indicates that the work item succeeded. Any other value would be interpreted as a failure.

The application server code is listed below. It can be found in the file /opt/UMC/wkf/demo/DummyHTTPServer.py. It is a simple Python script that implements a simple HTTP server and reacts in a very simple way to a POST request. More details of the HTTP support in Python can be obtained from the Python Library Reference.

"""Dummy HTTP Server.
 
This module builds on BaseHTTPServer by implementing the standard GET, POST
and HEAD requests in a fairly straightforward manner.
 
"""

__version__ = "0.1"
 
import os
import string
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import select
import whrandom
from StringIO import StringIO
 
class DummyHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
 
    """Simple HTTP request handler with GET, HEAD and POST commands.
 
    Generates a XML document with random values for VPI and VCI
    when receives a POST request.
 
    """
 
    server_version = "DummyHTTP/" + __version__
    generator = whrandom.whrandom()
 
    def do_GET(self):
        """Serve a GET request."""
        self.send_head()
        self.wfile.write("GET request succeded:\n")
 
    def do_HEAD(self):
        """Serve a HEAD request."""
        self.send_head()
 
    def do_POST(self):
        """Serve a POST request."""
        self.send_head()
        size = self.headers.get("Content-Length");
        #generates a constant document
        self.wfile.write("<Response><VPI>" + `self.generator.randint(0, 255)` + 
"</VPI>")
        self.wfile.write("<VCI>" + `self.generator.randint(32, 65535)` + "</VCI>")
        self.wfile.write("</Response>")
        self.wfile.write("\n")
        self.wfile.flush()
        print "document sent"
 
    def send_head(self):
        """Common code for GET and HEAD commands."""
 
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()
 
def test(HandlerClass = DummyHTTPRequestHandler,
         ServerClass = BaseHTTPServer.HTTPServer):
    BaseHTTPServer.test(HandlerClass, ServerClass)
 
 
if __name__ == '__main__':
    test()

[Contents] [Prev] [Next] [Index] [Report an Error] [No Frames]