# HG changeset patch # User paulb # Date 1196984418 0 # Node ID e77c5130e4ed70a6a0b3ce2ca9edb15907f8c16f # Parent a9b44a61e215981e9a8face9d1d697e327317916 [project @ 2007-12-06 23:40:18 by paulb] Added notes on the StoreSelector, revising the integration-related documentation to mention the class, removing less pertinent notes about using packages to maintain global objects (which is an elementary Python technique). diff -r a9b44a61e215 -r e77c5130e4ed docs/integrating.html --- a/docs/integrating.html Thu Dec 06 23:38:37 2007 +0000 +++ b/docs/integrating.html Thu Dec 06 23:40:18 2007 +0000 @@ -8,33 +8,52 @@
Most Web applications are not self-contained - instead of -providing information which is written into the application -code itself, they may often access data from other places or even -communicate with other systems. Since applications may be very -different in the way that they access external systems or the way -in which they obtain external information, WebStack does not mandate -rigid mechanisms for hooking into such systems or loading such -information. Instead, it is recommended that applications import -packages and modules which provide the functionality necessary to carry -out such integration.
+ +Most Web applications are not self-contained - instead of providing +information which is written into the application code itself, they may often +access data from other places or even communicate with other systems. Since +applications may be very different in the way that they access external systems +or the way in which they obtain external information, WebStack does not mandate +a single mechanism for hooking into such systems or loading such information. +Instead, it is recommended that applications import packages and modules which +provide the functionality necessary to carry out such integration, using the +appropriate conveniences (such as selector +resources) to manage that functionality where appropriate.
+Examples of packages and modules that might be used for integration -purposes include the following:
+ +Examples of packages and modules that might be used for integration purposes +include the following:
+In the simplest of cases, the use of external packages is as -straightforward as importing a Python module (or package) and then -using that module's contents. This can often be done in the resource code; for example:
-import urllib+ +
class MyResource:
def respond(self, trans):
[Examine the transaction, decide what the user wants to do.]
f = urllib.urlopen("http://www.boddie.org.uk/rss/feed.xml")
[Produce some kind of response which tells the user what happened.]
In the simplest of cases, the use of external packages is as straightforward +as importing a Python module (or package) and then using that module's +contents. This can often be done in the resource +code; for example:
+ ++import urllib + +class MyResource: + def respond(self, trans): + [Examine the transaction, decide what the user wants to do.] + + f = urllib.urlopen("http://www.boddie.org.uk/rss/feed.xml") + + [Produce some kind of response which tells the user what happened.] ++
In the above example, here is what happens:
+Where it happens and how often | |||
---|---|---|---|
Import urllib
-to gain access to functionality which we can then use to access a
-remote service. |
- This happens once - when -the above code is itself imported into Python. | +Import urllib to gain access to functionality which we
+ can then use to access a remote service. |
+ This happens once - when the above code is itself imported into + Python. |
Use the urlopen
-function of urllib to actually access a remote service. |
- This happens in the -resource code each time the resource decides to access the service. | +Use the urlopen function of urllib to
+ actually access a remote service. |
+ This happens in the resource code each time the resource decides to + access the service. |
In this case, the functionality is relatively easy to acquire and -does not require any initialisation. But what if we were connecting to -a database? There might be a need to specially initialise the database -module - only once, though - and then repeatedly use it. Consider this -highly artificial example:
-import mydb
connection = mydb.connect("me", "myPassword")
class MyResource:
def respond(self, trans):
[Examine the transaction, decide what the user wants to do.]
results = connection.query("feed", owner="boddie.org.uk")
[Produce some kind of response which tells the user what happened.] + +Using Database Connections
+ +In the above case, the functionality is relatively easy to acquire and does not +require any initialisation. But what if we were connecting to a database? There +might be a need to specially initialise the database module - only once, though +- and then repeatedly use it. Moreover, we may want to ensure that any +transactions created as our resources run are terminated when the resources +have themselves completed their work. At this point, it is worth considering +the
+ +StoreSelector
class, as described in the "Selectors - Components for Dispatching to +Resources" document. Consider this example:+from WebStack.Resources.Selectors import StoreSelector + +class MyResource: + def respond(self, trans): + [Examine the transaction, decide what the user wants to do.] + + connection = trans.get_attributes()["store"] + cursor = connection.cursor() + try: + cursor.execute("select url from feeds where owner=?", ["boddie.org.uk"]) + results = cursor.fetchall() + finally: + cursor.close() + + [Produce some kind of response which tells the user what happened.] + +def get_site_map(connection): + return StoreSelector(MyResource(), connection)+ +The initialisation would be done elsewhere, perhaps in the same module:
+ ++import mydb + +connection = mydb.connect("me", "myPassword") +try: + site = get_site_map(connection) + deploy(site) +finally: + connection.close() ++In the above example, here is what happens:
+
Where it happens and how often | |||
---|---|---|---|
Import the mydb
-module to gain access to database access functionality. |
- This happens once - when -the above code is itself imported into Python. | +Import the mydb module to gain access to database access functionality. |
+ This happens once - when the above code is itself imported into Python. | +
Initialise a database connection using the connect function from the mydb module. |
+ This also happens only once - when the above code is itself imported into Python. | +||
Wrap the application in a StoreSelector which manages
+ the database connection. |
+ This happens in the get_site_map function which
+ prepares the application before deployment. |
||
Initialise a database
-connection using the connect function from the mydb
-module. |
- This also happens only -once - when the above code is itself imported into Python. | +Make the connection available in a transaction object. | +This happens automatically for every incoming transaction or request to access the
+ application - it is managed by the StoreSelector object. |
Use the query
-method on the connection object to access a database. |
- This happens in the -resource code each time the resource decides to access the database. | +Obtain the connection from the attributes on the transaction object;
+ use the cursor method on the connection object to access
+ the database; use the methods on the cursor object. |
+ This happens in the resource code each time the resource decides to + access the database. | +
Terminate the active transaction on the connection object. | +This happens automatically for every completed transaction or request to access the
+ application - it is managed by the StoreSelector object. |
+ ||
Close the database connection using the close method on
+ the connection object. |
+ This also happens only once - when the application is + terminating. |
The choice of initialising the connection may seem arbitrary - why
-not just obtain a connection in the resource? Usually, such decisions
-are made on the basis of efficiency and on constraints outside the
-control of the application - some database systems limit the number of
-connections, for example, and if a large number of resources suddenly
-became active, some of them would fail to obtain connections if the
-connection initialisation code were in the respond
-method of the resource.
Of course, the above resource might not be the only resource to use -database connections. It might then be tempting to initialise a -connection for each module whose resource needs (or, since as normal -Python classes we can put many resources in a single module, whose -resources need) to access a database. But it would surely be more -convenient to define a single, central place to hold such global -resources.
-One approach is to define a module which can be accessed by all
-modules, and thus by all resources. Let us create such a module in the
-file Properties.py
which will reside alongside MyApplication.py
-(or whatever the application module is called). Inside the Properties
-module we can write the following code:
import mydb-
connection = mydb.connect("me", "myPassword")
Now, in each module containing resources which need to access the
-database, all we need to do now is to import the Properties
-module and to use the connection as defined in that module:
import Properties-
class MyResource:
def respond(self, trans):
[Examine the transaction, decide what the user wants to do.]
results = Properties.connection.query("feed", owner="boddie.org.uk")
[Produce some kind of response which tells the user what happened.]
This is a very simple approach that is technically outclassed by the -mechanisms available in some frameworks. Currently, WebStack does not -provide access to those more sophisticated mechanisms, however.
+ +The choice of initialising the connection may seem arbitrary - why not just
+obtain a connection in the resource? Usually, such decisions are made on the
+basis of efficiency and on constraints outside the control of the application -
+some database systems limit the number of connections, for example, and if a
+large number of resources suddenly became active, some of them would fail to
+obtain connections if the connection initialisation code were in the
+respond
method of the resource. Moreover, by using the
+StoreSelector
, a certain amount of "boilerplate" code can be
+hidden away and not written within each resource.