1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/docs/path-strategies.html Sat Jan 20 23:16:22 2007 +0000
1.3 @@ -0,0 +1,32 @@
1.4 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1.5 +<html xmlns="http://www.w3.org/1999/xhtml"><head> <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type" /><title>Path Processing Strategies</title>
1.6 +<meta name="generator" content="amaya 8.1a, see http://www.w3.org/Amaya/" /> <link href="styles.css" rel="stylesheet" type="text/css" /></head>
1.7 +<body><h1>Path Processing Strategies</h1>
1.8 +<p>In the development of most Web applications, the structure of the
1.9 +application - also known as the "site map" - needs to be defined
1.10 +at a very early stage. We might decide that if a user requests a
1.11 +certain path, a particular part of the application will be invoked, and
1.12 +we might define the site map in a number of different ways:</p><p>As a set of acceptable paths...</p><ul><li><code>/</code> is the main page</li><li><code>/services/finance/salaries/</code> is the salary report page</li><li><code>/services/customer/complaints/</code> is the complaints page</li></ul><p>As a tree of resources...</p><ul><li><code>/</code> is the main page</li><ul><li><code>.../services/</code> refers to services (which may not be defined as anything viewable)</li><ul><li><code>.../finance/</code> is the finance department</li><ul><li><code>.../salaries/</code> is the salary report page</li></ul><li><code>.../customer/</code> is the customer service department</li><ul><li><code>.../complaints/</code> is the complaints page</li></ul></ul></ul></ul><p>Since
1.13 +all of the action in WebStack applications takes place inside
1.14 +resources, the challenge is to define resources in such a way which
1.15 +makes processing paths relatively easy.</p><h2>Chaining Resources</h2><p>Whilst the classic resource, as described in <a href="resources.html">"Applications and Resources"</a>, might resemble a simple class whose <code>respond</code>
1.16 +method performs most of the necessary work, it is useful to reconsider
1.17 +such a resource as doing such work only for a particular narrow part of
1.18 +a larger Web application. Moreover, resources are not restricted in
1.19 +their usage of other objects to carry out their purpose, provided they
1.20 +are initialised with references to those objects.Consequently, it makes sense to consider defining a resource which, if it alone cannot process a request, invokes the <code>respond</code> method on another resource in order to get that resource to continue with the act of processing.</p><p>We
1.21 +can apply this insight to the above path processing scenario. If we
1.22 +first employ a resource to examine details of the path, and if that
1.23 +resource then invokes other resources to produce certain pages, we can
1.24 +separate the path processing from the rest of the application's
1.25 +functionality. So, for the first site map strategy, we could define a
1.26 +path processing resource as follows:</p><pre>from WebStack.Generic import EndOfResponse<br /><br />class PathProcessor:<br /><br /> "A path processing resource."<br /><br /> def __init__(self, main_page, salary_report_page, complaints_page):<br /><br /> # Supplied resources are chained to this resource.<br /><br /> self.main_page = main_page<br /> self.salary_report_page = salary_report_page<br /> self.complaints_page = complaints_page<br /><br /> def respond(self, trans):<br /><br /> # This is where the resources are invoked...<br /><br /> path = trans.get_path_without_query() # should really use an encoding here<br /> if path == "/":<br /> self.main_page.respond(trans)<br /> elif path == "/services/finance/salaries/":<br /> self.main_page.respond(trans)<br /> elif path == "/services/finance/salaries/":<br /> self.main_page.respond(trans)<br /><br /> # Administrative details...<br /><br /> else:<br /> trans.set_response_code(404) # not found!<br /> raise EndOfResponse</pre><p>Of
1.27 +course, more elegant methods of mapping paths to resources could be
1.28 +employed - a dictionary might be an acceptable solution, if defined in
1.29 +the initialiser method. The above class might be initialised as follows:</p><pre>main_page = MainResource()<br />salary_report_page = SalaryReportResource()<br />complaints_page = ComplaintsResource()<br />path_processor = PathProcessor(main_page, salary_report_page, complaints_page)</pre><p>For
1.30 +the second site map strategy, we retain the basic parts of the above
1.31 +strategy, focusing only on one level in the path as opposed to the
1.32 +complete path. However, this means that our path processing resources
1.33 +need to know exactly which part of the path they should be
1.34 +considering, and perhaps which part of the path has already been
1.35 +processed.</p><p>As described in <a href="path-info.html">"Paths To and Within Applications"</a>, special path information of the nature required is provided by two methods: <code>get_virtual_path_info</code> and <code>get_processed_virtual_path_info</code>. Such information can thus be obtained and updated at each level in the processing chain.</p><pre>class MainPathProcessor:<br /><br /> "A path processor for the top of the application."<br /><br /> def __init__(self, main_page, services_processor):<br /> self.main_page = main_page<br /> self.services_processor = services_processor<br /><br /> def respond(self, trans):<br /><br /> # This is where the resources are invoked...<br /><br /> path = trans.get_virtual_path_info() # should really use an encoding here<br /> if path == "/":<br /> self.main_page.respond(trans)<br /> elif path.startswith("/services/"):<br /> trans.set_virtual_path_info(path[len("/services"):]) # cut off "/services"<br /> self.services_processor.respond(trans)<br /><br /> # Administrative details...<br /><br /> else:<br /> trans.set_response_code(404) # not found!<br /> raise EndOfResponse</pre><p>A suite of similar classes can be defined and might be initialised as follows:</p><pre>main_page = MainResource()<br />salary_report_page = SalaryReportResource()<br />complaints_page = ComplaintsResource()<br />finance_processor = FinancePathProcessor(salary_report_page)<br />customer_processor = CustomerPathProcessor(complaints_page)<br />services_processor = ServicesPathProcessor(finance_processor, customer_processor)<br />main_processor = MainPathProcessor(main_page, services_processor)</pre><p>Fortunately, this latter strategy is supported by WebStack in the form of the <code>ResourceMap</code> module. See <a href="paths-filesystem.html">"Treating the Path Like a Filesystem"</a> and <a href="resource-map.html">"ResourceMap - Simple Mappings from Names to Resources"</a> for details.</p></body></html>
1.36 \ No newline at end of file